일단 접속을 해보면
index.php 창이 발생한다. 자 그럼 코드를 보자
코드를 다운받으면 index.php, step2.php 가 주어지는데 우리는 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>
</body>
</html>
코드를 보면 name=dnyang0310&& pw=d4y0r50ng+1+13
이 성립되면 step2.php로 넘어간다.
그리고 정규표현식을 보자
$name = preg_replace("/nyang/i", "", $input_name);
/nyang/: 이 정규식은 문자열에서 nyang이라는 단어를 찾는다.
i 플래그: i는 대소문자를 구분하지 않도록 만듭니다. 즉, Nyang, NYANG 등 다양한 대소문자 조합을 모두 매칭할 수 있다.
preg_replace: 이 함수는 해당 패턴을 찾아서 빈 문자열 ""로 치환한다.
즉, input_name에서 "nyang"이라는 문자열이 있으면 제거됩니다.
예를 들어:
입력: dnyang0310
결과: d0310
그럼 이걸 우회 할려면 어떻게 해야할까?
dnynyangang0310 이렇게 nyang을 중간에 nynyangang 넣어주면 우우회할 수 있다.
그 다음 비밀번호 정규표현식을 보자
$pw = preg_replace("/\d*\@\d{2,3}(31)+[^0-8\"]\!/", "d4y0r50ng", $input_pw);`
이 정규식은 특정 패턴을 "d4y0r50ng"으로 치환한다.
\d:
\d: 숫자(0-9)
: 앞의 패턴이 0번 이상 반복
\@:
특수 문자 @를 그대로 매칭
\d{2,3}:
\d{2,3}: 숫자가 2자리에서 3자리까지 등장하는 부분을 매칭
(31)+:
(31): 숫자 31이 등장하는 부분
+: 1번 이상 반복
즉, 31이 한 번 이상 반복되는 부분
예를 들어, 31, 3131, 313131 등이 매칭됩니다.
[^0-8\"]:
[^...]: 대괄호 안의 내용을 제외한 문자
0-8: 숫자 0부터 8까지를 의미
\": 큰따옴표(")
즉, 숫자 0에서 8 사이의 숫자나 큰따옴표가 아닌 문자
이 부분에서는 숫자 9나 다른 특수 문자
!:
! 문자를 그대로 매칭
그럼 1@11319!+1+13 이 정확한 답이 될 수 있다.
여기까지 풀었으면
이 화면을 볼 수 있다.
간단히 ls 를 입력하면
리눅스 명령어가 된다는걸 알 수 있고
문제에서 말한 ../dream/flag.txt 그래서 cat ../dream/flag.txt 하면 에러가 발생한다.
보니까
else if (preg_match("/flag/i", $cmd)) {
echo "<pre>Error!</pre>";
}
이렇게 필터링 하고 있다.
그렇다면
cat ../dream/fla*.txt
이게 정답이다.