SQL手注
导语
SQL注入漏洞作为臭名昭著的漏洞,已经有很多全自动攻击的工具了,但是我们是优秀的同学,我们要会用工具,还知道工具的原理。
寻找SQL注入漏洞
SQL注入常常出现在可以传递参数的位置,包括URL参数、搜索框、目录名、文件名等等,很多马虎的管理者因为对参数的过滤不严导致被攻击者所利用。
常见判断是否存在注入的语句有
数字型:
and 1=1/and 1=2 |
字符型:
and '1'='1 /and '1'='2 |
只要我们对sql语句的掌握够深,类似的判断语句还很多
实战学习
用了ctfhub的sql注入题目。
首先整数型注入,按照提示输入个1
下面也显示了对应的语句,但是我们发现他是select *,我们的注入语句是显示所有的查找到的条目,可是这里只返回了一条语句,猜测经过处理只显示一个条目。于是我们使用limit来验证猜测
这条语句理论上应该返回3个条目或者报错,然而却只返回一个条目,因此我们的猜测是正确的。解决的问题也简单,我们只要输入一个不存在的id,这时后端查找到的是NULL,于是就可以显示我们的union select的内容了。
接下来我们使用order by来判断条目的字段数量。
在3的时候就没有回显了,我们也可以判断出后端做了处理不显示报错信息。
接下来我们应该使用union来判断条目的字段对应显示在那个位置,但是我们一共就俩字段,可以判断,但没必要。
直接看数据库名
得到数据库的名字是sqli
然后information_schema3连
顺利得到flag。
常见的获取敏感信息的函数
user() 数据库用户名 |
举一反三
那么我们就基本可以总结书sql注入的普遍思路了。
- 判断是否有注入点
- 使用order by来判断返回的条目的字段数量
- 使用union判断每个字段的显示位置
- 使用database()等函数获取有用的信息
- 大声叫喊奥利给!
盲注
盲注和注入的最大区别在于他不会返回给你东西,只会在出错的时候报错或者显示不正常,因此盲注的payload通常类似下面
id=1 and (select length(database()))>4 //判断数据库名称的长度
id=1 and select ascii(substr(database(),1,1))>119 //判断数据库名第一个字符的ascii码
基本上除了比注入麻烦好多以外没什么特别难的
报错注入
报错注入也是查询结果不给显示的时候使用的,主要依赖floor() extractvalue()(updatexml())函数
floor()的报错注入
准确地说应该是floor()、rand()、group by的报错注入。
我们看下面这句
select count(*),(concat(floor(rand(0)*2),'@',(select version())))x from users group by x |
rand()函数的作用是随机生成一个0~1的数字,他还能接受一个seed的参数作为随机种子。rand(0)就是生成一个伪随机序列,自己试一下可以发现他是0110110。
而报错的主体是group by。
group by会形成一个虚拟表,首先以group by后面的表项作为主键,扫描select的每一个条目,将具有相同的主键的两个表项合并。这个过程对主键进行了两次运算。第一次是获取主键,第二次是向虚拟表中插入这个表项的时候。
在我们这个例子里,报错的过程大概是这样
- 获取主键的名称,扫描users表的第一项,假设我们的数据库版本号是5.7.19,根据rand(0)的序列,x的值为0@5.7.19(user只是单纯的提供我们能进行几次x的插入的工具表),此时虚拟表是空的,发现不存在这个条目,于是向其中添加一个条目,此时再次运算x的值为1@5.7.19,那么此时这个虚拟表如下
x | count(*) |
---|---|
1@5.7.19 | count(*) |
x | count(*) |
---|---|
1@5.7.19 | count(*) |
3.再下一个,主键是0@5.7.19,表内没有这个值,因此要插入
但是 ,插入表的时候再次计算得到x是1@5.7.19,也就是要往表里再插入一条1@5.7.19,count(*)的条目,由于主键是唯一的,所以必然会报错,这一条的结果也就返回了出来。
看到这里,相信大家都懂了,那么就有人要问了,万一我的user表不够长咋办啊?gnls你user表连三项都没有你这小破站是干啥的?那你去找个seed能生成0101或者1010序列的⑧
extractvalue()
extractvalue() :对XML文档进行查询的函数,其实就是相当于我们熟悉的HTML文件中用 <div><p><a>标签查找元素一样。
语法:extractvalue(目标xml文档,xml路径)
第二个参数 xml中的位置是可操作的地方,xml文档中查找字符位置是用 /xxx/xxx/xxx/…这种格式,如果我们写入其他格式,就会报错,并且会返回我们写入的非法格式内容,而这个非法的内容就是我们想要查询的内容。
直接使用~/XXX的非法格式
select username from security.user where id=1 and (extractvalue(‘anything’,concat(‘~’,(select database())))) |
于是他就会报错返回想要的内容。
此外还有updatexml()函数有相同的用法,只要把xml路径改成不合法的格式即可。
select username from security.user where id=1 and (updatexml(‘anything’,concat(‘~’,(select database())),’anything’)) |
参考
https://blog.csdn.net/qq_41059320/article/details/89281125
https://blog.csdn.net/he_and/article/details/80455884
https://blog.csdn.net/zpy1998zpy/article/details/80631036