ctf题目练手·四
0x00 前言
参考文章:https://www.cnblogs.com/zhengna/p/15905396.html#:~:text=CTFHub_201
需要培养一种能力:根据题目的不同响应去猜测题目的代码逻辑,并找到其中的漏洞。
0x01 题目
题目来源:2017-赛客夏令营-Web-Injection V2.0
index.php
题目提示是SQL注入,很明显从这个POST表单入手。
0x02 逻辑
概述
账号密码登录题,有两种类型:
- 同时验证:一条语句同时验证用户名和密码
- 先后验证:先验证用户名,再验证密码
对于不同的类型,通常采用不同的注入方式。
怎么分辨题目属于哪一种类型呢?
如果题目回显:用户名或者密码错误,那么很可能是第一种
如果题目回显:用户不存在、密码错误,那么很可能是第二种
下面谈谈如何应对这两种类型
同时验证
代码逻辑如下:
这种类型通常采用:
uname=-1' or 1=1 #&passwd=12313131
(这里的passwd已经被注释了,随便写)
此时执行的sql语句即为:
SELECT username, password FROM users
(WHERE后面恒真,省略)
先后验证
代码逻辑如下:
这种类型有两种方法:
方法一
如果给出一个不存在的用户aaa,那么如下语句会返回空:
SELECT password FROM member WHERE username='aaa'
既然返回空了,那么我们就可以尝试通过联合注入去调控这个值,原理语句如下:
SELECT password FROM member WHERE username='aaa' UNION SELECT 1
如此,返回值是1,也就是说跟password比较的值是1,那么password的值直接为1即可。
本题采用该方法的payload如下:(本题过滤了空格,利用/**/
代替)
user=1'/**/union/**/select/**/1/**/or/**/'1'='1&pass=1
小结
本方法深入探究原理:既然重点在比较上,那么就思考等号两边的值是否都可控。毫无疑问的是,参数pass的值是完全可控的,能不能让返回值(一般来说是数据库里的密码,其是不可控的)可控呢?,不妨跳开固有框架,不比较数据库里的密码,利用用户不存在搭配联合注入实现任意构造返回值,使得返回值可控。
方法二
不妨给出一个存在的用户admin,那么如下语句不为空:
SELECT password FROM member WHERE username='admin'
所以会正确返回数据库里的密码。
我们还是希望等号两边都可控,也就是不要返回数据库里的密码。
这时就要想到order by
数据库里的密码是一列结果,联合注入是一列结果,根据排序来决定第一列是哪一个结果。
原理语句如下:
SELECT password FROM member WHERE username='admin' UNION SELECT 0 order by 3 #
在 SQL 中,
ORDER BY 1
的默认顺序是升序(ASC)。这意味着结果将根据第一列的值从小到大进行排序。如果需要降序排序,可以使用ORDER BY 1 DESC
。
密码的值和0相比,肯定是0小,所以返回值是0。最后令参数pass为0即可。
结果如图:
小结
本方法跟方法一相同点在于都是想办法操控返回值。不同点在于是否需要正确的用户名。
0x04 总结
这道题给了我很大的启示:从本质上看问题。有时候看不到本质,那就根据已知情况去合理猜测。
对于本题而已,等于号的两边都应该可控。参数pass所比较的本质上是返回值而不是数据库的密码。返回值是什么,可以是数据库的密码,也可以基于联合注入结合其他方法所得到的新的语句的返回值。
逻辑很重要,积累很重要,路漫漫其修远兮,吾将上下而求索。