

서버에 접속해보면 문과 2개의 입력 필드가 보인다.

소스코드를 보면 nickname과 password가 input1,2라는 이름으로 step2.php에 전송되는 것을 볼 수 있다.
그럼 우선 문제 파일에 있는 step2.php 파일 코드를 확인해보자.
<?php
// POST request
if ($_SERVER["REQUEST_METHOD"] == "POST") {
$input_name = $_POST["input1"] ? $_POST["input1"] : "";
$input_pw = $_POST["input2"] ? $_POST["input2"] : "";
input1,2(nickname, password)를 받아서 변수에 저장하고 있다.
// 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);
패스워드에 알파벳이 포함되면 경고문을 출력, 아닌 경우 정규표현식으로 name 값에서 nyang을 제거하고 있고, 패스워드에서는 특정 패턴을 만족하는 문자열을 d4y0r50ng라는 값으로 변환하고 있다.
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"] : "";
name이 dnyang0310이고, pw가 d4y0r50ng+1+13이면 Step2로 넘어가며 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>";
}
}
cmd에 아무런 값도 입력되지 않으면 cmd 폼을 생성하고, cmd에 값이 입력된 경우에는 입력 값에 flag 문자가 들어있으면 Error! 문구를 출력하고, flag 문자열이 없으면 cmd에 입력된 값을 OS에서 실행한 결과를 출력한다.
그럼 우선적으로 풀어야할 것은 아래 정규 표현식을 통한 검증을 우회하는 것.
// 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);
name 값의 nyang 검증의 경우 preg_replace()는 재귀적으로 검증을 수행하는 것이 아니기 때문에 nynyangang처럼 겹쳐서 사용하면 통과가된다.
pw 값의 정규 표현식을 풀어보면 [숫자 0개 이상]@[숫자 2~3개][31 문자 1개 이상][0부터 8, "이 아닌 문자 1개]! 이다.
💡 정규 표현식 옵션
옵션 설명 () 특정 문자를 하나의 그룹으로 처리 ^ 부정 표현 * 0개 이상
검증을 통과하려면 name : dnyang0310에 pw : d4y0r50ng+1+13이어야 하기 때문에 아래와 같이 입력한다.
그럼 아래와 같이 Step2로 넘어가게 된다.

flag 값은 ../dream/flag.txt에 존재한다고 했지만 flag 문자열을 입력하면 에러가 발생한다. 이를 우회하기 위해 와일드 카드(*)를 사용해 파일을 읽어온다. 와일드 카드는 모든 것을 의미한다. 예를들어, f*는 f로 시작하는 모든 파일, *.txt는 확장자가 txt인 모든 파일을 의미하게 된다.
cat ../dream/*, cat ../dream/f*, cat ../dream/*.txt 등등 여러가지 방법으로 flag.txt 파일을 특정할 수 있다.
