[주요정보통신기반시설 웹 애플리케이션 취약점 분석·평가 21일 완성 코스] 14강 — [Day 14] 악성 파일 업로드
[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)--> [서버 명령어 실행 및 결과 반환]
⚠️ 왜 가장 위험한 취약점 중 하나일까요?
- 서버 완전 장악: 웹 서버 프로세스 권한으로 시스템 내부 파일 읽기/쓰기/삭제가 가능해집니다.
- 내부망 침투의 교두보: 공격자가 웹 서버를 발판 삼아(Pivoting) DB 서버나 기업 내부 네트워크로 침투할 수 있습니다.
- 랜섬웨어 및 악성코드 유포: 웹 서버의 소스 코드를 변조하여 방문자들에게 악성코드를 유포하는 숙주로 악용할 수 있습니다.
2. 취약점이 발생하는 주요 원인과 공격 예시
개발자들이 자주 범하는 실수 패턴과 이를 우회하는 공격 기법을 알아봅시다.
🚫 잘못된 검증 방식 3가지
클라이언트 측(JavaScript) 검증만 수행
- 브라우저에서
Form을 제출하기 전에 자바스크립트로.jpg,.png인지 검사하는 방식입니다. - 우회 방법: 공격자는 프록시 툴(Burp Suite 등)을 사용하여 자바스크립트 검증을 거치지 않고 직접 HTTP 요청을 보내거나, 자바스크립트 실행을 중단시킨 후 악성 파일을 전송합니다.
- 브라우저에서
MIME Type (Content-Type) 검증만 수행
- HTTP 요청 헤더의
Content-Type: image/png값을 검사하는 방식입니다. - 우회 방법: 공격자는 PHP 파일을 업로드하면서 헤더의
Content-Type값만image/png로 패킷을 변조하여 쉽게 우회합니다.
- HTTP 요청 헤더의
블랙리스트(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']);
}
?>
[공격 시나리오]
- 공격자가
webshell.php파일 업로드 시도. - 서버는 아무런 검증 없이
uploads/webshell.php경로에 저장. - 공격자는 브라우저 주소창에 다음 URL을 입력:
http://vulnerable-site.com/uploads/webshell.php?cmd=cat /etc/passwd - 서버 내부의 중요한 계정 정보가 브라우저 화면에 그대로 출력됨! 😱
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
로그인하면 댓글을 작성할 수 있습니다.