刷刷刷刷刷sql题
NSSCTF
【SWPUCTF 2021 新生赛】easy_sql
这题虽然之前做过,但为了学习sql,整理一下就再写一次
打开以后是杰哥的界面
注意到html网页标题的名称是 “参数是wllm”
那就传参数值试一试
首先判断注入类型(数字型或字符型)
传1
传2 没有回显
同样的,后面的3456都没有回显
光传abc也没有回显
所以应该是数字型注入
然后判断闭合方式
接下来传1' (单引号)
出现报错
然后传1" (双引号)
页面又有回显
回到报错的 1'页面,分析报错语句
注意看这个位置
这里要记住的是:无论是单引号还是双引号在sql语句中都是成对出现的,包括 ( ) { } 【】各种括号 。
所以上面的报错句应该注意到最后的一个引号,要成对则前面必有一个单引号与它成一对。
也就是说,在这个报错语句中,一对单引号 ' ' 包裹着刚才我们注入的内容:' 1' '
所以这一堆引号就该这么拆:
' ' 1' ' LIMIT 0,1 '
所以包裹着我们注入的 1' 的就是单引号 ' ' 。也就是说明这题的闭合方式是单引号。
既然如此那加个注释: --+
目的是把单引号注释掉
发现页面没有报错了,有了回显,这就说明闭合方式判断正确
这里还有一个验证是否存在sql漏洞的方法:
当输入1=1时(条件为真),页面正常显示或有回显
当输入1=2时(条件为假),页面未正常显示
这就说明我们输入的内容数据库是能够执行的,即存在sql注入漏洞
那么接下来就是一系列的爆数据库,直到爆出需要的信息(flag)
正规的讲叫先判断列数
语句是order by
比如现在一列列爆
第一列,有
第二列有
第三列也有
但是到了第三列就会显示它不认识了
包括后面的第5列也如此
也就是说,这个数据库里的表总的只有三列
既然查出了总列数,接下来就需要联合查询所有列数下的数据,语句 union select
这里要注意:需要把传入参数的值1改为-1
然后开始联合查询
可以看到用户名位于第2列的位置,密码位于第3列的位置 (回显位为2、3位)
接下来可以看看这两列的数据,一列列来,第2列:
有了 ,可以看到是test_db
第3列:
都是test_db ,这当然的,两个都在一个数据库(test_db)里面
爆出来的这个是数据库名
接下来查表名(table_name)
然后出现这么个东东
英语也不太好,翻译一下
ouou 我知道了,我只改了第2列数据库名的位置,忘了后面还有个第3列了
大意了haha
加入第3列
提示返回的信息超过一行
一个解决办法就是使用group_concat把table_name变为一行即可 group_concat(table_name)
得到有两个表的表名
接下来查列名(column_name ):
对应的把刚刚的表名table_name改为column_name(列名);
tables改为columns,最后加上刚查到的表名users
执行
select group_concat(column_name) from information_schema.columns where table_schema='test_db' and table_name='users'
得到列名为password
都查出来了,select后面的就全扔掉,看看列名为password的数据列里面有什么,有没有想要的数据(flag)但这里好像出了点问题,爆出来又是yyy(不对,没问题,我查的就是password,而password为yyy刚开始就告诉我了),所以问题在于没有爆出可用的列名
回去找了一下,应该是上一步爆列名的问题,命令
select group_concat(column_name) from information_schema.columns where table_schema='test_db' and table_name='users'
应该改写为
select group_concat(column_name) from information_schema.columns where table_schema='test_db'
即删去了后面的and tablename='users'
至于为什么要这么改,后面也想清楚了:
如果查列名的语句含有 and table_name='users' 这样就代表我们是查询名为users的表下的所有列名;
而如果删去 and table_name='users' 仅前面的语句就不指定表名而是查询所有表下的所有列名,这样才能把flag列名爆出来 (也就是说其实flag是存在于test_tb表下的,而并不在users表下,如果冒然的将查询列规定为users表下面,只会画蛇添足,还找不到flag)
弄清楚以后重新爆列名,不用多此一举限制查询的范围(删去 and table_name='users')
发现这次列名就全了,可以看到flag列了。
那么接下来直接爆flag
既然刚刚无意中发现flag不在users表下而是在test_tb表下,那就直接爆test_tb表的flag列即可
【SWPUCTF 2022 新生赛】ez_sql
打开环境后的页面
题目名sql,参数提示是nss,试着传个1
什么是相对安全的方式
返回题目看提示POST注入,这样一来就知道是用Hackbar了
先把刚get传参的的参数删,然后F12打开Hackbar进行POST传参1
哦豁直接出flag
但是发现flag不对
试试提交上面那个
也不对
换个思路,传abc无回显
说明应该是数字型
接下来判断闭合方式,单引号' 报错
进行语句分析得知闭合方式为单引号'
接下来判断是否存在sql漏洞 传参nss=-1' and 1=1 --+
翻译一下
说明应该是有字符被过滤了
搞了半天竟然是空格和or被过滤了
(这个or不仅仅包括普通的or,还有order by中的or,这个你敢信???我也是惊呆了)
然后把空格替换一下(用/**/替换)
接下来判断列数
发现又有回显了
4列不认识,说明只有三列
联合查询
但是这里union也被过滤,采用双写绕过
没有我们要的列数,那就切换页数
这里用limit1,1
看到NSS_db
再报表
,,,,这题是做不下去一点,不是看博客就算爆破也爆不出来information_schema被过滤
还是双写
【SWPUCTF 2021 新生赛】sql
还是杰哥
看看翻译
Waf是防火墙嘛,所以应该没有太重要,直接按上一题的思路
同样参数还是wllm
传参数字1有回显
传参字符abc没回显
说明是数字型注入
接下来判断闭合方式,单引号:'
报错
双引号:"
页面正常
和上面那题的剖析来看是一样的单引号闭合方式
接下来把单引号注释掉,但是发现查询的时候出现js弹窗警告
说明注释符 --+ 被过滤了,那就想替代方法来替换
上查了一下:
但是
可以看到这里的所有方法都被过滤了。。
后面想了想,很有可能是过滤了空格,空格的替换方法:
后面又测试了很多次才发现等号也被过滤了
那就再找等号的替换方法
选择了like(小写也可以) (但是我奇怪的是为什么在寻找闭合方式的时候用=没有报错)
然后终于绕过这两种过滤把单引号注释掉了 (页面正常显示,未报错)
接下来查列数
但是为什么没有回显
这里就感觉被过滤的字符没找准,这样太麻烦了些
后来突然想到那天在博客上问师兄的关于黑盒测试,有没有快速准确的方法,师兄给了提示:
关键字fuzz模糊测试,然后上网学习了相关用法
大概就是利用burpsuit的Inruder模块
把包发到Intruder模块之后先clear一下
然后选择要测试的参数位置(如;username=$test$)
用$符号标记注入点(支持多个位置同时测试)
我这里对三个点进行测试
然后在Attack type中选择策略(Sniper:逐个位置顺序测试(最常用))
其他:
Battering ram:所有位置同时使用相同payload
Pitchfork:不同位置使用不同payload列表
Cluster bomb:多payload组合测试
然后选择positions Add 在Payloads标签配置测试字典:
比如现在是SQLi/SQL注入
还有XSS/跨站脚本
OS Command/命令注入
还需要自定义关键字列表
比如
'
"
SELECT
UNION
<script>
/etc/passwd
${jndi:ldap://
...(根据测试的目标补充)
还有高级设置
如添加Payload处理规则
URL编码
HTML实体编码
大小写变异(如SeLeCt)
添加注释符(如/**/)
接下来实战直接传参1
然后抓包进行字符爆破
奇怪的是明明注释符--+上传时报错,bp却显示没有过滤
同样,空格也没显示过滤
我也不知道怎么个事儿
只能看看别人的博客说空格、等号被过滤了
然后用/**/代替空格,like代替= (这里的等号被过滤指的是传入参数的等号,如1=1,并不是传参时的wllm=的等号)
接下来判断列数
1、2、3都有回显,到4报错 (%23是替换#)
说明只有3列
联合查询判断回显位,可以看到回显位是2、3位(别忘了把1改为-1)
这里说一下为什么要把1改为-1
我们知道,当参数等于1时是有回显的,而参数的值通常为正整数,后端代码一般不会限制参数的负数值,但数据库里是没有负数值的信息的,所以这个负数值就可以作为一个“跳板”,把参数值改为-1后因为-1值的信息不会回显,然后语句中-1后面查询的信息结果就会回显而不会被1参数值的回显信息覆盖。
接下来查数据库名
可以看到数据库名为test_db
接下来查数据表名
这个有点长:?wllm=-1'/**/union/**/select/**/1,2,group_concat(table_name)/**/from/**/information_schema.tables/**/where/**/table_schema/**/like/**/'test_db'%23
接下来爆字段名
(LTLT_flag)?wllm=-1'/**/union/**/select/**/1,2,group_concat(column_name)/**/from/**/information_schema.columns/**/where/**/table_name/**/like/**/'LTLT_flag'%23
接下来很明显就爆flag字段即可
?wllm=-1'/**/union/**/select/**/1,2,group_concat(flag)/**/from/**/LTLT_flag%23
但是发现只有一部分(20个字符),说明一次只能输出20个字符
那就20个20个的爆吧
去查了一下发现用到mid函数
?wllm=-1'/**/union/**/select/**/1,2,mid(group_concat(flag),20,20)/**/from/**/LTLT_flag%23
表示输出flag字段中的第20个字符开始的后20个字符 ,爆出中间段的flag
然后用
?wllm=-1'/**/union/**/select/**/1,2,mid(group_concat(flag),40,20)/**/from/**/LTLT_flag%23
爆出最后的flag,表示输出flag字段中第40个字符开始的后20个字符
所以搜罗一下:
第一段: NSSCTF{50855895-d906
第二段:6-4039-955c-cd62e2e6
第三段:a8a7}
最后拼接一下就好了(需要注意爆出的中间段的flag第一个字母和开头段的最后一个是重复的,需要删去一个,我也提交了好几次不正确才发现这个问题)
然后提交
BUUCTF
【SUCTF 2019】EasySQL
打开环境是一个类似于登录界面
提示给flag,正确会告诉我
先提交个1看看,发现有回显
看不懂,查了一下
这说明后端代码使用了某些函数来输出变量的类型或内容,注入的值1被解释为布尔值TRUE,即SQL语句为真
然后试试看万能密码 ' or 1=1 #
发现报错nonono
说明有字符被过滤了
接下来看好了,因为这么多字符报错也不知道是谁被过滤,一个个测试太浪费时间,所以用抓包进行黑名单字符爆破
关闭代理,注入1提交后抓取数据包
右键send to Intruder
进入Intruder利用关键字字典对query进行爆破
先删除query的值1,然后点击 Auto$
可以看到右侧payloads栏可以设置关键字字典
这里如果本机存在现成的爆破字典的话可以直接load...在本机选择字典
但由于我没有找到免费且好用的字典,所以打算手动添加测试字典,比如常用的sql语句中会涉及字符select、sleep、union、or以及xor、if等,先尝试测试一下
点击Enter a new item栏手动一个个添加
输入
然后点击Add添加
一个个加进去
添加完毕点击Start attack开始爆破
爆破完毕后可以看到Payload后面对应的length长度
可以看到长度为560的字符是nonono(被过滤了的)
其他长度的正常,没有被过滤
这样一来我们就可以根据自己要构造的sql语句的字符进行爆破然后找到被过滤的字符并进行替换即可
而这题根据爆破结果可以得知字符union、if、xor、sleep、or甚至flag均被过滤,那在使用这些字符进行注入时就需要一 一替换或者找不到替换这些字符的方法的时候相应的如联合注入盲注都是用不了的
这样其实可以使用堆叠注入
堆叠注入:将多条sql语句放在一起,并用分号;隔开
比如现在我们需要先查询数据库名称
可以看到数据库名称已经回显,说明堆叠注入是可用的,那么接下来进行表名的查询
看到表名为flag
那想要flag应该就在这个表下面,但是我经过爆破发现from这个字符也被过滤了
重新注入其他字符试试
注入0:
可以看到无回显
注入2:
有回显
3、4、5等都有
注入a:
无回显
然后就发现数字注入除了0之外都有回显,而注入字母无回显
其实后面的我也不会,是现学的
这就可以猜测后端代码含有||或运算符
也就是说:
假设后端代码为:
$query = "SELECT * FROM users WHERE id = '$id1' or '$id2'
简化下来就是
$id1 or $id2
假设我们的注入点为$id1,则有:
情况1:
那么假如$id1是非0数字,语句1 or $id2 结果为1(不论or右边成不成立,左边为非0数字结果为1,整个语句就为1);
情况2:
假如$id1是0或字母
(1)$id2值为0或字母,值为0(假)
则 0 or 0 整个语句就为0(假)
(2)$id2值为非0数字,值为1(真)
则 0 or 1整个语句就为1(真) 当然,这种情况在这题是不存在的(因为刚测试过有没有回显的情况,说明$id2的值定然不可能为1,否则无论$id1的值为多少,整个语句都为1(真),都会有回显),也就是说$id2的值应该为0($id2应该为0或字母)
情况3:
假如$id1不是非0数字
(1)$id2值为1时整个语句为1(刚说了这题这种情况不存在)
(2)$id2值为0时整个语句为0
而在大佬的wp那里得到本题源码,的确如猜想
$sql = "select ".$post['query']."||flag from Flag";
别问大佬怎么知道的,有背景
这是大佬的wp:[SUCTF 2019]EasySQL1 题目分析与详解_[suctf 2019]easysql 1-CSDN博客
接下来查询flag有两个方法:
1、利用非预期漏洞获取flag
非预期漏洞也就是输入1,1时,sql语句变为select 1,1 || flag from Flag 其中由【1】和【1 || flag from Flag】两部分组成,并不是【1,1】||【flag from Flag】.非预期漏洞就是利用数据库对符号判断的不准确形成的漏洞
比如现在输入*,1
sql语句就变为了select *,1 || flag from Flag
其中分为两部分:
1、 select * from Flag
2、select 1 || flag from Flag
select * from Flag 通过查看表Flag中的所有数据可以get到flag
2、使用sql_mode中的PIPES_AS_CONCAT函数
PIPES_AS_CONCAT函数:将 || 或运算符 转换为连接字符,即将 || 前后拼接到一起
$id1 || flag from Flag 的意思是先查询$id1 再查询Flag目录下的flag,而不是查询$id1flag(也就是把查询结果拼接到一起,不要混淆喽)
所以构造查询结果为:
1;sql_mode=PIPES_AS_CONCAT;select 1
查询即可得到flag