MD5绕过

Posted H3rmesk1t

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MD5绕过相关的知识,希望对你有一定的参考价值。

MD5弱类型比较

<?php
highlight_file(__FILE__);
error_reporting(0);
$flag = "flag{H3rmesk1t_is_a_loser}";
$val1 = $_GET['val1'];
$val2 = $_GET['val2'];
if (isset($_GET['val1']) and isset($_GET['val2']))
{
	if ($_GET['val1'] != $_GET['val2'])
	{
		if ((md5($_GET['val1']) == md5($_GET['val2'])))
			echo $flag;
		else
			echo "you can't get flag";
	}
}
?>
<?php
highlight_file(__FILE__);
error_reporting(0);
$flag = "flag{H3rmesk1t_is_a_loser}";
$val1 = $_GET['val1'];
$val2 = $_GET['val2'];
if (isset($_GET['val1']) and isset($_GET['val2']))
{
	if ($_GET['val1'] != $_GET['val2'])
	{
		if ((md5($_GET['val1']) == md5($_GET['val2'])) and (md5(md5($_GET['val2'])) == md5(md5($_GET['val1']))))
			echo $flag;
		else
			echo "you can't get flag";
	}
}
?>

方法一:数组绕过

由于md5不能加密数组,在加密数组的时候会返回NULL,所以我们可以传入两个数组
数组绕过适用于源码中没有判断变量类型或内容,如果加上了过滤函数就不能使用了

常见过滤函数如下:

ctype_alnum ( string $text ) : bool
// 如果text中所有的字符全部是字母和(或者)数字,返回 TRUE 否则返回FALSE 

is_numeric ( mixed $var ) : bool
// 如果 var 是数字和数字字符串则返回 TRUE,否则返回 FALSE

在这里插入图片描述
在这里插入图片描述

方法二:科学计数法绕过

可以传入两个md5加密后是0e开头的字符串,需要注意的地方是,这个以0e开头的字符串只能是纯数字,这样php在进行科学计算法的时候才会将它转化为0;可以查找以0e开头md5加密相等的字符串,也可以自己编写代码,提供以下脚本

<?php
for($a=1;$a<=1000000000;$a++){
   $md5 = md5($a);
   if(preg_match('/^0e\\d+$/',$md5)){
      echo $a;
      echo "\\n";
      echo $md5;
      echo "\\n";
   }
}

常见的字符串

byGcY
0e591948146966052067035298880982

QNKCDZO
0e830400451993494058024219903391

s878926199a
0e545993274517709034328855841020

s155964671a
0e342768416822451524974117254469

s214587387a
0e848240448830537924465865611904

s214587387a
0e848240448830537924465865611904

s878926199a
0e545993274517709034328855841020

s1091221200a
0e940624217856561557816327384675

s1885207154a
0e509367213418206700842008763514

240610708
0e462097431906509019562988736854

314282422
0e990995504821699494520356953734

571579406
0e972379832854295224118025748221

903251147
0e174510503823932942361353209384

在这里插入图片描述
在这里插入图片描述

双MD5判断

对于有些题目,可能会经过两次MD5值的判断

MD5和双MD5以后的值都是0e开头的

CbDLytmyGm2xQyaLNhWn
770hQgrBOjrcqftrlaZk
7r4lGXCH2Ksu2JNT3BYM
脚本

# -*- coding: utf-8 -*-
import multiprocessing
import hashlib
import random
import string
import sys
CHARS = string.letters + string.digits
def cmp_md5(substr, stop_event, str_len,. start=0, size=20):
    global CHARS
    while not stop_event.is_set():
        rnds = ''.join(random.choice(CHARS) for _ in range(size))
        md5 = hashlib.md5(rnds)
        value = md5.hexdigest()
        if value[start: start+str_len] == substr:
            print rnds
            stop_event.set()
            '''
            #碰撞双md5
            md5 = hashlib.md5(value)
            if md5.hexdigest()[start: start+str_len] == substr:
                print rnds+ "=>" + value+"=>"+ md5.hexdigest()  + "\\n"
                stop_event.set()
            '''

if __name__ == '__main__':
    substr = sys.argv[1].strip()
    start_pos = int(sys.argv[2]) if len(sys.argv) > 1 else 0
    str_len = len(substr)
    cpus = multiprocessing.cpu_count()
    stop_event = multiprocessing.Event()
    processes = [multiprocessing.Process(target=cmp_md5, args=(substr,
                                         stop_event, str_len, start_pos))
                 for i in range(cpus)]
    for p in processes:
        p.start()
    for p in processes:
        p.join()

扩展构造

若有要求 md5 值的明文长度很小,其中只能出现一种字母,那么可以写脚本获取明文

$a = $_POST['a'];
$b = $_POST['b'];
$m = $_GET['m'];
$n = $_GET['n'];

if (!(ctype_alnum($a)) || (strlen($a) > 5)  || !(ctype_alnum($b)) || (strlen($b) > 6))
{
    echo "a OR b fail!";
    die();
}

if ((strlen($m) > 1) || (strlen($n) > 1))
{
    echo "m OR n fail";
    die();
}

$val8 = md5($a);
$val9 = strtr(md5($b), $m, $n);

echo PHP_EOL;
echo "<p>val8 : $val8</p>";
echo PHP_EOL;
echo "<p>val9 : $val9</p>";
echo PHP_EOL;
if (($val8 == $val9) && !($a === $b) && (strlen($b) === 5))
{
    echo "nice,good job,give you flag:";
    echo file_get_contents('/var/www/html/flag.php');
}

代码的意思就是需要一个长度小于等于 5 的字符串的 md5 值是科学计数法样式
还需要一个长度等于 5 的字符串的 md5 值在替换一个字符后能变成科学计数法样式的 md5,这也是我们要求的

import hashlib
import string

str_list = list(string.letters + string.digits)

for i in range(0, len(str_list)):
    for j in range(0, len(str_list)):
        for k in range(0, len(str_list)):
            for l in range(0, len(str_list)):
                for m in range(0, len(str_list)):
                    tmp = str_list[i] + str_list[j] + str_list[k] + str_list[l] + str_list[m]
                    str_hash = hashlib.md5(tmp).hexdigest()
                    check = str_hash[0:2]
                    str_hash = str_hash[2:32]
                    a = str_hash.replace('a', '1')
                    b = str_hash.replace('b', '1')
                    c = str_hash.replace('c', '1')
                    d = str_hash.replace('d', '1')
                    e = str_hash.replace('e', '1')
                    f = str_hash.replace('f', '1')
                    g = str_hash.replace('g', '1')
                    h = str_hash.replace('h', '1')
                    i1 = str_hash.replace('i', '1')
                    j1 = str_hash.replace('j', '1')
                    k1 = str_hash.replace('k', '1')
                    l1 = str_hash.replace('l', '1')
                    m1 = str_hash.replace('m', '1')
                    n = str_hash.replace('n', '1')
                    o = str_hash.replace('o', '1')
                    p = str_hash.replace('p', '1')
                    q = str_hash.replace('q', '1')
                    r = str_hash.replace('r', '1')
                    s = str_hash.replace('s', '1')
                    t = str_hash.replace('t', '1')
                    u = str_hash.replace('u', '1')
                    v = str_hash.replace('v', '1')
                    w = str_hash.replace('w', '1')
                    x = str_hash.replace('x', '1')
                    y = str_hash.replace('y', '1')
                    z = str_hash.replace('z', '1')
                    if check == '0e' and (
                            a.isdigit() or b.isdigit() or c.isdigit() or d.isdigit() or e.isdigit() or f.isdigit() or g.isdigit() or h.isdigit() or i1.isdigit() or j1.isdigit() or k1.isdigit() or l1.isdigit() or m1.isdigit() or n.isdigit() or o.isdigit() or p.isdigit() or q.isdigit() or r.isdigit() or s.isdigit() or t.isdigit() or u.isdigit() or v.isdigit() or w.isdigit() or x.isdigit() or y.isdigit() or z.isdigit()):
                        print tmp
                        print str_hash

MD5强类型比较

<?php
highlight_file(__FILE__);
error_reporting(0);
$flag = "flag{H3rmesk1t_is_a_loser}";
$val1 = $_GET['val1'];
$val2 = $_GET['val2'];
if (isset($_GET['val1']) and isset($_GET['val2']))
{
	if ($_GET['val1'] != $_GET['val2'])
	{
		if ((md5($_GET['val1']) === md5($_GET['val2'])))
			echo $flag;
		else
			echo "you can't get flag";
	}
}
?>

方法一:数组绕过

因为是强类型比较,用0e开头的字符串是没办法绕过的了,但是PHP自身的特性使得可以提交一个数组
而md5函数传入数组的返回值都是NULL,这样就可以绕过强类型比较了

在这里插入图片描述

方法二:使用md5加密后两个完全相等的两个字符串绕过

利用fastcoll_v1.0.0.5.exe来生成符合条件的字符串
构造:
(1)创建一个文本文件,写入任意的文件内容,命名为ywj.txt (源文件)
(2)运行fastcoll输出以下参数:-p 是源文件,-o是输出文件
执行命令:fastcoll_v1.0.0.5.exe -p ywj.txt -o 1.txt 2.txt
对产生的1.txt和2.txt文件进行测试

<?php 
function  readmyfile($path){
    $fh = fopen($path, "rb");
    $data = fread($fh, filesize($path));
    fclose($fh);
    return $data;
}
echo '二进制md5加密 '. md5( (readmyfile("D:\\\\ctf工具\\\\fastcoll_v1.0.0.5.exe\\\\1.txt")))."\\n";
echo  'url编码 '. urlencode(readmyfile("D:\\\\ctf工具\\\\fastcoll_v1.0.0.5.exe\\\\1.txt"))."\\n";
echo '二进制md5加密 '.md5( (readmyfile("D:\\\\ctf工具\\\\fastcoll_v1.0.0.5.exe\\\\2.txt")))."\\n";
echo  'url编码 '.  urlencode(readmyfile("D:\\\\ctf工具\\\\fastcoll_v1.0.0.5.exe\\\\2.txt"))."\\n";
二进制md5加密 ecd33e3e09ff2a58e1d9ed7189dc186b
url编码 abc%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%D6%16y%AC%CE%C5%A1LrY5fn%94%10%D9%01%C3%AC%F8%AAN%21%D0%27%BE%3Ej%A7%以上是关于MD5绕过的主要内容,如果未能解决你的问题,请参考以下文章

如何绕过MD5验证进入后台?

MD5绕过

php md5弱比较绕过

php md5弱比较绕过

MD5注入与MD5比较绕过

刷里程碑 怎样绕过MD5验证