File Upload Vulnerability [3]
DATE : 2023/9/17
Last updated
DATE : 2023/9/17
Last updated
앞선 글에서는 파일 업로드 공격에 대한 그 어떤 조치도 취하지 않는 경우를 살펴보았다.
사실 파일을 업로드하는 기능과 관련해 아무런 조치도 취하는 않는 경우는 보기 드물다고 한다.
반대로 결함이 없다고 생각을 하거나 어느 정도 보안 절차가 잘 갖추어졌다고 착각하는 경우!
사실은 파일 업로드 취약점이 존재해 이런 보안 절차를 우회 가능한 상황들이 더 많다고 한다.
이번에는 그 중에서도 파일 타입을 확인해 image file만을 업로드할 수 있도록
제한된 경우를 살펴볼 것이다.
"파일 타입을 제한했는데 뭐가 문제야!" 라는 착각을 하게 되는 경우,
어떤 방법으로 공격 받을 수 있는 지 바-로 알아보도록 하자.
LAB으로 들어가면 우측 상단에 있는 My account 버튼을 눌러Login 페이지로 이동할 수 있다.
LAB에서 기본적으로 제공하는 wiener:peter 계정으로 로그인한 후
이전 LAB과 동일하게 업로드할 파일을 선택한다.
첫 번째 LAB에서 사용한 코드와 동일한 webshell.php를 선택했다.
이제 Upload 버튼을 눌러보자!
파일 업로드를 시도했더니 "Only image/jpeg & image/png"인 파일만 올릴 수 있다고 한다.
여기서 이전 LAB과의 차이점을 알 수 있다.
이미지 파일을 업로드하는 form에서 PHP file을 업로드해도 아무런 문제 없이
파일을 올릴 수 있었던 이전 LAB과는 다르게 이번에는
업로드할 파일의 유형이(file type) image/jpeg OR image/png 인지 확인하고 있다.
그렇다는 건 서버에서는 어떤 값을 통해 업로드 하려는 파일이 이미지 파일인지 아닌 지를
다시 파일을 선택해서 Upload 버튼을 누르는 데, 이때 packet을 딱! 잡아보면
위와 같은 내용을 볼 수 있을 것이다.
현재 packet에서는 총 3가지의 데이터를 보내고 있는 걸 확인할 수 있다.
첫 번째 데이터 ) 업로드 한 파일
사용자가 업로드 하고자 한 파일의 정보를 기재해둔 부분으로
Content-Disposition header를 통해 이 데이터는 파일명이 "webshell.php"이고 내용이 ~php code~이며
Content-Type header를 통해 이 파일의 유형이 php인 걸 서버에 알려주고 있다.
두 번째 데이터 ) 파일 업로드를 요청한 계정 이름
두 번째 데이터는 계정 이름에 대한 데이터를 알려주고 있다.
세 번째 데이터 ) csrf
세 번째 데이터는 CSRF 공격을 방지하기 위해 서버에서 만들어 준 CSRF token 값을 다루고 있다.
세 가지 데이터에 대해 Content-Disposition header로 기본적인 정보를 알려주고 있는 데
PHP file과 연관된 부분에만 Content-Type header가 존재하는 걸 볼 수 있다.
Content-Type header는 application/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이었다!
확인하고 있다는 것인데..! 어떤 데이터를 가지고 확인하는 지 packet을 통해 알아보자
성공적으로 파일이 업로드 되었다고 한다!!