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去添加管理员

image-20240920160437816

后台RCE

后台RCE的最后点在htdocs/core/lib/functions.lib.phpdol_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代码虽然是可控的,但是是从数据库中查询的结果中获取的

关注permsenable,这两个都是可以直接进入verifCond的

image-20240920180748557

我们去前面看看这里执行的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函数的时候都是把写死的值填进去

image-20240923102911597

所以我们如果能找到一个INSERT进".MAIN_DB_PREFIX."menu中、可以控制permsenable字段并且entitymenu_handler能满足WHERE条件的语句即可,这里注意entity来源于$conf->entity

INSERT\s+INTO\s+"\.MAIN_DB_PREFIX\."menu

image-20240923102303827

的确存在这么个点,在同一个文件的create()函数

接下来得看看参数是否可控,这里的VALUES设定为成员属性,但是entity是$conf->entity,这里就直接满足了上面的where条件

所以这两个WHERE条件都解决了,剩下就是看permsenable是否可控了,在类内部没看到有对成员变量赋值的地方,所以还得全局搜索一下

发现permsenablemenus/edit.php中都是可以直接控制的,这个menu对象就是刚刚的那个类$menu = new Menubase($db)

image-20240923104703431

经过调试发现,这里menuId需要唯一否则会冲突无法写入数据库,这里的type需要设置为1,否则也会报错

image-20240923110647678

这个文件也是未授权的,可以直接构造调用到这里

接下来就可以研究一下,如何去绕过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"

image-20240923112537623

这样就会走入下面的这个判断,看注释这里的正则就是为了防止RCE而设计的

image-20240923112616995

一个是dol_eval函数的加强,这里forbiddenphpfunctions里添加了verifCond函数,直接禁止了verifCond的执行

image-20240923112658086

跟了一遍,几乎是转载了:https://blog.huamang.xyz/post/cve-2022-40871/#%E5%90%8E%E5%8F%B0rce

0%