简单攻击think_decrypt算法,MDAwMDAwMDAwM

2018/04/05 20:49 于 技术

微信 微博 豆瓣 人人

看到网站参数MDAwMDAwMDAwM开头的一串东西,刷了几个页面看到网站是thinkphp写的,翻了一下这个是think_encrypt加密出来的,带key。
但是这个加密算法不是一个散列的算法,里面用了md5仅仅是对key做了一次加密,后续没有用到。

那么在不知道秘钥的情况下可以很方便地对该算法进行攻击,暴力(因为算法的各种弱鸡,这个词有点严重了)拆解出key的md5值,毕竟算法中真正的key其实是这个md5值,知道这个md5值之后,就可以很方便地进行加密数据伪造。

以下步骤和数据仅供学习参考扩展,“单凭理论无法解决现实事情,需要理论与现实结合,才能更简单更快速地解决”

找出几个加密字符串,并确定这个是数字加密后的内容。

$exapmleencodea = [
    'MDAwMDAwMDAwMLR2uaE',
    'MDAwMDAwMDAwMLR2vaE',
    'MDAwMDAwMDAwMLR2x6E',
    'MDAwMDAwMDAwMLR2y6E',
    'MDAwMDAwMDAwMLOspZmIubtp',
    'MDAwMDAwMDAwMLOcpdyGz7tq',
    'MDAwMDAwMDAwMLOGx92G38mwhNtyoQ',
    'MDAwMDAwMDAwMLOcpdyGz7tq',
    'MDAwMDAwMDAwMLOGud2Gz9GxhriCmLHcdZ4',
    'MDAwMDAwMDAwMLSctaE',
    'MDAwMDAwMDAwMLScpaE',
    'MDAwMDAwMDAwMLSGsaE',
];

对于base64不再进行解读,根据理论,对数字字符串加密后的base64进行统计(也就两行代码,不贴,我用的md写的文字),每一位的字符有一部分限制,所以收紧了暴力的范围
一千万以内的数字有以下规则

0=>['M','N','O'],//第一位,只可能是这三个字符
1=>['Q','g','w','A','T','j','z','D'],
2=>['=','A','E','I','M','Q','U','Y','c','g','k'],
3=>['=','w','x','y','z','0','1','2','3','4','5'],
4=>['M','N','O'],
5=>['A','Q','g','w','D','T','j','z'],
6=>['=','A','E','I','M','Q','U','Y','c','g','k'],
7=>['=','w','x','y','z','0','1','2','3','4','5'],
8=>['M','N','O'],
9=>['A','Q','g','w'],
10=>['='],
11=>['='],

真正的key是md5之后的内容,每一位只可能是:16个字符,又收紧95%的暴力范围

$keychara = ['0','1','2','3','4','5','6','7','8','9','0','a','b','c','d','e','f'];

然后把解密代码进行改造对key的每一位进行排除拆解

    for ($i = 0; $i < $data_len; $i++) {
        $data_charint = ord(substr($data, $i, 1));
        //$key_charint = ord(substr($eqlen_keystring, $i, 1));
        foreach ($keychara as $kc) {
            $key_charint = ord($kc);
            if ($data_charint<$key_charint) {
                $thisposchar = chr(($data_charint + 256) - $key_charint);
            }else{
                $thisposchar = chr($data_charint - $key_charint);
            }
            if(in_array($thisposchar, $numcode[$i]))
            {
                $maybe[$i][] = $kc;//符合规矩 
            }
        }
    }

得出key的每一位有以下可能:

0=>['e','f'],
1=>['2','5'],
2=>['d'],
3=>['d'],

把可能性带入进行正式解密再排除

$maybekey = ['e2dd','e5dd','f2dd','f5dd'];
foreach ($maybekey as $key) {
    echo "\r\n\r\n$key :\r\n";
    foreach ($exapmleencodea as $encode) {
        $data   = str_replace(array('-','_'),array('+','/'),$encode);
        $mod4   = strlen($data) % 4;
        if ($mod4) {
           $data .= substr('====', $mod4);
        }
        $data   = base64_decode($data);
        $data   = substr($data,10);

        $x      = 0;
        $data_len    = strlen($data); 
        $eqlen_keystring   = $str = '';
        $eqlen_keystring = $key;
        $maybe = [];
        for ($i = 0; $i < $data_len; $i++) {
            $data_charint = ord(substr($data, $i, 1));
            $key_charint = ord(substr($eqlen_keystring, $i, 1)); 
                if ($data_charint<$key_charint) {
                    $thisposchar = chr(($data_charint + 256) - $key_charint);
                }else{
                    $thisposchar = chr($data_charint - $key_charint);
                } 
            $str .= $thisposchar;
            //echo $str."\r\n\r\n";
        }
        echo base64_decode($str)."\r\n";
    }
}

根据最后每一种可能的key decode出来的明文样子,得出前四位是f2dd,足够我自己用来数据伪造了

没精力写那么详细,要是有兴趣,对着think_decrypt一步一步看看,然后看我的思路即可。

MDAwMDAwMDAwMthinkphp