在一些64位的glibc的payload调用system函数失败问题
TOC
- 1. 问题
- 2. 原因
- 2.1. 演示
- 3. 解决办法
- 3.1. 改变payload长度
- 3.2. 栈转移
- 3.3. 调用execve
- 4. 总结
原先在做题的时候就发现了,一些新的64位的glibc在控制了程序流后,调用system函数的时候,会直接crash,经过调试之后,终于发现了问题所在。
问题
做64位pwn题的时候,特别是栈溢出,在控制程序流后,本以为直接调用system函数就能拿到shell,但是我们往往看到的却是crash:
Thread 2.1 "speedrun-002" received signal SIGSEGV, Segmentation fault. [Switching to process 25578] 0x00007f134a9fc2f6 in do_system (line=0x7f134ab60e9a "/bin/sh") at ../sysdeps/posix/system.c:125 125 ../sysdeps/posix/system.c: No such file or directory. LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA ─────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────── RAX 0x7f134ab60e97 ◂— sub eax, 0x622f0063 /* '-c' */ RBX 0x0 RCX 0x7f134ab60e9f ◂— jae 0x7f134ab60f09 /* 'sh' */ RDX 0x0 RDI 0x2 RSI 0x7f134ad9a6a0 (intr) ◂— 0x0 R8 0x7f134ad9a600 (quit) ◂— 0x0 R9 0x10 R10 0x8 R11 0x246 R12 0x7f134ab60e9a ◂— 0x68732f6e69622f /* '/bin/sh' */ R13 0x7ffe3e3eb140 ◂— 0x1 R14 0x0 R15 0x0 RBP 0x601ce1 ◂— 0x0 RSP 0x601c81 ◂— 0x0 RIP 0x7f134a9fc2f6 (do_system+1094) ◂— movaps xmmword ptr [rsp + 0x40], xmm0 ──────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────── ► 0x7f134a9fc2f6 <do_system+1094> movaps xmmword ptr [rsp + 0x40], xmm0 0x7f134a9fc2fb <do_system+1099> call sigaction <0x7f134a9ec110> 0x7f134a9fc300 <do_system+1104> lea rsi, [rip + 0x39e2f9] <0x7f134ad9a600> 0x7f134a9fc307 <do_system+1111> xor edx, edx 0x7f134a9fc309 <do_system+1113> mov edi, 3 0x7f134a9fc30e <do_system+1118> call sigaction <0x7f134a9ec110> 0x7f134a9fc313 <do_system+1123> xor edx, edx 0x7f134a9fc315 <do_system+1125> mov rsi, rbp 0x7f134a9fc318 <do_system+1128> mov edi, 2 0x7f134a9fc31d <do_system+1133> call sigprocmask <0x7f134a9ec140> 0x7f134a9fc322 <do_system+1138> mov rax, qword ptr [rip + 0x39bb7f] ───────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────── 00:0000│ rsp 0x601c81 ◂— 0x0 01:0008│ 0x601c89 —▸ 0x7f134ab60e97 ◂— sub eax, 0x622f0063 /* '-c' */ 02:0010│ 0x601c91 ◂— 0x0 ... ↓ 04:0020│ 0x601ca1 —▸ 0x7f134a9fc360 (cancel_handler) ◂— push rbx 05:0028│ 0x601ca9 —▸ 0x601c9d ◂— 0x4a9fc36000000000 06:0030│ 0x601cb1 ◂— 0x0 ... ↓ ─────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────── ► f 0 7f134a9fc2f6 do_system+1094 f 1 a f 2 0 Program received signal SIGSEGV (fault address 0x0)
|
程序直接crash了。
原因
主要原因是0x4F2F6
处的movaps [rsp+198h+var_158], xmm0
指令要求rsp+198h+var_158
的值是对齐16byte
(0x10),否则会直接触发中断从而crash。
.text:000000000004F2F1 movhps xmm0, [rsp+198h+var_190] .text:000000000004F2F6 movaps [rsp+198h+var_158], xmm0 ; here .text:000000000004F2FB call sigaction
|
演示
这里我用一个简单的程序来演示这个问题。
shell.c
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h>
int main() { system("/bin/sh"); return 0; }
|
程序编译之后是能正常运行的,但是我们要的是让程序不正常运行。
接下来直接我们就在.text:000000000004F2F6 movaps [rsp+198h+var_158], xmm0 ; here
这里下断点,也就是do_system+1094
处,然后运行到此。
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA ─────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────── RAX 0x7ffff7b97e97 ◂— sub eax, 0x622f0063 /* '-c' */ RBX 0x0 RCX 0x7ffff7b97e9f ◂— jae 0x7ffff7b97f09 /* 'sh' */ RDX 0x0 RDI 0x2 RSI 0x7ffff7dd16a0 (intr) ◂— 0x0 R8 0x7ffff7dd1600 (quit) ◂— 0x0 R9 0x7ffff7dd0d80 (initial) ◂— 0x0 R10 0x8 R11 0x246 R12 0x400594 ◂— 0x68732f6e69622f /* '/bin/sh' */ R13 0x7fffffffdc60 ◂— 0x1 R14 0x0 R15 0x0 RBP 0x7fffffffda40 ◂— 0x0 RSP 0x7fffffffd9e0 ◂— 0x0 RIP 0x7ffff7a332f6 (do_system+1094) ◂— movaps xmmword ptr [rsp + 0x40], xmm0 ──────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────── ► 0x7ffff7a332f6 <do_system+1094> movaps xmmword ptr [rsp + 0x40], xmm0 0x7ffff7a332fb <do_system+1099> call sigaction <0x7ffff7a23110> 0x7ffff7a33300 <do_system+1104> lea rsi, [rip + 0x39e2f9] <0x7ffff7dd1600> 0x7ffff7a33307 <do_system+1111> xor edx, edx 0x7ffff7a33309 <do_system+1113> mov edi, 3 0x7ffff7a3330e <do_system+1118> call sigaction <0x7ffff7a23110> 0x7ffff7a33313 <do_system+1123> xor edx, edx 0x7ffff7a33315 <do_system+1125> mov rsi, rbp 0x7ffff7a33318 <do_system+1128> mov edi, 2 0x7ffff7a3331d <do_system+1133> call sigprocmask <0x7ffff7a23140> 0x7ffff7a33322 <do_system+1138> mov rax, qword ptr [rip + 0x39bb7f] ───────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────── 00:0000│ rsp 0x7fffffffd9e0 ◂— 0x0 01:0008│ 0x7fffffffd9e8 —▸ 0x7ffff7b97e97 ◂— sub eax, 0x622f0063 /* '-c' */ 02:0010│ 0x7fffffffd9f0 ◂— 0x0 ... ↓ 04:0020│ 0x7fffffffda00 —▸ 0x7ffff7a33360 (cancel_handler) ◂— push rbx 05:0028│ 0x7fffffffda08 —▸ 0x7fffffffd9fc ◂— 0xf7a3336000000000 06:0030│ 0x7fffffffda10 —▸ 0x7ffff7ffe738 —▸ 0x7ffff7ffe710 —▸ 0x7ffff7ffa000 ◂— jg 0x7ffff7ffa047 07:0038│ 0x7fffffffda18 ◂— 0x0 ─────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────── ► f 0 7ffff7a332f6 do_system+1094 f 1 7ffff7a3344a system+10 f 2 4004f7 main+16 f 3 7ffff7a05b97 __libc_start_main+231 Breakpoint *(0x7ffff7a32eb0+1094)
|
然后在来看看rsp + 0x40
的值。
pwndbg> p/x $rsp+0x40 $1 = 0x7fffffffda20
|
可以看到此时的值是对齐的,所以可以正常运行,我们尝试对rsp
加1,看看会不会crash。
pwndbg> set $rsp=$rsp+1 LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA ─────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────── RAX 0x7ffff7b97e97 ◂— sub eax, 0x622f0063 /* '-c' */ RBX 0x0 RCX 0x7ffff7b97e9f ◂— jae 0x7ffff7b97f09 /* 'sh' */ RDX 0x0 RDI 0x2 RSI 0x7ffff7dd16a0 (intr) ◂— 0x0 R8 0x7ffff7dd1600 (quit) ◂— 0x0 R9 0x7ffff7dd0d80 (initial) ◂— 0x0 R10 0x8 R11 0x246 R12 0x400594 ◂— 0x68732f6e69622f /* '/bin/sh' */ R13 0x7fffffffdc60 ◂— 0x1 R14 0x0 R15 0x0 RBP 0x7fffffffda40 ◂— 0x0 *RSP 0x7fffffffd9e1 ◂— 0x9700000000000000 RIP 0x7ffff7a332f6 (do_system+1094) ◂— movaps xmmword ptr [rsp + 0x40], xmm0 ──────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────── ► 0x7ffff7a332f6 <do_system+1094> movaps xmmword ptr [rsp + 0x40], xmm0 0x7ffff7a332fb <do_system+1099> call sigaction <0x7ffff7a23110> 0x7ffff7a33300 <do_system+1104> lea rsi, [rip + 0x39e2f9] <0x7ffff7dd1600> 0x7ffff7a33307 <do_system+1111> xor edx, edx 0x7ffff7a33309 <do_system+1113> mov edi, 3 0x7ffff7a3330e <do_system+1118> call sigaction <0x7ffff7a23110> 0x7ffff7a33313 <do_system+1123> xor edx, edx 0x7ffff7a33315 <do_system+1125> mov rsi, rbp 0x7ffff7a33318 <do_system+1128> mov edi, 2 0x7ffff7a3331d <do_system+1133> call sigprocmask <0x7ffff7a23140> 0x7ffff7a33322 <do_system+1138> mov rax, qword ptr [rip + 0x39bb7f] ───────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────── 00:0000│ rsp 0x7fffffffd9e1 ◂— 0x9700000000000000 01:0008│ 0x7fffffffd9e9 ◂— 0x7ffff7b97e 02:0010│ 0x7fffffffd9f1 ◂— 0x0 03:0018│ 0x7fffffffd9f9 ◂— 0x6000000000000000 04:0020│ 0x7fffffffda01 ◂— 0xfc00007ffff7a333 05:0028│ 0x7fffffffda09 ◂— 0x3800007fffffffd9 06:0030│ 0x7fffffffda11 ◂— 0x7ffff7ffe7 07:0038│ 0x7fffffffda19 ◂— 0x100000000000000 ─────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────── ► f 0 7ffff7a332f6 do_system+1094 f 1 4004 f 2 9700000000000000 f 3 100007ffff7a05b f 4 6800000000000000 f 5 7fffffffdc f 6 e700000001000080 f 7 4004 f 8 a400000000000000 f 9 6b6cdf11464cf7 f 10 6000000000004004 Breakpoint *(0x7ffff7a32eb0+1094)
|
继续来查看rsp + 0x40
的值。
pwndbg> p/x $rsp+0x40 $2 = 0x7fffffffda21
|
可以看到此时已经不对齐了,那么继续运行。
pwndbg> c Continuing.
Thread 2.1 "shell" received signal SIGSEGV, Segmentation fault. 0x00007ffff7a332f6 in do_system (line=0x400594 "/bin/sh") at ../sysdeps/posix/system.c:125 125 in ../sysdeps/posix/system.c LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA ─────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────── RAX 0x7ffff7b97e97 ◂— sub eax, 0x622f0063 /* '-c' */ RBX 0x0 RCX 0x7ffff7b97e9f ◂— jae 0x7ffff7b97f09 /* 'sh' */ RDX 0x0 RDI 0x2 RSI 0x7ffff7dd16a0 (intr) ◂— 0x0 R8 0x7ffff7dd1600 (quit) ◂— 0x0 R9 0x7ffff7dd0d80 (initial) ◂— 0x0 R10 0x8 R11 0x246 R12 0x400594 ◂— 0x68732f6e69622f /* '/bin/sh' */ R13 0x7fffffffdc60 ◂— 0x1 R14 0x0 R15 0x0 RBP 0x7fffffffda40 ◂— 0x0 RSP 0x7fffffffd9e1 ◂— 0x9700000000000000 RIP 0x7ffff7a332f6 (do_system+1094) ◂— movaps xmmword ptr [rsp + 0x40], xmm0 ──────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────── ► 0x7ffff7a332f6 <do_system+1094> movaps xmmword ptr [rsp + 0x40], xmm0 0x7ffff7a332fb <do_system+1099> call sigaction <0x7ffff7a23110> 0x7ffff7a33300 <do_system+1104> lea rsi, [rip + 0x39e2f9] <0x7ffff7dd1600> 0x7ffff7a33307 <do_system+1111> xor edx, edx 0x7ffff7a33309 <do_system+1113> mov edi, 3 0x7ffff7a3330e <do_system+1118> call sigaction <0x7ffff7a23110> 0x7ffff7a33313 <do_system+1123> xor edx, edx 0x7ffff7a33315 <do_system+1125> mov rsi, rbp 0x7ffff7a33318 <do_system+1128> mov edi, 2 0x7ffff7a3331d <do_system+1133> call sigprocmask <0x7ffff7a23140> 0x7ffff7a33322 <do_system+1138> mov rax, qword ptr [rip + 0x39bb7f] ───────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────── 00:0000│ rsp 0x7fffffffd9e1 ◂— 0x9700000000000000 01:0008│ 0x7fffffffd9e9 ◂— 0x7ffff7b97e 02:0010│ 0x7fffffffd9f1 ◂— 0x0 03:0018│ 0x7fffffffd9f9 ◂— 0x6000000000000000 04:0020│ 0x7fffffffda01 ◂— 0xfc00007ffff7a333 05:0028│ 0x7fffffffda09 ◂— 0x3800007fffffffd9 06:0030│ 0x7fffffffda11 ◂— 0x7ffff7ffe7 07:0038│ 0x7fffffffda19 ◂— 0x100000000000000 ─────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────── ► f 0 7ffff7a332f6 do_system+1094 f 1 4004 f 2 9700000000000000 f 3 100007ffff7a05b f 4 6800000000000000 f 5 7fffffffdc f 6 e700000001000080 f 7 4004 f 8 a400000000000000 f 9 6b6cdf11464cf7 f 10 6000000000004004 Program received signal SIGSEGV (fault address 0x0)
|
从上面可以看到,程序就直接crash了。
解决办法
核心思想就是改变栈的地址。
- 改变payload长度
- 栈转移
改变payload长度
直接更改我们的payload长度,在栈溢出的时候栈的地址自然不同,然后将栈地址+1
,如果不行的话,就继续增加,最多也就改16次就一定会遇到栈对齐的情况。
栈转移
当payload有长度限制的时候,我们可以尝试进行栈转移来进行栈地址的改变,如果遇到了没有对齐的情况就继续将栈地址+1
,直到遇到栈对齐的情况。
调用execve
用execve函数来替换system函数,这个要求就更高,应为他需要三个参数才能正常调用。也就是说我们需要构造rdi
、rsi
、rdx
这三个参数。
int execve(const char * filename,char * const argv[ ],char * const envp[ ]);
|
总结
遇到问题就多上手调试一下。