본문 바로가기

웹 해킹

파일 다운로드 취약점과 실습 문제 풀이

- 파일 다운로드 취약점 이란?

 

    > 파일 다운로드 기능이 존재하는 웹 페이지에서 경로를 임의로 조작하여 내부의 자료를 다운로드 할 수 있는 취약점이다.

 

특징으로는 하드 코딩된 소스코드를 그대로 볼 수 있다는 점이 있다.

해당 취약점을 활용, 소스코드를 그대로 리버싱하여 무엇을 할 수 있을지 실습 문제로 알아보자.


문제 1 . Get Flag File 1

회원가입후 게시판에 파일 업로드를 하였다.

게시판 글 쓰기

이후 해당 파일의 다운로드 링크를 복사하여 보게되면 아래와 같은 링크를 얻을 수 있다.

http://ctf.segfaulthub.com:3184/index.php?page=download&filePath=%2Fvar%2Fwww%2Fhtml%2Fuploads%2F8_webshell.png

파일 경로를 그대로 받아와 해당 파일을 다운로드 할 수 있게 만들어진 코드인걸로 파악이 된다.

 

POC로 /etc/passwd를 가져와 보았다.

위와 같이 파일 경로가 그대로 노출이 되기 때문에 파일 다운로드 취약점을 활용 할 수 있게 되었다.

그치만 내가 얻어야하는건 POC가 아닌 flag. 다운로드 취약점을 활용할 만한 것을 살펴보다가, 위에 보았던 URL을 보면 index.php가 있음을 알고 index.php를 다운로드 해보았다.

 

index.php 파일을 살펴본 결과 웹 페이지 내의 기능을 하는 함수들을 모아놓은것으로 보였다. 친절하게 flag 파일은 ROOT경로에 있으며 /flag.txt를 확인하라고 한다. 다운로드 취약점을 활용 flag를 획득하였다.

 


문제 2 . Get Flag File 2

 

이번에도 위와 똑같은 시나리오로 진행한 후 index.php를 불러왔다.

 

위와 동일하게 /flag.txt로 바로 접근해보려 했으나 실패, 다른 것을 더 찾아보기로 하였다.

그중 글작성과, php 관련 확장자 필터링 함수를 보았다

// PHP 관련 확장자 필터링 함수
function isDangerousFile($filename) {
    $dangerous_extensions = [
        'php', 'php3', 'php4', 'php5', 'php7', 'phtml', 'phar',
        'inc', 'pl', 'py', 'jsp', 'asp', 'aspx', 'cgi', 'sh',
        'exe', 'bat', 'cmd', 'com', 'scr', 'pif', 'vbs', 'js'
    ];
    
    $extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
    return in_array($extension, $dangerous_extensions);
}
// 글쓰기 처리
if ($page === 'write') {
    if (!isset($_SESSION['user'])) {
        header('Location: index.php?page=login');
        exit;
    }
    if ($_SERVER['REQUEST_METHOD'] === 'POST') {
        $title = $_POST['title'] ?? '';
        $content = $_POST['content'] ?? '';
        $user_id = $_SESSION['user']['id'];
        if (!$title || !$content) {
            $error = '제목과 내용을 입력하세요.';
            render('write', ['error' => $error]);
            exit;
        }
        $stmt = $conn->prepare('INSERT INTO posts (user_id, title, content) VALUES (?, ?, ?)');
        $stmt->bind_param('iss', $user_id, $title, $content);
        if ($stmt->execute()) {
            $post_id = $conn->insert_id;
            // 파일 업로드 처리
            if (!empty($_FILES['file']['name'])) {
                $filename = basename($_FILES['file']['name']);
                
                // 위험한 파일 확장자 검증
                if (isDangerousFile($filename)) {
                    $error = '업로드가 허용되지 않는 파일 형식입니다. (PHP, 스크립트 파일 등)';
                    render('write', ['error' => $error]);
                    exit;
                }
                
                $upload_dir = __DIR__.'/uploads/';
                if (!is_dir($upload_dir)) mkdir($upload_dir, 0777, true);
                $filepath = $upload_dir . $post_id . '_' . $filename;
                if (move_uploaded_file($_FILES['file']['tmp_name'], $filepath)) {
                    // 상대 경로로 저장 (uploads/ 이후의 경로만)
                    $relative_path = 'uploads/' . $post_id . '_' . $filename;
                    $stmt2 = $conn->prepare('INSERT INTO files (post_id, filename, filepath) VALUES (?, ?, ?)');
                    $stmt2->bind_param('iss', $post_id, $filename, $relative_path);
                    $stmt2->execute();
                }
            }
            header('Location: index.php?page=board');
            exit;
        } else {
            $error = '글 등록에 실패했습니다.';
            render('write', ['error' => $error]);
            exit;
        }
    } else {
        render('write');
        exit;
    }
}

해당 코드를 보면 글 작성 기능을 실행시 PHP 관련 확장자 필터링 함수인 isdangerousFile을 불러와 확장자를 검사하는것을 알 수 있다. 확장자 검사하는것을 보면 지난 포스팅에서 다뤘던 .htaccess를 필터링 하지 않음을 알 수 있었다. 해당 취약점을 활용하여

이미지 파일을 업로드 후 웹 쉘을 실행하는 방식으로 웹 서버를 탈취해보려는 시도를 해보았지만 .htaccess 파일은 Apache에서 .htaccess라는 파일의 이름만 처리하도록 설계 되어있다. 해당 웹 서버는 파일 업로드시 $post_id값과 '_'를 붙여 5_.htaccess와 같은 이름으로 서버에 저장이 되기때문에 불가능하다. -> 실패

 

다음은 파일 다운로드 코드를 보았다. 작성하진 않았지만 POC코드로 /etc/passwd 를 가져오려 했지만 파일을 찾지 못하였다, 또한 앞 문제와 동일하게 flag.txt로 바로 접근했지만 해당 시도도 파일을 찾지 못한 이유가 파일 다운로드 코드안에 담겨있었다.

// 파일 다운로드
if ($page === 'download' && isset($_GET['filePath'])) {
    $filePath = $_GET['filePath'];
    
    // 취약점: 경로 검증이 약함 - 상대 경로 조작 가능
    $full_path = __DIR__ . '/' . $filePath;

    $full_path = str_replace("../", "", $full_path);
    
    // 기본적인 존재 여부만 확인 (경로 검증 없음)
    if (file_exists($full_path) && is_readable($full_path)) {
        header('Content-Description: File Transfer');
        header('Content-Type: application/octet-stream');
        header('Content-Disposition: attachment; filename="'.basename($filePath).'"');
        header('Content-Length: ' . filesize($full_path));
        readfile($full_path);
        exit;
    } else {
        echo '파일이 존재하지 않거나 접근 권한이 없습니다.';
        exit;
    }
}


$full_path = str_replace("../", "", $full_path); 해당 코드를 보면

"../"라는 문자열이 들어오게 되면 "" 공백으로 replace 해주는 함수가 존재한다. 이유를 알게 되었으니 우회해보자

"../" 가 들어왔을때 "" 공백으로 바꿔주게 된다면 ....//를 입력하게되면 "../"가 공백으로 바뀌기 때문에 ../로 인식되게 된다

해당 우회 기법을 통해 /etc/passwd 와 /flag.txt를 찾을수 있었다.

/etc/passwd
flag.txt

 

파일 다운로드 취약점을 활용하게되면 위와 같이 하드코딩된 소스코드를 그대로 볼 수 있기 때문에 공격자가 어떤식으로 우회가 가능할지 눈에 쉽게 보이게 된다.


 

'웹 해킹' 카테고리의 다른 글

불충분한 인증과 인가 취약점.  (0) 2025.07.26
File uplaod와 File Include 취약점  (1) 2025.07.20
리버스 쉘  (0) 2025.07.16
파일 업로드 취약점, 문제풀이  (1) 2025.07.13
CSRF 대응방법, SOP와 CORS  (2) 2025.07.09