☆ Beginner - phpreg ☆
[1] 문제
♣ phpreg는 Dreamhack CTF Season 3 Round #6 (Div2)에 출제된 문제이다.
♣ 위 문제는 php 파일을 읽어 Nicname과 Password를 찾아내고 system() 함수를 이용해 플래그를 획득하는 문제이다.
[2] 풀이
♣ 서버를 생성하고 생성된 URL을 클릭하여 웹 서버에 접속한다.
♣ Nickname과 Password를 입력하는 로그인 페이지가 나온다.
♣ 주어진 문제 파일을 다운받아 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>
<style type="text/css">
h4 {
color: rgb(84, 84, 84);
}
.box{
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
pre {
width: 80%;
}
.door_box {
position: relative;
width: 240px;
height: 180px;
margin: 20px 0px;
}
.door_black {
position: absolute;
width: 140px;
height: 180px;
background-color: black;
border-radius: 10px;
right:0px;
}
.door {
z-index: 2;
position: absolute;
width: 140px;
height: 180px;
background-color: #b9abf7;
border-radius: 10px;
right: 100px;
}
.door_cir{
z-index: 3;
position: absolute;
border-radius: 50%;
width: 20px;
height: 20px;
border: 2px solid rgba(255, 222, 113, 0.873);
background-color: #ffea98;
top: calc( 180px / 2 - 10px );
right: 10px;
}
</style>
</body>
</html>
# 비밀번호 필터링
if (preg_match("/[a-zA-Z]/", $input_pw)) {
echo "alphabet in the pw :(";
}
> 비밀번호에 영문자([a-zA-Z]가 포함된 경우 "alphabet in the ps :("를 출력한다.
> 영문자가 포함되지 않아야 한다는 것을 알 수 있다.
# 닉네임 및 비밀번호 변환
$name = preg_replace("/nyang/i", "", $input_name);
$pw = preg_replace("/\d*\@\d{2,3}(31)+[^0-8\"]\!/", "d4y0r50ng", $input_pw);
> preg_replace() 함수 : 문자열 내에서 정규 표현식을 사용하여 특정 패턴을 찾아 다른 문자열로 대체하는 함수이다.
> 닉네임 변환 : preg_replace("/nyang/i", "", $input_name)
= 대소문자를 무시하고 문자열 nyang을 빈문자열로 변환한다.
> 비밀번호 변환 : preg_replace("/ \d*\@\d{2,3}(31)+[^0-8\"]\! /", "d4y0r50ng", $input_pw)
= 정규표현식으로 비밀번호에서 특정 패턴을 찾아 "d4y0r50ng"로 변환한다.
# 정규표현식 해석
/\d*\@\d{2,3}(31)+[^0-8\"]\!/
> \d* : 임의의 숫자 0개 이상을 매치한다.
> \@ : @ 문자를 의미한다.
> \d{2,3} : 2-3 자리의 숫자를 매치한다.
> (31)+ : 숫자 "31"이 한 번 이상 반복된다.
> [^0-8\] : "0-8" 및 "를 제외한 모든 문자를 매치한다.
> \! : ! 문자를 의미한다.
# 로그인 조건 확인
if ($name === "dnyang0310" && $pw === "d4y0r50ng+1+13") {
...
} else {
echo "Wrong nickname or pw";
}
> 닉네임 : 변환된 값이 "dnyang0310"
> 비밀번호 : 변환된 값이 "d4y0r50ng+1+13"
=> 닉네임과 비밀번호가 일치하면 다음단계로 진행하고, 아니면 "Wrong nickname or pw"를 출력한다.
※ NickName과 Password가 PHP 소스코드 파일에 직접 노출되어있지만, 직접 입력할 경우 preg_replace() 함수에 의해 필터링된다. 또한 비밀번호에 알파벳이 들어가면 에러가 나게 된다.
♣ Nickname 입력값 찾기
# name의 값이 " dnyang0310"이 되어야 한다.
# dnyang이 입력되면 빈문자열로 대체되기 때문에 이를 우회해야 한다.
# 필터링이 되지 않도록 우회하기 위해 Nickname에는 "dnyanyangng0310"을 입력해야 한다.
♣ Password 입력값 찾기
# pw에는 알파벳 입력을 할 수 없다. 또한 정규 표현식에 맞게 문자열을 입력해야 원하는 비밀번호 값의 일부를 얻을 수 있다..
# 정규표현식에 해당하는 값을 입력하면 "d4y0r50ng"라는 비밀번호로 대체된다.
# 위 두 조건에 맞추어 Password를 작성하면 "0@1231_!+1+13"가 된다.
♣ "dnyanyangng0310"과 "0@1231_!+1+13"를 입력하여 제출버튼을 클릭한다.
♣ 문제 설명에 system() 함수를 이용하여 플래그를 획득하라고 힌트가 주어져 있었다. 플래그값은 "../flag.txt"에 위치한다.
♣ 소스코드 파일(step2.php)에 cmd 명령에 대한 필터링 처리가 되어있었다. 입력에 "flag"가 포함되면 "Error!"가 출력된다.
else if (preg_match("/flag/i", $cmd)) {
echo "<pre>Error!</pre>";
} else {
echo "<pre>--Output--\n";
system($cmd);
echo "</pre>";
}
♣ "flag"를 입력하지 않기 위해 와일드 카드를 사용하여 "cat ../dream/fla?.txt" 명령을 입력하여 제출한다.
♣ 플래그 값을 얻어내었다.
DH{ad866c64dabaf30136e22d3de2980d24c4da617b9d706f81d10a1bc97d0ab6f6}
♣ 제출 결과
'정보보안 > Dreamhack' 카테고리의 다른 글
[Dreamhack Wargame] Beginner - dreamhack-tools-cyberchef (0) | 2024.12.06 |
---|---|
[Dreamhack Wargame] Beginner : ex-reg-ex (0) | 2024.12.02 |
[Dreamhack Wargame] Beginner - blue whale (0) | 2024.11.29 |
[Dreamhack Wargame] Beginner - Exercise : Docker (0) | 2024.11.28 |
[Dreamhack Wargame] Beginnger - Exersice : SSH (0) | 2024.11.26 |