PHP中非法参数名问题分析

基础

源代码:

1
2
3
4
5
6
7
8
9
<?php
highlight_file(__FILE__);
error_reporting(0);

$var  = $_REQUEST['D T.'];
var_dump($_REQUEST);

echo '</br>';
echo phpversion();

可以看见这里做了一个传参,参数名为D T. 我们可以试一下传参

/img/PHP-parameter/2.png
可以看见这里将空格和.号做了转义变成了_

同样的我们举例子·

1
2
3
4
5
6
7
8
9
<?php
highlight_file(__FILE__);
error_reporting(0);

$var  = $_REQUEST['D_T.'];
var_dump($_REQUEST);

echo '</br>';
echo phpversion();

明显可以知道,我们无法传入我们需要的参数

那么此时要用到一个phpversion<8的特性:当传入的参数中含有[时,[会被转义成_但是后面的参数就不会被转义 也就是说

/img/PHP-parameter/3.png
可以看见我们传入的参数名是正确的

分析

首先,从php官网查看

/img/PHP-parameter/4.png
发现了这个特性 然后我们去github找到对应的代码
/img/PHP-parameter/1.png

可以看见这里对转义写的很明白了 所以我们在php8中可以预见

/img/PHP-parameter/5.png
后面的点号也被转义了

示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<?php
highlight_file(__FILE__);
error_reporting(0);
$query = $_SERVER['QUERY_STRING'];
if (preg_match('/_|%5f|\.|%2E/i', $query)){
    die('you are a hacker!');
}
$var  = $_REQUEST['D_T_'];
var_dump($_REQUEST);

echo '</br>';
echo phpversion();

这时候,需要你去传入D_T_这个参数,这个时候可以看见

$query = $_SERVER[‘QUERY_STRING’];

对传入的参数也做了限制,无法直接传入_所以我们就可以利用php的特性

/img/PHP-parameter/6.png
从而进行绕过

简单的举个CTF中的例子

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
highlight_file(__FILE__);
error_reporting(0);
$query = $_SERVER['QUERY_STRING'];
if (preg_match('/_|%5f|\.|%2E/i', $query)){
    die('you are a hacker!');


}
$var  = $_REQUEST['D_T.'];
$b  = $_GET['b'];
var_dump($_REQUEST);
if(is_null($var)){
    eval($b);
}else{

    echo '没有成功!';

}
echo '</br>';
echo phpversion();

所以我们的playload就是http://127.0.0.1/1/1.php?D T[=1&b=phpinfo();

/img/PHP-parameter/7.png