Insecure File Upload

Introduction

File upload는 웹에서 많이 사용되는 기술입니다. 로컬에 있는 파일을 서버로 업로드하는 기능인데, 안전하지 않은 파일이 업로드 되는 것은 보안적인 문제를 가집니다. 그리고 이렇게 File Upload를 이용한 공격들을 Insecure File Upload, Upload Insecure FIle, FIle Upload 취약점 등으로 불립니다.

보통 이러한 Insecure File Upload은 조건에 따라 WebShell, XSS, CSRF, 악성 파일 배포 경유지 등으로 사용되며 XSS 만큼 굉장히 넓은 영향을 가집니다.

Offensive techniques

Detect

File이 업로드 되는 구간은 모두 테스팅 포인트가 됩니다. 대표적으로 파일 업로드가 목적인 기능들, 이미지 등을 업로드 하는 기능들이며 이러한 부분은 눈으로 직접 식별하거나 도구들의 Passive Scan을 통해서 식별할 수 있습니다.

File Type 별 Attack Vector

Extensions Attack Vectors
JSP, ASP, PHP (ASPX, PHP5, Etc) Webshell / RCE
SVG, XML (And XML Based File) Persistant XSS / SSRF / XXE
GIF Persistant XSS / SSRF
CSV CSV injection
AVI, MP4, MPEG (Videos) LFI / SSRF
HTML, JS HTML injection / XSS / Open redirect
PNG, JPEG Persistant XSS, Pixel flood attack (DoS)
ZIP RCE via LFI / DoS
PDF, XSLX, PPTX, DOCS (OXML) SSRF / BLIND XXE

Exploitation

WebShell

Upload된 파일이 동작하는 서버가 PHP, JSP, ASP, Perl 등 파일 자체로 Server-side 동작이 가능한 경우 이를 통해 웹쉘을 업로드하여 시스템을 탈취할 수 있습니다.

Extensions

PHP

.php
.php3
.php4
.php5
.php7
.pht
.phps
.phar
.phpt
.pgif
.phtml
.phtm
.inc

JSP

.jsp
.jspx
.jsw
.jsv
.jspf

ASP

.asp
.aspx
.cer
.asa
.aspx;1.jpg (IIS <= 7.5)
.soap (IIS < 7.0) 

Perl

.pl
.pm
.cgi
.lib

Flash

.swf

Erlang Yaws Web Server

.yaws

Coldfusion

.cfm
.cfml
.cfc
.dbm

XSS

Upload한 파일의 경로에 접근할 때 Content-Type이 text/html, application/xml 등 브라우저에서 스크립트 동작이 가능한 Type인 경우 Persistant XSS와 동일하게 동작합니다. 이 때 업로드된 도메인의 역할과 권한이 중요하며, 실제 서비스 도메인과 같은 경우 서비스 도메인의 쿠키를 탈취하거나 주요 보안 정책(SOP, CSP 등)을 우회할 수 있어 리스크가 높습니다.

Overwrite Config

.htaccess 등 서비스에서 config 목적으로 사용되는 파일을 업로드하여 시스템 설정을 변경할 수 있습니다. 이러한 점을 이용하여 단순한 File Upload에서 RCE나 WebShell까지 리스크를 확장할 수 있습니다.

.htaccess
web.config
httpd.conf
__init__.py

.htaccess - run .php file

php_flag engine on

.htaccess - source code disclosure

php_flag engine off

package.json

"scripts": {
    "prepare" : "/bin/touch /tmp/pwned.txt"
}

composer.json

"scripts": {
    "pre-command-run" : [
    "/bin/touch /tmp/pwned.txt"
    ]
}

For 3rd Party CVE

File Upload를 통해 업로드된 파일이 다른 CLI Application이나 Library 등으로 처리되는 경우가 있습니다. 대표적으로 FFMpeg, Image Magick 이며 이러한 3rd Party가 사용되는 구간이라면 알려진 CVE 를 이용해서 RCE 등으로 업그레이드할 수 있습니다.

ZIP Slip

업로드된 파일을 서버에서 zip, tar, jar 등으로 압축 해제하는 경우 ZIP Slip 공격에 취약할 수 있습니다.

├── dir1
│   ├── file1.txt
│   ├── file2.txt
├── ../../../../../../evil.sh

ZIP Slip은 압축 파일 내부에 Path Traversal 구문을 포함한 파일을 넣어두어 압축 해제 시 공격자가 원하는 경로에 파일을 위치시키는 기법입니다. 자세한 내용은 아래 링크를 참고해주세요.

Cullinan > ZIP Slip

OXML XXE

서버가 pptx, xlsx 등 Office 관련 파일을 처리하는 경우 OXML XXE에 취약할 가능성이 높습니다. OXML XXE는 Offirce 관련 파일의 특성(ZIP 포맷이며 내부에 XML 파일을 가지고 있음)을 이용하여 XXE를 수행하는 방법으로 업로드된 문서 파일을 파싱하는 경우 해당 공격에 영향을 받을 수 있습니다.

├── /_rels/.rels
├── [Content_Types].xml
├── Default Main Document Part
│   ├── /word/document.xml
│   ├──    /ppt/presentation.xml ⬅️ 해당 파일에 XXE 코드 삽입
│   ├──    /xl/workbook.xml
...

자세한 내용은 아래 링크를 참고해주세요.

OOXML XXE Vulnerability (Exploiting XXE In file upload Function!)

Bypass protection

Double Extensions

.jpg.php

Reverse double extension

.php.jpg

Upper/LowerCase

.PhP
.PHp5
.JSp
.asP

Null byte

.php%00.gif
.php\x00.gif
.php%00.png
.php\x00.png
.php%00.jpg
.php\x00.jpg

RTLO

RTLO는 Right to Left Override로 오른쪽에서 왼쪽으로 글씨를 쓰는 언어권의 문자 포맷을 이용한 방법입니다.

name.%E2%80%AEphp.jpg

Blank char

file.php%20

CRLF

file.php%0d%0a.jpg

Magic Byte

PNG: \x89PNG\r\n\x1a\n\0\0\0\rIHDR\0\0\x03H\0\xs0\x03[
JPG: \xff\xd8\xff
GIF: GIF87a OR GIF8;

ADS

file.asp:123.jpg

More special chars

file.php........
file.jsp/././././.

Bypass MIME

업로드 시 Content-Type을 허용된 Type으로 변경합니다. Content-Type 기반의 검사 로직을 우회할 수 있습니다.


Content-Type : image/gif
Content-Type : image/gif
Content-Type : image/png
Content-Type : image/jpeg

Truncate File

Linux, macOS, Windows 그리고 JSP, ASP, PHP 등 Application 모두 서로 처리할 수 있는 파일의 최대 크기와 버퍼 크기가 다릅니다. 이러한 차이를 이용하여 파일 이름의 길이를 잘리도록 유도하여 확장자 검사를 우회할 수 있습니다.

POST /upload

-----------------------------313131052934083662144000709583
Content-Disposition: form-data; name="file"; filename="AAAAA.....php.jpg"
Content-Type: image/jpeg

예를들어 위와같이 파일 업로드 시 php.jpg로 업로드하여 확장자를 application에선 jpg로 인식 시키지만, 파일을 저장할 때 길이 차이로 인해 php 까지 잘리는 경우 실제 업로드된 파일은 php 확장자를 가지게됩니다.

More

이외에도 정말 많은 방법들이 존재합니다. 서버의 검증 로직을 파악하고, 이에 따라 맞춤형 우회 패턴을 사용하여 악의적인 파일을 업로드할 수 있습니다 :D

Defensive techniques

Defense Mechanism

기본적으로 File Upload는 한가지의 대응 방안이 아니라 여러가지의 대응방안을 교차 적용하여 대응해야합니다. 각각의 방안 모두 우회의 여지가 있기 때문에 여러겹으로 검증 로직이 존재해야 원하는 공격으로 부터 안전해질 수 있습니다.

In Upload Function

Check file extension

확장자 검사는 가장 File Upload의 가장 기본적인 대응방안입니다. 업로드되는 파일의 확장자를 허용할 확장자만 Allow-list 형태로 체크합니다.

.jpg => O
.png => O
.svg => X
.php => X
.html => X

Check file MIME

File upload 시 MIME Type에 대한 검증도 대응방안 중 하나입니다. 일반적으로 확장자 검사 또는 File header 검사와 병행됩니다.

Content-Type: image/jpeg => O
Content-Type: text/html => X

Check file header

파일 업로드 시 업로드된 파일의 Header를 검증하여 대응할 수 있습니다. 이미지 업로드 등 특정 파일만 허용하는 경우 효과적입니다.

ÿØÿàJFIF => O
ThisisHackCode => X

Uploaded server

Content-Type of Uploaded File

업로드된 파일의 Content-Type을 목적에 맞게 고정하는 형태로도 대응이 가능합니다. 또한 파일을 다운로드 처리하는 Content-Disposition: attachment 도 XSS 등의 공격에는 효과적으로 대응할 수 있습니다.

만약 업로드된 이미지가 저장된 서버라고 가정한다면, 아래와 같이 Type을 고정하여 HTML 등이 렌더링되지 않도록 제한할 수 있습니다.

Content-Type: image/jpeg

Random filename

업로드된 파일은 사용자가 전달한 파일 이름과 확장자를 그대로 쓰기보단 Random하게 생성한 문자열로 관리하는 것이 좋습니다. 이는 파일 이름과 확장자를 기반으로한 공격에 효과적으로 대응할 수 있습니다.

MyFile.png => X
6FC2321BF061F344AF2A45A74D2809F540C16907CBD986D8187979C4541E33E8.png => O

Hide upoaded path

사용자에게 업로드된 파일을 제공하는 것이 아니라면 업로드된 파일이 위치하는 서버는 내부로 숨기거나, 외부에 필요하더라도 사용자가 쉽게 경로를 파악할 수 없도록 처리하는 것이 좋습니다.

/uploaded_file/user.txt => X
/A45A74D2809F540C16907CBD986D8/1BF061F344AF2A/user.txt

Use Key/Value Storage

S3 같이 K/V 기반의 Storage는 기본적으로 File upload에 사용되는 여러가지 기법을 사용할 수 없게 만듭니다. 그래서 이러한 Storage의 선택으로 공격 포인트를 많이 줄일 수 있습니다.

Tools

Articles

References