简介
HadSky轻论坛程序为个人原创PHP系统,作者为蒲乐天,后端基于puyuetianPHP框架驱动,前端基于 puyuetianUI框架驱动,默认编辑器为puyuetianEditor富文本编辑器,其他非原创框架及驱动JQuery.js 及Font-Awesome字体库,前后端框架以及编辑器都由作者自研,使用此框架进行开发的系统还有 Yodati答题系统、JvHuo聚货网等。
路由分析
查看入口文件index.php
发现其包含了一个puyuetian.php的文件,跟进看看
发现前台路由文件,跟进一下
阅读代码可知其通过get传入c参数来控制路由,如果不传入该参数,则默认访问phpscript目录下 main.php,否则包含phpscript目录下相应文件实现相应功能。
后台路由在/admin/index.php为入口文件
这里的app其实代表app文件夹, superadmin:index则表示superadmin文件夹下的index.php文件,这样路由就定位到该php文件
这里传递另一个参数 s 来控制调用后台的某些功能点
任意文件写入
全局搜索file_put_contents
这里我们文件内容可控,现在看看哪调用了file_put_contents
switch ($type) {
case 'edit' :
if (filetype($path) != 'file') {
if ($_G['GET']['JSON']) {
ExitJson('不存在的文件');
}
PkPopup('{content:"不存在的文件",icon:2,shade:1,hideclose:1,submit:function(){location.href="index.php?c=app&a=filesmanager:index&path="}}');
}
$suffix = substr($path, strrpos($path, '.') + 1);
if (!InArray($suffixs, $suffix)) {
if ($_G['GET']['JSON']) {
ExitJson('不支持的文件格式');
}
PkPopup('{content:"不支持的文件格式",icon:2,shade:1,hideclose:1,submit:function(){location.href="index.php?c=app&a=filesmanager:index&path="}}');
}
$filecontent1 = file_get_contents($path);
$filecontent = htmlspecialchars($filecontent1, ENT_QUOTES);
if ($filecontent1 && !$filecontent) {
if ($_G['GET']['JSON']) {
ExitJson('不支持该文件编码,仅支持UTF-8');
}
PkPopup('{content:"不支持该文件编码,仅支持UTF-8",icon:2,shade:1,hideclose:1,submit:function(){location.href="index.php?c=app&a=filesmanager:index&path="}}');
}
if ($_G['GET']['JSON']) {
ExitJson($filecontent1, TRUE);
}
$path = str_replace('\\', '/', $path);
$paths = explode('/', $path);
$path = '';
for ($i = 0; $i < count($paths); $i++) {
if ($i == count($paths) - 1) {
$filename = $paths[$i];
} else {
$path .= $paths[$i] . '/';
}
}
ExitGourl('index.php?c=app&a=filesmanager:index&path=' . urlencode(realpath($path)) . '&editbtn=' . md5($filename));
break;
case 'save' :
if (filetype($path) != 'file') {
ExitJson('不存在的文件');
}
$suffix = substr($path, strrpos($path, '.') + 1);
if (!InArray($suffixs, $suffix)) {
ExitJson('不支持的文件格式');
}
$r = file_put_contents($path, $_POST['filecontent']);
ExitJson('保存失败:' . $path, $r);
break;
这里有个switch语句,需要$type=save
这里我们也是可控
再看看$path
这里的path参数有 realpath() 函数包裹和下面代码进行限制,以至于这个点不能直接创建新文件,而只能将任意内容写到存在的php文件中
如果不想覆盖原有php文件其实还可以通过先创建php文件再将文件内容写入到创建的文件中,代码如 下: 通过$type=mkfile,并且传入 mkname 参数即可创建文件,这样我们就可以通过创建的文件进行文件内容的写入
漏洞复现
之所以会说保存错误,是因为这给关键代码并没有被限制
任意文件读取
全局搜索file_get_contents
当$type=edit时会调用file_get_contents函数读取文件内容,而且当我们GET传入json参数时,就会进入ExitJson函数中,该函数将我们读取到的内容通过 json形式进行回显
漏洞复现
文件上传getshell
通过上传.zip压缩包然后自动解压缩来进行模板部署,而且这里可能会检测压缩包中内容是否合法,如果这里检测不完善或者该处压缩包可以伪造的话,那么大概率我们可以通过上传压缩文件来绕过该处的后缀检测,从而上传我们想要上传的文件。
定位文件app\superadmin\phpscript\app.php
这里就是上传zip文件的代码,可以看到这里代码121行的后缀白名单,然后通过ZipArchive class(php自带类库,可以对文件进行压缩与解压缩处理) 下的open方法打开压缩文件;然你通过ZipArchive::extractTo()方法将.zip文件解压到根目录。在此过程 中,并没有对解压后的文件进行后缀的校验
漏洞复现
上传一个php文件的压缩包