해당 바이너리는 64비트며 보호기법은 nx만 설정되어 있다.
바이너리를 실행하면
두번의 입력을 받고 종료된다.
심볼이 없어서 gdb로 함수를 열어볼 수 없다.
따라서 ida로 봐야했다.
main()함수의 헥스레이다.
v3에 16바이트 크기를 malloc으로 동적할당을 해준다.
그리고 *v3에 1을 넣는다.
그 다음 *(QWORD(v3) + 1)에 또다시 8바이트를 동적할당한다. v3가 가리키는 곳에서 한칸(8바이트) 추가된 위치에 할당을 해주는 것이다.
그리고 v4에 16바이트를 할당한 후 위와 비슷하게 *v4에 2를 넣는다. 그 다음 *(QWORT(v4) + 1)위치에 8바이트를 동적할당한다.
그리고 s라는 변수에 4096바이트를 fgets()를 통해 입력받고 strcpy()로 (v3+1)에 복사한다.
다음에도 마찬가지로 s에 4096바이트를 입력받고 strcpy()로 *(v4+1)에 그 값을 넣는다.
그리고 exit()함수로 바이너리를 종료한다.
우선 메인만 봤을 때는 main에서 다른함수로 jump하는 것은 없어서 이게 전부의 기능인듯싶으나 ida로 살펴보면 여러 함수가 많이 있다.
그 중 문제풀이와 관련될 것 같이 생긴 함수가 있어서 분석했다.
sub_400826()함수인데 보면 flag라는 파일을 읽어서 출력해주는 역할을 한다.
메인에서 이 함수로 넘어올 수 있는 방법은 eip를 조작하는 방법 말고는 없어보인다.
처음엔 어떻게 해야할지 막막해서 이전에 풀었던 문제들 중 힙에 대해 찾아보다가 알고보니 protostar excercise heap2와 너무 유사한 문제였다.
바이너리를 차근차근 짚어보면 쉽다.
우선 메인함수의 주소는 0x4008a8다.
x/52i를 하면 main의 어셈코드를 전부 출력할 수 있다.
여기서 bp를 적절히 주었다.
첫번째 fgets에 bp를 걸고 A 8바이트를 줬다.
일단 $rbp-0x1020 = v3 의 스택 상태를 확인해보자.
보면 $rbp-0x1020 에는 malloc(16)한 주소가 *v3에 있다. 그리고 $rbp-0x1018에는 *v4에 동적할당한 주소가 있다.
그리고 이제 strcpy(*((char **)v3 + 1), &s); 를 실행시킨 후 스택과 힙을 봐야한다.
*(v3 + 1)에 stdin이 복사되므로 *v4는 0x602010이므로 *(v3+1)은 8바이트가 더해진 0x602018이다. 즉 0x602018에 있는 주소에 stdin을 복사한다.
예상했던대로 0x602030에 아까 입력한 A 8바이트가 복사되었다.
그리고 그 다음 fgets에서 B를 8바이트 입력해봤다.
stdin에 B가 8바이트가 들어간 것을 확인할 수 있다.
이제 strcpy(*((char **)v4 + 1), &s); 를 확인해보자.
먼저 v4+1의 위치를 보면
0x602070이다.
0x00602010에서부터 메모리를 확인해보면
아까 확인했듯이 *v4는 0x602050이다.
즉 *(v4 + 1)은 0x602058인데 그 위치에 0x602070이 있다. 이 주소에 stdin을 넣는데.. 0x602030부터 overflow로 0x602058까지 덮어서 원하는 주소를 입력하면 eip를 조작할 수 있다.
eip를 조작해서 sub_400826()함수로 jump하면 된다.
다행히 이 바이너리의 마지막은 exit()로 끝나기 때문에 exit@got에 sub_400826()함수의 주소인 0x400826를 덮어버리면 바이너리 마지막 단계에서 sub_400826()함수를 실행하면서 flag를 읽어낼 수 있다.
0x602030부터 0x602054까지 40바이트가 차이가 나니 첫번째 fgets에서 dummy40바이트에 나머지 8바이트를 exit@got의 주소를 넣고 두번째 fgets에서 0x400826를 넣으면 익스가 된다.
exploit code
from pwn import * exit_got = 0x601068 exploit_addr = 0x400826 r = process("./warmheap") payload = "A"*40 payload += p64(exit_got) r.sendline(payload) r.sendline(p64(exploit_addr)) print r.recv()
'CTF' 카테고리의 다른 글
RCTF 2015 welpwn (0) | 2018.08.01 |
---|---|
EasyCTF2017 Simple ROP (0) | 2018.08.01 |
CodeGate2016 watermelon (0) | 2018.07.26 |
CodeGate2014 nuclear (0) | 2018.07.22 |
CodeGate 2014 angry_doraemon (0) | 2018.07.20 |