C 格式化字符串漏洞以segfault结束
我现在正在读《黑客——剥削的艺术》一书 这是我开发格式字符串代码的简化版本C 格式化字符串漏洞以segfault结束,c,path,formatting,environment-variables,exploit,C,Path,Formatting,Environment Variables,Exploit,我现在正在读《黑客——剥削的艺术》一书 这是我开发格式字符串代码的简化版本 /* fmt_vuln.c */ #include <stdio.h> #include <stdlib.h> #include <string.h> int main (int argc, char *argv[]){ char text [1024]; if (argc < 2){ printf ("Usage: %s <text to print
/* fmt_vuln.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main (int argc, char *argv[]){
char text [1024];
if (argc < 2){
printf ("Usage: %s <text to print>\n", argv[0]);
exit (0);
}
strcpy (text, argv[1]);
printf ("The wrong way to print user-controlled input:\n");
printf (text);
printf ("\n");
return 0;
}
我得到:
The wrong way to print user-controlled input:
AAAA59055000.58e347a0.58b68620.ffffffff.00000000.fba56ac8.58a9fc58.41414141
The wrong way to print user-controlled input:
Segmentation fault
所以,我看到第8个format参数是从format字符串的开头读取的
然后,当我运行命令时:
./getenv PATH ./fmt_vuln
我得到了地址:
0x7ffe2a673d84
所以我试着运行:(为了打印PATH变量)
我得到:
The wrong way to print user-controlled input:
AAAA59055000.58e347a0.58b68620.ffffffff.00000000.fba56ac8.58a9fc58.41414141
The wrong way to print user-controlled input:
Segmentation fault
为什么我会有错?从getenv程序中我得到了路径的地址,但程序仍然崩溃
感谢您的帮助。出于安全原因,并非计算机中的所有进程都共享同一个进程。当我谈论不同的内存空间时,我是什么意思?考虑以下2个程序:
//program 1
int main(int argc, char** argv){
printf("%02x", *((uint8_t*)0xf00fba11));
return 0;
}
//program 2
int main(int argc, char** argv){
printf("%02x", *((uint8_t*)0xf00fba11));
return 0;
}
如果这些程序同时运行(并且假设它们不发生segfault(它们几乎肯定会发生segfault)),它们将打印不同的值。怎么可能呢??它们都访问内存位置0xf00fba11!。。。还是他们
为了理解这里发生了什么,我们首先需要了解cpu从内存加载值时发生了什么。要从内存加载值,cpu向RAM发送一个请求,如下所示:
cpu
|-------------| |---------|
| read |-------address out to RAM (0xf00fba11)---->| RAM |
| | | |
| *0xf00fba11 |<---------data coming back to CPU----------| |
|-------------| |---------|
因此,如果在进程1中在内存地址0x7ffe2a673d84处加载环境变量,则它可能会转换为物理地址0x63002a673d84。此外,当进程2尝试访问*0x7ff32a673d84时,它将被映射到一个完全不同的地址,或者,在您的情况下,它可能被进程2取消映射,从而导致一个segfult。
所以坏消息是,我认为没有任何方法可以用代码“修复”这个问题。做你想做的事情会给你一个错误或者随机的,无用的数据。要获取您感兴趣的数据,您需要查看MMU配置设置并修改它们,除非您以提升的权限级别运行,否则不允许这样做
在我们分开之前,值得注意的是,为了在两个进程之间来回传递数据或访问共享软件库,进程之间可能存在一些共享的地址。也就是说,对于几个不同的进程,0x1000将转换为0x5000
或者我不知道你在说什么。我没有真正遵循关于
/getenv PATH./fmt\u vuln
的行,因为您使用64位系统,所以您的地址有8个字节
看看这个地址,它只有6个字节。这意味着较高的两个字节为零。但您不能简单地将零字节作为十六进制字符串提供,如\xff\xaa\xbb\x00
,因为程序会将该零字节解释为字符串的结尾
您需要使用32位系统来进行试验,x64体系结构将不允许您利用该漏洞。偶然发现了相同的东西(阅读同一本书)
getenv_addr
不是超级可靠的。我在fmt_vuln.c
中显示了PATH
的确切地址,并添加了:
printf("[*] %s is at %p\n", "PATH", getenv("PATH"));
这将为您提供一个应该可以工作的地址,并且与getenv_addr
给出的地址不应太远
此外,请确保禁用ASLR(地址空间布局随机化-基本上随机化地址空间位置):
并确保编译一个32位程序(
gcc-m32
)。您提到的这一行实际上是程序getenvaddr,可以在这里找到:。其次,您知道为什么在书中他们也这么做并得到PATH的值吗?他们从上一条评论中查找程序的地址,并完全按照我所做的做了(当然是他们得到的地址)。这段代码高度依赖于系统。我不确定你的系统,但在我的系统上,如果我运行几次get_env,每次我都会得到不同的地址。这听起来可能像是逃避回答,但我怀疑如果你使用的是这本书的第一版(写于2003年),那么写这本书的原始系统可能与你的不同。是的,同样在我的电脑上,我每次在get_env上都得到不同的结果。正如你所说,我认为它实际上是依赖于系统的。无论如何,谢谢你的帮助和详细的解释!
Process 1
asks for | gets physical address
------------------------------------
0x0000 - 0x0fff | ERROR SEGFAULT
0x1000 - 0x1fff | 0x70000 - 0x70fff
0x2000 - 0x2fff | 0x30000 - 0x30fff
0x3000 - 0x3fff | 0xa7000 - 0xa7fff
etc.... | etc.....
Process 2
asks for | gets physical address
------------------------------------
0x0000 - 0x0fff | ERROR SEGFAULT
0x1000 - 0x1fff | 0xb1000 - 0xb1fff
0x2000 - 0x2fff | 0x40000 - 0x40fff
0x3000 - 0x3fff | 0x1c000 - 0x1cfff
etc.... | etc.....
printf("[*] %s is at %p\n", "PATH", getenv("PATH"));
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space