记录网站:【CTF_Web:php弱类型绕过与md5碰撞 - CSDN App】http://t.csdnimg.cn/A58wf

MD5函数漏洞

$str1 = $_GET[‘str1’];
$str2 = $_GET[‘str2’];
if (md5($str1) == md5($str2)){
die(‘OK’); }

php弱类型比较产生的漏洞
想要满足这个判断只需要构造出MD5值为0e开头的字符串,这样的话弱类型比较会认为是科学技术法,0的多少次方都是0,因此可以绕过MD5

编码后0e开头的字符串:
QNKCDZO(0e830400451993494058024219903391)
aabg7XSs(0e087386482136013740957780965295)
aaabEgHn(0e418636035810609803317995275027)
240610708
s878926199a
s155964671a
s214587387a
还有MD5和双MD5以后的值都是0e开头的
CbDLytmyGm2xQyaLNhWn
770hQgrBOjrcqftrlaZk
7r4lGXCH2Ksu2JNT3BYM

md5()数组绕过。

如果我们传入/?name[]=1,那$name的值就是一个数组,name[]=1,2也一样,两个数组进行比较的时候会比较数组内的元素,但md5编码就不一样了,md5()函数统一把数组当成字符串array,这也就导致只要两个都是数组,那他们的md5编码都一样,都为字符串array的md5编码。

PHP特性
$str1 = $_GET[‘str1’];
$str2 = $_GET[‘str2’];

if (md5($str1) === md5($str2)) {
die(‘OK’);
}

因为是强类型比较,用0e开头的字符串是没办法绕过的了,但是PHP自身的特性使得可以提交一个数组,
而md5函数传入数组的返回值都是NULL,这样就可以绕过强类型比较了。所以这里用GET传入?str1[]=1&str2[]=2就行了
补充:md5()或者sha1()之类的函数计算的是一个字符串的哈希值,对于数组则返回false,如果$str1和$str2都是数组则双双返回FALSE,
两个FALSE相等得以绕过

MD5碰撞

$str1 = (string)$_GET[‘str1’];
$str2 = (string)$_GET[‘str2’];

if (md5($str1) === md5($str2)) {
die(‘OK’);
}

由于强制类型转换,传数组就不可行了,这里就需要MD5碰撞,对于需要两个内容不同但是MD5值相同的文件,使用Fastcoll就可以了

绕过md5()来构造攻击语句

select * from ‘admin’ where password=md5($pass,true)

ffifdyop

这个点的原理是 ffifdyop 这个字符串被 md5 哈希了之后会变成 276f722736c95d99e921722cf9ed621c,这个字符串前几位刚好是 ‘ or ‘6,
而 Mysql 刚好又会吧 hex 转成 ascii 解释,因此拼接之后的形式是select * from ‘admin’ where password=‘’ or ‘6xxxxx’。等价于 or 一个永真式,因此相当于万能密码,可以绕过md5()函数

md5碰撞(最强解)

a=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%00%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%55%5d%83%60%fb%5f%07%fe%a2
&b=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%02%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%d5%5d%83%60%fb%5f%07%fe%a2

$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

以0e开头的原字符串md5后的密文还是以0e开头
0e215962017

超过精确度的弱类型问题

超过精确度的数字(小数点后超过17位)在进行弱类型比较时,会出 现相等的情况。例如var_dump(0.99999999999999999==1)的结果为 True。

in_arrray()函数

in_array()函数的基本格式为:in_array($search,Array()),表示搜索 $search是否为数组Array()的元素。in_array()函数实际上存在第三个参 数,该参数默认为false。如果第三个参数设置为true,则判断$search与 数组的值类型是否相同,即进行强类型比较;若第三个参数设置为 false,则in_array()函数进行判断的时候,会强制将$search的值转换为 数组的值类型,此时就是弱类型比较。

eregi()函数

eregi()函数用于在一个字符串中搜索指定模式的字符串,搜索时不区分 大小写。
关于eregi()函数的考点一般为:eregi()函数可以被%00截断(PHP5版 本,该函数在PHP7中被弃用)。
eregi(“111”.substr($input,0,1),“1114”) and substr($input,0,1) !=4
该语句要求$input的第一个字符不能为4,但同时要求字符串111与 $input的第一个字符拼接后的结果必须能够匹配字符串1114。按照常 理,这是相互矛盾的,此时可以使用%00来进行输入。请注意,%00在 此处表示一个字符,即\0。之所以会出现截断问题,是因为PHP的底层 是基于C语言实现的,而在C语言里,字符串是以\0作为结尾的。

md5长度限制强相等

总思路:传相同字符的不同数据类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?php
error_reporting(0);
highlight_file(__FILE__);

class ctfshow {
private $d = '';
private $s = '';
private $b = '';
private $ctf = '';

public function __destruct() {
$this->d = (string)$this->d;
$this->s = (string)$this->s;
$this->b = (string)$this->b;

if (($this->d != $this->s) && ($this->d != $this->b) && ($this->s != $this->b)) {
$dsb = $this->d.$this->s.$this->b;

if ((strlen($dsb) <= 3) && (strlen($this->ctf) <= 3)) {
if (($dsb !== $this->ctf) && ($this->ctf !== $dsb)) {
if (md5($dsb) === md5($this->ctf)) {
echo file_get_contents("/flag.txt");
}
}
}
}
}
}

unserialize($_GET["dsbctf"]);

1.php浮点数常量NAN和INF:
在PHP中,NAN是一个特殊的浮点数值,表示非数值(Not-A-Number)。当一个运算无法计算结果时,比如零除以零,就会产生NAN。
PHP中的INF是一个特殊的浮点数值,表示无穷大(Infinity)。当数值超过PHP_FLOAT_MAX或者使用一些数学函数产生极大或极小的结果时,就会得到INF。

img

img

利用思路:
php浮点数常量NAN和INF:
使用浮点常量INF分别给ctf和dsb变量赋值,长度都为3,dsb是字符串类型,ctf是浮点型,由于MD5是以字符串形式进行加密的,所以他们的MD5值是相等的。这样就达到了绕过的目的。

2.dsb会被转化成字符串类型,但是ctf不会,所以可以利用不同类型的相同字符绕过。比如:

md5(‘123’)=md5(123)