상세 컨텐츠

본문 제목

DVWA : File Upload - High level

Vulnerability Assessment/Web Application

by DarkSoul.Story 2025. 1. 5. 17:19

본문

반응형
이 문서에 포함된 어떠한 내용도 불법적이거나 비윤리적인 목적으로 보안 도구나 방법론을 사용하도록 가르치거나 장려하지 않습니다. 항상 책임감 있는 태도로 행동하세요. 여기에 설명된 도구나 기법을 사용하기 전에 개인 테스트 환경 또는 허가를 받았는지 확인하세요.

 

[ 환경 ]

DVWA v1.9
Burp Suite Community Edition v2024.11.2

1.  Source code analysis

[그림 1] High level Source code

업로드된 파일 정보 추출

$uploaded_name = $_FILES[ 'uploaded' ][ 'name' ];
$uploaded_ext  = substr( $uploaded_name, strrpos( $uploaded_name, '.' ) + 1);
$uploaded_size = $_FILES[ 'uploaded' ][ 'size' ];
$uploaded_tmp  = $_FILES[ 'uploaded' ][ 'tmp_name' ];
  • $uploaded_name : 사용자가 업로드한 파일 이름
  • $uploaded_ext : 파일 이름에서 마지막 점(.) 이후의 문자열을 추출하여 확장자를 가져온다.
  • 예 : image.jpg → jpg
  • $uploaded_size : 업로드된 파일의 크기(바이트 단위)
  • $uploaded_tmp : 서버가 파일을 임시로 저장하는 경로로, 이후 이 경로에서 최종 저장 경로로 파일을 이동한다.

 이미지 파일 검증

if( ( strtolower( $uploaded_ext ) == "jpg" || strtolower( $uploaded_ext ) == "jpeg" || strtolower( $uploaded_ext ) == "png" ) &&
    ( $uploaded_size < 100000 ) &&
    getimagesize( $uploaded_tmp ) ) {
  • 파일 확장자 검증 : 확장자가 jpg, jpeg, png인지 확인하며, 대소문자를 구분하지 않기 위해 strtolower( ) 사용
  • 파일 크기 검증 : 파일 크기가 100KB(100,000 바이트) 미만인지 확인한다.
  • 이미지 여부 확인 : getimagesize(  )를 사용하여 파일이 실제로 이미지인지 확인하며, 유효한 이미지 파일이 아니면 false를 반환한다.

보안상 문제점

 확장자 검증만으로는 불충분 

  • 파일 확장자는 사용자가 변경 가능.
  • 예: 악성 PHP 파일(shell.php)을 shell.png로 이름을 변경하여 업로드 가능

MIME 타입 검증 부족

  • 클라이언트 측에서 MIME 타입을 조작하여 악성 파일을 업로드 가능

업로드 디렉토리 보호 부족

  • 업로드 디렉토리 내 파일이 실행 가능 상태라면, 공격자가 업로드된 스크립트를 실행할 수 있음

 

2. Practical exercises

Midium level에서 진행했던것 처럼  Content-Type을 image/jpeg로 변경해서 전송하는 경우 소스코드에서 확인하였듯이 아래 조건이 아니기 때문에 [그림 2]와 같이 차단되는것을 확인할 수 있다.

  • 파일 확장자는 png, jpeg, jpg이여하 한다.
  • 파일 크기가 100kb 미만이어야 한다.
  • 파일이 실제로 이미지 파일이 이어야 한다. (getimagesize(  ) 함수 사용)

[그림 2] WebShell 업로드 실패

 

High level에서는 getimagesize(  )를 사용하여 파일이 실제로 이미지인지 확인하고 있다. getimagesize(  )는 PHP에서 제공하는 함수로, 이미지 파일의 크기와 속성에 대한 정보를 가져오는 데 사용된다. 이 함수는 이미지를 읽고 그 파일의 기본적인 속성을 반환하므로 이미지 파일 처리나 검증 작업에 유용하다.

 

함수 정의

array getimagesize(string $filename, array &$image_info = null)
  • 매개변수
  • $filename:
    • 크기를 가져올 이미지 파일의 경로
    • 로컬 파일 시스템 경로나 URL을 사용할 수 있다. (파일이 원격 서버에 있다면 PHP가 allow_url_fopen 설정에 따라 접근 가능해야 함)
  • &$image_info (선택 사항):
    • 이미지 파일의 확장된 정보를 담는 연관 배열로 반환된다.
    • exif_imagetype()와 비슷한 확장 정보를 제공한다.
  • 반환 값
    • 성공하면 이미지 정보가 담긴 배열을 반환한다.
    • 실패하면 false를 반환한다.

반환되는 배열 정보

getimagesize()가 반환하는 배열은 다음과 같은 정보를 포함한다.

인덱스 설명
0 이미지의 너비 (픽셀 단위)
1 이미지의 높이 (픽셀 단위)
2 이미지의 MIME 타입을 나타내는 정수값
3 MTML에서 사용할 수 있는 width와 height 속성 문자열
mime 이미지의 MIME 타입 (예:  imge/jpeg)

 

MIME 타입 값 ($imageInfo[2])

getimagesize()는 이미지 타입을 정수로 반환하며, 주요 값은 다음과 같다.

타입
1 GIF
2 JPEG
3 PNG
4 SWF
5 PSD
6 BMP
7 TIFF (기본)
8 TIFF (모서리)
9 JPC
10 JP2
11 JPX
12 JB2
13 SWC
14 IFF
15 WBMP
16 XBM

 

getimagesize(  )는 이미지와 관련된 정보를 쉽게 얻을 수 있는 강력한 도구이면서 이미지 검증과 관리에 필수적으지만, 완벽한 보안 대책은 아니다. 이를 우회하기 위해  Burp Suite로 Intercept 하여 다음과 같이 변경한다.

ㅁ filename="simple-php-web-shell.php.jpeg"
ㅁ Content-Type: image/jpeg
ㅁ HTTP Body 시작 부분에 GIF 파일 시그니처  GIF89a 추가

[그림 3] 검증 우회

 

이렇게 변경 후 전송하면 파일 확장자 검증 부분에서 마지막 .을 기준으로 오른쪽의 내용을 확장자로 가져와서 검증하기 때문에 허용 확장자명인 jpeg가된다. 여기서 주의할점은 확장자만 변경한다고, 이미지 파일로 인식하지 않는다. 그렇기 때문에 HTTP Body 시작점에 GIF 이미지의 Signature를 입력하여, 이미지라고 인식시켜 검증을 우회할 수있다.

[그림 4] 검증 우회

 

업로드된 경로에 접근해보면, WebShell은 PHP이나 업로드 당시 파일 Signature를 GIF로 변경하였기 때문에 PHP가 실행되는게 아니라 이미지가 출력된다.

[그림 5] 업로드 후 접근

 

이상태에서는 WebShell을 실행 시킬 수 없기 때문에 다른 취약점과 연계해야 한다. 사용할 취약점은 File Inclusion이다. 업로드된 WebShell의 확장자가 .jpeg 이미지 파일이라도 코드는 Shell 코드 이기 때문에 File Inclusion 취약점을 이용하면 WebShell을 실행시킬 수 있다. File Inclusion을 클릭 후 PHP Wrapper의 파일 시스템(file://)를 이용하여 WebShell의 전체 경로를 입력하면, [그림 6]과 같이 WebShell을 실행 시킬 수 있다.

[그림 6] File Inclusion 취약점을 이용하여 WebShell 실행

 

반응형

관련글 더보기