天天看點

ctf中MD5繞過詳細總結及例題[BJDCTF2020]Easy MD5

一、首先是MD5()函數的作用?

MD5()函數的作用是計算字元串的MD5散列。

傳回值:如果成功則傳回已計算的 MD5 散列,如果失敗則傳回 FALSE。

二、PHP == 弱類型比較繞過?

代碼:

<?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";
	}
}
?>//此時如果輸入 ver1[]=1&ver2[]=2,傳回flag
           

這裡比較的是PHP弱類型,需要繞過MD5()。

方法一:數組繞過

由于MD5不能加密數組,在加密數組的時候會傳回NULL,是以我們可以傳入兩個數組繞過。适用于源碼中沒有判斷變量類型或内容,如果加上了過濾函數就不能使用了。

常見的過濾函數:

ctype_alnum(string $text):bool類型
    //如果text中所有的字元都是字母或者數字,則傳回true,否則false
is_numeric(mixed $ver):bool類型
    //如果ver是數字或者數字字元串,則傳回true,否則傳回false
           

例如:

<?php
highlight_file(_FILE_);
error_reporting(0);
$flag="flag{123456789}";
$ver1=$_GET['ver1'];
$ver2=$_GET['ver2'];
if(isset($_GET['ver1'])and isset($_GET['ver2']))
{
    if($GET['ver1']!=$_GET['ver2'])
    {
        if((md5($_GET['ver1'])==md5($_GET['ver2'])) and is_numeric($_GET['ver1']) and is_numeric($_GET['ver2']))
            echo $flag;//如果加密和ver1和ver2相等且ver1和ver2都是數字或者數字字元串,則..
        else
            echo "you can't get flag";
    }
}
?>//此時如果輸入 ver1[]=1&ver2[]=2,傳回you can't get flag
           

方法二:科學計數法繞過

原理:可以傳入兩個md5加密後是0e開頭的字元串,但這個以0e開頭的字元串隻能是純數字,這樣php在進行科學計算法的時候會将它轉化為0。

<?php
for($a=1;$a<=1000000000;$a++){
   $md5 = md5($a);
   if(preg_match('/^0e\d+$/',$md5)){//preg_match函數是進行正規表達式的比對,成功傳回1,否則傳回0,前面的參數是要搜尋的模式、字元串形式,後面的參數指輸入的字元串。
      echo $a;
      echo "\n";
      echo $md5;
      echo "\n";
   }
}
?>//加密後是0e開頭的數字字元串:
QNKCDZO
240610708
314282422
s878926199a
s155964671a
s214587387a
s214587387a
           

例如:

<?php
highlight_file(_FILE_);
error_reporting(0);
$flag="flag{123456789}";
$ver1=$_GET['ver1'];
$ver2=$_GET['ver2'];
if(isset($_GET['ver1'])and isset($_GET['ver2']))
{
    if($GET['ver1']!=$_GET['ver2'])
    {
        if((md5($_GET['ver1'])==md5($_GET['ver2'])) and ctype_alnum($_GET['ver1']) and ctype_alnum($_GET['ver2']))
            echo $flag;//如果加密和ver1和ver2相等且ver1和ver2都是數字或者數字字元串,則..
        else
            echo "you can't get flag";
    }
}
?>//此時如果輸入 ver1=240610708&ver2=314282422,傳回$flag,此時ver1和ver2加密後都是0e開頭
           

雙MD碰撞繞過

md和md5後都是以0e開頭的字元串:
CbDLytmyGm2xQyaLNhWn
770hQgrBOjrcqftrlaZk
7r4lGXCH2Ksu2JNT3BYM
           

三、PHP===強類型比較繞過?

代碼:

<?php
highlight_file(_FILE_);
error_reporting(0);
$flag = "flag{122365944454}";
$ver1=$_GET['ver1'];
$ver2=$_GET['ver2'];
if (isset($_GET['ver1']) and isset($_GET['ver2']))
{
    if ($_GET['ver1'] != $_GET['ver2']){
        if(md5($_GET['ver1'])===md5($_GET['ver2']))
            echo $flag;
        else
            echo "you can't get flag";
    }
}
?>
           

方法:數組繞過

原理同上、過程同上,可使用。

注:使用md5加密後完全相等的兩個字元串繞過,不能用。

這是剛剛同上第二種方法,加密後’oe’開頭的字元串,但因為強比較會比較類型和值,是以不能用這個方法來繞過。

當然可以試試加密後類型和值都完全相等的字元串。有篇部落格說可以利用fastcoll_v1.0.0.5.exe來生成符合條件的字元串,還沒試過,待考察。

連結:https://blog.csdn.net/LYJ20010728/article/details/116779357

四、sql注入類的MD5繞過?

起因:為了資訊的安全,在資料庫裡存放密碼的時候都是進行了加密處理的,大多數查詢語句在沒有進行處理的情況下應該是:

原理:ffifdyop經過MD5加密後變為’or’6xxx阿巴阿巴,

而在mysql中,在用作布爾型判斷時,以數字開頭的字元串會被當成整型,不過由于是字元串,是以後面必須要有單引号括起來的,比如:‘xxx’or’6xxxxxx’,就相當于’xxx’or 6,就相當于 'xxx’or true,是以傳回值是true。

是以查詢時就變成了:

sql代碼:select * from flag where user='amdin' and password=''or'6xxxx',等于 password=''or true == ture
           

進而實作了繞過。

開始做題:

題目叫easy md5,但是進去看見一個輸入框,直覺跟sql有關,是以往輸入框裡面輸入ffifdyop試試,

果然頁面發生變化:

ctf中MD5繞過詳細總結及例題[BJDCTF2020]Easy MD5

打開f12看源碼,發現:

ctf中MD5繞過詳細總結及例題[BJDCTF2020]Easy MD5

這裡直接用科學計數法繞過a和b

這裡我構造了一個payload,

發現一直是404,

ctf中MD5繞過詳細總結及例題[BJDCTF2020]Easy MD5

發現是自己多打了一個斜杠(部落客糾結了一個小時)

于是修改payload,

得到頁面:

ctf中MD5繞過詳細總結及例題[BJDCTF2020]Easy MD5

終于看見希望了,flag近在咫尺!

這裡看代碼是php強類型比較,用數組繞過,構造payload如下圖:

ctf中MD5繞過詳細總結及例題[BJDCTF2020]Easy MD5

得到結果:

ctf中MD5繞過詳細總結及例題[BJDCTF2020]Easy MD5