在CTF中可以说是经常碰到md5加密了,一般都是进行强比较
抑或是弱比较
,考法非常多,但是万变不离其中。只要我们掌握了原理,一切问题便迎刃而解了。
不能防止碰撞破解
。两串不同的字符串
加密出来的内容却是相同的
先提两个例子:
var_dump("123a"==123)
var_dump("123a"=="123")
在没有认真总结前,完全不知道弱比较还要区分与字符串类型比较
还是与int类型比较
上述实例的结果是:
True
False
PHP规定当进行字符串与数字的弱比较时
,会进行如下步骤
:
先看字符串开头是否为数字,如果为数字,则截止到连续数字的最后一个数字,即"123abc456"
=>123
如果开头不为数字,则判断为false,即0。因此
("aaa123"==0)
=>true
("123a"==123)
=>true
思维导图:
正如上面所言:
var_dump("123a"=="123"); //False
因为这个是字符串之间进行比较,想要绕过这个弱比较只能用0e
的方式。
在PHP中"0e"判断为科学计数法,0e123就是0的10123次方
不难推出:0e123456789==0e1
// 因为0的任意次方都为0
不过有一个注意点:
"0e123456"=="0e345" //True
"0e12adfc"=="0e345" //False
在0e后面不能含有字母!!!
在0e后面不能含有字母!!!
在0e后面不能含有字母!!!
否则判断为False
#实例
<?php
if("0e23253"=="0e2345")
{
echo 'yes';
}
?>
输出:
yes
在CTF中,会遇到如下的MD5弱比较题目
<?php include "flag.php"; $md5_1=$_GET['md5_1']; $md5_2=$_GET['md5_2']; if(md5($md5_1)==md5($md5_2) & $md5_1 != $md5_2) { echo $flag; } else { echo "try harder"; } ?>
这个时候就要利用0e
的形式来解题,找到两个不同字符,md5加密后却都是0e324234的形式。如何寻找这样的字符串?
1.脚本寻找
import multiprocessing import hashlib import random import string import sys CHARS = string.ascii_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.encode()) value = md5.hexdigest() if value[start: start + str_len] == substr: md5 = hashlib.md5(value.encode()) 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) > 2 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()
用法:
输入命令
python md5.py "0e" 0
"0e" =>要跑的字符
0 =>要跑的字符的起始位置
脚本寻找要浪费大概十分钟左右的时间才能找出一个,可以用网上现成的,如果题目要求比较特殊的话,再利用自己的脚本跑
2.百度
MMHUWUV 0e701732711630150438129209816536 |
MAUXXQC 0e478478466848439040434801845361 |
IHKFRNS 0e256160682445802696926137988570 |
GZECLQZ 0e537612333747236407713628225676 |
GGHMVOE 0e362766013028313274586933780773 |
GEGHBXL 0e248776895502908863709684713578 |
EEIZDOI 0e782601363539291779881938479162 |
DYAXWCA 0e424759758842488633464374063001 |
这样子就出flag了
这一类题型要求满足$a是0e开头,且加密后也是0e开头
在网上收集了这些结果:
0e215962017 0e291242476940776845150308577824 |
0e1284838308 0e708279691820928818722257405159 |
0e1137126905 0e291659922323405260514745084877 |
0e807097110 0e318093639164485566453180786895 |
0e730083352 0e870635875304277170259950255928 |
弱比较主要就是以上两种类型。
方法一:
数组绕过
<?php include "flag.php"; $md5_1=$_GET['md5_1']; $md5_2=$_GET['md5_2']; if(md5($md5_1)===md5($md5_2) & $md5_1 != $md5_2) { echo $flag; } else { echo "try harder"; } ?>
md5_1[]=1&md5_2[]=2
因为PHP对无法md5加密的东西不加密,结果为NULL,虽然会报错,但是null=null,逻辑关系为True。所以可以输出flag
方法二:
两串不一样的字符,加密结果却相同:
$a=M%C9h%FF%0E%E3%5C%20%95r%D4w%7Br%15%87%D3o%A7%B2%1B%DCV%B7J%3D%C0x%3E%7B%95%18%AF%BF%A2%02%A8%28K%F3n%8EKU%B3_Bu%93%D8Igm%A0%D1%D5%5D%83%60%FB_%07%FE%A2
$b=M%C9h%FF%0E%E3%5C%20%95r%D4w%7Br%15%87%D3o%A7%B2%1B%DCV%B7J%3D%C0x%3E%7B%95%18%AF%BF%A2%00%A8%28K%F3n%8EKU%B3_Bu%93%D8Igm%A0%D1U%5D%83%60%FB_%07%FE%A2
这个我的脚本就跑不出来了,是网上收集的。
<?php error_reporting(0); include "flag.php"; highlight_file(__FILE__); if($_POST['param1']!==$_POST['param2']&&md5($_POST['param1'])===md5($_POST['param2'])){ echo $flag; }
这题也是两个解法:
法一:
param1[]=1¶m2[]=2
法二:
param1=M%C9h%FF%0E%E3%5C%20%95r%D4w%7Br%15%87%D3o%A7%B2%1B%DCV%B7J%3D%C0x%3E%7B%95%18%AF%BF%A2%02%A8%28K%F3n%8EKU%B3_Bu%93%D8Igm%A0%D1%D5%5D%83%60%FB_%07%FE%A2¶m2=M%C9h%FF%0E%E3%5C%20%95r%D4w%7Br%15%87%D3o%A7%B2%1B%DCV%B7J%3D%C0x%3E%7B%95%18%AF%BF%A2%00%A8%28K%F3n%8EKU%B3_Bu%93%D8Igm%A0%D1U%5D%83%60%FB_%07%FE%A2
<?php include 'conn.php'; highlight_file("index.php"); //level 1 if ($_GET["hash1"] != hash("md4", $_GET["hash1"])) { die('level 1 failed'); } //level 2 if($_GET['hash2'] === $_GET['hash3'] || md5($_GET['hash2']) !== md5($_GET['hash3'])) { die('level 2 failed'); } //level 3 $query = "SELECT * FROM flag WHERE password = '" . md5($_GET["hash4"],true) . "'"; $result = $mysqli->query($query); $row = $result->fetch_assoc(); var_dump($row); $result->free(); $mysqli->close(); ?>
levle 1
很明显,这种是要md4加密,并且是"0e"+"数字" 加密后还是"0e"+"数字"的形式,上脚本:
import multiprocessing import hashlib import random import string import sys CHARS = string.digits def cmp_md4(substr, stop_event, str_len, start=0, size=18): global CHARS while not stop_event.is_set(): rnds = ''.join(random.choice(CHARS) for _ in range(size)) rnds = "0e"+rnds md4 = hashlib.new('md4', rnds.encode("utf-8")) value = md4.hexdigest() if value[start: start + str_len] == substr: print(value) if value[2:].isdigit(): print(rnds) 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_md4, 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()
测试一下,可行
level 2
法一:
hash2[]=1&hash3[]=2
法二:
hash2=M%C9h%FF%0E%E3%5C%20%95r%D4w%7Br%15%87%D3o%A7%B2%1B%DCV%B7J%3D%C0x%3E%7B%95%18%AF%BF%A2%02%A8%28K%F3n%8EKU%B3_Bu%93%D8Igm%A0%D1%D5%5D%83%60%FB_%07%FE%A2&hash3=M%C9h%FF%0E%E3%5C%20%95r%D4w%7Br%15%87%D3o%A7%B2%1B%DCV%B7J%3D%C0x%3E%7B%95%18%AF%BF%A2%00%A8%28K%F3n%8EKU%B3_Bu%93%D8Igm%A0%D1U%5D%83%60%FB_%07%FE%A2
level 3
结果:
只要构造 xx 'or xxxx
的形式就可以了
具体可以看这篇文章
这个是我觉得以后为了避免大家都用现有的收集字符串解题而出的,比如:
<?php include("flag.php"); $a = md5($_GET['a']); if($a==123) { echo $flag; } else { echo "nonono"; } ?>
要构造一个开头是123且后面是字母的字符串:
脚本:
import multiprocessing
import hashlib
import random
import string
import sys
CHARS = string.ascii_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.encode())
value = md5.hexdigest()
if value[start: start + str_len] == substr:
print(rnds)
print(value)
stop_event.set()
if __name__ == '__main__':
substr = sys.argv[1].strip()
start_pos = int(sys.argv[2]) if len(sys.argv) > 2 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()
终端输入python .\MD5碰撞.py "123" 0
实践试一下:
注意点:跑出来的123后面第一个字符要是字母,如果不是多跑几次,概率还是挺大的。
还有关于双md5的题目等等,只要掌握了这些思想,看到题目就能想到解法了。这个脚本也是面向百度编程找到的,有一个脚本能跑是比较好的,可以应对各种新情况。使用python脚本是因为有多线程模式,速度更快。
文章浏览阅读695次。SpringBoot项目引入外部jar包_springboot引入外部jar包
文章浏览阅读3.1k次,点赞19次,收藏84次。Java系列(面试必备):HashMap 和 Hashtable 的 6 个区别!前言今天博主将为大家分享:Java系列(面试必备):HashMap 和 Hashtable 的 6 个区别!不喜勿喷,如有异议欢迎讨论!首先推荐结合博主的这篇文章进行阅读===>Java系列(面试必备):简单的hashCode和equals面试题,有好多坑!HashMap 和 Hashtable 是 J..._java hashtable的优缺点
文章浏览阅读5.7k次。查询语句中,字段类型使用错误,在es中查询字段类型为int,而查询语句中错误地用成了string。_elasticsearch exception [type=search_phase_execution_exception, reason=all s
文章浏览阅读113次。这些部分将指导您完成一系列步骤,从配置开发环境到使用 STM32f429zi (nuleo-f429zi) 和 W5300-TOE 运行以太网示例 基本设置请参阅“入门”指南。_w5500 mqtt onenet
文章浏览阅读381次,点赞5次,收藏7次。1.也可以叫做,它是一种搜索的方式。2.回溯是递归的副产品,只要有递归就会有回溯。回溯与递归相辅相成,只要有递归就有回溯。通常递归函数的下面就是回溯的逻辑。3.,如果想让回溯法高效一些,可以加一些剪枝的操作,但也改不了回溯法就是穷举的本质。(暴力查找)5.回溯法解决的问题:(1)组合问题:N个数里面按一定规则找出k个数的集合;(2)切割问题:一个字符串按一定规则有几种切割方式;(3)子集问题:一个N个数的集合里有多少符合条件的子集;(4)排列问题:N个数按一定规则全排列,有几种排列方式;
文章浏览阅读6.7k次,点赞2次,收藏28次。1、如下图,只需在丝印 VCC GND 处供 3.3V 电源即可启动开发板2、上电后开发板会释放热点。其中SSID: wireless-tagPwd: wireless-tag3、电脑或手机连接此热点后,登录网页 http://192.168.4.1 进入 WEBSERVER 界面。如下图:4、上图中有两个红色框 Get Still 和 Start Stream(Stop Stream)。点击 Get Still,摄像头抓取一张图片,并显示在黑色区域;点击 Start Stream_esp32 cam说明书
文章浏览阅读5.2k次。Attempt to invoke virtual method 'void android.widget.TextView.setText(java.lang.CharSequence)' on a null object reference_attempt to invoke virtual method 'void android.widget.textview.settext(java.
文章浏览阅读2.4k次。题目大意:给定一棵树,每个点有点权,支持下列操作: 1.某个点的点权+a 2.某棵子树所有点权+a 3.查询某个点到根路径上的点权和 这个用入栈出栈序就可以了 入栈为正,出栈为负,那么一个点到根路径上的权值和就是入栈出栈序中[1,入栈位置]的和 而子树在入栈出栈序中是连续的,因此用线段树维护一下就可以了 (似乎只要无脑链剖就可以了?#include #include_haoi2015 t2-bzoj4034
文章浏览阅读3.7k次。3D数学基础(一)——左手坐标系和右手坐标系1、左手坐标系左手坐标系的定义伸出左手,让拇指和是指成L型,大拇指向右,食指向前,中指指向前方,这样便定义好了一个左手坐标系,其中拇指为x轴,食指为Y轴,中指为Z轴。图示2、右手坐标系右手坐标系的定义右手坐标系与左手坐标系相反图示3、意义左手坐标系和右手坐标系虽然定义简单,并且可以相互转换,但是在一个场景中定义好坐标系是左手坐标..._3d左手坐标系
文章浏览阅读278次。一、Java NIO 的核心组件Java NIO的核心组件包括:Channel(通道),Buffer(缓冲区),Selector(选择器),其中Channel和Buffer比较好理解 简单来说 NIO是面向通道和缓冲区的,意思就是:数据总是从通道中读到buffer缓冲区内,或者从buffer写入到通道中。二、Java NIO Selector1. Selector简介选择器..._java nio selecter
文章浏览阅读2.3k次,点赞4次,收藏20次。Oracle数据库在Linux系统上安装步骤比较多,为了方便Oracle数据库的安装,编写了以下脚本,简化了Oracle数据库的安装。_linux安装oracle11g数据库
文章浏览阅读60次。1、TCP/IP协议栈四层模型 TCP/IP这个协议遵守一个四层的模型概念:应用层、传输层、互联层和网络接口层。 网络接口层 模型的基层是网络接口层。负责数据帧的发送和接收,帧是独立的网络信息传输单元。网络接口层将帧放在网上,或从网上把帧取下来。 互联层 互联协议将数据包封装成internet数据报,并运行必要的路由算法。 这里有四个互联协议: 网际协议IP...