1. 万能密码登录
登录逻辑代码如上,
什么是sql注入?
有时候我们需要用户输入一些参数来帮助构造sql语句,完成数据库查询。但是因为输入的数据没有进行任何限制,所以当数据中包含了而已sql语句,就能劫持原来的sql语句,产生sql注入。
在登录时随便输入用户密码,
拼接成如上sql语句。
要想成功进行登录,就必要
$row有数据,则select语句where必须为真,那么拼接后的sql语句只需要满足where为真的条件即可,这里pwd字段进行了md5加密,无法构造,可以从user字段入手。
接下来用户名输入admin’ or ‘1’=’1,密码随便
拼接成这样,因为and优先级大于or,所以where结果是true or (true and false)=true,登录成功
2. 猜解注入获取密码
如果这时候我除了登录外,我还想获取用户密码,应该怎么办?
第一步:先构造出登录成功的语句
为了方便,使用发包方式
输入的是user’#,这样就能注释后面语句,相当于where user=’admin’#,为true登录成功
第二步:猜测密码字段
现在我们是不知道表中有什么字段,首先要获取密码字段。这里我们知道登录的时候肯定用的是用户表,所以这里不需要猜测用户表。
常见的密码字段有pwd,pass,password,以及与form表单中相同的字段。另外也可以使用字典爆破。
现在输入admin' and pass!=''#
假如pass不是密码字段,不存在这个字段的话,一般就会报错或者本来是登录成功的变成登录失败,因为密码一般不为空,所以字段存在就为true,而user=’admin’也是true的,所以可以利用这个特性判断字段是否正确。
这里经过几次尝试,得出pwd是密码字段
第三步:获取密码长度
Mysql中有一个length函数,来获取当前字段的值的长度
因为where是否为true取决于pwd字段,所以只要用二分法就能获取密码的长度,如上图length(pwd)>20是为true的,所以密码大于20位,
失败,密码在21-40位之间
31-40位之间
以此类推,得到密码位32位
第四步:猜解密码
Mysql中mid函数MID(字符串,位置,长度)。ASCII函数获取一个字符的ascii值,常用的acsii的值有‘0’为48,‘A’为65,‘a’为97。
因此输入admin' and ascii(mid(pwd,1,1))>65#
发现第一位密码为数字
小于52
大于48
不大于50
最终确定第一位密码的ascii值是50,对应的字符为’2’。
接下来31位也如此处理,admin' and ascii(mid(pwd,2,1))>65#
最后得到结果是
21232f297a57a5a743894a0e4a801fc3
是md5加密,扔去解密
http://www.cmd5.com/
3. UNION注入绕过无密码字段查询
这个与(1)的区别就是密码验证不是判断是否有数据返回,而是通过用户查询的这条记录,然后判断传入的密码是否跟数据库中的相同。
当如果依旧输入admin'#
发现登陆失败,为什么呢?
因为虽然构造sql语句成功,也返回了结果
但是这里的判断还是没有通过,因为密码不正确。
那有什么方法呢?
如果能控制返回结果不就行了么。
第一步:判断表中有多少个字段
使用order by可以进行判断表中有多少个字段,order by除了可以按字段名排序外,也可以按字段的列数来排序。
这里表示按第3列排序
但是如果这里写4
就报错了。
证明用户表有3个字段。
第二步:使用UNION查询
在mysql里union可以把两条语句查询的结果合并,但两个结果集字段的列数要相等
这里我们先清除语句1的结果,合并的结果就只能是语句2了
select null,null,null
上面这条语句是最终结果,但是我不知道密码账号分别在第几个字段,所以这里可以将所有字段都填入密码
首先将随便一个字符串md5加密
Md5(’123’)=’ 202cb962ac59075b964b07152d234b70’
最后输入
用户名admin' and 0 union select '202cb962ac59075b964b07152d234b70','202cb962ac59075b964b07152d234b70','202cb962ac59075b964b07152d234b70'#
密码123
为什么这样能登录成功?
当输入上面语句时,构造的语句为
select * from user where user='admin' and 0 union select '202cb962ac59075b964b07152d234b70','202cb962ac59075b964b07152d234b70','202cb962ac59075b964b07152d234b70'
返回的结果是
select '202cb962ac59075b964b07152d234b70','202cb962ac59075b964b07152d234b70','202cb962ac59075b964b07152d234b70'
但判断的时候
输入的密码正好是123
的md5值正确,登录成功
4. 添加密码字段获取密码
这是(3)的另一种方法,这里我想既然你sql语句不写密码字段,那我就写回去。
第一步:猜解密码字段
(2)中提到了方法,这里不再讲述
第二步:猜解密码
这里跟(2)的差不多,但也有点不同
无论where是true还是false都是登录失败,原因(3)中提到了,那该怎么区分?
Mysql中的if函数IF(条件,返回1,返回2),当条件成立返回返回1,否则返回返回2,这里如果输入admin' and IF(length(pwd)<7,'test',exp(~1))#
exp(~1)在mysql里会报错,那么一个报错,一个登录失败,就能进行区分
5.with rollup(更新)
在CTF上面看到这种思路,这里加上..
本来
with rollup是分组后这些统计函数的结果再总体统计一次
这行是with rollup新增的
但是如果不用sum这些函数
对谁进行分组谁就变成NULL
利用这个特性,这里我干脆所有都变成NULL
可以看到最后一行是全NULL的
回到[3]的题目
这里我就是取全NULL的一行,但是有一个问题,就算pwd="",经过md5后也是有值的
不过php的md5有一个特性就是md5的参数如果传入一个数组会返回NULL
登录成功
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)