9주차 과제_LFI
참고 문서
1. File upload vulnerability
파일 업로드 취약점 : 서버의 파일 시스템에 사용자가 원하는 경로 또는 파일 명 등으로 업로드가 가능하여 악영향을 미칠 수 있는 파일이 업로드되는 취약점
File Upload : 웹 서비스를 통해 파일을 서버에 업로드하는 기능 / 사용자의 사진, 문서와 같은 파일을 서버에 업로드하여 다른 사용자들과 공유를 위한 것
사용자의 파일이 서버의 파일 시스템에 저장되어 처리된다는 이유로 인해 취약점이 발생
-> 사용자가 파일 업로드 시 파일의 내용과 함께 파일의 이름도 함께 서버로 전송되는데, 이때 서버가 아무런 검증이 없다면 서버의 파일 시스템에 원하는 파일을 저장할 수 있다.


CGI(Common Gateway Interface) : 사용자의 요청을 받은 서버가 동적인 페이지를 구성하기 위해 엔진에 요청을 보내고 엔진이 처리한 결과를 서버에게 반환하는 기능 / 확장자를 통해 웹 어플리케이션 엔진에 요청 여부를 판단
(ex) php, jsp, asp
(ex) 웹 서버는 Apache, 웹 어플리케이션은 php를 사용하는 서버에 사용자가 요청을 보내면,
Apache는 사용자의 요청을 해석하고, 사용자가 요청하는 리소스의 확장자가 php엔진을 사용하기로 설정되어 있는 확장자라면 mod_php(CGI)를 통해 사용자의 요청을 php 엔진이 처리 및 실행하도록 요청
// e.g. Apache 설정 파일
<FilesMatch ".+\.ph(p[3457]?|t|tml)$">
SetHandler application/x-httpd-php
</FilesMatch>
위 코드를 보면 .php, .php3/4/5/7, .pht, .phtml 확장자 등을 가진 파일이라면, php에서 처리되도록 핸들링 됨을 확인할 수 있다.
Python의 flask, django 와 Nodejs의 express : 서버,CGI,웹 어플리케이션 등이 통합된 프레임워크, 미리 라우팅 된 경로에만 접근이 가능하도록 설정하여 서비스됨
웹 서비스가 동작하는 경로에 사용자가 원하는 파일 내용과 파일 명을 업로드 할 수 있다면, 서버가 엔진에 요청하는 확장자를 업로드하여 서버의 웹 어플리케이션에 원하는 코드를 실행 할 수 있음
웹 어플리케이션이 실행하는 코드를 악의적인 공격자가 조작할 수 있다면, 웹 어플리케이션 언어에 내장된 OS 명령어 등을 사용할 수 있으며, 해당 서버의 쉘을 웹을 통해 사용 -> WebShell(웹쉘)이라는 악성코드가 등장하게 됨
php 파일을 업로드하여 php를 실행시키거나 html파일 등을 업로드하여 Stored XSS 취약점을 발생시킬 수 있다.
-> .php, .php3/4/5/7, .pht, .phtml 등의 파일 확장자를 업로드하여 서버의 엔진이 처리하도록 유도할 수 있음
(ex)
// exploit.php
<?php
system("ls");
?>
<!-- exploit.html -->
<script>alert(1);</script>
2. command injection
OS Command : linux(ls, pwd, ping, zip), windows(dir, pwd, ping) 등의 OS에서 사용하는 명령어 / 이를 실행하기 위해 PHP(system), Node JS(child_process), Python(os.system)과 같은 함수가 존재 / 내부적으로 셸(Shell)을 이용해 실행
웹 어플리케이션에서 OS Command를 사용하는 이유 : 이미 기능을 구현한 OS 실행 파일이 존재할 때 코드 상에서 다시 구현하지 않고 이를 실행하면 더 편리하기 때문
OS Command를 사용할 때 사용자의 입력 값을 검증하지 않고 함수의 인자로 전달한다면, 특수 문자를 이용해 사용자가 원하는 명령어를 함께 실행할 수 있음
/* `` : 명령어 치환
``안에 들어있는 명령어를 실행한 결과로 치환, 중복 사용은 불가능*/
$ echo `echo theori`
theori
/* $() : 명령어 치환
$()안에 들어있는 명령어를 실행한 결과로 치환, 중복 사용이 가능*/
$ echo $(echo theori)
theori
/* && : 명령어 연속 실행
한 줄에 여러 명령어를 사용하고 싶을 때 사용, 앞 명령어에서 에러가 발생하지 않아야 뒷 명령어를 실행*/
$ echo hello && echo theori
hello
theori
/* || : 명령어 연속 실행
한 줄에 여러 명령어를 사용하고 싶을 때 사용, 앞 명령어에서 에러가 발생해야 뒷 명령어를 실행*/
$ cat / || echo theori
cat: /: Is a directory
theori
/* ; : 명령어 구분자
한 줄에 여러 명령어를 사용하고 싶을 때 사용, 단순히 명령어를 구분하기 위해 사용, 앞 명령어의 에러 유무와 관계 없이 뒷 명령어를 실행*/
$ echo hello ; echo theori
hello
theori
/* | : 파이프
앞 명령어의 결과가 뒷 명령어의 입력으로 들어감*/
$ echo id | /bin/sh
uid=1001(theori) gid=1001(theori) groups=1001(theori)
Command Injection 취약점을 막기 위해서는, 사용자의 입력 데이터가 Command 인자가 아닌 다른 값으로 해석되는 것을 방지해야 함 / 가장 좋은 방법은 웹 어플리케이션에서 OS Command를 사용하지 않는 것
OS Command에 사용자의 입력 데이터를 사용해야할 경우, 필터링을 통해 Command Injection을 방지해야함 (크게 화이트/블랙 리스트 필터링 방식으로 나뉨)
/* 정규식을 통한 화이트리스트방식 필터링
: e.g. ping을 보내는 페이지의 경우 사용자가 입력한 IP가 정상적인 IP 형식인지 정규식으로 검증 후 사용 */
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를 따옴표로 감싸서 사용 */
if '\'' in ip:
return 'not allowed character'
return run_system(f'ping -c 3 \'{ip}\'')
/* 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. Command injection

password를 알아내서 입력하면 문제가 풀리는 것이었다. 화면은 제출창밖에 없었다. 그래서 우선 127.0.0.1을 쳤더니 아래의 첫 번째 사진처럼 무슨 내용이 나와있었다. command injection을 활용해서 문제를 풀면 될 거 같다고 판단했다. 그래서 127.0.0.1; ls을 쳐보니 아래의 두 번째 사진과 같이 index.php가 나왔다. 그래서 127.0.0.1; cat index.php를 쳐보니 아래의 세번째 사진과 같이 나왔다. 그래서 형광펜 친 문자열을 입력해서 문제를 풀었다.




2. File Vulnerability-1)

위의 문제처럼 password를 찾아서 입력하면 문제가 풀린다. 문제는 아래 맨 왼쪽 사진과 같은데 어떻게 해야 할지 모르겠었다. 그래서 그냥 마음에 드는 거 선택해보고 그랬는데, actions에 있는 폭탄을 눌렀더니 저장되었다. 그리고 upload에서 사진을 업로드하니까 등록이 됐다. 근데 아무런 힌트는 없었다. 그래서 그냥 또 사진을 올려보고 그랬다. 근데 얻을 수 있는 정보는 아무것도 없었다. 그래서 문제 제목을 다시 봤다. File upload - Double extensions였다. 그래서 double extensions, 즉 a.php.png처럼 확장자를 두 번 쓰는 것을 사용해야 될 거 같았다. 그래서
<?php
echo `ls -a`; // ``안에 들어있는 명령어를 실행한 결과로 치환
?>
를 a.php.png로 저장하고 업로드해보니, ls -a의 실행 결과가 잘 나왔다. 나온 결과 중에 .과 ..이 있어서, 우선 echo `cd .; ls -a`로 해봤는데 동일한 결과가 나왔다. 그래서 echo `cd ..; ls -a`으로 다시 해보니 긴 문자열이 있었다. 그래서 비밀번호인가 해서 입력해봤지만 틀렸다. 그래서 더 알아보기 위해서 echo `cd ..; cd ..; ls -a`로 했더니, 여러 파일이 있었다. 근데 password가 있어보일 거 같은 파일은 없는 거 같아서 echo `cd ..; cd ..; cd ..; ls -a`로 더 알아봤다. 그랬더니 .passwd가 있었다. 그래서 최종적으로
<?php
echo `cd ..; cd ..; cd ..; cat .passwd`;
?>
를 이중 확장자로 저장하고 업로드해서, 비밀번호를 알아냈고 문제를 풀 수 있었다. 너무 일일이 푼 느낌이 있어서 더 간단하게 푸는 방법에 대해서 알아봐야 될 거 같다.









3. File Vulnerability-2)

이번 문제도 password를 찾아서 입력하면 풀리는 문제다. 우선 봤는데 해골 사진이 무서웠다. 근데 이번에도 저번과 비슷하게 업로드를 해서 풀 수 있을 거 같았다. 그래서 위의 문제에서 푼 것과 같이 이중 확장자로 해봤다. 그랬더니 정말 png로만 인식했다. 그래서 이번 문제의 제목인 MIME type에 대해 알아봤다. MIME type은 Multipurpose Internet Mail Extensions의 약자로, 클라이언트에게 전송된 문서의 다양성을 알려주기 위한 메커니즘이다. text, image, audio 등 여러 타입이 있지만, 그 중 image 타입에서의 일반적인 서브타입의 예시로는 image/gif, image/png, image/jpeg 등이 있다. 문제에서 보면 GIF, JPEG, PNG만 업로드가 된다고 한다. 그래서 MIME type을 변환시킴으로써 문제를 풀 수 있을 거라 생각했다. MIME type을 변환시킬 수 있는 방법을 찾아보니 너무 다양하고 어려운 방법들이 있었다. 그 중 간단하게 변환하고 바로 업로드할 수 있는 Burp Suite를 사용하기로 했다. 우선
<?php
echo `ls -a`;
?>
를 echo_ls.php로 저장하고 파일 선택을 했다. 그리고 Content-Type: application/octet-stream을 Content-Type: image/png로 변경시켜주니 업로드를 할 수 있었다. 그래서 이전 문제 풀이처럼 계속 파일을 찾아봤다. 최종적으로는
<?php
echo `cd ..; cd ..; cd ..; cat .passwd`;
?>
를 저장해서 해주니 password를 알아내서 문제를 풀 수 있었다!!










참고 : File upload vulnerability https://dreamhack.io/learn/1/15#20
command injection https://dreamhack.io/learn/1/15#10
워게임 1 https://www.root-me.org/en/Challenges/Web-Server/PHP-Command-injection
워게임 2 https://www.root-me.org/en/Challenges/Web-Server/File-upload-Double-extensions
워게임 3 https://www.root-me.org/en/Challenges/Web-Server/File-upload-MIME-type