roger 发表于 2020-4-27 00:32:46

64位的glibc的payload调用system函数失败问题

原先在做题的时候就发现了,一些新的64位的glibc在控制了程序流后,调用system函数的时候,会直接crash,经过调试之后,终于发现了问题所在。

实验用的文件下载,百度网盘:https://pan.baidu.com/s/1mEcCIzeYtDIo-xmHsM8AFA (提取码:ycyx)。
# 问题
做64位pwn题的时候,特别是栈溢出,在控制程序流后,本以为直接调用system函数就能拿到shell,但是我们往往看到的却是crash:
```
Thread 2.1 "speedrun-002" received signal SIGSEGV, Segmentation fault.

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 ]─────────────────────────────────────────────────
RAX0x7f134ab60e97 ◂— sub    eax, 0x622f0063 /* '-c' */
RBX0x0
RCX0x7f134ab60e9f ◂— jae    0x7f134ab60f09 /* 'sh' */
RDX0x0
RDI0x2
RSI0x7f134ad9a6a0 (intr) ◂— 0x0
R8   0x7f134ad9a600 (quit) ◂— 0x0
R9   0x10
R100x8
R110x246
R120x7f134ab60e9a ◂— 0x68732f6e69622f /* '/bin/sh' */
R130x7ffe3e3eb140 ◂— 0x1
R140x0
R150x0
RBP0x601ce1 ◂— 0x0
RSP0x601c81 ◂— 0x0
RIP0x7f134a9fc2f6 (do_system+1094) ◂— movaps xmmword ptr , xmm0
──────────────────────────────────────────────────[ DISASM ]───────────────────────────────────────────────────
► 0x7f134a9fc2f6 <do_system+1094>    movaps xmmword ptr , xmm0
   0x7f134a9fc2fb <do_system+1099>    call   sigaction <0x7f134a9ec110>

   0x7f134a9fc300 <do_system+1104>    lea    rsi, <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
───────────────────────────────────────────────────[ STACK ]───────────────────────────────────────────────────
00:0000│ rsp0x601c81 ◂— 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 , xmm0指令要求rsp+198h+var_158的值是对齐16byte(0x10),否则会直接触发中断从而crash。
```
.text:000000000004F2F1 movhpsxmm0,
.text:000000000004F2F6 movaps, xmm0 ; here
.text:000000000004F2FB call    sigaction
```
# 演示
这里我用一个简单的程序来演示这个问题。

shell.c
```
// compiled: gcc -g -no-pie -Og shell.c -o shell
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main()
{
    system("/bin/sh");
    return 0;
}
```
程序编译之后是能正常运行的,但是我们要的是让程序不正常运行。

接下来直接我们就在.text:000000000004F2F6 movaps , xmm0 ; here这里下断点,也就是do_system+1094处,然后运行到此。
```
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
─────────────────────────────────────────────────[ REGISTERS ]─────────────────────────────────────────────────
RAX0x7ffff7b97e97 ◂— sub    eax, 0x622f0063 /* '-c' */
RBX0x0
RCX0x7ffff7b97e9f ◂— jae    0x7ffff7b97f09 /* 'sh' */
RDX0x0
RDI0x2
RSI0x7ffff7dd16a0 (intr) ◂— 0x0
R8   0x7ffff7dd1600 (quit) ◂— 0x0
R9   0x7ffff7dd0d80 (initial) ◂— 0x0
R100x8
R110x246
R120x400594 ◂— 0x68732f6e69622f /* '/bin/sh' */
R130x7fffffffdc60 ◂— 0x1
R140x0
R150x0
RBP0x7fffffffda40 ◂— 0x0
RSP0x7fffffffd9e0 ◂— 0x0
RIP0x7ffff7a332f6 (do_system+1094) ◂— movaps xmmword ptr , xmm0
──────────────────────────────────────────────────[ DISASM ]───────────────────────────────────────────────────
► 0x7ffff7a332f6 <do_system+1094>    movaps xmmword ptr , xmm0
   0x7ffff7a332fb <do_system+1099>    call   sigaction <0x7ffff7a23110>

   0x7ffff7a33300 <do_system+1104>    lea    rsi, <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
───────────────────────────────────────────────────[ STACK ]───────────────────────────────────────────────────
00:0000│ rsp0x7fffffffd9e0 ◂— 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 ]─────────────────────────────────────────────────
RAX0x7ffff7b97e97 ◂— sub    eax, 0x622f0063 /* '-c' */
RBX0x0
RCX0x7ffff7b97e9f ◂— jae    0x7ffff7b97f09 /* 'sh' */
RDX0x0
RDI0x2
RSI0x7ffff7dd16a0 (intr) ◂— 0x0
R8   0x7ffff7dd1600 (quit) ◂— 0x0
R9   0x7ffff7dd0d80 (initial) ◂— 0x0
R100x8
R110x246
R120x400594 ◂— 0x68732f6e69622f /* '/bin/sh' */
R130x7fffffffdc60 ◂— 0x1
R140x0
R150x0
RBP0x7fffffffda40 ◂— 0x0
*RSP0x7fffffffd9e1 ◂— 0x9700000000000000
RIP0x7ffff7a332f6 (do_system+1094) ◂— movaps xmmword ptr , xmm0
──────────────────────────────────────────────────[ DISASM ]───────────────────────────────────────────────────
► 0x7ffff7a332f6 <do_system+1094>    movaps xmmword ptr , xmm0
   0x7ffff7a332fb <do_system+1099>    call   sigaction <0x7ffff7a23110>

   0x7ffff7a33300 <do_system+1104>    lea    rsi, <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
───────────────────────────────────────────────────[ STACK ]───────────────────────────────────────────────────
00:0000│ rsp0x7fffffffd9e1 ◂— 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 3100007ffff7a05b
   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 ]─────────────────────────────────────────────────
RAX0x7ffff7b97e97 ◂— sub    eax, 0x622f0063 /* '-c' */
RBX0x0
RCX0x7ffff7b97e9f ◂— jae    0x7ffff7b97f09 /* 'sh' */
RDX0x0
RDI0x2
RSI0x7ffff7dd16a0 (intr) ◂— 0x0
R8   0x7ffff7dd1600 (quit) ◂— 0x0
R9   0x7ffff7dd0d80 (initial) ◂— 0x0
R100x8
R110x246
R120x400594 ◂— 0x68732f6e69622f /* '/bin/sh' */
R130x7fffffffdc60 ◂— 0x1
R140x0
R150x0
RBP0x7fffffffda40 ◂— 0x0
RSP0x7fffffffd9e1 ◂— 0x9700000000000000
RIP0x7ffff7a332f6 (do_system+1094) ◂— movaps xmmword ptr , xmm0
──────────────────────────────────────────────────[ DISASM ]───────────────────────────────────────────────────
► 0x7ffff7a332f6 <do_system+1094>    movaps xmmword ptr , xmm0
   0x7ffff7a332fb <do_system+1099>    call   sigaction <0x7ffff7a23110>

   0x7ffff7a33300 <do_system+1104>    lea    rsi, <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
───────────────────────────────────────────────────[ STACK ]───────────────────────────────────────────────────
00:0000│ rsp0x7fffffffd9e1 ◂— 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 3100007ffff7a05b
   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了。

# 解决办法
核心思想就是改变栈的地址。

1.改变payload长度
2.栈转移
## 改变payload长度
直接更改我们的payload长度,在栈溢出的时候栈的地址自然不同,然后将栈地址+1,如果不行的话,就继续增加,最多也就改16次就一定会遇到栈对齐的情况。

## 栈转移
当payload有长度限制的时候,我们可以尝试进行栈转移来进行栈地址的改变,如果遇到了没有对齐的情况就继续将栈地址+1,直到遇到栈对齐的情况。

# 调用execve
用execve函数来替换system函数,这个要求就更高,应为他需要三个参数才能正常调用。也就是说我们需要构造rdi、rsi、rdx这三个参数。
```
int execve(const char * filename,char * const argv[ ],char * const envp[ ]);
```
# 总结
遇到问题就多上手调试一下。
页: [1]
查看完整版本: 64位的glibc的payload调用system函数失败问题