【问题标题】:Unable to inject valid instruction pointer during exploit在利用期间无法注入有效的指令指针
【发布时间】:2019-02-18 20:57:09
【问题描述】:

我试图利用给定的程序,但我不知道我做错了什么。长话短说,我设法注入代码来覆盖 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 ?? ()

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

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,但仅此而已。 伙计们,这是怎么回事?

【问题讨论】:

  • 那么,0x0000555555554e6e 是什么?
  • lea rdi,[rip+0x20126b] 不会因为任何现有的寄存器内容而出错。我认为唯一的解释是0x0000555555554e6e 不在可执行页面中。是在.data还是什么的,你编译的目标程序没有-zexecstack? (是的,该 gcc 选项适用于 .data 和 BSS 以及实际堆栈。)
  • @PeterCordes,我很确定代码是可执行的,因为我可以从程序本身运行它。地址0x0000555555554e6e 指向一个名为process 的函数中的特定行,我知道我可以执行它。
  • 您对0x0000555555554e6e 的反汇编是在实际目标进程发生段错误后提取的吗?除非发生了raise(SIGSEGV)kill(pid, SIGESGV) 的操作,否则我不知道那条指令还会出现什么错误,如果它是这样反汇编的。您可以检查/proc/PID/maps 以查找包含该地址的映射的权限。这一切都是从 GDB 内部运行的,因此 ASLR 始终处于禁用状态(程序的重复运行将在同一地址加载。)
  • @PeterCordes 嗯,我想你可以做点什么。所以可执行文件是预编译的,我也得到了 C 语言的源代码。当我从 GDB 运行 exec 并反汇编函数时,我总是得到相同的地址,0x0000555555554e6e。那是我要执行的特定代码行。但是当我从 Pwntools 运行它时,同一行代码的地址发生了变化。所以也许我的策略是正确的。可能是我没有正确的地址来处理通过 Pwntools 执行程序时的特定实例。是否可以注入某种相对指令指针?

标签: c assembly stack-overflow exploit pwntools


【解决方案1】:

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

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

(GCC 在默认情况下生成 PIE 可执行文件是 Linux 上的新事物;如果您遵循旧教程,它可能会假设可执行文件本身是位置相关的,并且只有库 + 堆栈会被 ASLRed。32-bit absolute addresses no longer allowed in x86-64 Linux? )

有关禁用 ASLR 或构建非 PIE 可执行文件的系统范围或每个进程的方法,请参阅 Disable randomization of memory addresses

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-23
    • 1970-01-01
    • 1970-01-01
    • 2021-11-27
    • 2021-02-23
    相关资源
    最近更新 更多