본문 바로가기
정보보안/Dreamhack

[Dreamhack Wargame] Beginner - phpreg

by 용오동 2024. 12. 4.
반응형

 

☆ Beginner - phpreg ☆


[1] 문제

♣ phpreg는 Dreamhack CTF Season 3 Round #6 (Div2)에 출제된 문제이다.

♣ 위 문제는 php 파일을 읽어 Nicname과 Password를 찾아내고 system() 함수를 이용해  플래그를 획득하는 문제이다.

 

드림핵 워게임 - phpreg / 출처 : Dreamhack


[2] 풀이

 

♣ 서버를 생성하고 생성된 URL을 클릭하여 웹 서버에 접속한다.

드림핵 워게임 - phpreg / 출처 : Dreamhack

 

♣ Nickname과 Password를 입력하는 로그인 페이지가 나온다.

 

♣ 주어진 문제 파일을 다운받아 php 코드를 확인한다.

드림핵 워게임 - phpreg / 출처 : Dreamhack

 

# 다운받은 step2.php 파일의 소스코드 내용은 아래와 같다.

더보기
<html>
<head>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
<title>PHPreg</title>
</head>
<body>
  <!-- Fixed navbar -->
  <nav class="navbar navbar-default navbar-fixed-top">
    <div class="container">
      <div class="navbar-header">
        <a class="navbar-brand" href="/">PHPreg</a>
      </div>
      <div id="navbar">
        <ul class="nav navbar-nav">
          <li><a href="/">Step 1</a></li>
          <li><a href="/step2.php">Step 2</a></li>
        </ul>
      </div><!--/.nav-collapse -->
    </div>
  </nav><br/><br/><br/>
  <div class="container">
    <div class="box">
      <!-- PHP code -->
      <?php
          // POST request
          if ($_SERVER["REQUEST_METHOD"] == "POST") {
            $input_name = $_POST["input1"] ? $_POST["input1"] : "";
            $input_pw = $_POST["input2"] ? $_POST["input2"] : "";

            // pw filtering
            if (preg_match("/[a-zA-Z]/", $input_pw)) {
              echo "alphabet in the pw :(";
            }
            else{
              $name = preg_replace("/nyang/i", "", $input_name);
              $pw = preg_replace("/\d*\@\d{2,3}(31)+[^0-8\"]\!/", "d4y0r50ng", $input_pw);
              
              if ($name === "dnyang0310" && $pw === "d4y0r50ng+1+13") {
                echo '<h4>Step 2 : Almost done...</h4><div class="door_box"><div class="door_black"></div><div class="door"><div class="door_cir"></div></div></div>';

                $cmd = $_POST["cmd"] ? $_POST["cmd"] : "";

                if ($cmd === "") {
                  echo '
                        <p><form method="post" action="/step2.php">
                            <input type="hidden" name="input1" value="'.$input_name.'">
                            <input type="hidden" name="input2" value="'.$input_pw.'">
                            <input type="text" placeholder="Command" name="cmd">
                            <input type="submit" value="제출"><br/><br/>
                        </form></p>
                  ';
                }
                // cmd filtering
                else if (preg_match("/flag/i", $cmd)) {
                  echo "<pre>Error!</pre>";
                }
                else{
                  echo "<pre>--Output--\n";
                  system($cmd);
                  echo "</pre>";
                }
              }
              else{
                echo "Wrong nickname or pw";
              }
            }
          }
          // GET request
          else{
            echo "Not GET request";
          }
      ?>
    </div>
  </div>

  <style type="text/css">
    h4 {
      color: rgb(84, 84, 84);
    }
    .box{
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
    }
    pre {
      width: 80%;
    }
    .door_box {
      position: relative;
      width: 240px;
      height: 180px;
      margin: 20px 0px;
    }
    .door_black {
      position: absolute;
      width: 140px;
      height: 180px;
      background-color: black;
      border-radius: 10px;
      right:0px;
    }
    .door {
      z-index: 2;
      position: absolute;
      width: 140px;
      height: 180px;
      background-color: #b9abf7;
      border-radius: 10px;
      right: 100px;
    }
    .door_cir{
      z-index: 3;
      position: absolute;
      border-radius: 50%;
      width: 20px;
      height: 20px;
      border: 2px solid rgba(255, 222, 113, 0.873);
      background-color: #ffea98;
      top: calc( 180px / 2 - 10px );
      right: 10px;
    }
  </style>
</body>
</html>​

 

# 비밀번호 필터링

if (preg_match("/[a-zA-Z]/", $input_pw)) {
    echo "alphabet in the pw :(";
}

    > 비밀번호에 영문자([a-zA-Z]가 포함된 경우 "alphabet in the ps :("를 출력한다.

    > 영문자가 포함되지 않아야 한다는 것을 알 수 있다.

 

# 닉네임 및 비밀번호 변환

$name = preg_replace("/nyang/i", "", $input_name);
$pw = preg_replace("/\d*\@\d{2,3}(31)+[^0-8\"]\!/", "d4y0r50ng", $input_pw);

    > preg_replace() 함수 : 문자열 내에서 정규 표현식을 사용하여 특정 패턴을 찾아 다른 문자열로 대체하는 함수이다.

    > 닉네임 변환 : preg_replace("/nyang/i", "", $input_name)

       = 대소문자를 무시하고 문자열 nyang을 빈문자열로 변환한다.

    > 비밀번호 변환 : preg_replace("/ \d*\@\d{2,3}(31)+[^0-8\"]\! /", "d4y0r50ng", $input_pw)

        = 정규표현식으로 비밀번호에서 특정 패턴을 찾아 "d4y0r50ng"로 변환한다.

 

# 정규표현식 해석

/\d*\@\d{2,3}(31)+[^0-8\"]\!/

    > \d* : 임의의 숫자 0개 이상을 매치한다.

    > \@ : @ 문자를 의미한다.

    > \d{2,3} : 2-3 자리의 숫자를 매치한다.

    > (31)+ : 숫자 "31"이 한 번 이상 반복된다.

    > [^0-8\] : "0-8" 및 "를 제외한 모든 문자를 매치한다.

    > \! : ! 문자를 의미한다.

 

# 로그인 조건 확인

if ($name === "dnyang0310" && $pw === "d4y0r50ng+1+13") {
    ...
} else {
    echo "Wrong nickname or pw";
}

    > 닉네임 : 변환된 값이 "dnyang0310"

    > 비밀번호 : 변환된 값이 "d4y0r50ng+1+13"

    => 닉네임과 비밀번호가 일치하면 다음단계로 진행하고, 아니면 "Wrong nickname or pw"를 출력한다.

 

※ NickName과 Password가 PHP 소스코드 파일에 직접 노출되어있지만, 직접 입력할 경우 preg_replace() 함수에 의해 필터링된다. 또한 비밀번호에 알파벳이 들어가면 에러가 나게 된다.

 

♣ Nickname 입력값 찾기

# name의 값이 " dnyang0310"이 되어야 한다.

# dnyang이 입력되면 빈문자열로 대체되기 때문에 이를 우회해야 한다.

# 필터링이 되지 않도록 우회하기 위해 Nickname에는 "dnyanyangng0310"을 입력해야 한다.

 

♣ Password 입력값 찾기

# pw에는 알파벳 입력을 할 수 없다. 또한 정규 표현식에 맞게 문자열을 입력해야 원하는 비밀번호 값의 일부를 얻을 수 있다..

# 정규표현식에 해당하는 값을 입력하면 "d4y0r50ng"라는 비밀번호로 대체된다.

# 위 두 조건에 맞추어 Password를 작성하면  "0@1231_!+1+13"가 된다.

 

♣ "dnyanyangng0310"과 "0@1231_!+1+13"를 입력하여 제출버튼을 클릭한다.

 

♣ 문제 설명에 system() 함수를 이용하여 플래그를 획득하라고 힌트가 주어져 있었다. 플래그값은 "../flag.txt"에 위치한다.

 

♣  소스코드 파일(step2.php)에 cmd 명령에 대한 필터링 처리가 되어있었다. 입력에 "flag"가 포함되면 "Error!"가 출력된다.

else if (preg_match("/flag/i", $cmd)) {
    echo "<pre>Error!</pre>";
} else {
    echo "<pre>--Output--\n";
    system($cmd);
    echo "</pre>";
}

 

♣ "flag"를 입력하지 않기 위해 와일드 카드를 사용하여 "cat ../dream/fla?.txt" 명령을 입력하여 제출한다.

 

♣ 플래그 값을 얻어내었다.

DH{ad866c64dabaf30136e22d3de2980d24c4da617b9d706f81d10a1bc97d0ab6f6}

 

♣ 제출 결과


반응형