Tag:md5()

Tag (md5())'s result:

详细分析md5{d_base64}解密方式

0x00 概述 最近测试某系统遇到一种加密方式,形似gsiSbcE5GNnTqndI2Hy4tA==,经查阅资料得知是md5{d_base64}加密,此文将详细介绍其解密方式。   0x01 手动解密 看到最后的==,第一反应就是base64,所以先放到base64解密的网站解密看看,结果如下图…… 乱码,后面查阅资料得知这里要用二进制方式打开。 现在开始手动解密: 先看看base64编码表 00        A        16        Q        32        g        48        w 01        B        17        R        33        h        49        x 02        C        18        S        34        i        50        y 03        D        19        T        35        j        51        z 04        E        20        U        36        k        52        0 05        F        21        V        37        l        53        1 06        G        22        W        38        m        54        2 07        H        23        X        39        n        55        3 08        I        24        Y        40        o        56        4 09        J        25        Z        41        p        57        5 10        K        26        a        42        q        58        6 11        L        27        b        43        r        59        7 12        M        28        c        44        s        60        8 13        N        29        d        45        t        61        9 14        O        30        e        46        u        62        + 15        P        31        f        47        v        63        /   将gsiSbcE5GNnTqndI2Hy4tA==去掉最后的==,再对照表一一对应解密,得 32 44 34 18 27 28 04 57 06 13 39 19 42 39 29 37 54 07 50 56 45 00 再将上面的数字转二进制 0b是二进制,要补齐6位,如18-010010,04-000100,再去掉开头的0b。 接着拼接成8位,如32-100000,44-101100就拼接成10000010 接着转成hex,这里利用python先二转十,再十转十六 得82,其余同理,结果拼接一起得 82C8926DC13918D9D3AA7748D87CB8B4 明显的32位md5,直接解密即可得明文。 总结下解密流程: 去掉==—>对照编码表解出数字—>数字转二进制—>补6拼8—>转hex—>得32位md5—>解密得明文 其实在线解码只要勾选16进制显示即可 加密过程: 由解密过程逆向推理: 32位md5—>两个字符1组共16组hex—>转十进制—>转二进制—>补8拼6—>对照编码表得字符—>连接得密文   0x02 工具解密 手动解密费时费力,可以直接用工具解密,这里介绍几个工具。 1. http://www.fourmilab.ch/webtools/base64/ 新建base.b64,写入密文,再输入命令 base64 –decode base64.b64 base64.tmp 再用winhex打开base64.tmp即可获得32位md5(直接文本打开会乱码,所以要以二进制打开)   2. PasswordsPro.v2.5.4.0 这个软件貌似是直接解32位md5,所以关键看字典。   3.cmd5可以直接解密,也是看字典。   4. 脚本解密: https://github.com/theLSA/md5Base64Cracker #coding:utf-8 #Author:LSA #Description:Crack md5{d_base64} encryption #Data:20180306 #Version:v1.0 import md5 import optparse base64Table = {‘+’: 62, ‘/’: 63, ‘1’: 53, ‘0’: 52, ‘3’: 55, ‘2’: 54, ‘5’: 57, ‘4’: 56, ‘7’: 59, ‘6’: 58, ‘9’: 61, ‘8’: 60, ‘A’: 0, ‘C’: 2, ‘B’: 1, ‘E’: 4, ‘D’: 3, ‘G’: 6, ‘F’: 5, ‘I’: 8, ‘H’: 7, ‘K’: 10, ‘J’: 9, ‘M’: 12, ‘L’: 11, ‘O’: 14, ‘N’: 13, ‘Q’: 16, ‘P’: 15, ‘S’: 18, ‘R’: 17, ‘U’: 20, ‘T’: 19, ‘W’: 22, ‘V’: 21, ‘Y’: 24, ‘X’: 23, ‘Z’: 25, ‘a’: 26, ‘c’: 28, ‘b’: 27, ‘e’: 30, ‘d’: 29, ‘g’: 32, ‘f’: 31, ‘i’: 34, ‘h’: 33, ‘k’: 36, ‘j’: 35, ‘m’:……

MD5长度扩展攻击总结

0x00: MD5算法原理: 填充+压缩 先进行消息长度的填充(padding)。填充完后,初始化的4个Magic number会和第一个64字节的Message block进行md5 compress压缩算法。压缩算法完成后,会产生新的4个Magic number。这样再进行第二个64字节Message block的md5 compress压缩算法。以此类推……直到压缩到最后64个字节的(Message block + padding),最后得到的Magic number经过hex转化就是最后的md5 hash值 ************************** 术语解释: 填充: 如果输入信息的长度(字节)对64求余的结果不等于56,就需要填充使得对64求余的结果等于56。填充的方法是填充一个\x80和n个0。填充完后,信息的长度为N*64+56(字节),并且最后8个字节用来记录原始输入信息长度 Magic number: 代码中的0x67452301L, 0xefcdab89L, 0x98badcfeL, 0x10325476L这4个初始化的number(固定的)就被称为Magic number或者是md5 iv(md5 向量) ***************************** 0x01: md5长度扩展攻击: 影响的算法:使用了Merkle–Damgård construction进行数据的压缩的算法,流行算法比如MD5、SHA-1等。 当已知以下二点 md5(salt+message)的值 salt+message长度 我们可以在不知道salt的具体内容的情况下,计算出任意的md5(salt+message+padding+append)值, (注:padding是 salt+message/secret 最后的填充字节, append是任意扩展字符(串)。) 因为在进行md5(salt+message+padding+append)的时候,在对append进行padding之前的Message block,和md5(salt+message)产成的Message block一样 所以,我们就能在不知道salt的情况下,只需根据md5(salt+message)的结果,逆向出最后一次的4个Magic number。 逆向算法很简单: def compute_magic_number(self, md5str): self.A = struct.unpack(“I”, md5str[0:8].decode(‘hex’))[0] self.B = struct.unpack(“I”, md5str[8:16].decode(‘hex’))[0] self.C = struct.unpack(“I”, md5str[16:24].decode(‘hex’))[0] self.D = struct.unpack(“I”, md5str[24:32].decode(‘hex’))[0] ############################################## //此例来源于:http://www.joychou.org/index.php/web/hash-length-extension-attack.html?utm_source=tuicool&utm_medium=referral 拿admin举例,md5经过padding后,由于只有64字节,所以只进行一轮md5 compress。压缩算法完成后,产生的新的Magic number为 A=0x292f2321LB=0xa7a5577aLC=0xe4a8943LD=0xc31f804aL md5的加密结果是21232f297a57a5a743894a0e4a801fc3,我们将A大小端逆序一下,变成21232F29,刚好是md5的前8位。以此类推 ############################################## 根据这4个Magci number,再和扩展的字符串append(此时的append要进行填充,填充的长度是len(salt+message+padding+append))进行md5 compress,最后的结果即md5(salt+message+padding+append),append表示要扩展的字符串,padding表示对salt+message长度进行padding后的结果。 就是说: 关键bug(感觉不算bug,只是这类hash算法的特性而已)就在于知道md5(salt+message)的值后可以很容易逆向出最后一次的4个Magic number。 知道了这4个magic number和salt+message的长度后,我们就可以构造padding(salt+message),这样md5(salt+message+padding(salt+message))后得出就是这4个magic number(刚好是64字节),之后md5算法再padding(append),就可以在不知道salt的情况下得到md5(salt+message+padding(salt+message)+append)。 ########################################## //此例来源于www.joychou.org/index.php/web/hash-length-extension-attack.html?utm_source=tuicool&utm_medium=referral 举个实例: 已知salt的长度为4,message为admin,md5(salt+message)的值为c7813629f22b6a7d28a08041db3e80a9,想扩展的字符串append为joychou,计算md5(salt+message+padding+append)的值,padding表示对salt+message长度进行填充后的结果 c7813629f22b6a7d28a08041db3e80a9逆向出magic number为: A=0x292f2321L B=0xa7a5577aL C=0xe4a8943L D=0xc31f804aL 先对append进行padding,padding结果用padding(append) 800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003802000000000000 长度57个字节,注意最后8个字节0x238为len(salt+message+padding+append),即568bit,71字节 再用这4个magic number对append产生的Message block进行md5 compress,最后结果为06cf5a94dcda53659f58c0f411ba0bd8 ########################################################### 0x02: CTF实例cn有签名限制的读取任意文件writeup 大概代码逻辑: if url有filepath参数且不空并且有sign参数且不空,则myreadfile($_GET[‘filepath’],$mysalt,$_GET[‘sign’]);传递文件路径,salt和签名。在myreadfile函数,执行$res=checksign($filepath,$mysalt,$sign);函数到checksign($message,$mysalt,$sign)函数里校验签名,true就getfile(),false就echo ‘sign error!’; else 打印出mysalt的长度(int(32)),并打印出md5($mysalt.$message);的值(f3d366138601b5afefbd4fc15731692e),这里的message即文件路径。 所以要getflag就要能执行getfile(),要执行getfile()就要签名校验通过,要签名校验通过就要$sign==md5($mysalt,$message)。$message是文件路径由我们输入,$sign签名也由我们输入,所以如果知道$mysalt即SALT的值,就可以getfile()了,不过这里就是不知道SALT的值,那如何绕过呢,自然联想到md5 长度扩展攻击了…… 思路: 尝试读取已知的/etc/hosts lab1.xseclab.com/decrypt1_53a52adb49c55c8daa5c8ee0ff59befe/md5_le.php?filepath=/etc/hosts&sign=f3d366138601b5afefbd4fc15731692e 得 ## # Host Database # # localhost is used to configure the loopback interface # when the system is booting. Do not change this entry. ## 127.0.0.1 localhost 255.255.255.255 broadcasthost ::1 localhost 尝试读取/etc/passwd 1.已知mysalt长度32,那么mysalt+/etc/hosts=4+10=14 2.已知md5(mysalt+/etc/hosts)=f3d366138601b5afefbd4fc15731692e 满足md5长度扩展攻击的二个条件。 直接用工具吧。(相关工具见文末) Payload:lab1.xseclab.com/decrypt1_53a52adb49c55c8daa5c8ee0ff59befe/md5_le.php?filepath=%2fetc%2fhosts%80%00%00%00%00%00%00%00%00%00%00%00%00X%01%00%00%00%00%00%00%2Fetc%2Fpasswd&sign=8dcc79bf6581da3e30313a5a686261dd 显示sign error 尝试读取/etc/shadow 还是sign error 真神奇……不是说读取任意系统文件可以getflag吗?签名也是工具生成,不会错。 尝试读取/etc/hosts Payload:lab1.xseclab.com/decrypt1_53a52adb49c55c8daa5c8ee0ff59befe/md5_le.php?filepath=%2fetc%2fhosts%80%00%00%00%00%00%00%00%00%00%00%00%00%00P%01%00%00%00%00%00%00%2Fetc%2Fhosts&sign=75221e2e5cd1cd1c7694cbd386571ffe 显示Flag is: Md5LenghtExtAttackNowYouSee 这都可以,不是说除已经告知的/etc/hosts文件外,若能读取到任意系统文件即可获取Flag吗?又神奇了…… 还有看源码filepath是文件路径,最后getfile(),但是%2fetc%2fhosts%80%00%00%00%00%00%00%00%00%00%00%00%00%00P%01%00%00%00%00%00%00%2Fetc%2Fhosts这一长串是怎么识别为/etc/hosts的,又神奇了…….   0x03: 防御hash length extender attack (1)使用HMAC-SHA1之类的HMAC算法 (2)针对Flickr API等将参数签名的应用来说,secret放置在 参数末尾也能防止这种攻击。如将md5($salt.$role)替换成md5($role.$salt)   0x04: 相关工具 https://github.com/JoyChou93/md5-extension-attack https://github.com/iagox86/hash_extender https://github.com/bwall/HashPump   0x05: 参考链接 blog.chinaunix.net/uid-27070210-id-3255947.html www.joychou.org/index.php/web/hash-length-extension-attack.html?utm_source=tuicool&utm_medium=referral blog.csdn.net/u011500307/article/details/24095891                            

php+mysql实现超原始的注册登录

涉及主要知识点: 1.php操作mysql 2.加密函数md5() 3.php用?页面间传递参数 4.$_GET[]和$_POST[] 平台:redhat6+php5.3+mysql14.14+ Apache/2.2.15 (经典LAMP) 注册页面(regtest.php): <!DOCTYPE html PUBLIC “-//W3C//DTD HTML 4.01 Transitional//EN” “http://www.w3.org/TR/html4/loose.dtd”> <html> <head> <meta http-equiv=”Content-Type” content=”text/html; charset=gb2312″> <title>welcome to regtest.php</title> </head> <body> <h1>reg</h1> <form method=”post” action=”reg_check.php”> username<input type=”text” name=”username” > password:<input type=”password” name=”password”> password again:<input type=”password” name=”pwd_again”> <input type=”submit” value=”submit”> <input type=”reset” value=”clean”> </form> </body> </html> 注册验证页面(reg_check.php): 用于验证注册和写入数据库 <?php $db = mysql_connect(“127.0.0.1″,”root”,”root”) or die(“Fail to connect db”); mysql_select_db(“userdb”,$db) or die (“can’t connect to userdb”.mysql_error()); $username=$_POST[‘username’]; $password=$_POST[‘password’]; $pwd_again=$_POST[‘pwd_again’]; if($username==””||$password==””) { echo”error:username or password empty”; } else { if($password!=$pwd_again) { echo”password is different!”; echo”<a href=’regtest.php’>input again</a>”; } else { $md5pass=md5($password); $sql=”insert into user(username,password) values(‘$username’,’$md5pass’)”; $result=mysql_query($sql); if(!$result) { echo”Fail reg!”.mysql_error(); echo”<a href=’regtest.php’>返回</a>”; } else { echo”Success reg!”; } } } ?> 看下数据库: 登录页面(logintest.php): <!DOCTYPE html PUBLIC “-//W3C//DTD HTML 4.01 Transitional//EN” “http://www.w3.org/TR/html4/loose.dtd”> <html> <head> <meta http-equiv=”Content-Type” content=”text/html; charset=gb2312″> <title>welcome to login</title> </head> <body> <form method=”post” action=”login_check.php”> username:<input type=”text” name=”username” > password:<input type=”password” name=”password”> <input type=”submit” value=”login”> <input type=”reset” value=”clean”> <a href=”regtest.php” >reg</a> </form> </body> </html> 登陆验证页面(login_check.php) <?php $username=$_POST[‘username’]; $password=$_POST[‘password’]; $db = mysql_connect(“127.0.0.1″,”root”,”root”) or die(“Fail to connect db!”); mysql_select_db(“userdb”,$db)……