티스토리 뷰

Wargame/Dreamhack

phpreg

장일영 2024. 5. 24. 12:00

문제 설명

873

php로 작성된 페이지입니다.

알맞은 Nickname과 Password를 입력하면 Step 2로 넘어갈 수 있습니다.

Step 2에서 `system()` 함수를 이용하여 플래그를 획득하세요.

플래그는 `../dream/flag.txt`에 위치합니다.

플래그의 형식은 DH{...}입니다.

 

풀이

Step 1 페이지의 form에 nickname과 password를 입력하고 일정 조건을 만족하면 Step 2로 넘어갈 수 있다.

<form method="post" action="/step2.php">
	<input type="text" placeholder="Nickname" name="input1">
	<input type="text" placeholder="Password" name="input2">
	<input type="submit" value="제출">
</form>

 

따라서 nickname과 password를 알아낼 수 있는 정보는 `step.php` 파일에 있다.

<?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";
          }
      ?>

 

코드의 흐름을 먼저 살펴보면 유저가 form에 입력한 각각의 값은 php 코드 내에서 `$input_name`, `$input_pw` 변수에 할당된다. 다음으로 조건문이 실행되는데 가장 바깥의 조건문은 요청이 GET인 경우 Not GET request 문자열을 출력하도록 하고, 요청이 POST인 경우 pw filtering을 진행하도록 한다.

pw filtering은 일단 이렇게 생겼다.

<?php
	if(preg_match("/[a-zA-Z]/". $input_pw)) {
		echo "alpabet in the pw :(";
	}
	else {}
?>

 

가장 첫번째 조건은 password에 알파벳 대문자 또는 소문자가 포함하고 있을 때 true를 반환한다. 따라서 password에 알파벳을 포함하지 않으면 else문을 탈 수 있다.

 

else문을 보면 다음과 같다.

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

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

 

우선 입력받은 값 중 특정 패턴과 매치하는 부분을 교체하는 과정을 거친다. 그 결과가 각각 if문의 조건과 일치하면 다음으로 넘어갈 수 있다.

nickname 부분을 먼저 확인하면 `/nyang/i` 정규식과 매치되는 부분을 제거했을 때 dnyang0310이 도출되어야 한다. i 플래그는 대소문자를 구분하지 않는다는 의미다. 만약 nickname으로 dnyang0310을 입력하는 경우 d0310이 된다. 따라서 dnyang라는 문자열을 남기려면 닉네임은dnyangnnyangynyanganyangnnyanggnyang0310이 되어야 한다.

 

password 부분은 `\d*\@\d{2,3}(31)+[^0-8\"]\!`과 매치되는 부분이 d4y0r50ng 문자열로 치환된다. 해당 정규식이 의미하는 바는 다음과 같다.

  • 알파벳, 숫자 또는 언더스코어 중 한 글자 또는 공백 문자에 @를 붙인다.
  • 2글자 이상 3글자 이하의 숫자로 이루어진 문자열에 ’31’을 최소 한 번은 붙인다.
  • 0부터 8 사이의 숫자와 큰따옴표를 포함하지 않는 문자 하나에 느낌표를 붙인다.

위 조건을 만족하는 여러 답이 있겠지만 최소 길이로 하기 위해 @12319!+1+13를 password로 사용했다.

 

이 조건을 만족하면 마지막 분기를 탈 수 있다.

<?php>
	echo '<h4>Step 2 : Almost done...</h4><div class="door_box...';
	
	$cmd = $_POST["cmd"] ? $_POST["cmd"] : "";
	
	if($cmd === "") {
		echo '<p><form method="post" action="/step2.php">...';
	}
	else if (preg_match("/flag/i", $cmd)) {
		echo "<pre>Error!</pre>";
	}
	else {
		echo "<pre>--Output--\n";
		system($cmd);
		echo "</pre>";
	}
<?>

 

코드를 확인해보면 유저가 입력한 값은 `$cmd` 변수에 할당된다. 값이 없으면 form 태그가 출력되고, 값이 있는 경우 `/flag/i` 패턴과 일치하는지 확인한다. 일치하는 경우 Error를 반환하고 그렇지 않으면 `system()` 함수를 호출한다.

따라서 이 명령어를 통해 Flag를 알아내야 한다. 단순히 `cat ../dream/flag.txt` 명령어를 사용하면 위의 if 분기에서 문자열이 매치되어 Error를 반환하게 된다. 따라서 flag 또는 FLAG라는 문자열을 사용하지 않고 해당 파일을 읽어야 한다.

따라서 와일드카드를 이용해 `cat ../dream/*.txt` 명령어를 통해 해당 파일을 읽어오면 Flag를 얻을 수 있다.

'Wargame > Dreamhack' 카테고리의 다른 글

xss-2  (0) 2024.05.24
xss-1  (0) 2024.05.24
ex-reg-ex  (0) 2024.05.24
64se64  (0) 2024.05.24
baby-linux  (0) 2024.05.24
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2026/06   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함