简单攻击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

支付宝,openssl_sign(): supplied key param cannot be coerced into a private key

2018/01/27 08:46 于 技术

微信 微博 豆瓣 人人

这篇文章前提排除了openssl自身的问题(好多年没有写东西,应该咋说?)

新版本的支付宝API不再用老的MD5进行签名,出现这个问题后
检查配置文件中的私钥是否是一行乱码(不带-----BEGIN RSA PRIVATE KEY-----和-----END RSA PRIVATE KEY-----)
如果没问题,那就注意一下,可能是下面这个情况:
你用他自己的生成工具生成的公钥和私钥,是否用的PHP但是选成了Java用的用一种padding对私钥进行了填充的选项(那个PKCS8Java用,非PKCS1Java用)

为什么会出现这个脑残的原因,也不会有人往这上面考虑的原因在哪:

选择PKCS8处理后的私钥,在windows上和openssl1.0.0版本上面是可以通过openssl_sign()的,没有问题可以签名成功。
但是在低版本的openssl上要出现openssl_sign(): supplied key param cannot be coerced into a private key

所以,
生成一对正确的秘钥就可以了。
也可以用你服务器上的openssl生成然后填充。

支付宝新API官方的SDK太臃肿了,又不是阿里云那种一堆服务,再说连阿里云的SDK也不只带runtime啊................,如果仅仅用一两个功能的话,最好自己简化一下。

微信带参数二维码上面的坑

2017/06/16 00:41 于 技术

微信 微博 豆瓣 人人

临时的可以用数字,永久的也可以用数字
扫描的时候服务端通过scene_id分辨不出来是临时还是永久的二维码,只能从ticket上(一个长度近100的字符串,检索效率肯定不行)

如果永久和临时同时使用,永久的参数就不要用存数字了...
如果业务量小,预计不会使用到临时的(永久的限量100000),忽略以上建议

js小数的精度问题

2017/06/05 21:17 于 技术

一般在换算的时候出现问题
比如

console.log(2+(-2.06))

function fixnum(_v)
{
if (isNaN(_v) || _v=="" || _v==0) {
return 0.00;
}
_v = parseFloat(_v);
//js小数失精度
_v = parseFloat(_v.toFixed(2) );
return _v;
}

在计算的时候也不要
r+=fixnum(_v);
使用
r=fixnum(r+fixnum(_v));

G17使用效果

2017/05/15 17:54 于 活着

有效果,明显减少细微抖动感。
不过宝马的加油口比较细,用起来很麻烦,用完一箱就不用了。

我现在做法是每两三万公里做一次四轮定位,连续用机箱宝马自己的添加剂。零下温度也不会有抖动。

12