Notice
Recent Posts
Recent Comments
Link
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
Archives
Today
Total
관리 메뉴

binee::

[Codegate 2016] watermelon write up 본문

CTF

[Codegate 2016] watermelon write up

binee108 2016. 3. 27. 00:31

2016 Codegate 대회 당시에 old school에 올인하는 바람에 재대로 보지도 못했던 문제인데,

대회 끝나고 확인 해보니 취약점도 쉽게 찾을 수 있고, exploit 과정 중 어려운 점도 없는 문제였다. 다음 대회 때는 포기 할 건 빨리 포기하고 풀 수 있는 문제에 전념해야 될 것 같다.


pwnable 시작하면서 leak을 이용해서 문제를 푸는 방법은 알고 있었지만,

실제로 직접 leak을 해서 offset을 구한 것은 처음이여서 대회 당시에 잡았다 해도

쉽게 풀지 못 했을지도 모른다. 따라서 이번 writeup을 작성하면서, leak에 대한 개념도 완전히 잡을 수 있었고, leak을 통해 얻은 주소로 offset을 구하는 여러 방법에 대해서도 알 수 있었다. 요근래 CTF 관련 writeup을 보면서 공부하는데, write up은 많이 올라와서 좋은데, system 함수의 offset을 구하는 과정을 모두 생략해서 올린다.

공부하는 입장으로서는 어떻게 system 함수의 offset을 구했는지 알 수가 없어서 답답했다.

나와 같은 초보자분들이 있다면 이 글로 도움이 되었으면 좋겠다.


그리고 라이브러리의 offset을 구하는 각자의 노하우가 있는 것으로 알고 있는데,

아량 깊은 고수님이 계신다면 뎃글로 여러방법을 소개해주시거나 관련 URL을 남겨 주시면 정말 감사하겠습니다.


write up 작성중.. 출제자가 풀이를 올렸네요ㅠㅠ

https://bpsecblog.wordpress.com/2016/03/26/watermelon-feat-%EC%B6%9C%EC%A0%9C%EC%9E%90-in09/

참고하시면 정석 풀이를 보실 수 있습니다.




Binary 분석


watermelon elf 바이너리를 확인 해보면


watermelon: ELF 32-bit LSB  executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=155b637b98c19cff6d3fce40c52dfe301ef746b0, stripped


위와 같이 32bit elf 파일인 것을 확인 할 수 있다.


파일의 보호기법을 보면 NX-bit와 Stack Canary가 있는 것을 확인 할 수 있다.


NX-bit가 있는 것으로 봐서는 RTL이나 ROP를 이용 해야 될 것으로 판단된다.

하지만 binary 크기가 작고 dynamically linked인 것으로 보아 ROP로 쓸 가젯을 구하기 쉽지 않을 것으로 예상된다.

또한 Stack canary가 있는 것으로 보아 FSB, canary leak 취약점이 필요 할 것 같다.





Program Logic 분석




IDA를 통해서 main함수의 로직을 확인해보면 위와 같다.

기능으로는 add, view, modify가 있었고, 숨겨진 menu가 있었는데

이를 secret_menu로 명명했다. 해당 메뉴에 대해서는 분석해보지 않았지만 8자리 문자를 입력받고 암호화한 2진수를 출력한다. 느낌이 함정 같은 느낌이 든다. 일단 넘어가자.


main 함수에 4400바이트 크기로 v4 변수 하나가 선언 되어있는 것을 확인 할 수 있다.

해당 v4는 add, view, modify 함수에 인자로 사용 되는 것으로 보아, music list를 관리하는 변수인 것 같다.



add 함수 내용을 살펴보면 music과 artist 정보를 입력 받는다.

music list를 관리하는 인자값을 a1에 music값과 artist값, list_count 값을 넣는 것을 볼 수 있다.

a1 + 4 +  (list_count * 44) 에 21바이트를 music에 대한 string 값을 넣고

a1 + 24 + (list_count * 44) 에 21바이트를 artist에 대한 string 값을 넣는다.

a1 + (list_count * 44) 에 list_count 값을 저장한다.


위에 넣는 데이터이 구조를 봐서는


struct MusicList{

int num;

char music[20];

char artist[20];

}


총 44바이트인 위와 같은 구조체를 가진다는 것을 추측 할 수 있다.

그래서 list_count * 44 값을 더해서 구조체 배열에 접근하는 것으로 추측된다.



view 함수는 add 함수에서 추가한 구조체에 내용을 출력하는 것을 알 수 있다.

별다른 분석이 필요 없으므로 생략.




modify 함수를 살펴보면 artist 정보를 수정하는 부분에서

20바이트가 아니라 200바이트를 입력 받는 것을 확인 할 수 있다. 

해당 부분에서 overflow가 발생 할 것 같다. 이부분으로 eip 컨트롤 할 수 있을 것 같으므로

일단 체크 해두자.


modify함수를 통해서 Buffer OverFlow가 발생하는 것 같다고 했다.

실제로 Buffer OverFlow가 발생하는지

Stack구조를 확인해보자.


music_list[4400byte] + stack_canary[4byte] + sfp[4byte] + ret[4byte] 로 추측된다.

실제로 그런지 gdb를 통해서 music_list 변수값과 return address까지의 차이를 구해보자.


music_list address : 0xffffc46c

stack_canary address : 0xffffd59c

return address : 0xffffd5ac


music_list에서 ret까지 4416바이트가 차이 난다.

16바이트 중  stack_canary, sfp 각각 4바이트씩 차지하므로

8바이트의 dummy값이 존재하는 것을 알 수 있다.

실제 프롤로그를 확인해보면



push ebp 이외에도


push edi

push ebx 가 있는 것을 확인 할 수 있다.


따라서 스택구조를 다시 그려보면 아래와 같다는 것을 확인 할 수 있다.


music_list[4400byte] + stack_canary[4byte] + dummy[8] + sfp[4byte] + ret[4byte]


music_list를 100개를 추가하고 마지막 100번째 구조체에서

artist 값을 200(기존20byte + 추가 180byte)까지 입력 받으므로

최대 4580까지 쓸 수 있다는 것을 알 수 있다.

return address는 4416에 위치하므로 충분히 Buffer OverFlow로 EIP를 컨트롤 할 수 있는 것을 알 수 있다.






Exploit


분석 결과  Stack OverFlow가 가능 한 것을 확인했다.

NX-bit가 걸려 있고, ,Stack Canary 및 ASLR이 걸려 있으므로,

우선적으로 Stack Canary를 우회를 해야한다.


일반적으로 Stack Canary를 우회하는 방법으로는

Format String Bug와 Canary leak 두가지 방법 중 하나를 이용해야한다.


다행히 modify 함수에서 입력받는 함수가 

read 함수이므로, 문자열 입력이 null terminated로 끝나지 않는다.

artist 값을 20byte를 채우고 마지막을 null byte로 끝내지 않으면

Stack Canary영역까지 문자열로 인식하여, Canary값까지 출력하게 될 것이다.


Stack Canary Leak을 통해서 Canary 값을 알아내고 알아낸 Canary 값을 그대로 넣어주면

손 쉽게 Stack Canary 값을 우회 할 수 있다.


add 함수에서 read함수로 21바이트를 받으므로 a를 20개를 입력하고 전달하면 

엔터값인 0x0a값도 같이 넘어간다. 따라서 canary 값을 훼손시키므로

a문자 19개를 입력하고 전달해서 스택값을 확인해보면



stack canary 값이 00 1d fe 27

0x001dfe27 로 나오는데, null값이 있었다.

처음에 read함수가 null terminated하는 줄 알고 당황했었는데,

a값 18개를 넣고 확인해보니



canary 값 첫 1byte는 leak되는 것을 방지하기 위해서 00을 넣는 것을 알 수 있다.

(이번에 처음 알았다..)

따라서 총 21바이트를 덮어야 하므로 a 문자 20개를 넣어서 0x0a 값과 함께

총 21바이트를 덮어서 leak 을 할 수 있었다.



0x000cfc4b(canary 값) 을 구할 수 있는 것을 확인 할 수 있다.



5%가 출력 된 것을 볼 수 있다.

canary 값이 아스키 표현식으로 모두표현 될 수 없으므로,

정확한 canary 값을 알 수 없다.

하지만 python으로 recv하면 binary로 값으로 canary가 leak되는 것을 확인 할 수 있다.


동일한 방법으로 libc의 값도 leak을 하면 된다.

return address 이전 값까지 문자열로 채워넣고

return address 값을 leak하면 __libc_start_main+243 값을 얻을 수 있다.

해당 값으로 __libc_start_main의 라이브러리 주소를 구할 수 있다.


__libc_start_main 값으로 system 함수의 주소 구해야 하는데,

먼저 현재 사용하고 있는 libc의 버전을 알아야지 정확한 offset값을 구할 수 있다.

보통 http://libcdb.com/ 사이트를 이용해서

함수 2개의 주소 값으로 현재 사용하고 있는 libc의 버전을 확인 할 수 있다.

__libc_start_main과 비교대상의 함수 주소를 하나 더 알아내면

libc의 버전을 알아 낼 수 있다.


현재 바이너리에서 사용한 함수 중 하나를 선택해서

GOT 영역의 값을 leak을 해야하는데,

RTL를 통해서 알아 낼 수 있다.


payload를

100번째 artist 값에

"a"*20 + canary + "b"*12 + write_plt + 0x00000001 + print_got + 0x00000004

로 넣어주면 스택구조는 아래와 같아 질 것 이다.


music_list[4400byte] + stack_canary[4byte] + dummy[8] + sfp[4byte] + write_plt[4byte] + 0x00000001 + &print_got + 0x00000004 


따라서 rtl를 통해서 write 함수가 표준입출력으로 print_got영역의 4byte 값을 출력 할 것이다.

이것을 통해서 print의 libc의 값을 알아 낼 수 있다.




그림과 같이 libc_start_main_243주소는 f7542a83이고

printf 의 주소는 0xf756280이다.





http://libcdb.com/ 사이트를 이용해서 system 함수의 offset을 구해보자.






system 함수의 offset은 00040190 이고



/bin/sh의 offset은 00160a24 이다.




__libc_start_main의 offset은 0x00019990 이므로

libc_base는 F7529000인 것을 알 수 있다.

libc_base의 값은 계속 바뀌니까, exploit을 짤 때 libc_base를 구하는 방법만 기억하면 된다.


최종 exploit code는 아래와 같다.





번외.

libc의 offset을 구하기 위해서는 라이브러리 함수 주소 2개가 필요해서

RTL로 write 함수를 사용해서 leak하는 것이 보편적이다.

하지만 실제 CTF 대회 중에는 빠르게 풀어야 하므로,

라이브러리 주소 한 개만으로 offset을 알아내는 편이다.


https://github.com/niklasb/libc-database

위 사이트의 프로그램을 이용하면

__libc_start_main ret 주소 하나만으로

system 주소와 /bin/sh의 값을 구할 수 있다.

(단, ubuntu에 대한 libc만 찾아주므로 단점이 있다.)


이 방법을 알려준 bbolmin 감사감사.


'CTF' 카테고리의 다른 글

[sCTF 2016] pwn2 write up  (0) 2016.04.19
[sCTF 2016] pwn1 write up  (0) 2016.04.19
[Codegate 2016] oldschool write up  (2) 2016.04.19
[Codegate 2016] manager write up  (0) 2016.04.02
[Boston key party 2015] simple Calc write up  (1) 2016.03.07