CTF PHP特性利用
# CTF PHP特性利用
# 1.数组
preg_match(),匹配到参数是数组是报错,返回0
intval(),参数是数组时,报错返回1
if(isset($_GET['num'])){
$num = $_GET['num'];
if(preg_match("/[0-9]/", $num)){
die("no no no!");
}
if(intval($num)){
echo $flag;
}
}
2
3
4
5
6
7
8
9
# 2.=比较
==,判断值是否相同,不关注数据类型
===,值,数据类型都要相同
<?php
var_dump(1=='1');
var_dump(1==='1');
?>
2
3
4
运行结果
bool(true)
bool(false)
2
# 3.字符串与数字的比较
字符串和数字进行弱比较时,将字符串转化为数字
- 数字开头的字符串 --- 开头数字
- 字符串开头的字符串 --- 0
eg.
<?php
# 1 和 0 比较
var_dump(1=='0str');
# 0 和 0 比较
var_dump(0=='str');
?>
2
3
4
5
6
运行结果
bool(true)
bool(true)
2
GET传入的数据默认作为字符串
# 4.intval()函数
intval($val,$base),var是传入的变量参数,base表示这个参数的进制,默认十进制
intval(4476,0),0表示根据var开始的数字决定使用的进制,0x十六进制,0八进制,1-9十进制
eg.intval(0x117c,0)===4476
if(isset($_GET['num'])){
$num = $_GET['num'];
if($num==="4476"){
die("no no no!");
}
if(intval($num,0)===4476){
echo $flag;
}else{
echo intval($num,0);
}
}
2
3
4
5
6
7
8
9
10
11
程序里要求这个数的八进制数与十进制数4476等值,转换一下,10574,前面补个八进制特征数0
传参url?num=010574
# 5.md5(),sha1()函数
# 5.1 数组绕过---强比较
md5(),sha1()无法对数组加密,对数组加密返回的是null
a[]=1,b[]=2,md5(),sha1()作用后,返回null null=null,这是一种绕过方式
代码
<?php
$a[]=1;
$b[]=2;
var_dump(md5($a)===md5($b));
var_dump(sha1($a)===sha1($b));
?>
2
3
4
5
6
运行结果
bool(true)
bool(true)
PHP Warning: md5() expects parameter 1 to be string, array given in /tmp/sandbox.s0-s0;c118,c849/home/.code.tio on line 4
PHP Warning: md5() expects parameter 1 to be string, array given in /tmp/sandbox.s0-s0;c118,c849/home/.code.tio on line 4
PHP Warning: sha1() expects parameter 1 to be string, array given in /tmp/sandbox.s0-s0;c118,c849/home/.code.tio on line 5
PHP Warning: sha1() expects parameter 1 to be string, array given in /tmp/sandbox.s0-s0;c1
2
3
4
5
6
给出了比较结果,程序也报错了,利用无法加密而返回了null值,绕过md5,sha1函数
# 5.2 0e绕过---弱比较
如果两个字符串经过md5加密得到两个都是0e开头的字符串,在弱比较是会作为数字0
注意:0e绕过只适用弱比较
md5()后0e开头的串
240610708:0e462097431906509019562988736854
QLTHNDT:0e405967825401955372549139051580
sha1()后0e开头的串
aaK1STfY: 0e76658526655756207688271159624026011393
aaO8zKZF: 0e89257456677279068558073954252716165668
# 5.3 $md5=md5($md5)
0e215962017这个payload很完美,本身0e开头,md5后也是0e开头
$md5="0e215962017";
var_dump(md5($md5));
string(32) "0e291242476940776845150308577824"
2
3
# 5.4 md5($pwd,true)绕过
在ctfshow中web9,部分代码如下
通过 md5($str, true) 返回的原始二进制格式的哈希值是一串字节,每个字节都表示为 8 位二进制数。这些二进制数据通常无法直接以可读的方式显示出来,因为其中可能包含控制字符或不可打印字符,因此在输出时会显示为乱码或者不可见字符。
$sql="select * from user where username ='admin' and password ='".md5($password,true)."'";
$result=mysqli_query($con,$sql);
2
其中存在一个漏洞,当$password=ffifdyop时,md5('ffifdyop',true)将得到'or'6É]é!r,ùíb,哇太神奇辣,拼接后的sql直接绕过了and条件
类似的还有
ffifdyop 4SV7p bJm4aG bNas5p ckHAEb
# 5.5 文件md5比较
验证文件md5是否相同,使用fastcoll工具生成相同md5的文件
fastcoll下载地址http://www.win.tue.nl/hashclash/fastcoll_v1.0.0.5.exe.zip (opens new window)
用法:新建题目文件(txt,png,jpg,exe,pdf等),直接拖到fastcoll.exe上,会生成两个文件,md5相同
# 一些操作函数
# 1.parse_str($v1,$v2)
parse_str() 函数用于将查询字符串解析到变量中。它将查询字符串解析为变量,并将变量设置为当前符号表的条目。其中,$v1 是要解析的查询字符串,$v2 是用来存储解析结果的数组。
如果 $v1 是 'name=binjie&age=25',那么 parse_str($v1, $v2) 执行后,$v2 将会包含键值对 ['name' => 'binjie', 'age' => '25']。
$query = "name=Ajay";
parse_str($query, $result);
print_r($result);
2
3
结果
Array
(
[name] => John
)
2
3
4
在使用GET[]传参时,会变成?v1=name=Ajay,有点奇怪
发现在$v1=1时,返回了一个空数组,var_dump($v2)=array[],即$v2=null
# 2.strrev(str1)
strrev 是 PHP 中的一个内置函数,用于反转字符串
$str = "Hello, World!";
$reversed = strrev($str);
echo $reversed; // 输出:!dlroW ,olleH
2
3
# 3.ereg()
ereg 函数是 PHP 中用于执行正则表达式匹配的函数之一,但**自 PHP 5.3.0 版本起已被废弃。**建议使用 preg_match 函数来代替
ereg()函数会被%00截断