File Upload Vulnerability [3]

DATE : 2023/9/17

File Upload Vulnerability - Labs

앞선 글에서는 파일 업로드 공격에 대한 그 어떤 조치도 취하지 않는 경우를 살펴보았다.

사실 파일을 업로드하는 기능과 관련해 아무런 조치도 취하는 않는 경우는 보기 드물다고 한다.

반대로 결함이 없다고 생각을 하거나 어느 정도 보안 절차가 잘 갖추어졌다고 착각하는 경우!

사실은 파일 업로드 취약점이 존재해 이런 보안 절차를 우회 가능한 상황들이 더 많다고 한다.

이번에는 그 중에서도 파일 타입을 확인해 image file만을 업로드할 수 있도록

제한된 경우를 살펴볼 것이다.

"파일 타입을 제한했는데 뭐가 문제야!" 라는 착각을 하게 되는 경우,

어떤 방법으로 공격 받을 수 있는 지 바-로 알아보도록 하자.


[ LAB#2 ]

LAB으로 들어가면 우측 상단에 있는 My account 버튼을 눌러Login 페이지로 이동할 수 있다.

LAB에서 기본적으로 제공하는 wiener:peter 계정으로 로그인한 후

이전 LAB과 동일하게 업로드할 파일을 선택한다.

<?php echo file_get_contents('/home/carlos/secret'); ?>

첫 번째 LAB에서 사용한 코드와 동일한 webshell.php를 선택했다.

이제 Upload 버튼을 눌러보자!

파일 업로드를 시도했더니 "Only image/jpeg & image/png"인 파일만 올릴 수 있다고 한다.

여기서 이전 LAB과의 차이점을 알 수 있다.

이미지 파일을 업로드하는 form에서 PHP file을 업로드해도 아무런 문제 없이

파일을 올릴 수 있었던 이전 LAB과는 다르게 이번에는

업로드할 파일의 유형이(file type) image/jpeg OR image/png 인지 확인하고 있다.

그렇다는 건 서버에서는 어떤 값을 통해 업로드 하려는 파일이 이미지 파일인지 아닌 지를

확인하고 있다는 것인데..! 어떤 데이터를 가지고 확인하는 지 packet을 통해 알아보자 😋

다시 파일을 선택해서 Upload 버튼을 누르는 데, 이때 packet을 딱! 잡아보면

위와 같은 내용을 볼 수 있을 것이다.

현재 packet에서는 총 3가지의 데이터를 보내고 있는 걸 확인할 수 있다.

첫 번째 데이터 ) 업로드 한 파일

Content-Disposition: form-data; name="avatar"; filename="webshell.php"
Content-Type: application/x-php

~php code~

사용자가 업로드 하고자 한 파일의 정보를 기재해둔 부분으로

Content-Disposition header를 통해 이 데이터는 파일명이 "webshell.php"이고 내용이 ~php code~이며

Content-Type header를 통해 이 파일의 유형이 php인 걸 서버에 알려주고 있다.

두 번째 데이터 ) 파일 업로드를 요청한 계정 이름

Content-Disposition: form-data; name="user"

wiener

두 번째 데이터는 계정 이름에 대한 데이터를 알려주고 있다.

세 번째 데이터 ) csrf

Content-Disposition: form-data; name="csrf"

4OwD~~v5fh

세 번째 데이터는 CSRF 공격을 방지하기 위해 서버에서 만들어 준 CSRF token 값을 다루고 있다.

세 가지 데이터에 대해 Content-Disposition header로 기본적인 정보를 알려주고 있는 데

PHP file과 연관된 부분에만 Content-Type header가 존재하는 걸 볼 수 있다.

Content-Type headerapplication/x-php와 같이 파일 유형에 대한 정보를 알려주는 헤더

서버는 이 header의 값을 보고 지금 전달하고자 하는 파일이 어떤 유형 인지를 알 수 있다.

이번 LAB에서는 file type이 오직 image/jpeg or image/png 이어야 한다고 했으므로

Content-Type 값을 조작해 packet을 보내볼까 한다.

다른 부분은 손대지 않고 Content-Type 값만 image/jpeg로 바꿨다.

이 상태로 packet forward를 하면

성공적으로 파일이 업로드 되었다고 한다!! 👍

파일을 올렸으니 이제는 실행시킬 일만 남았다..!

URL 바에 /files/avatars/webshell.php를 입력하면 업로드한 파일이 실행되면서

/home/carlos/secret file 내용을 알 수 있게 된다.

(여기서 주목할 점은 현재 공격자의 계정은 wiener인데, carlos 계정의 파일을 읽을 수 있다는 것!)

찾아낸 flag를 제출하면

이번 LAB도 마무리 =D


이번 LAB에서는 파일 유형을 확인해 서버에서 업로드 할 수 있는 파일 유형을 제한해두고 있었다.

하지만, Content-Type header 값을 바꿈으로써 간단하게 검증 체제를 우회했다..!

그럴 수 있었던 이유는 정말 단순하게 Content-Type 값만 확인했기 때문이다.

"Content-Type: image/jpeg"의 의미는 업로드 할 파일이 이미지 파일이라는 건데

실제로 업로드 할 파일의 확장자가 jpeg인지 또는 파일 내용이 jpeg 값 인지 확인하는 과정이 없다!!

그렇다 보니 Content-Type header 값만 조작해서 파일 유형을 확인하는 과정을 통과하고

실제로는 PHP code가 서버로 업로드 되는 것이다.

이렇게 파일 업로드 공격을 예방하기엔 빈 틈 있는 검증 체제가 존재할 수 있다는 것이고

결함이 존재하는 지, 충분한 방어가 이루어지는 지 꼼꼼하게 따져볼 필요성을 보여주는 LAB이었다!

Last updated