目录

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;
    }
}
1
2
3
4
5
6
7
8
9

# 2.=比较

==,判断值是否相同,不关注数据类型
===,值,数据类型都要相同

<?php
var_dump(1=='1');
var_dump(1==='1');
?>
1
2
3
4

运行结果

bool(true)
bool(false)
1
2

# 3.字符串与数字的比较

字符串和数字进行弱比较时,将字符串转化为数字

  • 数字开头的字符串 --- 开头数字
  • 字符串开头的字符串 --- 0
    eg.
<?php
# 1 和 0 比较
var_dump(1=='0str');
# 0 和 0 比较
var_dump(0=='str');
?>
1
2
3
4
5
6

运行结果

bool(true)
bool(true)
1
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);
    }
}
1
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));
?>
1
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
1
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"
1
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);
1
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);
1
2
3

结果

Array
(
    [name] => John
)
1
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
1
2
3

# 3.ereg()

ereg 函数是 PHP 中用于执行正则表达式匹配的函数之一,但**自 PHP 5.3.0 版本起已被废弃。**建议使用 preg_match 函数来代替
ereg()函数会被%00截断

最后一次更新于: 2024/10/31, 18:45:07