File Upload
공격자가 원하는 임의의 파일을 서버에 업로드할 수 있는 공격
1) 발생 원인
- 파일 업로드 시 검증을 제대로 거치지 않음
- 예를 들어 프로필 사진을 업로드하는 곳이라면 이미지 파일만 올릴 수 있게 해야하는데 그런 과정이 없음
2) 발생 위치
- 파일을 업로드할 수 있는 곳
- 게시판, 프로필 사진, 서류 제출, 파일 업로드를 통한 신분증 인증 등
- 파일을 파라미터로 보내고 있는지 버프 스위트로 확인
목차
- Content-Type 변조
- 파일 저장 경로 변조
- 확장자 업로드 제한 우회
- 헥사에 실행 코드 삽입하여 우회
파일 업로드 진단 시 우회 가능한 상황들
10% 정도(?) 부족한 파일 검증
▷ Content-Type 변조
- 서버에서 업로드 파일의 Content-Type을 검증할 경우
if ($_FILES['___']['type'] == "image/jpeg") {
// 서버에 저장
} else {
// 돌아가
};
- MIME 타입(image/jpeg 등)을 정해두고 업로드 한 파일의 Conent-Type 헤더의 값과 같은지 확인함
[+] MIME 타입:
웹으로 파일 주고 받을 때 파일을 잘 전달하기 위해 해당 형식에 맞게 인코딩하는데 이 형식을 나타내는 방식인 듯
★ 내 서버에서 실습해보기
- 관련 코드
if ($_FILES['image']['type'] == "image/jpeg") {
//파일의 MIME타입이 jpeg 형식이면
move_uploaded_file($_FILES['image']['tmp_name'],$targetPath);
//서버에 파일 저장
//DB저장, 게시글로 리다이렉션 코드 생략
} else {
echo "<script>alert('이미지 형식만 지원됩니다.');</script>";
//파일 형식이 jpeg가 아니면 alert 출력
}
- 웹쉘 업로드 실습
가입된 계정으로 사이트 접속 |
웹쉘 코드가 작성된 php 파일을 업로드 |
alert창이 출력되며 업로드 실패함 |
우회를 염두에 두며 다시 게시물 작성 |
요청 데이터를 변조하기 위해 버프 스위트의 intercept 기능을 활성함 |
업로드 버튼 클릭 |
인터셉트한 요청 데이터의 본문 내용 중 파일의 Content-Type을 확인 |
application/octet-stream이었던 형식을 image/jpeg로 변조 변조한 요청을 forward 버튼을 눌러 전송 |
정상 업로드를 알리는 alert 확인 |
업로드된 게시물 읽기 페이지로 리다이렉션 됨 |
서버에 저장된 것도 확인할 수 있음 |
- 파일의 MIME 타입을 지정하여 검증할 경우 요청 데이터의 Content-Type 변조를 통해 우회 가능
▷ 파일 저장 경로 변조
- 서버에서 파일 저장 경로의 실행 권한을 제한할 경우 업로드 시 저장 경로를 변조함
파일 저장 경로에 .htaccess 파일을 생성한 뒤 위와 같은 설정을 추가 |
-> 맨 첫 줄의 "\.php$" 설명 ** \는 이스케이프 **.php 는 확장자명 **$는 문자열의 끝 => 파일 이름의 끝이 .php인 놈만 해당 |
★ 내 서버에서 실습해보기
웹쉘을 포함한 파일을 업로드함 |
웹쉘 파일을 새탭에서 열기 |
서버에서 실행되지 않은 채 단순 문자열로 출력되는 것을 확인 |
/var/www/html/img가 아닌 다른 디렉토리에 파일을 저장할 게시물 작성 |
버프 스위트의 intercept 기능 활성화 후 게시글 업로드 |
webshell.php였던 파일 이름을 ../webshell.php로 변경 후 forward로 요청 전송 |
원래 var/www/html/img/webshell.php에 저장되었으나 변경 후 var/www/html/webshell.php에 저장하게 됨 |
정상 업로드 됨 |
업로드 후 리다이렉션 된 페이지에서 웹쉘을 찾아 우클릭 새 탭에서 열기를 클릭 |
하면 여전히 안되는 것을 볼 수 있음 |
- 이 우회방법의 경우 서버가 파일 이름을 그대로 저장해야 가능한 듯함
- 내 서버는 사용자가 설정한 파일 이름에서 앞에 /어쩌구/저쩌구 다 떼고 마지막 파일 이름만 남겨놔서 적용 안됨
- 이 우회 방법은 디렉토리 트래버설(이동)을 이용한 파일 덮어쓰기 공격(?)으로도 이어질 수 있을 것으로 보임
- 파일 덮어쓰기 공격: /etc/passwd 파일을 /../../etc/passwd라는 제목의 파일을 업로드하여 덮어씌우기 등
▷ 확장자 업로드 제한 우회
- 서버에서 확장자명이 .php인 파일을 실행 (혹은 업로드)하지 못하게 막을 경우 확장자명을 우회함
해당 디렉토리에 저장되는 파일 중 확장자명이 .php 인 파일의 경우 php실행을 막도록 .htaccess로 설정 |
★ 내 서버에서 실습해보기
웹쉘 파일의 확장자명을 .php에서 .phtml로 수정한 뒤 업로드 |
업로드 완료 |
리다이렉션된 페이지에서 웹쉘 파일을 찾아 우클릭한 후 새 탭에서 열어 웹쉘을 실행함 |
cmd 파라미터로 ls 명령어를 수행한 결과 웹쉘 코드가 정상 작동되는 것을 확인함 |
- 서버에서 파일 확장자명으로 실행 및 업로드 제한할 경우 다른 형태의 확장자명으로 우회 가능함
우회 가능 확장명 ↓
https://vulp3cula.gitbook.io/hackers-grimoire/exploitation/web-application/file-upload-bypass
▷ 헥사에 실행 코드 삽입하여 우회
- 파일 시그니처로 파일 형식을 검증하는 서버의 경우
- 가장 많이 접할 우회 방법
파일 시그니처 란?
- 파일 맨 앞부분에 삽입하는 8바이트 데이터로, 이 데이터를 통해 파일의 형식이 무엇인지 구분할 수 있음.
- "매직 넘버"라고도 함
★ 내 서버에서 실습해보기
- 관련 코드
<?php
function file_vali_check($tmp_file) {
$bin_file = fopen($tmp_file,'rb');
$signature = fread($bin_file,8);
fclose($bin_file);
$hex_sig = bin2hex($signature);
if($hex_sig === "89504e470d0a1a0a") {
return true;
} else {
echo "<script>alert('png 형식만 지원됩니다.');
location.href='upload.php';</script>'";
exit;
}
}
if($_SERVER['REQUEST_METHOD'] === 'POST') {
$png_file = file_vali_check($_FILES['image']['tmp_name']);
if (isset($_FILES['image']) && $_FILES['image']['error'] === 0 && $png_file) {
//서버와 DB에 파일 저장
} else {
// 돌아가
}
}
?>
- POST 요청이 들어오면 파일 임시 저장 경로를 매개로 파일 시그니처 검증을 시작함
- 파일을 바이너리 읽기 형식으로 열고 핸들($bin_file)로 파일 맨 앞부분 8바이트를 읽어와 저장
- 파일 닫음
- 문자열로 저장된 8바이트 데이터를 HEX 값으로 변경하여 PNG의 파일 시그니처와 비교 (***bin2hex함수는 hex 값을 소문자로 변경)
- 두 데이터가 일치하면 "참" 전달, 일치하지 않으면 alert출력 후 게시글 작성 페이지로 리다이렉션
- 업로드한 파일이 PNG 형식 + 업로드한 파일 있음 + 에러 없음 => 데이터 저장
- 세 조건 중 하나라도 해당하지 않으면 게시글 작성 실패
파일이 업로드되는지 확인하기 위해 일반 PNG 형식 이미지를 업로드 |
정상적으로 업로드 됐다는 alert창 확인 |
업로드한 게시물 읽기 페이지로 리다이렉션 됨 PNG 파일은 서버에서 정상적으로 처리하고 있다는 것을 확인 |
헥스 에디터로 이미지 파일을 열고 웹쉘 스크립트 삽입 후 php로 저장 |
이미지 파일이 php 파일로 저장됨 |
웹쉘 스크립트가 포함된 파일을 업로드함 |
정상적으로 업로드 됨 |
깨진 이미지 파일을 우클릭하여 새 탭에서 이미지를 열어봄 |
새 탭으로 연 파일에 cmd 명령어를 파라미터로 요청했으나 아무런 변화가 없음 당연함 php 확장자는 실행 제한했었음 |
php였던 파일 확장자를 pHp로 변경한 뒤 저장 |
확장자명을 pHp로 수정한 파일 업로드 |
게시글 업로드됨 |
하지만 웹쉘은 작동하지 않음 다른 확장자명으로 바꿔서 시도함 |
pHp였던 확장자명을 phtml로 수정 |
확장자명을 수정한 파일과 함께 게시글을 업로드 |
게시글 업로드됨 |
업로드한 파일을 우클릭하여 새 탭에서 엶 |
맨 처음 파일 시그니처와 함께 이미지가 완전히 깨진 형태로 출력되는 것을 확인 |
ls 명령어를 전달한 결과 웹쉘 코드를 삽입했던 위치에서 img 디렉토리의 파일 목록을 확인할 수 있었음 |
pwd 명령어 입력 결과 |
왠지 두번 출력됨 아 이제보니 ls 명령어도 마지막에 있는 뭘봐라이언 파일명을 두 번 출력함 system함수가 마지막 줄을 한 번 출력하고 echo가 파일 목록을 한 번 출력해서 중복된다는 듯 (system 함수 결과를 변수에 저장해서 출력하는 웹쉘은 한번만 출력됨) |
- 파일 시그니처를 통해 파일 형식을 검증하는 방법은 꽤 안전한 검사 방법일 수는 있지만 완전한 방법은 아님
- 파일을 헥스 에디터로 열어 웹쉘 스크립트를 삽입하고 확장자명을 서버측 실행 스크립트로 수정하면 우회가 가능할 수 있음
- 그리고 아예 스크립트 파일을 헥스 에디터로 열고 이미지 파일 시그니처를 앞에 넣는 방식으로도 우회 가능한 듯함
[+] .htaccess로 확장자를 제한하면 pHp로 업로드해도 실행이 안됨
★ 이 방법으로 우회할 때 유의할 점
- 파일 확장자를 png가 아닌 php로 해야 서버가 이 파일을 실행시킴!
- .php.png 식의 이중확장자도 안됨
파일 업로드 우회 가능 케이스 정리
1) MIME 타입 검증 시
- 프록시 툴에서 Content-Type 수정하여 우회
2) 파일 저장 경로에 php 스크립트 실행 막을 때
- 서버에서 사용자가 설정한 파일명을 그대로 저장할 경우 상위 디렉토리에 저장하여 우회
3) 파일 확장자명 차단할 때
- 실행 가능한 다른 확장자명으로 우회
4) 파일 시그니처로 파일 형식 검증할 때
- php 파일에 이미지 파일 시그니처를 삽입하거나 이미지 파일에 웹쉘 코드 삽입하여 우회
그림 파일 웹쉘이 뭘까
'모의해킹 스터디 복습' 카테고리의 다른 글
모의해킹 스터디 14주차(1): 파일 업로드 (0) | 2025.01.31 |
---|---|
모의해킹 스터디 13주차(2): CSRF - 보안 정책, 대응 방안 (0) | 2025.01.22 |
모의해킹 스터디 13주차(1): CSRF vs XSS (0) | 2025.01.17 |
모의해킹 스터디 12주차: CSRF (사이트 간 요청 위조) (0) | 2025.01.14 |
모의해킹 스터디 11주차: XSS - 데이터 추출, 대응 방안 (0) | 2024.12.30 |