By choirish | August 10, 2018
(난) 알고싶지만 (너)에겐 쓸데없는 Web
잡동사니 CH.03
안녕하세요, choirish
입니다 :)
알쓸웹잡 세 번째 시간(!)
webhacking.kr
문제를 풀다 찾아본 내용에 대해 썰을 풀어보겠습니다.
오늘의 탐구 Challenge
- Challenge 25
- LFI(Local File Inclusion)
- Challenge 48
- OS Command Injection
Challenge 25
해당 페이지의 index.php 소스 코드가 있는 디렉터리 정보가 힌트로 공개되었다.
URL을 보면, file
변수의 값을 GET 방식으로 전달하는 것을 알 수 있다.
왠지 file
변수에 hello
를 넣음으로써
hello.txt 파일의 내용을 불러와 하단의 회색 박스에 표시해주는 것 같다.
hello.txt 파일의 내용을 직접 확인해보니 “hello world”로, 회색 박스와 일치한다(!)
그럼… file
변수를 이용하여 password.php를 읽으면 될 것 같은데…
?file=hello
형태로 입력하는 것으로 보아
해당 페이지에서는 파일 이름만 file
변수로 받고,
.txt 확장자를 자동으로 추가하여 불러오도록 되어있는 것 같다.
그렇다면… \x00
를 이용하여 .txt 확장자를 떼어버리자(!)
위와 같이 입력했더니, password.php의 내용이 회색박스에 뙇 성공적으로 출력되었다(!)
해당 페이지에서는 GET 방식을 통해 파일 이름을 전달 받아 이를 실행한다.
php에서는 include
구문(statement)이 이러한 기능을 한다.
PHP include statement
지정된 text/code/markup 파일을 가져와 읽고 실행한다.
웹사이트의 여러 페이지에서 하나의 PHP/HTML/text을 공통적으로 불러와 실행해야 할 때 유용하게 쓸 수 있다.
그런데 해당 문제에서와 같이 include
구문의 인자값에 사용자의 입력이 영향을 미칠 수 있는 경우,
(임의의 파일을 실행함으로써) 임의의 명령을 실행할 수 있는 LFI(Local File Inclusion) 취약점이 발생할 수 있다.
LFI… 내가 임의의 파일을 코드에 포함시켜 실행할 수 있는 취약점이라고,
많이 들어는 봤는데 내가 잘 알고 있는지 모르겠다… ㅇㅅㅇa
include 구문에 의해서만 발생 가능한 녀석인지…
어떻게 활용할 수 있는지…
한번 알아보자(!)
About LFI(Local File Inclusion)
LFI 취약점을 검색하면 항상, include
구문을 통해 발생된다는 내용이 대부분이여서…
LFI 취약점은 include
구문에 의해서만 발생가능한 건가…? 궁금했었다.
뭔가 취약점이 발생한다고 하면, 유사한 상황을 일으키는 함수의 종류가 여러개 있거나…
사실 지금 고민해보니 나도 잘 모르겠지만ㅋㅋㅋ
왠지 그냥 처음엔 함수 하나를 잘못 써서 이런 문제가 발생한다고? 라는 의문이 들었다 ㅎ (왜그랫지?)
의식의 흐름을 그냥 따라가보면..
사실 다른 취약점들도 특정 함수나 기능을 안전하게 사용하지 않아서 발생하는 게 꽤 많긴하네….?! ㅋㅋ
그런데 그냥… pwnable에서 buffer overflow가 발생할 수 있는 함수가 매우 다양하고,
command injection이 발생하는 system 함수가 언어마다 조금씩 이름이 다르다거나 유사한 기능을 가진 함수가 몇 개 더 있기 마련이니..
LFI 취약점도, include
말고 다른 함수들도 있지 않을까? 한번 생각해봤던 것 같다 ㅎㅎ
그래서 검색해보았더니(!)
PHP에서 이러한 기능을 하는 구문으로, include
/ require
요 두가지가 있더라.
include
와 require
의 차이는 “에러가 발생한 경우 어떻게 동작하는가” 이다.
- include will only produce a warning (E_WARNING) and the script will continue
- require will produce a fatal error (E_COMPILE_ERROR) and stop the script
일반적으로 include
를 훠얼씬 많이 쓰는 것 같으니, require
도 있구나~ 알고 넘어가면 될 것 같다.
사실 LFI 취약점의 정의를 봐도, include/require
구문에서 발생하는 취약점이야(!)라고 해놓지는 않았다.
A file inclusion vulnerability is a type of vulnerability that is most commonly found to affect web applications that rely on a scripting run time. This issue is caused when an application builds a path to executable code using an attacker-controlled variable in a way that allows the attacker to control which file is executed at run time.
요약하면, 웹 애플리케이션이 실시간으로 파일을 불러와 이를 실행할 때
해당 파일의 이름을 사용자가 컨트롤할 수 있고, 이를 제대로 검사하지 않는 경우 LFI 취약점이 발생하는 것이다.
그래서 꼭 include/require 구문이 아니더라도,
같은 기능을 하는 커스텀 함수를 만들어 사용하는 경우에도
사용자 입력을 안전하게 검증하지 않으면 LFI 취약점이 발생할 수 있다.
하지만 결론은, 이래나저래나 어쩃든 include
구문의 기능을 안전하게 사용하지 못했을 때 일어나는 거니까(!)
LFI 취약점이 발생하는 함수가 뭐야? 하나뿐이야? 라고 따질 필요없이
취약점이 발생하는 원인과 취약점의 본질에만… 집중하자(!)는 것이다 ^^
Example
LFI 취약점이 발생 가능한 예제 코드를 찾아보았다(!)
OWASP Testing Guide 페이지 하단에,
GET 방식으로 파일이름을 받아 특정 확장자로 지정한 후 include 하는 php 코드가 예시로 나와있는데…
<?php “include/”.include($_GET['filename'].“.php”); ?>
challenge 44의 코드가 왠지 딱 이렇게 생겼을 느낌이 든다 ^^
nullbyte를 이용하여 지정된 확장자를 떼어내는 방법도 함께 잘 설명되어 있다.
그.런.데. nullbyte를 사용하여 확장자를 우회하는 방법은
낮은 버전의 php 에서만 된다는 소문을 듣게 되었다(!)
StackOverflow - null byte injection not happening
php - Null byte 관련 이슈
그래서 찾아봤더니… php 5.3.4 버전 이후로,
PATH를 처리할 때 null byte 뒤에 오는 부분을 잘라내는 문제를 수정하였다고 한다^^
PHP 5.3.4 Release Announcement
bugs.php.net - Request #39853
그렇다면… null byte도 못쓰는데…
LFI 방어 기법( ex : input filters )을 어떻게 우회할 수 있을까?!
PHP Wrappers
php wrapper는, wrapper라는 단어의 뜻처럼 “코드나 데이터를 둘러싼 또 하나의 코드”로,
wrapper로 감싼 data나 코드를 해당 wrapper의 기능을 통해 처리하는 녀석이다(!)
사실 처음 들으면 이게 무슨 소리지(?) 뜬구름 처럼 들릴 수도 있는데…
나는 일단… wrapper가 data를 특정 형태로 처리? 변환? 해주는 녀석이라고 이해하기로 했다 ㅋㅋ
무튼(!) 웹 애플리케이션의 사용자 input 필터링을 피하고,
내가 원하는 값을 잘 전달하기 위해 wrapper로 한번 숨겨서 감싸넣어보자…! 라고 생각하는 것이다.
정확한 의미와 기능은… 각자 직접 써보면서 몸소 느껴보길 ^^
사실 흔히 보는 http://
도, HTTP 프로토콜을 통해 파일이나 리소스(resouces)에 접근하기 위한 URL-syntax 형식의 wrapper 라고 한다(!)
그 이외에도… php는 다양한 built-in wrapper 를 제공하는데…
각 wrapper의 세부 활용법은 너무 무궁무진하므로…
hakin9.org
에 소개된 세 가지의 wrapper만 간단히 살펴보자(!)
hakin9.org - Web Application Penetration Testing: Local File Inclusion (LFI) Testing
php - expect://
php - php://
php - zip://
1. expect://
- Process Interaction Streams
- system commands를 실행해 준다(!)
2. php://filter
- Accessing various I/O streams
- 다양한 In/Out Stream을 다루는데, 이 중에서
filter
기능을 활용하자(!)
convert.based64-encode
: 데이터를 base64로 인코딩
resource
: php://filter의 필수 parameter. 필터링할 stream을 명시
3. zip://
- Compression Streams
- zip 파일의 압축을 풀고, zip 파일 안에 들어있는 특정 파일을 실행한다(!)
zip://file.zip#shell.php
: file.zip 안에 들어있는(#) shell.php를 실행
php wrappers 외에, LFI 를 공략할 수 있는 다양한 전략들은 아래 링크 페이지를 참고하자(!)
Local File Inclusion Vulnerability
5 ways to Exploit LFi Vulnerability
Challenge 48
메모를 남길 수 있고, 원하면 파일도 함께 업로드할 수 있다.
메시지 길이에는 제한이 딱히 없는 것 같은데…(잘모름)
첨부파일의 이름은 최대 3글자까지만 가능하다 (수상해)
memo는 “aaa”, 첨부 파일 이름은 “bbb”로 Send 해보자.
불쌍한(?) 여자아이 얼굴이다…
(나도 귀여운 캐릭터얼굴하고싶은데… 방법이 뭐지?…!)
upload file
을 클릭하면 업로드한 파일의 내용을 확인할 수 있는데, 파일의 내용은 모두 null이 된다.
그리고 URL을 보면, 업로드한 파일(“bbb”)이
해당 문제 페이지의 소스코드가 있는 디렉터리(/challenge/bonus/bonus-12/) 안의 upload 디렉터리에 저장됨을 알 수 있다.
이 때, 등록한 메모를 Delete
하면 메모와 함께 upload 디렉터리의 “bbb” 파일도 사라진다.
그러면… 아마 서버에서는 system 같은 명령어를 사용해서 /upload/bbb
를 삭제하지 않을까…? 예상해 볼 수 있다.
그러면…… bbb
에 이상한 짓을 하면, system 명령을 통해 내가 원하는 명령어를 실행하는 것도 가능할 것 같은데…(!)
이게 바로 Command Injection(!) 이다 ^^
Command Injection
사용자의 입력이 쉘 명령으로 실행되거나, 쉘 명령어에 영향을 미칠 때, 임의의 명령을 삽입하여 실행할 수 있는 공격 방법
Shell Command 에서 사용되는 특수 문자(
;
&&
||
$
등)를 이용하여, 명령어 삽입 가능
A ; B
: A 명령 성공여부에 관계없이, A를 실행한 후 B를 실행A && B
: A 명령이 성공했을 때만, A 성공 후 B를 실행A || B
: A 명령이 실패했을 때만, A 실패 후 B를 실행
howtogeek.com - How to Run Two or More Terminal Commands at Once in Linux
그렇다면, 첨부 파일 이름의 길이 제한이 3글자 이므로
첨부 파일의 이름을 ;ls
로 설정하여 업로드할 수 있다.
그랬더니, 웹 서버의 해당 페이지 디렉토리에서 ls
명령을 실행한 결과가 다음과 같이 출력된다.
제일 마지막에 수상한 zwitter_admin.php 페이지로 접속하면, 성!공!
그런데… 파일 이름을 ;id
로 만들고 업로드했다가 삭제했더니
id 명령어 실행 결과는 출력해주지 않더라…
ls 명령어만 실행가능하도록 필터링(?) 해두신건가… 넘나 제한적인 것(!)
그리고… ;
가 아닌 다른 특수문자로도 시도해보고 싶어서
||
를 이용하여 파일을 업로드해보고 싶었는데…
파일 이름에 |
을 쓸 수가 없더라…ㅋㅋㅋㅋ
사실 Command Injection을 처음 알게 된 건…
공유기에 이 공격 방법이 잘 먹힌다는 소문을 들은 거였는데 ㅋㅋㅋ
이번엔 Command Injection이 웹 애플리케이션 관점에서는 어떻게 활용될 수 있는지 한번 알아보자(!)
About Command Injection
Command Injection 취약점은 사실 Windows/Linux/Unix 등의 OS 시스템이 사용되는 곳이라면 어디든지 존재할 수 있다.
공유기에도 조그맣지만 Linux OS를 탑재하고 있고,
웹페이지도 결국 웹서버(Windows/Linux/…)를 통해 동작하므로, Command Injection의 가능성은 항상 존재하는 것이다.
그렇다면, 웹 애플리케이션에서는 왜 system 명령이 필요할까?
- 가끔 웹 서버의 OS 시스템과 상호작용할 일이 생긴다. 가령…
- 웹 애플리케이션을 구성하는 언어와 다른 언어로 짜여진 애플리케이션이나 스크립트를 실행해야 할 수 있다.
- 웹 서버에 존재하는 파일을 동적으로 사용(삭제 등)해야 할 수 있다.
원하는 쉘 명령어를 프로그램 내에서 자유롭게 쓸 수 있도록 해주는 녀석이라…
매우 강려크하다(!)
그래서 더 조심해서 써야 한다(!)
C, PHP 에서는 공통적으로 system
함수가 이런 역할을 하는데,
언어마다 이러한 기능을 하는 함수 이름도 다르고, 종류도 다양하다.
나는 PHP 언어에서, 쉘 명령어를 실행할 수 있는 대표적인 함수들을 한번 살펴보았다.
세 함수 모두 Execute an external program 기능을 한다.
검색하다보니 StackOverflow에 PHP exec() vs system() vs passthru()
를 제목으로,
세 함수의 차이점에 대한 질문/답변이 잘 나와있다.
- exec() is for calling a system command, and perhaps dealing with the > output yourself.
- system() is for executing a system command and immediately displaying the output - presumably text.
- passthru() is for executing a system command which you wish the raw return from - presumably something binary.
세 함수 모두 시스템 명령어를 실행하는데, 결과값의 형태에 따라 상황에 맞게 사용할 수 있다.
Example
OWASP 페이지의 Example 6에, Command Injection에 취약한 php 코드가 간단한 예시로 나와있는데
challenge 48의 코드도 왠지 딱 비슷하게 생겼을 느낌이 든다.
<?php
print("Please specify the name of the file to delete");
print("<p>");
$file=$_GET['filename'];
system("rm $file");
?>
그렇다면… 웹 애플리케이션 상에서 Command Injection 공격을 수행할 경우,
우리가 풀어본 48번 문제처럼 Command를 실행한 결과를 매번 바로 확인할 수 있나?
아니다(!)
Visible(?) or Blind(?)
blackhat EUROPE 2015에서 @ancst 님이 발표한 내용을 참고하면,
공격 결과가 출력되는지 여부에 따라 Command Injection을 다음과 같이 분류하였다.
1. Results-based command injections
- Vulnerable Application이 Command 실행 결과를 출력하는 경우
- 공격자는 공격 결과와 성공 여부를 바로 확인할 수 있다.
2. Blind command injections
- Vulnerable Application이 Command 실행 결과를 출력하지 않는 경우
- 공격자는 공격 실행 결과를 곧바로 확인할 수 없다.
- Time-based technique / File-based technique 활용 가능
앞서 알아본 exec / system 함수의 차이점을 활용한 한 줄 예제는 다음과 같다.
1. Results-based command injections
<?php
system("/bin/ping -c 4 ".$_GET["addr"]);
?>
2. Blind command injections
<?php
exec("/bin/ping -c 4 ".$_GET["addr"]);
?>
결과가 출력되지 않는 상황에서는, 공격 결과를 어떻게 확인 할 수 있는지
@ancst 님의 발표자료에 예제와 함께 설명되어 있으니 이를 참고하자(!)
blackhat.com - Commix:Detecting & Exploiting Command Injection Flaws.
마무리하며… 갑작스런 의식의 흐름 고백 타임
흠냐… 사실 요새 마음의 여유가 없었다… (뜬금포?..!)
ㅋㅋㅋㅋ 그래서.. 문제를 풀면서 흥미와 재미있는 궁금증이 막 샘솟지 않았다…(고백)
그래서…. 이번엔 그냥 기본 개념을 차근차근 되돌아보는 시간을 가졌다 ^^
그런데 다행히 (개인적으로는) 도움이 되었다(!)
예전에 LFI 취약점을 야매로 공부한 적이 있었는데…
그 때는 그냥 30% 이해하는 정도?로 외우듯이 개념을 되뇌었다…
그래서 그 때는 조금만 지나도 개념을 까먹고 백지가 되었는데… (흑역사)
이렇게 다시 LFI를 만나게 되어 차근차근 개념을 되짚어보니
역시(!) 과거의 나보다 훨씬 이해도가 높아진 현재의 나를 발견할 수 있었다…(!)
오늘의 교훈
- 아는 것이 쌓일 수록, 보고 이해하는 정도가 점점 더 많이 깊어진다.
- 지금 다 이해할 수 있으면 좋지만, 그럴 수 없다면…
다른 것도 공부하면서 돌고 돌아 하나씩 주워담다보면 나중에 결국 자연스레 이해할 수 있을테니 너무 초조해하지 말자 ^0^
TO BE CONTINUED… SEE YOU IN CH.04 (!)