涉及知识点:ereg函数存在00截断的漏洞

zkctf一道代码审计的题,代码如下:

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
31
32
<?php 
include("./flag.php");
show_source(__FILE__);
error_reporting(0);
$a=$_GET['a'];
if(stripos($a,'.'))
{
echo 'Hahahahahaha';
die();
}
$data = @file_get_contents($a,'r');
if($data=="1433223!!!"){
if (isset ($_GET['password']))
{
if (ereg ("^[a-zA-Z0-9]+$", $_GET['password']) === FALSE){
echo 'You password must be alphanumeric';
}else if (strlen($_GET['password']) < 8 && $_GET['password'] > 9999999){
if (strpos ($_GET['password'], '-') !== FALSE)
{
die('Flag: ' . $flag);
}else{
echo('- have not been found');
}
}else{
echo 'Invalid password';
}
}
}else{
echo 'Unhappy!';
}

?>

分析代码得知,要拿到flag需要满足五个条件:
1.$data==1433223!!!
2.isset ($_GET[‘password’],password值存在
3.ereg (“^[a-zA-Z0-9]+$”, $_GET[‘password’]) === FALSE,password值中含有任意字母或数字。
4.strlen($_GET[‘password’]) < 8 && $_GET[‘password’] > 9999999,password的字符长度小于8,且值大于9999999。
5.strpos ($_GET[‘password’], ‘-‘) !== FALSE,在password中存在”-“。

要满足第一个条件$data==1433223!!!,需要再分析代码

1
2
$a=$_GET['a'];
$data = @file_get_contents($a,'r');

可知data的值是通过以只读方式打开名为a的文件,且文件内容为1433223!!!,利用php://input,使a=php://input,该文件内容为post内容,post方式传入1433223!!!即可满足第一个条件。

接着通过get传参满足第二第三个条件,第四个条件password的长度不能大于8,且值要大于999999,我们可以用科学记数法达到这个条件。
最后一个条件在password中存在”-“,看起来很容易达到,但是再结合第三个条件password值中只能含有字母或数字,就知道需要通过别的方法绕过了,通过查询知道ereg函数存在00截断的漏洞,ereg函数在遇到%00会被截断,之后的就不会再判断,所以我们可以把”-“写在%00后面。
综上,我们可以把password的值设为1e9%00-,%00算一个字符,一共5个字符,满足长度小于8的条件

因此get传参:?a=php://input&password=1e9%00-
post传参:1433223!!!
en
得到flag


知识点总结:
show_source : 别名highlight_file() 高亮显示一个文件
stripos — 查找字符串首次出现的位置(不区分大小写)
strpos — 查找字符串首次出现的位置(区分大小写)
file_get_contents — 将整个文件读入一个字符串
isset — 检测变量是否已设置并且非 NULL
ereg — 正则表达式匹配
preg_match — 执行匹配正则表达式

ereg函数有漏洞,可以进行00截断
使用科学记数法可以使字符串长度缩短