Security:哈希长度扩展攻击

典型的hash算法,hash = md5((secret + data)),在服务器会校验hash的值。在不知道secret的情况下,如果知道secret的长度,可以算出一个吻合的hash值。举例如下:

  • 服务器的secret = "secret", 加密算法为md5((secret + data))
  • 服务器算好后,把data和hash值一起给客户端
  • 服务器接收到请求后,通过再次计算比对,如果匹配证明是合法的请求

比如data = "data",正常情况下,可以算出一对值:

secret = "akSK06mn91c2MxARSrOBTqdmhVCMkkoZ"
data = "riguz"
token = secret + data = "akSK06mn91c2MxARSrOBTqdmhVCMkkoZriguz";
md5 = md5(token) = "38a67feac3cf91cf3e68467ae803a21b"

现在,利用hash_extender可以计算出一对值:

./hash_extender --data riguz --secret 32 --append helloworld --signature 38a67feac3cf91cf3e68467ae803a21b --out-data-format html --table
md4       dd0c44d807b1c3ca0365b1e656fd1d39 riguz%80%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%28%01%00%00%00%00%00%00helloworld
md5       1800bc243a00db801833b6e48c1b74ef riguz%80%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%28%01%00%00%00%00%00%00helloworld

其中%80%00这种是URL编码后的字符串,即0x80,。假设服务端收到这个字符串,会进行匹配,我们用java代码模拟一下:

String test = "akSK06mn91c2MxARSrOBTqdmhVCMkkoZriguz%80%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%28%01%00%00%00%00%00%00helloworld";
        try {
            String t = URLDecoder.decode(test, "ISO-8859-1");
            String hex = Hex.hexViewer(t.getBytes("ISO-8859-1"));
            System.out.println(hex);
            String md5 = Hashs.encrypt("MD5", t.getBytes("ISO-8859-1"));
            System.out.println("MD5:" + md5);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

输出为:

Address /  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f Dump
00000000| 61 6b 53 4b 30 36 6d 6e 39 31 63 32 4d 78 41 52 akSK06mn91c2MxAR
00000010| 53 72 4f 42 54 71 64 6d 68 56 43 4d 6b 6b 6f 5a SrOBTqdmhVCMkkoZ
00000020| 72 69 67 75 7a 80 00 00 00 00 00 00 00 00 00 00 riguz
00000030| 00 00 00 00 00 00 00 00 28 01 00 00 00 00 00 00 
00000040| 68 65 6c 6c 6f 77 6f 72 6c 64  _  _  _  _  _  _ helloworld

MD5:1800bc243a00db801833b6e48c1b74ef

可以看出算出的md5值与hash_extender生成的md5值是匹配的,如果服务器做比对的话,就会认为这个值是合理的。 Refer: