[주요정보통신기반시설 웹 애플리케이션 취약점 분석·평가 21일 완성 코스] 14강 — [Day 14] 악성 파일 업로드

⚡ 정다은 · 2026-10-04 14:00 · 조회 32

[Day 14] 악성 파일 업로드 (Malicious File Upload) - 웹 서버를 점령하는 위험한 통로

안녕하세요! Hackerstory 공부방의 IT/보안 튜터, 정다은입니다. 👋

어느덧 **'주요정보통신기반시설 웹 애플리케이션 취약점 분석·평가 21일 완성 코스'**의 14일 차에 접어들었습니다! 전체 코스의 3분의 2 지점을 통과하고 계신 여러분, 정말 대단하십니다. 👏

오늘 우리가 다룰 주제는 웹 보안 진단 실무에서 고위험(High/Critical) 취약점으로 가장 자주 분류되는 [Day 14] 악성 파일 업로드입니다.

게시판의 첨부파일, 프로필 이미지 변경 기능 등 웹 서비스에서 파일 업로드는 필수적인 기능입니다. 하지만 개발자가 이 업로드 로직을 소홀히 검증하면 공격자는 서버를 완전히 장악할 수 있습니다. 오늘 강의를 통해 악성 파일 업로드의 원리부터 파괴력, 그리고 완벽한 방어 수단까지 하나씩 파헤쳐 보겠습니다!


1. 악성 파일 업로드 취약점이란? (개념 설명)

📌 파일 업로드 취약점의 정의

악성 파일 업로드 취약점은 웹 애플리케이션에서 파일 업로드 기능을 제공할 때, 업로드되는 파일의 형식, 확장자, 실행 권한 등을 적절히 검증하지 않아 서버 측에서 실행 가능한 스크립트 파일이 그대로 저장되고 실행되는 취약점을 의미합니다.

💣 웹셸(WebShell)이란?

이 취약점을 논할 때 결코 빠질 수 없는 개념이 바로 **웹셸(WebShell)**입니다.

  • 웹셸(WebShell): 공격자가 웹 서버에 업로드하여 원격으로 시스템 명령어를 실행할 수 있도록 제작한 웹 스크립트 파일 (PHP, JSP, ASP, Python 등)입니다.
  • 웹셸이 업로드되고 실행 권한이 부여되는 순간, 공격자는 웹 브라우저를 통해 서버의 CUI(명령 줄 인터페이스)를 얻은 것과 다름없게 됩니다. 이를 보안 용어로 **원격 코드 실행(RCE, Remote Code Execution)**이라고 합니다.
[공격자] --(웹셸 업로드: shell.php)--> [웹 서버 (Upload 디렉터리)]
[공격자] --(http://site.com/upload/shell.php?cmd=ls)--> [서버 명령어 실행 및 결과 반환]

⚠️ 왜 가장 위험한 취약점 중 하나일까요?

  1. 서버 완전 장악: 웹 서버 프로세스 권한으로 시스템 내부 파일 읽기/쓰기/삭제가 가능해집니다.
  2. 내부망 침투의 교두보: 공격자가 웹 서버를 발판 삼아(Pivoting) DB 서버나 기업 내부 네트워크로 침투할 수 있습니다.
  3. 랜섬웨어 및 악성코드 유포: 웹 서버의 소스 코드를 변조하여 방문자들에게 악성코드를 유포하는 숙주로 악용할 수 있습니다.

2. 취약점이 발생하는 주요 원인과 공격 예시

개발자들이 자주 범하는 실수 패턴과 이를 우회하는 공격 기법을 알아봅시다.

🚫 잘못된 검증 방식 3가지

  1. 클라이언트 측(JavaScript) 검증만 수행

    • 브라우저에서 Form을 제출하기 전에 자바스크립트로 .jpg, .png 인지 검사하는 방식입니다.
    • 우회 방법: 공격자는 프록시 툴(Burp Suite 등)을 사용하여 자바스크립트 검증을 거치지 않고 직접 HTTP 요청을 보내거나, 자바스크립트 실행을 중단시킨 후 악성 파일을 전송합니다.
  2. MIME Type (Content-Type) 검증만 수행

    • HTTP 요청 헤더의 Content-Type: image/png 값을 검사하는 방식입니다.
    • 우회 방법: 공격자는 PHP 파일을 업로드하면서 헤더의 Content-Type 값만 image/png로 패킷을 변조하여 쉽게 우회합니다.
  3. 블랙리스트(Blacklist) 기반 확장자 검증

    • .php, .jsp, .asp 등 위험한 확장자를 금지 목록에 넣어두는 방식입니다.
    • 우회 방법:
      • 대소문자 혼용 (.PhP, .jSp)
      • 우회 확장자 활용 (.php3, .php5, .phtml, .phar, .inc, .jspx, .asa 등)
      • 특수문자 및 공백 추가 (shell.php., shell.php%00.jpg 등 구형 환경 우회)

💻 실습 코드로 보는 취약점 예시

[취약한 서버 측 코드 예시 (PHP)]

<?php
// /uploads/ 디렉터리에 사용자가 올린 파일명 그대로 저장
$target_dir = "uploads/";
$target_file = $target_dir . basename($_FILES["fileToUpload"]["name"]);

// 파일 저장 (아무런 검증 없이 그대로 저장함!)
if (move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file)) {
    echo "파일이 업로드되었습니다: " . $target_file;
} else {
    echo "업로드 실패!";
}
?>

[공격자가 작성한 웹셸 (webshell.php)]

<?php
// URL 파라미터로 받은 'cmd' 명령어를 시스템에서 실행
if(isset($_GET['cmd'])) {
    system($_GET['cmd']);
}
?>

[공격 시나리오]

  1. 공격자가 webshell.php 파일 업로드 시도.
  2. 서버는 아무런 검증 없이 uploads/webshell.php 경로에 저장.
  3. 공격자는 브라우저 주소창에 다음 URL을 입력: http://vulnerable-site.com/uploads/webshell.php?cmd=cat /etc/passwd
  4. 서버 내부의 중요한 계정 정보가 브라우저 화면에 그대로 출력됨! 😱

3. 실무 적용 가능한 완벽 보안 대책

악성 파일 업로드 취약점을 완벽하게 막기 위해서는 **'단 하나의 검증'에 의존해서는 안 되며, 다중 방어 체계(Defense in Depth)**를 구축해야 합니다.

🛡️ 1. 파일 확장자 화이트리스트(Whitelist) 검증 (필수)

허용할 확장자만 명확하게 정의하고, 그 외의 모든 확장자는 차단합니다.

<?php
$allowed_ext = array('jpg', 'jpeg', 'png', 'gif', 'pdf'); // 허용된 확장자 목록

$file_name = $_FILES['fileToUpload']['name'];
$file_ext = strtolower(pathinfo($file_name, PATHINFO_EXTENSION)); // 확장자 추출 및 소문자 변환

// 화이트리스트 검증 (서버 측에서 수행)
if (!in_array($file_ext, $allowed_ext)) {
    die("허용되지 않는 파일 형식입니다.");
}
?>

🛡️ 2. 파일명 난수화 및 경로 이격 (UUID 사용)

사용자가 올린 원본 파일명을 그대로 저장하면 공격자가 파일 경로를 추측하여 접근하기 쉬워집니다.

  • 업로드 시 UUID 또는 무작위 난수를 생성하여 파일명을 변경합니다.
  • 확장자도 안전한 확장자만 다시 붙여서 저장합니다.
// 예시: original_filename.php -> 550e8400-e29b-41d4-a716-446655440000.png
$new_filename = vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex(random_bytes(16)), 4)) . '.' . $file_ext;

🛡️ 3. 업로드 디렉터리의 실행 권한(Exec Option) 제거 (핵심!)

만약 악성 파일이 업로드되었다 하더라도, 해당 디렉터리에서 파일이 '실행'되지 않고 단순 다운로드/열람만 가능하도록 웹 서버를 설정하면 웹셸 동작을 무력화할 수 있습니다.

  • Apache Web Server (.htaccess 또는 httpd.conf 설정):

    <Directory "/var/www/html/uploads">
        # 해당 디렉터리 내의 스크립트 실행을 금지
        Options -ExecCGI
        RemoveHandler .php .phtml .php3 .php5 .jsp .asp
        RemoveType .php .phtml .php3 .php5 .jsp .asp
        <FilesMatch "\.(php|phtml|php3|php5|jsp|asp|cgi)$">
            Order allow,deny
            Deny from all
        </FilesMatch>
    </Directory>
    
  • Nginx Web Server (nginx.conf 설정):

    location /uploads/ {
        # uploads 디렉터리 하위의 php 파일 실행을 차단
        location ~ \.(php|phtml|php3|php5|jsp|asp)$ {
            deny all;
            return 403;
        }
    }
    

🛡️ 4. 웹 서버 외부 저장소(External Storage) 활용

가장 이상적인 방어책은 업로드된 파일을 웹 서버 내부(Web Root)가 아닌 완전히 분리된 다른 장소에 저장하는 것입니다.

  • AWS S3, Google Cloud Storage 등 Object Storage 활용: 파일이 웹 서버 파일 시스템에 저장되지 않으므로, 웹셸이 업로드되어도 웹 서버 환경에서 코드로서 실행될 가능성이 0%가 됩니다.
  • WAS 외부의 전용 File Server 활용: Web Root (/var/www/html/) 외부의 디렉터리 (/data/app_files/)에 저장하고, 파일 요청 시 별도의 다운로드 프로시저를 거치도록 구현합니다.

4. 핵심 요약 및 진단 체크리스트

실무에서 진단원으로 활동하거나 보안성을 평가할 때 아래 항목을 반드시 체크하세요!

진단 항목 핵심 점검 내용 보안 상태
확장자 검증 서버 측 코드에서 화이트리스트 방식으로 확장자를 검증하는가? ✅ safe
파일명 난수화 업로드 파일명이 추측 불가능한 문자열(UUID 등)로 재지정되는가? ✅ safe
실행 권한 제거 업로드 디렉터리에 스크립트 실행 권한(Exec)이 제거되어 있는가? ✅ safe
저장 위치 분리 Web Root 외부에 저장되거나 S3 등 외부 스토리지 서비스를 활용하는가? ✅ safe

튜터 다은의 한 줄 요약: *"파일 업로드는 **'화이트리스트 검증'**으로 1차 방어하고, '디렉터리 실행 권한 제거' 및 **'외부 스토리지 저장'*을 통해 2차 무력화를 완성해야 합니다!"


오늘 학습한 [Day 14] 악성 파일 업로드는 웹 애플리케이션 보안 진단에서 매우 높은 비중을 차지하는 항목입니다. 원리와 대응 방안을 머릿속에 꼭 그려두시길 바랍니다.

오늘도 끝까지 읽어주셔서 감사합니다. 질문이 있으시다면 언제든 댓글로 남겨주세요! 😉


🔮 다음 챕터 예고

내일 Day 15에서는 악성 파일 업로드와 바늘과 실처럼 따라다니는 취약점, [Day 15] 파일 다운로드(File Download) 취약점에 대해 배웁니다.

서버 내의 /etc/passwd나 web.config 같은 중요한 시스템 설정 파일을 공격자가 임의로 다운로드받는 원리와, 디렉터리 순회(Directory Traversal) 공격 방어법에 대해 자세히 알아보겠습니다.

내일 또 만나요! 수고 많으셨습니다! 🎈

댓글 0

로그인하면 댓글을 작성할 수 있습니다.