【问题标题】:How to defeat a segmentation fault strategically?如何战略性地克服分段错误?
【发布时间】:2014-03-20 03:26:16
【问题描述】:

标题具有误导性;让我澄清一下。首先让我们考虑一个安全上下文。

攻击操作写入一些未映射/不可访问的内存(例如,由于堆缓冲区溢出)。假设我可以捕获内存访问冲突触发的信号。

在信号处理程序中,我可以策略性地“静音”写操作吗?一个类比是将标准输出重定向到 /dev/null。同时,我需要让写操作完成,否则控制流无法继续前进(例如,写指针在循环中没有增加)并且程序运行被卡住。

我认为这个想法的意义在于它可以在不使系统崩溃的情况下使攻击静音,对吧?

编辑:我无法更改用户代码。我考虑在我的信号处理程序中操纵 PC 以跳过 mov 指令。它会起作用吗?

【问题讨论】:

  • 内存访问冲突会导致未定义的行为或程序崩溃。除非您在谈论编译器如何处理它,否则您如何捕获和处理 信号
  • 一些有价值的信息是here
  • 感谢 ajay anatolyg。我知道一般你不能省略这样的信号,程序状态可能已经损坏,但我的情况很特殊。当我收到信号时,我是 100% 攻击者没有机会破坏任何程序数据。在我的例子中,信号仅仅意味着攻击者已经触摸了我故意设置的页面,就像electric fence 所做的那样。
  • Afaik,段错误的处理程序不能返回,因为这只会导致段错误被重新抛出。这意味着,您只能通过调用abort()exit() 或尝试longjmp() 退出信号处理程序来完成。如果这样的事情是可能的,那么做对是非常困难的。但是,最重要的是,我认为你问错了问题。如果你想阻止攻击,你必须修复易受攻击的代码,而不仅仅是试图逮捕攻击者。如果易受攻击的代码太复杂而无法修复,请重写它。
  • 在这种情况下,您只需在从处理程序返回之前更改页面上的保护,它就会“工作”。但是,你得到了什么?您允许攻击者覆盖内存,这并不是向前迈出的一大步,是吗?首先需要通过正确验证来防止攻击者进行缓冲区溢出。一旦他们能够写入一些“非法”的地方,你就只能选择崩溃,或者允许他们执行任意代码......这两者都不好。

标签: c linux memory-management segmentation-fault signals


【解决方案1】:

您绝对可以做到,但这很困难,而且如果不构建整个软件堆栈以抵御此类故障,就无法做到。当你完成时,你可能最终会实现一半的 Erlang :)

实际上,您必须在附加到您自己的应用程序的单独线程中运行调试器,并使用特定于平台的调试 API 来获取在监视线程中发生硬件 (CPU) 异常的通知。

收到此类通知后,被监控的线程被挂起,您将可以访问故障发生时的寄存器状态。此时,您可以反汇编指令以确定其长度,并用 NOP 重写它。您还需要确定发生故障的指令在什么样的内存空间中 - 如果它在您自己的代码中,您绝对不应该触摸任何东西并简单地恢复线程,让本机信号/异常处理程序(如果有) 搞定此事。您应该只在此类问题发生在非代码区域(例如:数据区域)时才发现它们。

唉,在大多数正常的平台上,数据页面无论如何都不会是可执行的,因此您捕获的硬件异常将表明代码执行是在一个不可执行的页面中尝试的。除了进行堆栈分析并确定代码应该在哪里执行之外,没有任何简单的方法可以解决。在运行时通过使页面可执行来击败数据执行预防将是一个非常糟糕的主意

理想情况下,当故障发生时,您应该有一种机制来终止和重新启动相关线程。这就是 Erlang 采用的方法:let it crash 并重新启动崩溃的线程/进程。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-05-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多