티스토리 뷰
문제 설명
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를 얻을 수 있다.
- Total
- Today
- Yesterday
- linux
- SEO
- 회고
- Dreamhack
- Spring Security
- Bandit
- opengraph
- Spring
- PS
- XSS
- test
- oauth2
- webgoat
- sqli
- askers
- java
- React
- Framework
- WEB
- WarGame
- Database
- sql injection
- Misc
- Transaction
- JPA
- DP
- CSRF
- math
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 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 |