Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 无法理解格式字符串攻击代码_C - Fatal编程技术网

C 无法理解格式字符串攻击代码

C 无法理解格式字符串攻击代码,c,C,我在阅读文章时遇到了这段显示格式字符串利用的代码 到目前为止,我所了解的是%x的序列将继续打印当前%esp上方地址的值(我假设堆栈向下向较低地址增长) 我无法理解的是,给定的输入存储在缓冲区数组中,该数组与当前%esp的距离不能小于512字节。那么,输出如何在4个%x之后,即当前%esp的4个地址的正上方,包含4141(AAAA的十六进制表示)。我也努力盯着汇编代码看,但我想我无法理解堆栈上字符串的操作。在进入snprintf时,堆栈具有以下功能: 0xbfd257d0: 0xxxxxx

我在阅读文章时遇到了这段显示格式字符串利用的代码

到目前为止,我所了解的是
%x
的序列将继续打印当前
%esp
上方地址的值(我假设堆栈向下向较低地址增长)


我无法理解的是,给定的输入存储在
缓冲区
数组中,该数组与当前
%esp
的距离不能小于512字节。那么,输出如何在4个
%x
之后,即当前
%esp
的4个地址的正上方,包含
4141
(AAAA的十六进制表示)。我也努力盯着汇编代码看,但我想我无法理解堆栈上字符串的操作。

在进入
snprintf
时,堆栈具有以下功能:

0xbfd257d0:     0xxxxxxxxx      0xxxxxxxxx      0xxxxxxxxx      0x080484d5
0xbfd257e0:     0xbfd25800      0x00000200      0xbfd25a00      0x00000000
0xbfd257f0:     0x00000000      0x00000000      0x00000000      0x00000000
0xbfd25800:     0x00000000      0x00000040      0xb7f22f2c      0x00000000
0xbfd25810:     0x00000000      0x00000000      0x00000000      0x00000000

0xbfd25800 -> target (initially 0x00000000 0x00000040 ...)
...        -> garbage
0xbfd257e8 -> pointer to buffer
0xbfd257e4 -> 512
0xbfd257e0 -> pointer to target
0xbfd257df -> return address

target
snprintf
将其字用作参数之前,会被
snprintf
的结果覆盖:它首先在0xbfd25800处写入“AAAA”(0x414141),然后“%x”读取0xbfd257ec处的值并写入0xbfd25804,…,然后“%x”读取0xbfd25800处的值(0x414141)并将其写入0xbfd25814,…

首先,让我们在调用snprintf()后查看堆栈:

实际上,我们可以看到,在0xbffff00c,字符串已经格式化,所以sprintf()就在那里编写。我们还可以在0xBFFFFF0处看到snprintf()的最后一个参数:target的地址,实际上是0xbffff00c。 因此,我可以推断字符串是从堆栈上分配的空间的末尾保存到开头的,我们还可以看到添加strcpy():

blackbear@blackbear-笔记本电脑:~$cat prova.c
#包括
#包括
内部主(空)
{
char secret[]=“hack.se是跛脚的”;
字符缓冲区[512];
字符目标[512];
printf(“secret=%p\n”,&secret);
strcpy(目标,“ABCDEF”);
fgets(缓冲区,512,标准输入);
snprintf(目标,512,缓冲区);
printf(“%s”,目标);
}
blackbear@blackbear-笔记本电脑:~$gcc prova.c-g
prova.c:在函数“main”中:
prova.c:14:警告:格式不是字符串文字,也没有格式参数
prova.c:14:警告:格式不是字符串文字,也没有格式参数
blackbear@blackbear-笔记本电脑:~$gdb./a.out-q
从/home/blackbear/a.out读取符号…完成。
(gdb)突破13
0x8048580处的断点1:文件prova.c,第13行。
(gdb)运行
启动程序:/home/blackbear/a.out
机密=0xbffff40c
prova.c处的断点1,main():13
13个FGET(缓冲器,512,标准输入);
(gdb)x/10x$esp
0xBFFFFF0:0xbffff00c 0x080486bd 0x00000007 0x00155d7c
0xbffff000:0x00155d7c 0x000000f0 0x000000f0 0x44434241
0xbffff010:0x00004645 0x00000004
(gdb)

就这样!总之,我们在那里找到了字符串,因为字符串以相反的方式存储在堆栈上,并且目标的开始(或结束?)靠近esp。

我不理解您的命令调用。
~/research/paper
是可执行文件吗?我会理解
/myprog
cat inputdata./myprog
但我不明白你在做什么。好的,我明白了<执行code>a.out
,打印
secret=0xbffffc68
,然后等待用户输入。对我来说,这只是将输入回显到最后一行的屏幕上,然后退出<代码>~/research/paper只是一个shell提示符。@kerrek SB:我很抱歉。我删除它是为了让它更清晰。我没有得到并且需要测试的是
fgets
如何从stdin读取超过'AAAA'字节的数据。它是否应该达到EOF而不是实际读取512字节?我的意思是当它读到stdin时,它应该得到一个以null结尾的字符串,然后是EOF吗?@Shickadance先生:如果遇到换行符,fgets会在缓冲区中读取atmost next n-1个字符。肯定的是,
target
会因为
snprintf
而被覆盖,但我没有得到后面的部分,即在snprintf使用其单词作为参数之前。我认为目标被snprintf覆盖了。我的问题是,target的值1414141是如何被过度写入的?换句话说,缓冲区中%x%x…的序列如何被1414141替换?@终端,其中0xbfd25800现在包含零,在计算%x序列之前,会被
snprintf
的“AAAA”部分覆盖,因为
snprintf
从字符串的左侧开始复制所有内容,直到它到达%x为止。这样,它就不必分配一个临时缓冲区来格式化整个字符串并一次将其全部复制。@karl bielefeldt:谢谢,我找到了!!那么我想在这个链接上给出的解释是不正确的。这将是伟大的,如果你们中的任何人都可以抛出一些解释后给出的代码链接在原来的帖子。我相信我误解了那里的一些东西,特别是他们是如何找到缓冲区的偏移量的。@karl bielefeldt:最后我得到了那篇文章想要传达的东西。谢谢你的帮助。
[root@knark]$ ./a.out
secret = 0xbffffc68
AAAA%x %x %x %x %x %x %x //Input given
AAAA4013fe20 0 0 0 41414141 33313034 30326566
- [root@knark]$ 
0xbfd257d0:     0xxxxxxxxx      0xxxxxxxxx      0xxxxxxxxx      0x080484d5
0xbfd257e0:     0xbfd25800      0x00000200      0xbfd25a00      0x00000000
0xbfd257f0:     0x00000000      0x00000000      0x00000000      0x00000000
0xbfd25800:     0x00000000      0x00000040      0xb7f22f2c      0x00000000
0xbfd25810:     0x00000000      0x00000000      0x00000000      0x00000000

0xbfd25800 -> target (initially 0x00000000 0x00000040 ...)
...        -> garbage
0xbfd257e8 -> pointer to buffer
0xbfd257e4 -> 512
0xbfd257e0 -> pointer to target
0xbfd257df -> return address
Reading symbols from /home/blackbear/a.out...done.
(gdb) run
Starting program: /home/blackbear/a.out 
secret = 0xbffff40c
ABCDEF%x %x %x %x %x %x %x

Breakpoint 1, main () at prova.c:13
13      printf("%s",target);
(gdb) x/20x $esp
0xbfffeff0: 0xbffff00c  0x00000200  0xbffff20c  0x00155d7c
0xbffff000: 0x00155d7c  0x000000f0  0x000000f0  0x44434241
0xbffff010: 0x35314645  0x63376435  0x35353120  0x20633764
0xbffff020: 0x66203066  0x34342030  0x32343334  0x33203134
0xbffff030: 0x34313335  0x20353436  0x37333336  0x35333436
(gdb) 
blackbear@blackbear-laptop:~$ cat prova.c
#include <stdio.h>
#include <string.h>

int main(void)
{
    char secret[]="hack.se is lame";
    char buffer[512];
    char target[512];

    printf("secret = %p\n", &secret);

    strcpy(target, "ABCDEF");   
    fgets(buffer,512,stdin);
    snprintf(target,512,buffer);
    printf("%s",target);
}
blackbear@blackbear-laptop:~$ gcc prova.c -g
prova.c: In function ‘main’:
prova.c:14: warning: format not a string literal and no format arguments
prova.c:14: warning: format not a string literal and no format arguments
blackbear@blackbear-laptop:~$ gdb ./a.out -q
Reading symbols from /home/blackbear/a.out...done.
(gdb) break 13
Breakpoint 1 at 0x8048580: file prova.c, line 13.
(gdb) run
Starting program: /home/blackbear/a.out 
secret = 0xbffff40c

Breakpoint 1, main () at prova.c:13
13      fgets(buffer,512,stdin);
(gdb) x/10x $esp
0xbfffeff0: 0xbffff00c  0x080486bd  0x00000007  0x00155d7c
0xbffff000: 0x00155d7c  0x000000f0  0x000000f0  0x44434241
0xbffff010: 0x00004645  0x00000004
(gdb)