SQL注入

第一步
SQL注入
type
status
date
slug
summary
tags
category
icon
password
📎
想了一下,原本博客的记录方式更像是知识介绍,就是整合各个网站的内容,反而和学习这一初衷相违背,所以重新以边学边记的方式记录,自己也就当从0开始学习。

数据库识别

在进行SQL注入前,你必须要知道数据库的类型和版本,再查询对应的语法。 假设注入点是 id=1,则有下表的区别:
Payload
MySQL
MSSQL
Oracle
PostgreSQL
'a'||'b'='ab'
False (0=0)
False (语法错)
True
True
'a'+'b'='ab'
True (0=0)
True (拼接)
False (语法错)
False (语法错)
'a' 'b'='ab'
True (MySQL 允许空格连接)
False (语法错)
False (语法错)
False (语法错)
length('a'+'b')
1 (是'0')
2 (是'ab')
-
-
对于OraclePostgreSQL,再细分下可以通过(SELECT 1 FROM dual)=1判断(只有 Oracle 需要 dual 表)
弄清楚数据库类型后再用联合注入查验版本:
  • MySQL/PG: UNION SELECT version(), NULL...
  • MSSQL: UNION SELECT @@version, NULL...
  • Oracle: UNION SELECT banner, NULL FROM v$version
大致语法可访问SQL injection cheat sheet

联合注入

要使 UNION 查询生效,必须满足两个关键要求:
  • 各个查询必须返回相同数量的列。
  • 每个查询中各列的数据类型必须兼容。
所以获取原来查询的相关信息是非常重要的,有两种常见的方法:

ORDER BY

 
注入一系列的ORDER BY子句,并递增指定的列索引,直到出现错误。例如,如果注入点是原始查询中WHERE子句内的带引号字符串,提交:
直至报错。

UNION SELECT

提交一系列指定不同数量空值的UNION SELECT负载:
ORDER BY不同的是要等不报错并且UNION SELECT可以更进一步的推断数据类型,例如把NULL换成1或者’1‘,有下面三种反应:
  • 报错 = 数据类型错了。
  • 没反应(页面正常) = 数据类型对了,但这一列不显示数据(运气不好)。
  • 看到字符 = 数据类型对了,且找到了输出位置(运气爆棚,注入成功)。
当SELECT只有一列可以查询相关信息而你懒的查两次的时候(肯定不是我),可以用|| '~' ||连接符,例如:

盲注

大多数情况下我们没那么容易可以直接注入得到信息,网站可能不直接显示敏感的信息,只是对于对错进行响应,基于网站的响应不同我们可以进行盲注。

布尔盲注

布尔盲注的核心在于:通过页面返回内容的“真/假”差异,来逐个比特地推断数据。
  1. 寻找注入点
在URL参数、POST数据、Cookie、HTTP头等等中寻找交互点。
  1. 构造逻辑判断
分别注入'AND '1'='1 --'AND '1'='2 --查看页面的响应的区别,如果有则纯在布尔盲注。
  1. 长度判断
判断想要得到信息的长度,这里以密码为例,注入:
  1. 爆破信息
一般来说手动一个个判断比较繁琐,所以我们可以通过使用Burp Intruder(Cluster Bomb模式)来进行爆破,示例:

隐错注入

通过页面状态码判断条件是否为真,一般语法(不同数据库有细微差别):
页面不报错,条件为假。
页面报错,条件为真。

显错注入

顾名思义是通过故意报错来展示信息:
由于密码一般是字符串型,所以会报错,并且打印。

时间盲注

当前面的都不起效时就可能是时间盲注了,一般的逻辑就是当判断条件为真时,延迟响应:

总结

对于这四种盲注,我整理出了一个表格记入:
注入类型
核心特征
提取数据方式
典型 Payload (非同一数据库写法)
适用场景
攻击效率
布尔盲注
页面内容发生变化。 真 -> 显示“欢迎回来” 假 -> 显示“用户不存在”
二分法推断。 根据页面内容差异判断真假。
AND 1=1 (正常) AND 1=2 (缺字/空白)
页面屏蔽了报错,但会根据查询结果显示不同内容。
🐢 (需逐字爆破)
隐式报错注入
页面状态码发生变化。 真 -> HTTP 500 (崩溃) 假 -> HTTP 200 (正常)
二分法推断。 制造逻辑:猜对就崩溃(除以零),猜错就正常。
CASE WHEN (1=1) THEN 1/0 ELSE 'a' END (利用数学错误炸掉数据库)
页面屏蔽了报错内容,且内容无变化,但会返回 500 状态码。
🐢 (需逐字爆破)
显式报错注入
页面直接打印出类似 XPATH syntax error: 'p@ssword' 的错误信息。
直接读取。 构造错误让数据库把数据“吐”在报错信息里。
AND updatexml(1, concat('~', (SELECT pass...), '~'), 1) CAST((SELECT...) AS int)
页面没有屏蔽报错。
极高 🚀 (1次请求 = 1条数据)
时间盲注
页面响应时间发生变化。 真 -> 10秒后才加载 假 -> 毫秒级加载
时序推断。 制造逻辑:猜对就睡,猜错就醒。
IF (1=1) WAITFOR DELAY '0:0:10' pg_sleep(10)
最后手段。 无回显、无报错、状态码永远 200。
极低 🐌 (受网速影响大,最慢)

 
 
 
 
 
 
 
 
 
 
 
 
上一篇
Daily Brief(Notion 自动日报)
下一篇
为什么换博客?
Loading...