Drupageddon:SQL 注入、数据库抽象和数十万个网站

作者:Shea Nangle

Drupal 是一款非常广泛使用的开源内容管理系统。它最初于 2001 年发布,最近的统计数据显示,Drupal 是第三流行的内容管理系统,略低于 800,000 个网站使用 Drupal 作为内容管理系统。

Drupal 使用 PHP 编写,其架构设计为使用数据库后端来存储网站内容和设置,无论是成熟的数据库管理系统(如 MySQL)还是嵌入式 DBMS(如 SQLite)。在最近的版本中,Drupal 提供了数据库抽象层,以便于使用多种数据库管理系统来支持给定的 Drupal 安装。数据库抽象层提供了一致的编程接口,可以用来与各种数据库系统通信,而无需开发特定于给定数据库管理系统的代码。

由于 Drupal 7 版本中引入的数据库抽象层中的漏洞,Drupal 7 在 7.32 版本之前容易受到 SQL 注入攻击。本文介绍了 SQL 注入攻击,专门 بررسی了 Drupageddon 漏洞,并解释了许多针对 SQL 注入攻击的潜在防御措施。

SQL 注入

SQL 注入是一种攻击方法,其中恶意 SQL 代码包含在用户输入中,导致执行所述 SQL 代码作为应用程序使用的 SQL 语句的一部分。SQL 注入攻击可能导致权限绕过和/或提升、机密信息泄露以及数据库信息损坏等影响。

命令注入攻击,例如 SQL 注入,通常位于 OWASP(开放 Web 应用程序安全项目)Web 应用程序安全风险十大列表的顶部或附近。SQL 注入攻击可能是最广为人知的命令注入攻击类型,但注入攻击可能发生在应用程序向解释器提供数据的任何时候。最近的 Bash 漏洞(称为 Shellshock)就是一个与 SQL 注入无关的命令注入攻击示例。

SQL 注入示例

一个 SQL 注入攻击示例从使用 SQL 语句的代码开始,例如


$db_statement = "SELECT COUNT(1) FROM `users` WHERE 
 ↪`username` = '$username' AND `password` ='$password'";

在针对此类代码的 SQL 注入攻击中,攻击者向应用程序提供输入,例如以下内容


$username = "badUser";
$password = "' OR '1'='1";

使用此示例,执行的 SQL 语句变为以下内容


SELECT COUNT (1) FROM `users` WHERE `username`='badUser' 
 ↪AND `password`='' OR '1'='1';

在上面的示例中,这导致返回“users”表中所有行的计数,而与提供的用户名或密码无关,因为条件 '1'='1' 始终返回为 true。如果此示例中显示的查询用于身份验证目的,则示例 SQL 注入攻击刚刚绕过了相关应用程序的身份验证过程。

SQL 注入攻击以及一般的其他命令注入攻击,对 Web 应用程序构成重大风险。攻击者相对容易执行对 SQL 注入漏洞的利用,并且攻击本身和对易受攻击代码的搜索都很容易自动化。此外,SQL 注入攻击的影响通常非常严重,正如在上面的身份验证示例以及 Drupageddon 的具体示例中所看到的那样。

Drupageddon

Drupageddon 漏洞最初由 SektionEins GmbH 在为使用 Drupal 作为内容管理系统的客户执行安全审计时发现。SektionEins GmbH 于 2014 年 9 月 16 日向 Drupal 开发人员报告了该漏洞。Drupal 于 2014 年 10 月 15 日公开披露了该漏洞,使用了 Drupal 咨询标识符 DRUPAL-SA-CORE-2014-005 和 CVE 标识符 CVE-2014-3704。公开披露包括漏洞描述以及漏洞缓解建议。缓解此漏洞的主要建议是立即升级到 Drupal 7.32 版本。对于无法立即升级到 Drupal 7.32 版本的网站管理员,提供了一个补丁来解决 SQL 注入漏洞。

SektionEins 将此漏洞昵称为 Drupageddon,因为利用此漏洞可能对基于 Drupal 的网站产生潜在影响。(注意:在许多新闻报道中,此漏洞被称为“Drupalgeddon”,这是不准确的。“Drupalgeddon”一词指的是一种旨在用于诊断可能由于 Drupageddon 漏洞而受到损害的 Drupal 实例的诊断工具。)

成功利用此攻击可能导致执行任意 PHP 命令、权限提升、安装系统后门和其他漏洞利用。此外,利用此漏洞不需要在利用之前对目标 Drupal 实例进行任何类型的成功身份验证。

据估计,在 Drupageddon 漏洞宣布后的几个小时内,攻击者正在使用活跃的和自动化的漏洞利用程序来攻击基于 Drupal 的网站。

2014 年 10 月 29 日,Drupal 安全团队发布了咨询标识符 DRUPAL-PSA-2014-003。此咨询通知基于 Drupal 的网站的管理员,如果他们在 2014 年 10 月 15 日 2300 UTC(SA-CORE-2014-005 中最初宣布漏洞后的七个小时)之前未进行修补/升级,则应将所有使用易受攻击的 Drupal 版本的基于 Drupal 的网站视为已受损。

在 Drupageddon 漏洞的情况下,Drupal 提供的数据库抽象层包含一个名为 expandArguments 的函数,该函数用于扩展数组,这些数组为用于支持 Drupal 安装的 SQL 查询提供参数。由于编写此函数的方式,将带有键的数组(而不是没有键的数组)作为函数的输入可以用于执行 SQL 注入攻击。

expandArguments 函数的潜在(非恶意)用途如下


$query = "SELECT COUNT(1) FROM `users` WHERE `id` IN (:userids)"; 
$args = [ 'userids' => [ 1, 2, 3, ] ]; 
$db->expandArguments($query, $args);

这将导致以下 SQL 语句


SELECT COUNT(1) FROM `users` WHERE `id` IN 
 ↪(:userids_0, :userids_1, :userids_2);

但是,通过提供精心制作的参数数组,攻击者可以执行 SQL 注入攻击


$query = "SELECT COUNT(1) FROM `users` WHERE `id` 
 ↪IN (:userids)";
$args = [ 'userids' => [ '0); DROP TABLE 
 ↪importantInformation; --' => 1 ], ];
$db->expandArguments($query, $args);

这将导致以下 SQL 语句


SELECT COUNT (1) FROM `users` WHERE `id` IN (:userids_0); 
 ↪DROP TABLE importantInformation; --)

-- 标记该行剩余部分为 SQL 注释,避免了由于未匹配的右括号而导致的语法错误。执行此类恶意查询的结果显然可能是灾难性的。

建议

可以使用多种策略来最大程度地降低 SQL 命令注入攻击的风险。这些包括输入清理和白名单、使用参数化查询以及纵深防御。

输入清理和白名单

可用于预防 SQL 注入攻击的一种策略是对用户输入进行清理和白名单。此策略通过分析用户将提供的预期或有效输入以及尝试破坏您的基于 Web 的应用程序的攻击者可能提供的输入来实现。在初始分析之后,将需要添加清理代码,以便在使用用户输入到任何数据库查询之前删除或转义用户提供的任何有害/不需要的输入。在本文前面给出的 SQL 注入示例中,可以使用两个潜在的清理和白名单处理过程。

在前面给出的 SQL 注入示例中,假设您之前已告知 Web 应用程序的用户,用户名的有效字符是 a–z、A–Z、0–9 和“.”。这将代表使用基于白名单的输入验证的绝佳机会。在这种输入验证方法中,您将构造一个用户输入的允许字符白名单,并且仅允许限于这些字符的用户输入传递到数据库进行处理。在这种情况下,您要么会丢弃用户作为其用户名提供的除 a–z、A–Z、0–9 和“.”之外的任何字符,要么您根本会拒绝在用户输入包含白名单中未包含的任何字符后执行任何处理。使用此示例,将以下内容作为 username 值提供的攻击


$username = "x'; DROP TABLE importantInformation; 
 ↪SELECT * FROM users WHERE username = 'badUser'";
$password = "Test";

要么会被拒绝,要么会被清理(如果丢弃了不适当的字符)为以下内容


$username = "xDROPTABLEimportantInformation
↪SELECTFROMusersWHEREusernamebadUser";

如果在本示例中使用清理,这将导致执行以下 SQL 语句


SELECT COUNT(1) FROM `users` WHERE `username`=
↪'xDROPTABLEimportantInformationSELECTFROMusersWHEREusernamebadUser' 
 ↪AND `password`='Test';

在不进行清理的情况下,将执行以下 SQL 语句


SELECT COUNT(1) FROM users WHERE username='$username = 
 ↪"x'; DROP TABLE importantInformation; SELECT COUNT(1) 
 ↪FROM users WHERE username = 'badUser' AND password = Test';

这导致执行了两个 SELECT 语句,并且还导致删除了 importantInformation 表。

(注意:此 SQL 示例还代表了其他安全问题,即数据库中的密码似乎以纯文本形式存储。但是,这超出了本文的范围,并且密码加密对 SQL 注入攻击的漏洞没有影响。)

在用户身份验证示例中,还需要额外的处理来处理用户提供的密码。假设您允许所有键盘字符,以便允许尽可能复杂的密码,您不能简单地拒绝包含潜在危险字符的密码输入。在这种情况下,您将希望通过在查询处理之前转义用户输入来清理用户输入。在本示例中,以下输入


$username = "badUser";
$password = "' OR '1'='1";

将被转义为以下内容


$username = "badUser";
$password = "\' OR \'1\'=\'1";

然后,这将导致执行以下 SQL 语句


SELECT COUNT (1) FROM users WHERE username='badUser' 
 ↪AND password='\' OR \'1\'=\'1';

此版本的 SQL 语句将导致返回 users 表中用户名字段的内容等于字符串“badUser”,并且密码字段的内容等于文字字符串“' OR '1'='1" 的行数(即,攻击已被阻止)。

使用参数化查询

防止 SQL 注入的另一种策略是使用参数化查询。使用参数化查询,SQL 语句是预定义的,并存储在数据库服务器上,占位符表示将在查询中使用的参数。当需要执行相关 SQL 语句时,相关用户输入会在执行之前添加到查询中,数据库服务器会自动处理任何相关的用户输入转义。

在先前显示的用户身份验证示例中,参数化版本的查询将类似于以下内容


SELECT * FROM users WHERE username=?un? AND password=?pw?;

当需要执行 SQL 语句时,数据库管理系统会对相关参数执行任何需要的转义,然后执行 SQL 语句,转义后的参数将取代占位符的位置。

纵深防御

在非常高的层面上,防止 SQL 注入攻击的最佳计划是纵深防御的总体策略。此方法依赖于同时部署多种不同的防御机制,总体策略是,如果攻击者能够击败一种防御机制,其他防御机制仍然会到位,并且仍然能够防御/检测尝试的攻击。在 Drupageddon 示例中,除了先前提到的防御策略之外,以下并行防御策略将有助于最大程度地降低由于 SQL 注入而导致系统受损的风险。

  • 系统和应用程序更新: 使系统和应用程序保持最新的更新是个人和组织应实施以防止系统和应用程序受损的第一道防线之一。在 Drupageddon 案例中,升级到 Drupal 7.32 版本或安装 Drupal 开发人员提供的补丁都可以立即缓解 Drupageddon 漏洞。尽管 Drupageddon 漏洞自 2011 年就已存在,但没有证据表明在 SektionEins 公开披露 Drupageddon 之后,该漏洞被大量利用。

  • 入侵检测系统: 大多数当前的入侵检测系统都包含检测尝试 SQL 注入攻击的功能。这些系统可以提供尝试 SQL 注入攻击的早期警告,并且如果与入侵防御功能配对使用,通常可以阻止攻击发生。

  • 限制数据库权限: 用于应用程序的数据库用户的权限应尽可能限制为允许执行所需数据库活动以支持应用程序功能的最小权限集。例如,如果应用程序所需数据库活动只是从数据库读取数据,请考虑将应用程序使用的数据库帐户限制为只读帐户。这不会阻止旨在不当访问信息的 SQL 注入攻击,但会阻止旨在对数据库进行未经授权更改的 SQL 注入攻击。

  • 系统和应用程序监控: 尽管系统和应用程序日志记录和监控本身并不能防止 SQL 注入攻击发生,但它们将有助于检测尝试的攻击。此外,使用诸如文件完整性监控之类的功能可以帮助检测由于 SQL 注入攻击而导致的系统受损结果。

  • 代码审计: 对应用程序中使用的源代码进行审计可以帮助识别相关应用程序中的安全漏洞。事实上,Drupageddon 漏洞是由于对 Drupal 代码库执行的源代码审计而发现的。源代码审计通常应由负责创建相关源代码的一方以外的另一方执行,因为这为源代码提供了全新的视角。不幸的是,源代码审计通常非常昂贵且耗时。

资源

网站内容管理系统的使用情况:http://w3techs.com/technologies/overview/content_management/all

Drupal 使用情况统计:http://trends.builtwith.com/cms/Drupal

OWASP 十大列表:https://www.owasp.org/index.php/Top_10_2013-Top_10"

SA-CORE-2014-005 — Drupal 核心 — SQL 注入:https://www.drupal.org/SA-CORE-2014-005

Drupal 核心 — 高度关键 — 公告 — PSA-2014-003:https://www.drupal.org/PSA-2014-003

Drupalgeddon:https://www.drupal.org/project/drupalgeddon

咨询 01/2014:Drupal — 预身份验证 SQL 注入漏洞:https://www.sektioneins.de/en/advisories/advisory-012014-drupal-pre-auth-sql-injection-vulnerability.html

Drupal 7.31 预身份验证 SQL 注入漏洞:https://www.sektioneins.de/en/blog/14-10-15-drupal-sql-injection-vulnerability.html

Drupal 7.32 两周后 — PoC:https://www.sektioneins.de/en/blog/14-11-03-drupal-sql-injection-vulnerability-PoC.html

加载 Disqus 评论