CTF:PHP MD5函数0E绕过漏洞

  • Post author:
  • Post category:php


CTF:PHP MD5函数0E绕过漏洞

作者:高玉涵

博客:blog.csdn.net/cg_i

时间:2021.6.1 8:43


背景



昨天参加了一场CTF线上赛,面对行业内的安全强队,比赛成绩相差巨大。通过这次比赛,找到了差距,找到了不足,更增长了知识。子曰:“学而不思则罔,思而不学则殆。”计划将经后每次比赛,解题过程中的困惑、思路、整理后分享出来,以达起到巩固知识,也便于帮助有需要的人。因个人能力所限,文中难免会有错误,不妥之处还请批评指正。


赛题源码

本职工作极少接触CTF相关知识,初看此题直接是懵的。代码清晰而简单这里不表,唯一让我困惑的是if($c == md5($c))这一条语句,分析可知当$c==md5($c) 即可拿到Flag。

心中诧异:

这怎么可能!加密前后的值要相等?逻辑上不通啊!难道要用到md5撞库?这种概率也太小了,假设真的存在这种可能,即使不考虑其巨大的计算量,稍微对加密原理有些常识的人就应知道,世上根本不会存在“加密前后的值要相等”(这还算得上加密码?)我走进了知识盲区,走进了思维的死胡同。

在长时间的懵圈后,我逐渐冷静下来并断定,主办方不可能出道需耗时100年(我电脑的计算力)才能得出的答案的题。直觉告诉我突破口应是md5()这个函数,它可能存在我不知道的漏洞,确定方向后接下来就是对它发起进攻。


MD5


算法

首先还是说一下什么是MD5算法,MD5全名消息摘要算法(Message-Digest Algorithm 5),是一种密码散列函数,可以产生一个128位(16字节)的哈希值(hash value),用于确保信息传输的完整一致性,它的基础原理就是将数据预算变为另一固定长度的值。


MD5


的特点


长度一致性

:任意长度的数据,计算出来的哈希值长度都是固定的128位。


不对称性:

从原数据计算哈希值十分容易,但是知道哈希值去碰撞原数据十分困难。


MD5


算法的基本原理

这里采用网上一个大佬绘制的图。


MD5


算法的安全问题

其实不仅是MD5,任何一个hash函数,都有被碰撞的可能,所谓碰撞,就是输入不同的值Value和Value得到相同的hash值,这其实不难证明,MD5生成的hash值是由128位组成的,而它必然是一个有限集合,而我们的输入数据是一个无限集,一个无限集映射到有限集上,必然存在两个或多个无限集中的元素映射到同一有限集元素的情况。


PHP  MD5


中的安全问题




相等操作符:

用来比较两个值,测试其相等性。

PHP中有两个相等操作符“==”和“===”。$a == $b,如果类型转换后$a和$b相等,则输出true。$a === $b,如果$a和$b相等,并且类型也相同,则输出true。

PHP是弱类型语言,所以有时会根据引用变量时所处的环境,将变量自动转换为最适合的类型。下面给出例子:

$total = “45 fire engines”; 
$incoming = 10;        
$total = $incoming + $total; // $total = 55

因为最前面的$total字符串以整数值开头,所以计算中就使用了这个值。如果数学计算中用到包含e或E(表示科学计数法)的字符串,这个字符串将作为浮点数进行计算。

有了上述知识我们就可以通过构造特别参数,将原本不相等的if判断相等。

原理:

在进行“==”判断的时候,会先将字符串类型转化成相同再比较。转换的规则为,若该字符串以合法的数值开始,则使用该值,否则其值为0。因此,根据这一点,可以遍历出一个字符串,其MD5加密前后都是’0e’开头且后面纯数字,这样就能保证值是相等。


Python


写的暴库代码(注:2020.6.4修改,原我写的多进程代码存在BUG,这里引用了网上的一段代码)

import hashlib

def md5_enc(s):
    m = hashlib.md5()
    m.update(str(s).encode('utf-8'))
    return m.hexdigest()

if __name__ == '__main__':
    result = []
    for i in range(0, 9999999999):
        i = '0e' + str(i)
        enc = md5_enc(i)
        print(i+" md5 is "+enc)
        # md5值前两位为0e
        if enc[:2] == "0e":
            # md5值0e后为纯数字
            if enc[2:].isdigit():
                result.append(i)
                print("Got Result:"+i)
                break

跑了40分钟得到一个值:0e215962017

MD5 == 0e291242476940776845150308577824

构造URL:http://1.1.1.1/2.php?a=1&b=0&c=0e215962017,成功取得FLAG。如下图。


CTF


意义所在

CTF题都是由业内专家命题,往往凝聚着他们多年积累出来的技能,是信息安全基本概念、攻防技术、技巧浓缩和提炼。能够给不能层次的人在技术上带来提高。除此之外,高质量得CTF题都没法直接使用现成工具解出,一般需要在理解基本原理的基础上,自己编写代码来求解,这个过程会加深和巩固计算机基础知识,通过CTF大赛和国内外强队比拼,增长了知识,开阔了视野,提升了能力。



版权声明:本文为cg_i原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。