我在维基百科中读到了关于ROP的这些句子: “面向返回的编程是堆栈粉碎攻击的高级版本。通常,当攻击者利用程序中的错误(通常是缓冲区溢出)来操纵调用堆栈时,就会出现这些类型的攻击。”
这意味着如果不发生缓冲区溢出,则不会发生ROP。但是有些编译器(在我的例子中是LLVM)支持检测缓冲区溢出,但是对ROP的防御是开放的。
我很困惑。有没有我没想过的东西?
答案 0 :(得分:3)
Clang支持三个缓冲区溢出检测器,即 AddressSanitizer(-fsanitize = address), - fsititize = bounds,和 SafeCode。这些系统在方面有不同的权衡 性能损失,内存开销, 和检测到的错误类 。
因此它只能检测某些类别的错误(并非所有错误),这意味着它有错误的否定。
问题主要在于,任何静态的程序分析都不能, 一般 ,既健全又完整。也就是说,任何试图检测缓冲区溢出的静态分析都会出现误报和/或漏报。这是Rice's theorem的推论,它直观地指出程序的任何重要属性都是 通常 不可判定。这里的“ ”这个词很重要,对于 所有 程序来说都很重要。
误报是指静态分析将程序语句标记为缓冲区溢出而不是。 误判是指静态分析将程序语句标记为安全缓冲区访问而不是。
在许多领域中,最广泛采用的方法不仅仅是缓冲区溢出检测(例如,基于签名的入侵检测),而是容忍误报而非误报,因为否定误报会太多并且会淹没程序员并掩盖真正的问题。如果检测问题是可判定的但是太复杂(例如,NP-hard)来准确解决,则也应用该方法。底线, 近似渗透到计算机科学 。
答案 1 :(得分:2)
可以使用几种技术来检测缓冲区在运行时溢出的可能性。
一个非常便宜并且在现代编译器生成的代码中默认启用,仅在概率上检测堆栈上的缓冲区溢出(缓冲区溢出,例如,(2 32 -1)/ 2 32 被检测到的机会),并且仅在从受保护功能返回之前检查它们(这是检查的非常好的时间,但意味着检测不是瞬时的)。它的工作原理是插入一个“canary”值,当函数开始执行时,攻击者无法在堆栈帧的顶部预测,并通过在函数结束时检查金丝雀的值& #39;执行。
上述技术非常有趣,因为它便宜;在一次检查中,它可以很好地保护在功能期间可能发生的所有基于堆栈的缓冲区溢出。但是:
它不能防止基于堆的缓冲区溢出。
攻击者可以将自己限制为基于堆栈的小缓冲区溢出,以便更改某些局部变量和函数参数的内容,而不会覆盖金丝雀。这可能足以控制目标。
攻击者可以试着猜测金丝雀的价值。每次尝试时有2次 32 的机会,如果允许它们导致尽可能多的缓冲区溢出(例如,在未受监视的服务器中并且在每次崩溃后自动重新启动),最终可能会幸运。
根据this article,GCC开发人员认为即使用一次检查保护每个功能仍然太多(我在GCC中称之为-fstack-protector
的选项)使用启发式算法来省略各种功能的检查,包括一些可能有用的功能。
另一方面,有一些技术能够以更高的成本检测运行时缓冲区溢出的所有可能性。
在运行时系统地防止所有缓冲区溢出是没有不可能的。它只比上面的廉价支票贵。有些技术虽然效率更高,但却足够便宜,可以归属于编译器功能,所以很多人都会在Clang或GCC中将它们视为默认禁用选项。检测堆上和堆栈上的所有缓冲区溢出的技术会产生高达900%的开销(它们会使执行速度降低10倍)。大多数负责部署软件的人都没有发现这种妥协是可以接受的,因此这些技术只能在specialized academic C compilers,source-to-source transformation tools sold separately from the compiler或sound static analyzers used as C interpreters中找到。
重申一下,在运行时检测所有缓冲区溢出并不是不可能的。赖斯定理不适用。这样做的仪器技术实在太昂贵(运行时速度)。
另一种可能性不同的方法是静态检查程序是否有任何缓冲区溢出的可能性,以及可能发送给它的任何可能的输入。这样,程序可以使用普通的编译器进行编译并全速运行,而不会有远程代码执行的风险。这就是赖斯定理开始应用的地方:它说不可能制造一个自动静态分析仪来保证所有安全程序都是安全的。这在实践中没有问题,因为Rice的定理并没有说保证一个特定的安全程序是安全的。 重要的是建立一个静态分析仪,对于一个不能保证安全的程序永远不会说“安全”。静态分析仪总是被允许说“可能”,而实践中唯一的困难是如果它经常说“可能”,因为它永远不能确定任何程序是否安全。
上述类型的静态分析仪称为声音静态分析仪。它们有点难以使用,并且大多只在学术界讨论,但是,例如,我在a company工作,销售健全的静态分析仪以及将其应用于安全关键C软件组件的专业知识。我们验证的第一个C库是PolarSSL,用于特定配置。因为我们已经检查过在我们选择的配置中从网络发送到PolarSSL服务器的任何消息都不会发生缓冲区溢出,所以可以使用普通的编译器进行编译,并且可以避免缓冲区溢出的所有后果(通常是C&# 39;未定义的行为),包括ROP攻击。