系统命令注入的介绍与代码防御

来源:互联网 发布:哪个cms好 编辑:程序博客网 时间:2024/05/01 19:33

0x01 介绍

       该软件使用受外部影响的输入来构造操作系统命令的全部或一部分,但未能对可能修改所需操作系统命令的元素进行无害化处理。这样一来,攻击者就可以直接在操作系统上执行意外的危险命令。在攻击者没有对操作系统的直接访问权的情况下(例如在 Web 应用程序中),此弱点可能导致脆弱性。反过来说,如果该弱点发生在特权程序中,攻击者有可能能够指定通常不可访问的命令,或者通过攻击者不具备的特权调用替代命令。如果受到威胁的进程未遵循最低特权原则,那么该问题会变得更严重。其原因是攻击者控制的命令可能通过特定系统特权运行,这会加重危害。存在操作系统命令注入的至少两种子类型:

[1] 应用程序计划执行受其控制的单个固定程序

        它计划使用外部提供的输入作为该程序的参数。例如,程序可能使用 system("nslookup [HOSTNAME]") 来运行 nslookup,并允许用户提供 HOSTNAME 以用作参数。攻击者无法阻止 nslookup 执行。但是,如果程序不从 HOSTNAME 参数中除去命令分隔符,攻击者就可以将分隔符放置到参数中,从而能够在 nslookup 完成执行后执行其自己的程序。

[2] 应用程序接受输入,并将其用于完全地选择要运行的程序以及要使用的命令

           应用程序只是将此完整命令重定向至操作系统。例如,程序可能使用“exec([COMMAND])”来执行用户提供的 [COMMAND]。如果 COMMAND 受到攻击者的控制,那么攻击者可以执行任意命令或程序。如果命令是使用 exec() 和 CreateProcess() 之类的函数执行的,攻击者可能无法将多个命令组合到同一行中。这些变体代表不同的程序员错误。在第一个变体中,程序员清楚地表明来自不可信方的输入将作为要执行的命令中的部分参数。在第二个变体中,程序员不希望命令可供任何不可信方访问,但可能未考虑到恶意攻击者可提供输入的其他方式。

          例如:某些脚本通过操作系统调用来运行命令。有时,URL 参数会用作命令的一部分。在这种情况下,就有可能注入将在操作系统上运行的代码。此类代码注入可能使用各种语法:

command1 | command2(使用 command1 的输出作为 command2 的输入 - 攻击形式将是 "| command")

command1 && command2(在 command1 的返回码为 true 的情况下运行 command2 - 攻击形式将是 "&& command")

command1 || command2(在 command1 的返回码为 false 的情况下运行 command2 - 攻击形式将是 "|| command")

         有时,第一条命令包含在单引号 (') 或双引号 (") 中,因此要执行第二条命令,就需要首先将引号转义。通过使用这些变体,攻击者可尝试在主机上运行任意代码。

0x02 威胁影响

     由于未对用户输入正确执行危险字符清理,可能会在 Web 服务器上运行远程命令。这通常意味着完全破坏服务器及其内容

0x03 修复思路

[1] 使用库调用

      如果可能,使用库调用而不是外部进程来创建所需功能。

[2] 策略:沙箱或监狱

       在进程和操作系统之间强制实施严格边界的“监狱”或类似沙箱环境中运行代码。这可能会有效限制您的软件可访问特定目录中的哪些文件或者可以执行哪些命令。操作系统级别的示例包括 Unix chroot jail、AppArmor 和 SELinux。通常,受管代码可提供一定的保护。例如,Java SecurityManager 中的 java.io.FilePermission 允许您指定针对文件操作的限制。这可能不是可行的解决方案,并且它仅限制了对操作系统的影响;您的应用程序的其余部分仍有可能受到损害。请注意避免 CWE-243 以及与监狱相关的其他弱点。

[3] 策略:库或框架

      使用不允许此弱点出现的经过审核的库或框架,或提供更容易避免此弱点的构造。例如,考虑使用 ESAPI 编码控件http://www.owasp.org/index.php/ESAPI或类似的工具、库或框架。这些将帮助程序员以较少出错的方式对输出编码。

[4] 策略:输入验证

      假定所有输入都是恶意的。使用“接受已知善意”输入验证策略:严格遵守规范的可接受输入的白名单。拒绝任何没有严格遵守规范的输入,或者将其转换为遵守规范的内容。不要完全依赖于针对恶意或格式错误的输入的黑名单。但是,黑名单可帮助检测潜在攻击,或者确定哪些输入格式不正确,以致应当将其彻底拒绝。

       执行输入验证时,请考虑所有潜在相关的属性,包括长度、输入类型、可接受的值的完整范围、缺少或多余的输入、语法、在相关字段之间是否一致以及是否遵守了业务规则。作为业务规则逻辑的示例,“boat”可能在语法上有效(因为它仅包含字母数字字符),但如果预期为颜色(如“red”或“blue”),那么它就无效。构造操作系统命令字符串时,请使用严格的白名单以根据请求中参数的预期值来限制字符集。这将间接限制攻击的范围,但是此技巧的重要性不及适当的输出编码和转义。

        请注意,适当的输出编码、转义和引用是防止操作系统命令注入的最有效解决方案,虽然输入验证可能会提供一定的深度防御。这是因为,它会有效限制输出中出现的内容。输入验证并不总是能够防止操作系统命令注入,尤其是在您需要支持可包含任意字符的自由格式文本字段的情况下。例如,调用邮件程序时,您可能需要允许主题字段包含在其他情况下很危险的输入(如“;”和“>”字符),这些输入需要转义或以其他方式进行处理。在此情况下,除去该字符可能会降低操作系统命令注入的风险,但是这会产生不正确的行为,因为这样就不会按照用户的需要来记录主题字段。这可能看起来只是略有不便,但在程序依赖于结构良好的主题行以便向其他组件传递消息时,这种情况就更为重要。

        即使在验证中出错(例如,在 100 个输入字段中忘记一个字段),相应的编码仍有可能针对基于注入的攻击为您提供防护。只要输入验证不是孤立完成的,便仍是有用的技巧,因为它可以大大减少攻击出现的机会,使您能够检测某些攻击,并提供正确编码所无法解决的其他安全性优势。[5] 策略:环境固化

[4] 最低特权

    使用完成必要任务所需的最低特权来运行代码。https://buildsecurityin.us-cert.gov/daisy/bsi/articles/knowledge/principles/351.html

如果可能,请使用仅用于单个任务的有限特权来创建孤立的帐户。这样,即使攻击成功,攻击者也无法立即访问软件或其环境的其余部分。例如,数据库应用程序很少需要以数据库管理员身份运行,特别是在日常操作中。


欢迎大家分享更好的思路,热切期待^^_^^ !

0 0