1

我试图利用给定的程序,但我不知道我做错了什么。长话短说,我设法注入代码来覆盖 RIP。这意味着我应该能够重定向代码执行,但问题是,我得到了 SIGSEGV。我是否必须以特殊方式设计注入堆栈才能获得 SIGSEGV?

我的游戏计划是利用该功能mainloop并更改返回地址。该函数的堆栈mainloop具有以下值:

0000| 0x7fffffffdff0 --> 0xa7400ffffe010 
0008| 0x7fffffffdff8 --> 0xf423f55758260 
0016| 0x7fffffffe000 --> 0x7fffffffe010 --> 0x5555555550b0 (<__libc_csu_init>:  push   r15)
0024| 0x7fffffffe008 --> 0x5555555550a4 (<main+66>: mov    eax,0x0)

所以返回地址存储在0x7fffffffe008,我设法用指向我要执行的代码的地址覆盖了那个值。在这种情况下,地址0x555555554e6e

程序的回溯如下:

#6  0x0000555555554fab in mainloop ()
#7  0x00005555555550a4 in main ()
#8  0x00007ffff7e1109b in __libc_start_main (main=0x555555555062 <main>, argc=0x1, argv=0x7fffffffe0f8, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, 
stack_end=0x7fffffffe0e8) at ../csu/libc-start.c:308
#9  0x000055555555486a in _start () 

如您所见,当我退出时,mainloop我将返回到main,而当我退出 main 时,我会转到一堆 libc 函数,以便程序干净地退出(?)。

那么当我运行我的漏洞代码时会发生什么?这:

0000| 0x7ffe1b3d4150 --> 0x424142001b3d4170 
0008| 0x7ffe1b3d4158 ("ABABABABABABABABnNUUUU")
0016| 0x7ffe1b3d4160 ("ABABABABnNUUUU")
0024| 0x7ffe1b3d4168 --> 0x555555554e6e ('nNUUUU')
0032| 0x7ffe1b3d4170 --> 0x55a34784000a 
0040| 0x7ffe1b3d4178 --> 0x7f7c156c409b (<__libc_start_main+235>:      mov    edi,eax)
0048| 0x7ffe1b3d4180 --> 0x0 
0056| 0x7ffe1b3d4188 --> 0x7ffe1b3d4258 --> 0x7ffe1b3d5474 ("./device")

你看到的是堆栈。我添加了一些字节,以便您获得更多上下文。但我认为我设法为我的漏洞打到了正确的填充尺寸。我设法更改了第 24 个字节的值。

但是我的 PEDA/GDB 似乎并不将该值视为指令指针,这很奇怪。它似乎将其视为 C 字符串(?)。回溯看起来像这样:

#6  0x000055a347849fab in mainloop ()
#7  0x0000555555554e6e in ?? ()
#8  0x000055a34784000a in ?? ()
#9  0x00007f7c156c409b in __libc_start_main (main=0x55a34784a062 <main>, argc=0x1, argv=0x7ffe1b3d4258, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, 
stack_end=0x7ffe1b3d4248) at ../csu/libc-start.c:308
#10 0x000055a34784986a in _start () 

当我退出时,我mainloop在 PEDA/GDB 中得到以下信息:

Stopped reason: SIGSEGV
0x0000555555554e6e in ?? ()

如果我i f在 GDB 中运行命令,我会得到:

Stack level 0, frame at 0x7ffe1b3d4178:
 rip = 0x555555554e6e; saved rip = 0x55a34784000a
 called by frame at 0x7ffe1b3d4180
 Arglist at 0x7ffe1b3d4168, args: 
  Locals at 0x7ffe1b3d4168, Previous frame's sp is 0x7ffe1b3d4178
 Saved registers:
  rip at 0x7ffe1b3d4170 

在地址0x0000555555554e6e,程序执行以下 ASM:

0x0000555555554e6e <+172>:  lea    rdi,[rip+0x20126b]        #    0x5555557560e0 <flag2>

所以我似乎有正确的 RIP,但仅此而已。伙计们,这是怎么回事?

4

1 回答 1

1

当您从 GDB 中启动程序时,GDB(默认情况下)禁用 ASLR。在 PIE 可执行文件中,静态代码/数据地址是随机的。仅当您知道正确的绝对地址时,才能注入返回地址。

但显然您有时会在 GDB 之外启动您的程序,其中地址每次都不相同0x0000555555554e6e这显然会导致段错误,并且与您声称/假设的相反,您的问题并未显示出在发生段错误的实际过程中与实际的反汇编。

(GCC 在默认情况下生成 PIE 可执行文件是 Linux 上的新事物;如果您遵循旧教程,它可能会假设可执行文件本身是位置相关的,并且只有库 + 堆栈会被 ASLRed。32 位绝对地址否x86-64 Linux 中不再允许?

有关禁用ASLR 或构建非 PIE 可执行文件的系统范围或每个进程的方法,请参阅禁用内存地址随机化。

于 2019-02-19T19:27:01.587 回答