Talking about md5 weak type comparison and strong collision

Preface

In CTF, the topic of md5 is too common. Although there are many articles in this area, they are relatively scattered. Here we mainly focus on the problems of weak type and strong collision of md5 encountered during my study and competition from shallow to deep. Sort it out.

This article involves practical exercises on knowledge points: a brief discussion on md5 weak type comparison and strong collision related experiments: Weekly CTF (This course aims to provide some CTF topics to friends who are interested in CTF, so that everyone can learn relevant knowledge through these topics. )

basic knowledge

There are two comparison symbols in php == and ===== When comparing, if you compare a number and a string or compare a string involving digital content, the string will be converted to a number and the comparison will follow Numerically.

=== When comparing, it will first judge whether the types of the two strings are equal, and then compare.

Compare

Strings that start with 0e and are numbers, and weak type comparisons are all equal to 0.

String of numbers

== compare

Test code

 <?php
if (isset($_POST['a']) and isset($_POST['b']))
{
    if ($_POST['a'] != $_POST['b'])
    {
        if (md5($_POST['a']) == md5($_POST['b']))
            echo 'flag';
        else
            echo 'you are wrong';
    }
    else echo "请输入不同的a,b值";
}

Solution 1

Since md5 cannot encrypt an array, it will return NULL when encrypting an array

Return NULL

So, we can pass in two arrays

Pass in two arrays

Solution 2

You can pass in two md5 encrypted strings starting with 0e. It should be noted that this string starting with 0e can only be a pure number, so that php will convert it to 0 when performing scientific calculations. . You can search for strings that start with 0e and are encrypted with md5, or you can write your own code and provide the following script.

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

Pass in two md5 encrypted strings that start with 0e

s1502113478a
0e861580163291561247404381396064

s1885207154a
0e509367213418206700842008763514

s1836677006a
0e481036490867661113260034900752

s155964671a
0e342768416822451524974117254469

s1184209335a
0e072485820392773389523109082030

flag

===Compare

<?php
if (isset($_POST['a']) and isset($_POST['b']))
{
    if ($_POST['a'] != $_POST['b'])
    {
        if (md5($_POST['a']) === md5($_POST['b']))
            echo 'flag';
        else
            echo 'you are wrong';
    }
    else echo "请输入不同的a,b值";
}
?>

Solution 1:

You can also pass in two arrays, but it is no longer suitable to pass in two strings starting with 0e, because === is a strong collision of md5 and is strictly filtered.

Pass in two arrays

Solution 2:

Use md5 to encrypt two identical strings to bypass filtering.

How to generate two different strings, but MD5 is the same? After referring to how to build the same MD5 with different values , we can use the fast MD5 collision generator to build two strings with the same MD5 but completely different content.

fastcoll_v1.0.0.5.exe.zip

structure

Create a text file, write any file content, and name it ywj.txt (source file)

Run fastcoll to output the following parameters. -p is the source file, -o is the output file

fastcoll_v1.0.0.5.exe -p ywj.txt -o 1.txt 2.txt

Create a text file

test

Test the 1.txt and 2.txt files produced

<?php 
function  readmyfile($path){
    $fh = fopen($path, "rb");
    $data = fread($fh, filesize($path));
    fclose($fh);
    return $data;
}
echo '二进制md5加密 '. md5( (readmyfile("1.txt")));
echo "</br>";
echo  'url编码 '. urlencode(readmyfile("1.txt"));
echo "</br>";
echo '二进制md5加密 '.md5( (readmyfile("2.txt")));
echo "</br>";
echo  'url编码 '.  urlencode(readmyfile("2.txt"));
echo "</br>";
二进制md5加密 8e4ef6c69a337c0de0208455ee69a416

url编码 1%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%00%00%A3njn%FD%1A%CB%3A%29Wr%02En%CE%89%9A%E3%8EF%F1%BE%E9%EE3%0E%82%2A%95%23%0D%FA%CE%1C%F2%C‍4P%C2%B7s%0F%C8t%F28%FAU%AD%2C%EB%1D%D8%D2%00%8C%3B%FCN%C9b4%DB%AC%17%A8%BF%3Fh%84i%F4%1E%B5Q%7B%FC%B9RuJ%60%B4%0D7%F9%F9%00%1E%C1%1B%16%C9M%2A%7D%B2%BBoW%02%7D%8F%7F%C0qT%D0%CF%3A%9DFH%F1%25%AC%DF%FA%C4G%27uW%CFNB%E7%EF%B0

二进制md5加密 8e4ef6c69a337c0de0208455ee69a416

url编码 1%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%00%00%A3njn%FD%1A%CB%3A%29Wr%02En%CE%89%9A%E3%8E%C6%F1%BE%E9%EE3%0E%82%2A%95%23%0D%FA%CE%1C%F2%C4P%C2%B7s%0F%C8t%F28zV%AD%2C%EB%1D%D8%D2%00%8C%3B%FCN%C9%E24%DB%AC%17%A8%BF%3Fh%84i%F4%1E%B5Q%7B%FC%B9RuJ%60%B4%0D%B7%F9%F9%00%1E%C1%1B%16%C9M%2A%7D%B2%BBoW%02%7D%8F%7F%C0qT%D0%CF%3A%1DFH%F1%25%AC%DF%FA%C4G%27uW%CF%CEB%E7%EF%B0

As you can see, the results of the binary md5 encryption of the 1.txt and 2.txt files are exactly the same. Since the files 1.txt and 2.txt contain invisible characters, they need to be url encoded before use. It can be seen that the two strings after url encoding are not exactly the same, which meets our need to enter two different parameters.

The two strings after url encoding are not exactly the same

When the question limit cannot be passed in an array, but only a string, as in the following example, only solution 2.

<?php
if((string)$_GET['a'] !== (string)$_GET['b'] && md5($_GET['a'])===md5($_GET['b'])){
    echo "you are right";
}
else {
    echo "you are wrong";
}

HECTF ezphp

Source code

<?php 
error_reporting(0);
highlight_file(__file__);
include('flag.php'); 
$string_1 = $_GET['str1']; 
$string_2 = $_GET['str2']; 

if($_GET['param1']!==$_GET['param2']&&md5($_GET['param1'])===md5($_GET['param2'])){
        if(is_numeric($string_1)){ 
            $md5_1 = md5($string_1); 
            $md5_2 = md5($string_2); 
            if($md5_1 != $md5_2){ 
                $a = strtr($md5_1, 'cxhp', '0123'); 
                $b = strtr($md5_2, 'cxhp', '0123'); 
                if($a == $b){
                    echo $flag;
                }
            }  
            else {
               die("md5 is wrong"); 
            }
            } 
        else {
        die('str1 not number'); 
        }
    }

?>

First look at the usage of some strtr() function:

The strtr() function converts specific characters in a string.

Specific character

Observing the source code, four parameters are required. First, param1===param2. Because there are no other restrictions, we can pass in two arrays. For str1 and str2, first str1 can only be numbers, and finally $a == $b, but md5_1 != md5_2, so we cannot pass in two md5 encrypted strings beginning with 0e.

And because the cxhp in str1 and str2 encrypted by md5 will be replaced with 0123, that is, c will be replaced with 0, so a string starting with ce will be replaced with a string starting with 0e.

It is conceivable that as long as you find two strings starting with ce after being encrypted by md5, or one string starting with ce after being encrypted by md5, and one string starting with 0e after being encrypted by md5, you can bypass the filtering.

Construction script

This is the script at the beginning, with few return values ​​and slow execution speed.

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

The beginning script

This is a further optimized script

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

Further optimized script

Further optimized script

Actual combat drill

<?php
function random() { 
    $a = rand(133,600)*78;
    $b = rand(18,195);
    return $a+$b;
}
$r = random();
    if((string)$_GET['a']==(string)md5($_GET['b'])){
        if($a.$r == $b) {
            print "Yes,you are right";
        }
        else {
            print "you are wrong";
        }
    }

?>

Observing the code, there is a rondom method that returns a random number. In this question, we don’t need to know what is returned. We only need to know that the returned number is a string of numbers. Two parameters a and b are passed in, and the string is required to be passed in, and b will be encrypted by md5. Finally, let $a.$r == $b. Because it is a weak type comparison, and only strings can be passed in, what I want is to compare two strings starting with 0e. As we already know, a string starting with 0e can only be a pure number, so php is doing science It will be converted to 0 in the calculation method. So make sure that $a starts with 0e, because $r is a string of numbers, so $a.$r can still be parsed as 0 in PHP. Because $b is the parameter b encrypted by md5, we can pass in the string starting with 0e after md5 encryption.

Incoming md5 encryption

1

Guess you like

Origin blog.51cto.com/14601372/2621565