[BJDCTF2020]Easy MD5
[BJDCTF2020]Easy MD5
打开靶机,看到一个输入框,首先尝试是不是sql注入,结果发现尝试了很多payload,都没有任何回显,只是知道了它是通过get传参的,所以我们看看响应头
从中我们可以看到有一段sql语句,还有一个md5函数,我们先来了解一下md5这个函数的相关知识
这个md5函数可以根据这个row参数的不同,来返回不同格式的数据
<?php
$str = "jinx";
echo "字符串:".$str."<br>";
echo "TRUE - 原始 16 字符二进制格式:".md5($str, TRUE)."<br>";
echo "FALSE - 32 字符十六进制格式:".md5($str)."<br>";
?>
返回结果:
这里我们要做的就是,假如我们转递进去的内容经过这个md5加密之后的结果为'or'+一段内容
并且在or后面加的这一段内容为true,在这种条件下就可以实现那个select * from 'admin' where password=md5($pass,true)
sql语句的注入
并且这里还有一个知识点就是在mysql当中只要or后面的内容为数字+字符串
也就是or 1……
这样之后返回的值就为true
我们用mysql实际演示一下
原本有一个这样的表
然后我们直接去找pass为123的那条数据
然后再用or连接'数字+字符串'的查询语句,可以发现,确实查出了所有的语句,证明了只要or后面+(数字+字符串),返回结果就为true
所以我们的目的就是去寻找一个字符串,使它经过MD5加密之后的值是'or'+数字……我们这里找了一个字符串就是:ffifdyop,我们可以看一下加密之后的结果
其实这里具体的值应该是: 'or'6
然后我们在输入框里输入'or'6
我们审查源代码:
$a = $GET['a'];
$b = $_GET['b'];
if($a != $b && md5($a) == md5($b)){
发现这里是要让我们这里传入两个不一样的参数值,但是在md5加密之后又要相等
这里就有了一个新的知识:==弱比较的时候会把两边的变量类型先转换成一样的再进行比较
而我们要做的就是让他们在转换之后的值相等,这里也有一个知识点就是0e在比较的时候会被当作科学计数法
0e6=0*10^6
1e6=1*10^6
所以我们所做的就是传入一个字符串,使它经过md5加密的值为0e开头,从而再转换类型的时候会被当成是0,从而相等
这里有一些字符,在加密之后为0e开头:
原值:QNKCDZO 加密后的值:0e830400451993494058024219903391 240610708 0e462097431906509019562988736854 s878926199a 0e545993274517709034328855841020 s155964671a 0e342768416822451524974117254469 s214587387a 0e848240448830537924465865611904 s214587387a 0e848240448830537924465865611904 s878926199a 0e545993274517709034328855841020 s1091221200a 0e940624217856561557816327384675
所以我们这里就可以往a和b当中随便传两个上述的值就可以
其实这里还有一种绕过的方法就是传入两个不同的数组变量,因为md5函数不能对数组变量进行加密,如果传进去的是数组变量,就会返回NULL,这个时候弱比较的值也是会相等的,这里要注意的是a[]和b[]的值也要是不相等的才行
传进去之后页面上就出现了一段代码,我们也同样进行审计
<?php
error_reporting(0);
include "flag.php";
highlight_file(__FILE__);
if($_POST['param1']!==$_POST['param2']&&md5($_POST['param1'])===md5($_POST['param2'])){
echo $flag;
}
这里的逻辑和上面的差不多,不过这里的比较改成了前面改成弱比较,后面是强比较,前面是弱比较,我们就不能使用之前那种使它的值为0e开头的那种方法,只能通过传递数组的方式来使他们的弱比较的值不相等,使它们经过md5之后的值又相等