引言
2021.06 百灵鸟团队纳新玩家活动
2021年6月27日,新的纳新玩家活动开始了,还是渗透测试题。如果您成功拿下目标,请第一时间联系对应的邮箱。关于团队申请方式及后期活动都在附件中有说明。
目标地址:119.45.4.159
任务获取目标服务器中“Hi RedTeam”文件内容,即可(“Hi RedTeam”是文件名,强调是文件名)。【截止日期2021年7月4日】
上个月底某天刷着说说,正好看到有师傅转发了这个活动。
寻思着那几天摸鱼比较有空,来随便玩了玩,这里也就简单记录一下。
步骤
目标靶机地址:http://119.45.4.159/
(现在应该关了
用的是 Bludit 这个 CMS. (GitHub repo)
fscan 一下
# ./fscan -h 119.45.4.159
___ _
/ _ \ ___ ___ _ __ __ _ ___| | __
/ /_\/____/ __|/ __| '__/ _` |/ __| |/ /
/ /_\\_____\__ \ (__| | | (_| | (__| <
\____/ |___/\___|_| \__,_|\___|_|\_\
fscan version: 1.6.2
start infoscan
(icmp) Target '119.45.4.159' is alive
icmp alive hosts len is: 1
119.45.4.159:888 open
119.45.4.159:21 open
119.45.4.159:22 open
119.45.4.159:80 open
119.45.4.159:8888 open
alive ports len is: 5
start vulscan
[*] WebTitle:http://119.45.4.159:888 code:403 len:262 title:403 Forbidden
[*] WebTitle:http://119.45.4.159:8888 code:302 len:219 title:Redirecting...
[*] WebTitle:http://119.45.4.159 code:200 len:27 title:欢迎使用Bludit | BLUDIT
[*] WebTitle:http://119.45.4.159:8888/login code:200 len:24 title:安全入口校验失败
[+] InfoScan:http://119.45.4.159:8888/login 宝塔-BT.cn
已完成 5/5
scan end
8888 端口有个 删库 宝塔,不过日不起来。
dirsearch 发现 80 端口主站有备份文件泄露。
下载下来。
\bl-content\databases\users.php
<?php defined('BLUDIT') or die('Bludit CMS.'); ?>
{
"admin": {
"nickname": "Admin",
"firstName": "\u7ba1\u7406\u5458",
"lastName": "",
"role": "admin",
"password": "0b6142813f850401af6f2dc79e0e54ca11e8ebde",
"salt": "60d801bb12cea",
"email": "",
"registered": "2021-06-27 12:42:35",
"tokenRemember": "",
"tokenAuth": "2ffb21608fe6d91865de3ea1ff3366a3",
"tokenAuthTTL": "2009-03-15 14:00",
"twitter": "",
"facebook": "",
"instagram": "",
"codepen": "",
"linkedin": "",
"github": "",
"gitlab": ""
}
}
到 https://www.somd5.com/ 解密一下
得到密码为 redteam
。
登录进入后台。
版本信息
当然,通过 CSS 等也可以知道版本信息为 3.12.0
根据 GitHub 上的 Bludit v3.13.0,发现果然有洞,修了个文件上传的漏洞。
根据 https://github.com/bludit/bludit/issues/1218
好家伙,是尖尖师傅挖的洞!
然后发现他把 uploadBackup 这个函数都删了……
这路走不通。
再搜了一下还有不少 XSS 的洞,也没啥用。
看源码,文件上传都有拓展名的过滤,3.13.0 版本新增了 Mime type 校验,也没啥用。
再看插件,发现有个插件 Remote Content 可以下载文件。
This plugin provides an easy way to have the content of your site on Github or similar and in turn is synchronized with your Bludit.
源码路径在 backup\bl-plugins\remote-content\plugin.php
关键源码如下。
public function beforeAll()
{
// Check Webhook
$webhook = $this->getValue('webhook');
if ($this->webhook($webhook)) {
$this->cleanUp();
// Download files
$this->downloadFiles();
// Delete the current content
$this->deleteContent();
// Generate the new content
$this->generateContent();
// End request
$this->response(array('status'=>'0'));
}
}
private function downloadFiles()
{
// Download the zip file
Log::set('Plugin Remote Content'.LOG_SEP.'Downloading the zip file.');
$source = $this->getValue('source');
$destinationPath = $this->workspace();
$destinationFile = $destinationPath.'content.zip';
TCP::download($source, $destinationFile);
// Uncompress the zip file
Log::set('Plugin Remote Content'.LOG_SEP.'Uncompress the zip file.');
$zip = new ZipArchive;
if ($zip->open($destinationFile)===true) {
$zip->extractTo($destinationPath);
$zip->close();
}
// Delete the zip file
unlink($destinationFile);
return true;
}
// Delete the page and uploads directories from bl-content
private function deleteContent()
{
// Clean the page database
global $pages;
$pages->db = array();
Filesystem::deleteRecursive(PATH_PAGES);
Filesystem::deleteRecursive(PATH_UPLOADS);
mkdir(PATH_PAGES, DIR_PERMISSIONS, true);
mkdir(PATH_UPLOADS, DIR_PERMISSIONS, true);
mkdir(PATH_UPLOADS_PROFILES, DIR_PERMISSIONS, true);
mkdir(PATH_UPLOADS_THUMBNAILS, DIR_PERMISSIONS, true);
return true;
}
private function cleanUp()
{
$workspace = $this->workspace();
Filesystem::deleteRecursive($workspace.DS);
mkdir($workspace, DIR_PERMISSIONS, true);
return true;
}
private function generateContent()
{
global $pages;
$root = Filesystem::listDirectories($this->workspace());
$root = $root[0]; // first directory created by the unzip
// For each page inside the pages directory
// Parse the page and add to the database
if (Filesystem::directoryExists($root.DS.'pages')) {
$parentList = Filesystem::listDirectories($root.DS.'pages'.DS);
foreach ($parentList as $parentDirectory) {
$parentKey = basename($parentDirectory);
if (Filesystem::fileExists($parentDirectory.DS.'index.md')) {
$row = $this->parsePage($parentDirectory.DS.'index.md');
$row['slug'] = $parentKey;
$pages->add($row);
}
$childList = Filesystem::listDirectories($parentDirectory.DS);
foreach ($childList as $childDirectory) {
$childKey = basename($childDirectory);
if (Filesystem::fileExists($childDirectory.DS.'index.md')) {
$row = $this->parsePage($childDirectory.DS.'index.md');
$row['slug'] = $childKey;
$row['parent'] = $parentKey;
$pages->add($row);
}
}
}
Theme::plugins('afterPageCreate');
reindexCategories();
reindexTags();
}
return true;
}
就利用 backup.zip
,随便 echo 个东西。
在自己 VPS 上把这个压缩包放好,起个 web 服务。
Source
就填 VPS 上文件的地址。
访问 http://119.45.4.159/bacw 触发。
而后在 http://119.45.4.159/bl-content/workspaces/remote-content/index.php 就看到这个 233 了。说明有戏。
再写个一句话木马上去。
蚁剑成功连上!
同理,冰蝎也可。
然而反弹 shell 没有回显啊……
另外也限制了能访问的目录。
发现有个 .user.ini
里设置了 open_basedir
.
参考 php文件包含目录配置open_basedir的使用与性能分析
open_basedir 将php所能打开的文件限制在指定的目录树中,包括文件本身。当程序要使用例如fopen()或file_get_contents()打开一个文件时,这个文件的位置将会被检查。当文件在指定的目录树之外,程序将拒绝打开。
把这个 .user.ini
重命名,然后就能不受这个限制,访问其他目录啦。
然而 disable_functions 貌似绕不来啊。。
passthru,exec,system,putenv,chroot,chgrp,chown,shell_exec,popen,proc_open,pcntl_exec,ini_alter,ini_restore,dl,openlog,syslog,readlink,symlink,popepassthru,pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,imap_open,apache_setenv
噢,不用绕了……
发现所需要的 Hi RedTeam
文件就在 wwwroot 的另一个目录下。(旁站嘛)
完事~
小结
其实难度还好,就这样吧(
顺便,感谢大师傅出题,师傅们太强啦 Orz!
官方 Writeup 也出来了:
原来还有一种通过 API 上传图片的漏洞来日的方法啊。
(溜了溜了喵~