문제 설명

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

알맞은 Input 값을 입력하고 플래그를 획득하세요.

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

풀이

해당 문제로 접속하면 아래와 같은 입력 폼이 2개가 존재한다.

image-20240202200443099

소스 코드

소스 코드는 index.php, check.php, flag.php가 있고 다음과 같다.

index.php

<html>
<head>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
<title>php7cmp4re</title>
</head>
<body>
    <!-- Fixed navbar -->
    <nav class="navbar navbar-default navbar-fixed-stop">
      <div class="container">
        <div class="navbar-header">
          <a class="navbar-brand" href="/">php7cmp4re</a>
        </div>
        <div id="navbar">
          <ul class="nav navbar-nav">
            <li><a href="/">index page</a></li>
          </ul>
        </div><!--/.nav-collapse -->
      </div>
    </nav>
    <div class="container">
      <div class="box">
      <h4>Enter the correct Input.</h4>
        <p>
          <form method="post" action="/check.php">
              <input type="text" placeholder="input1" name="input1">
              <input type="text" placeholder="input2" name="input2">
              <input type="submit" value="제출">
          </form>
        </p>
      </div>

    <?php
        require_once('flag.php');
        error_reporting(0);
    ?> 
    </div> 
</body>
</html>

check.php

<html>
<head>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
<title>php7cmp4re</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="/">php7cmp4re</a>
        </div>
        <div id="navbar">
          <ul class="nav navbar-nav">
            <li><a href="/">Index page</a></li>
          </ul>
        </div><!--/.nav-collapse -->
      </div>
    </nav>
    <div class="container">
    <?php
    require_once('flag.php');
    error_reporting(0);
    // POST request
    if ($_SERVER["REQUEST_METHOD"] == "POST") {
      $input_1 = $_POST["input1"] ? $_POST["input1"] : "";
      $input_2 = $_POST["input2"] ? $_POST["input2"] : "";
      sleep(1);

      if($input_1 != "" && $input_2 != ""){
        if(strlen($input_1) < 4){
          if($input_1 < "8" && $input_1 < "7.A" && $input_1 > "7.9"){
            if(strlen($input_2) < 3 && strlen($input_2) > 1){
              if($input_2 < 74 && $input_2 > "74"){
                echo "</br></br></br><pre>FLAG\n";
                echo $flag;
                echo "</pre>";
              } else echo "<br><br><br><h4>Good try.</h4>";
            } else echo "<br><br><br><h4>Good try.</h4><br>";
          } else echo "<br><br><br><h4>Try again.</h4><br>";
        } else echo "<br><br><br><h4>Try again.</h4><br>";
      } else{
        echo '<br><br><br><h4>Fill the input box.</h4>';
      }
    } else echo "<br><br><br><h3>WHat??!</h3>";
    ?> 
    </div> 
</body>
</html>

flag.php

<?php
    $flag = 'flag{**Sample**}'
?> 


소스 코드를 분석해보면 flag.php는 그냥 FLAG가 flag 변수에 들어있고 형식을 알려준다.


index.php에서 중요한 소스 코드는 아래와 같다. check.php로 POST 메소드로 전송되는 폼이 있고, 입력 폼 2개는 각각 input1과 input2가 존재한다. php 코드는 require_once 함수를 사용해서 flag.php 파일을 읽어오고, error_reporting 함수의 인자가 0이므로 오류 출력을 끈 것을 볼 수 있다.

<form method="post" action="/check.php">
  <input type="text" placeholder="input1" name="input1">
  <input type="text" placeholder="input2" name="input2">
  <input type="submit" value="제출">
</form>
    
<?php
    require_once('flag.php');
    error_reporting(0);
?> 


check.php에서 중요한 소스 코드는 아래 코드이다. check.php처럼 require_once 함수를 사용해 flag.php 파일을 읽어오고 error_reporting 함수로 오류 출력을 끄고 있다. 아래의 주석으로 친절하게 POST 메소드 요청이 어떻게 처리되는지 보여주고 있다. 요청되는 메소드가 POST이면 input1에 입력한 값은 input_1로 input2에 입력한 값은 input_2의 변수에 저장된다.

input_1과 input_2의 값이 둘 다 존재해야 하고 input_1의 길이는 4보다 작아야 한다. 또한 8보다 작고, 7.A보다 작아야 하며, 7.9보다는 커야 한다. input_2는 길이가 3보다 작고 1보다 커야 한다. 값은 숫자 74보다 작아야 하고, 문자 74보다 커야 한다고 한다.

<div class="container">
<?php
require_once('flag.php');
error_reporting(0);
// POST request
if ($_SERVER["REQUEST_METHOD"] == "POST") {
  $input_1 = $_POST["input1"] ? $_POST["input1"] : "";
  $input_2 = $_POST["input2"] ? $_POST["input2"] : "";
  sleep(1);

  if($input_1 != "" && $input_2 != ""){
    if(strlen($input_1) < 4){
      if($input_1 < "8" && $input_1 < "7.A" && $input_1 > "7.9"){
        if(strlen($input_2) < 3 && strlen($input_2) > 1){
          if($input_2 < 74 && $input_2 > "74"){
            echo "</br></br></br><pre>FLAG\n";
            echo $flag;
            echo "</pre>";
          } else echo "<br><br><br><h4>Good try.</h4>";
        } else echo "<br><br><br><h4>Good try.</h4><br>";
      } else echo "<br><br><br><h4>Try again.</h4><br>";
    } else echo "<br><br><br><h4>Try again.</h4><br>";
  } else{
    echo '<br><br><br><h4>Fill the input box.</h4>';
  }
} else echo "<br><br><br><h3>WHat??!</h3>";
?> 
</div> 


FLAG 조건

앞에서 약간 설명이 길었는데 flag의 조건은 다음과 같다.

  1. input1과 input2의 값이 둘 다 존재해야 한다.
  2. input1의 길이는 4보다 작아야 하고, 문자 8과 7.A보다 작아야 하며, 문자 7.9보다 커야 한다.
  3. input2의 길이는 2어야 하고, 숫자 74보다 작고, 문자 74보다 커야 한다.


여기서 숫자도 아니고 문자열과 연산을 하고 있다. php 7.0 이상부터는 타입 힌팅 강화라는 것에 의해 funtion ( int $foo )라고 했을 때, “100”의 문자를 넘기면 int 형의 100으로 변환된다고 한다. 따라서 문자열을 정수로 비교할 때, 문자열을 정수로 변환하려 시도한다는 것을 알 수 있다.


7.A라는 문자열은 처음 보는 형태이다. 이는 찾아보니 16진수로 나타내어 A가 16진수로 0x41이 된다. ASCII 코드 표를 살펴보면 9인 0x39보다 커야 하므로 이 사이에 있는 문자는 : ; < = > ? @의 문자가 해당된다.


따라서 7.:문자를 input1 자리에 넣고 input2는 일단 74를 넣어서 확인해보았다.

image-20240202212326660

개발자 도구로 확인해보면 Good try.라는 문자열이 보인다. 이는 input1의 조건을 만족했다는 문자열이다.

image-20240202222552847


두 번째로 input2에 들어갈 값의 길이는 1과 3 사이이고, “74” < input2 < 74 이어야 한다. php에서는 문자열에서 숫자로 형변환할 때, 숫자가 아닌 문자를 만날 때까지 가장 긴 문자를 찾는다. 만약 7:이라고 한다면 이는 "74"보다 크고 숫자인 74 보다 작게 되는 것이다. 따라서 7 다음에 숫자가 아닌 아무 특수문자나 영문자를 써주면 이를 만족한다. 한글은 참고로 한 글자에 3바이트로 해석하니 안된다.

image-20240202225507628

image-20240202225558979

댓글남기기