CTF_Web:php弱类型绕过与md5碰撞

0x00 前言

md5碰撞只是一种掌握php弱类型的方式,弱类型的内容有很多,数组、字符串比较等等,但不论以哪种方式考,涉及的知识点都是相通的,希望通过对基础知识的分享与大家一同学习进步。

0x01 什么是md5

“MD5,即消息摘要算法(英语:MD5 Message-Digest Algorithm)。是一种被广泛使用的密码散列函数,将数据(如一段文字)运算变为另一固定长度值,是散列算法的基础原理,可以产生出一个128位(16字节)的散列值(hash value),用于确保信息传输完整一致。

显然128位不足以把世界上所有消息的摘要毫不重复的计算出来,当然现在16字节(128位)、32字节(256位)的md5也都有,选择位数多的方式可以在一定程度上减少硬碰撞(collision)的可能性。

在php语言中调用中md5的使用方式为:

",md5($str),"
"; //为字符串计算摘要值 $files = "02.php"; echo "file_md5-->",md5_file($files);//为文件计算摘要值 ?>

得到默认32字节的密文。


由于php中的md5默认返回32字节的结果,所以要得到16字节的需要使用字符串截取。

",md5($str),"
"; //为字符串计算摘要值 $md5Str = substr(md5($str),8,16);//获取16字节的摘要值 echo "16byte-->",$md5Str; ?>

这是因为32字节的字符串中间8-24字节与16字节加密的结果是相同的,所以在php中我们可以通过这一方式来获得16字节的摘要值。


0x02 什么是php弱类型

php是一门弱类型的语言,它不会严格检验变量类型,变量可以不显示地声明其类型,而是在运行期间直接赋值。

在php中比较是否相等有两种符号:=====
其中==在比较时会将不同类型的变量或值转换为相同类型再进行比较。
===则直接比较类型是否相同,如果同类型,再比较值。
那么php弱类型这里的“弱”,指的不是某个类型有什么问题,而是整个php语言中某些函数在处理赋值、字符串比较、变量比较的过程中对类型似乎并不关心,弱化了类型带来的影响,在使用某个变量时不需要我们定义变量的类型,而是根据内容判断这是什么类型,从而导致了各种漏洞的发生。
例如:

 

其结果为:

bool(true)
bool(true)
bool(false)
bool(true)
bool(true)
bool(false) 

上述判断输出的原因是,在php中当一个字符串被当作一个数值来取值时,如果该字符串没有包含'.','e','E',并且其数值值在整形的范围之内时,该字符串被当作int来取值,其他所有情况下都被作为float来取值,而该字符串的开始部分决定了它的值,如果该字符串以合法的数值开始,则使用该数值,否则其值为0。
所以在上面的情况中,1a转换为1a1转换为0,而"0e123456"=="0e234567"相互比较的时候,会将0e这类字符串识别为科学技术法的数字,0的无论多少次方都是零,所以相等。

0x03 md5==绕过(0e比较)

上面这段代码中就是上述0e开头的所有字串都被认为是0,所以我们先看看md5('QNKCDZO')的结果是0e830400451993494058024219903391,那么所有0e开头的md5串都可以满足上面的条件。
常用的有:

QNKCDZO
0e830400451993494058024219903391
240610708
0e462097431906509019562988736854
s878926199a
0e545993274517709034328855841020
s155964671a
0e342768416822451524974117254469
s214587387a
0e848240448830537924465865611904

包含了纯数字、纯字母、数字字母组合三种类型的结果,在没有条件限制的情况下,无论使用哪一个都可以成功绕过。在上面的代码中使用?a=240610708,即可打印flag值。

0x04 md5===绕过(数组比较)

在php中的hash函数md5、sha1等处理中若传入一个数组的值,则会报错返回NULL,而返回的值在类型和内容上都是相同的,所以可以用来绕过某些两边参数可控的场景,上面只能控制一边的值传入,所以数组类型不适用。


上述的例子中传入?a[]=a&b[]=b即可满足既不相等,md5后又相等的条件,虽然报错,但仍然输出了正确的值。

Warning: md5() expects parameter 1 to be string, array given in 1.php on line 5
Warning: md5() expects parameter 1 to be string, array given in 1.php on line 5
ook!

0x05 md5===绕过(硬碰撞)

前面我们也提到了md5无论是32位还是16位,都不可能不重复的表示所有信息,这种重复的例子就称为 硬碰撞 ,有如下代码:

";
echo md5($s2),"
"; echo md5($s3),"
"; ?>

当传入的值为

?a=%af%13%76%70%82%a0%a6%58%cb%3e%23%38%c4%c6%db%8b%60%2c%bb%90%68%a0%2d%e9%47%aa%78%49%6e%0a%c0%c0%31%d3%fb%cb%82%25%92%0d%cf%61%67%64%e8%cd%7d%47%ba%0e%5d%1b%9c%1c%5c%cd%07%2d%f7%a8%2d%1d%bc%5e%2c%06%46%3a%0f%2d%4b%e9%20%1d%29%66%a4%e1%8b%7d%0c%f5%ef%97%b6%ee%48%dd%0e%09%aa%e5%4d%6a%5d%6d%75%77%72%cf%47%16%a2%06%72%71%c9%a1%8f%00%f6%9d%ee%54%27%71%be%c8%c3%8f%93%e3%52%73%73%53%a0%5f%69%ef%c3%3b%ea%ee%70%71%ae%2a%21%c8%44%d7%22%87%9f%be%79%6d%c4%61%a4%08%57%02%82%2a%ef%36%95%da%ee%13%bc%fb%7e%a3%59%45%ef%25%67%3c%e0%27%69%2b%95%77%b8%cd%dc%4f%de%73%24%e8%ab%66%74%d2%8c%68%06%80%0c%dd%74%ae%31%05%d1%15%7d%c4%5e%bc%0b%0f%21%23%a4%96%7c%17%12%d1%2b%b3%10%b7%37%60%68%d7%cb%35%5a%54%97%08%0d%54%78%49%d0%93%c3%b3%fd%1f%0b%35%11%9d%96%1d%ba%64%e0%86%ad%ef%52%98%2d%84%12%77%bb%ab%e8%64%da%a3%65%55%5d%d5%76%55%57%46%6c%89%c9%df%b2%3c%85%97%1e%f6%38%66%c9%17%22%e7%ea%c9%f5%d2%e0%14%d8%35%4f%0a%5c%34%d3%73%a5%98%f7%66%72%aa%43%e3%bd%a2%cd%62%fd%69%1d%34%30%57%52%ab%41%b1%91%65%f2%30%7f%cf%c6%a1%8c%fb%dc%c4%8f%61%a5%93%40%1a%13%d1%09%c5%e0%f7%87%5f%48%e7%d7%b3%62%04%a7%c4%cb%fd%f4%ff%cf%3b%74%28%1c%96%8e%09%73%3a%9b%a6%2f%ed%b7%99%d5%b9%05%39%95%ab
&b=%af%13%76%70%82%a0%a6%58%cb%3e%23%38%c4%c6%db%8b%60%2c%bb%90%68%a0%2d%e9%47%aa%78%49%6e%0a%c0%c0%31%d3%fb%cb%82%25%92%0d%cf%61%67%64%e8%cd%7d%47%ba%0e%5d%1b%9c%1c%5c%cd%07%2d%f7%a8%2d%1d%bc%5e%2c%06%46%3a%0f%2d%4b%e9%20%1d%29%66%a4%e1%8b%7d%0c%f5%ef%97%b6%ee%48%dd%0e%09%aa%e5%4d%6a%5d%6d%75%77%72%cf%47%16%a2%06%72%71%c9%a1%8f%00%f6%9d%ee%54%27%71%be%c8%c3%8f%93%e3%52%73%73%53%a0%5f%69%ef%c3%3b%ea%ee%70%71%ae%2a%21%c8%44%d7%22%87%9f%be%79%6d%c4%61%a4%08%57%02%82%2a%ef%36%95%da%ee%13%bc%fb%7e%a3%59%45%ef%25%67%3c%e0%27%69%2b%95%77%b8%cd%dc%4f%de%73%24%e8%ab%66%74%d2%8c%68%06%80%0c%dd%74%ae%31%05%d1%15%7d%c4%5e%bc%0b%0f%21%23%a4%96%7c%17%12%d1%2b%b3%10%b7%37%60%68%d7%cb%35%5a%54%97%08%0d%54%78%49%d0%93%c3%b3%fd%1f%0b%35%11%9d%96%1d%ba%64%e0%86%ad%ef%52%98%2d%84%12%77%bb%ab%e8%64%da%a3%65%55%5d%d5%76%55%57%46%6c%89%c9%5f%b2%3c%85%97%1e%f6%38%66%c9%17%22%e7%ea%c9%f5%d2%e0%14%d8%35%4f%0a%5c%34%d3%f3%a5%98%f7%66%72%aa%43%e3%bd%a2%cd%62%fd%e9%1d%34%30%57%52%ab%41%b1%91%65%f2%30%7f%cf%c6%a1%8c%fb%dc%c4%8f%61%a5%13%40%1a%13%d1%09%c5%e0%f7%87%5f%48%e7%d7%b3%62%04%a7%c4%cb%fd%f4%ff%cf%3b%74%a8%1b%96%8e%09%73%3a%9b%a6%2f%ed%b7%99%d5%39%05%39%95%ab
&c=%af%13%76%70%82%a0%a6%58%cb%3e%23%38%c4%c6%db%8b%60%2c%bb%90%68%a0%2d%e9%47%aa%78%49%6e%0a%c0%c0%31%d3%fb%cb%82%25%92%0d%cf%61%67%64%e8%cd%7d%47%ba%0e%5d%1b%9c%1c%5c%cd%07%2d%f7%a8%2d%1d%bc%5e%2c%06%46%3a%0f%2d%4b%e9%20%1d%29%66%a4%e1%8b%7d%0c%f5%ef%97%b6%ee%48%dd%0e%09%aa%e5%4d%6a%5d%6d%75%77%72%cf%47%16%a2%06%72%71%c9%a1%8f%00%f6%9d%ee%54%27%71%be%c8%c3%8f%93%e3%52%73%73%53%a0%5f%69%ef%c3%3b%ea%ee%70%71%ae%2a%21%c8%44%d7%22%87%9f%be%79%ed%c4%61%a4%08%57%02%82%2a%ef%36%95%da%ee%13%bc%fb%7e%a3%59%45%ef%25%67%3c%e0%a7%69%2b%95%77%b8%cd%dc%4f%de%73%24%e8%ab%e6%74%d2%8c%68%06%80%0c%dd%74%ae%31%05%d1%15%7d%c4%5e%bc%0b%0f%21%23%a4%16%7c%17%12%d1%2b%b3%10%b7%37%60%68%d7%cb%35%5a%54%97%08%0d%54%78%49%d0%93%c3%33%fd%1f%0b%35%11%9d%96%1d%ba%64%e0%86%ad%6f%52%98%2d%84%12%77%bb%ab%e8%64%da%a3%65%55%5d%d5%76%55%57%46%6c%89%c9%df%b2%3c%85%97%1e%f6%38%66%c9%17%22%e7%ea%c9%f5%d2%e0%14%d8%35%4f%0a%5c%34%d3%73%a5%98%f7%66%72%aa%43%e3%bd%a2%cd%62%fd%69%1d%34%30%57%52%ab%41%b1%91%65%f2%30%7f%cf%c6%a1%8c%fb%dc%c4%8f%61%a5%93%40%1a%13%d1%09%c5%e0%f7%87%5f%48%e7%d7%b3%62%04%a7%c4%cb%fd%f4%ff%cf%3b%74%28%1c%96%8e%09%73%3a%9b%a6%2f%ed%b7%99%d5%b9%05%39%95%ab

三个返回相同的md5值,可以通过其有限计算的特性绕过特定的条件。

ea8b4156874b91a4ef00c5ca3e4a4a34
ea8b4156874b91a4ef00c5ca3e4a4a34
ea8b4156874b91a4ef00c5ca3e4a4a34

0x06 json解码绕过

php在处理传入的json串时使用json_decode将其解码,再进行比较时,我们不需要知道比较字串的内容,也可以利用字符串与0比较为真的特点绕过。

abc;
var_dump($b->abc == $flag);
if ($b->abc == $flag)
    echo $flag;
else
    echo "error!!";
?>

当传入?a={"abc":0}时,分别输出

0
bool(true) 
ook!

注意这里的{"abc":0},0是数字,而加双引号{"abc":"0"}之后两边都是字符,就不相等了。

0x07 array_search 绕过

原理都是类型转换的问题,函数的原型为:
mixed array_search ( mixed $needle , array $haystack [, bool $strict = false ] )
其中$needle,$haystack必需,$strict可选 函数判断$haystack中的值是存在$needle,存在则返回该值的键值(数组的下标,例如该值在第一位返回0,第二位返回1),第三个参数默认为false,如果设置为true则会进行严格过滤(带类型的比较)。


其结果为:

int(0) 
int(1)
int(2)
bool(false) 

0x08 小结

从上面我们可以看出,所有绕过的形式都是基于弱类型的比较,或值对于不合规参数类型的错误处理,数组与字符串、字符串与整数等等情形,我们不能保证每个用户都乖乖输入我们想要的值,因此在php中限定用户输入的类型和值就显得尤为重要。

这里感谢 Mrsm1th 师傅的分享,自己动手接受知识会更快。

你可能感兴趣的:(CTF_Web:php弱类型绕过与md5碰撞)