0x00 前言
审计出三个漏洞
1.SQL时间盲注漏洞
2.后台GetShell
3.鸡肋本地包含漏洞
0x01 CMS介绍
官网地址:http://www.gxlcms.com/
Gxlcms有声小说系统是一件采集快速建立一个听书站。用PHP写的,最新版要求PHP>5.4。使用了THINKPHP框架。
源码下载地址:http://bbs.gxlcms.com/article/1
0x03 SQL盲注
漏洞文件:Lib\Home\Action\UpdownAction.class.php
漏洞代码:show函数
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
| public function show($id,$type,$model='ting'){ $rs = D(ucfirst($model)); if($type){ $cookie = $model.'-updown-'.$id; if(isset($_COOKIE[$cookie])){ $data['data']=0; $data['info']="您已操作过,晚点再试!"; $data['status']=0; $this->ajaxReturn($data); } if ('up' == $type){ $rs->where(array('ting_id'=>$id))->setInc($model.'_up'); setcookie($cookie, 'true', time()+intval(C('user_second'))); }elseif( 'down' == $type) $rs->where(array('ting_id'=>$id))->setInc($model.'_down'); setcookie($cookie, 'true', time()+intval(C('user_second'))); } } $array = $rs->field(''.$model.'_up,'.$model.'_down')->find($id); if (!$array) { $array[$model.'_up'] = 0; $array[$model.'_down'] = 0; } $arrays['data']=$array[$model.'_up'].':'.$array[$model.'_down']; $arrays['info']="感谢您的参与,操作成功!"; $arrays['status']=1; $this->ajaxReturn($arrays); }
|
这套CMS使用了THINKPHP框架(自带SQL防注入功能),但是还是存在SQL注入。首先来看下这个函数,这个函数有三个变量:id,type,model。$id经过where方法,而最终经过THINKPHP框架只的parseValue,对单引号进行过滤的。$type,只是进行一个if判断,没有进入mysql语句中。最终出现问题的是出现在$model变量上。
field中调用了$model变量,不过没对$model变量进行过滤,可以进行SQL注入,不过只能进行SQL时间盲注。
可以使用SQLMAP进行注入:
1
| sqlmap --dbms=mysql --technique=T -u "http://127.0.0.1/index.php?s=updown-show--id-1-type-1-model-1*"
|
在以前的老版本中,还有类似的SQL注入,不过新版本修复了。
文件:Lib\Lib\Action\Home\HitsAction.class.php
函数:show()
与上面类似。就不贴代码了。
0x04 后台GetShell
漏洞文件:Lib\Admin\Action\AdminAction.class.php
漏洞函数:configsave()
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 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
| public function configsave() { $config = $_POST["config"]; $config["site_tongji"] = stripslashes($config["site_tongji"]); $config["play_collect_content"] = stripslashes($config["play_collect_content"]); $config["admin_time_edit"] = (bool) $config["admin_time_edit"]; $config["url_tingdata"] = trim($config["url_tingdata"]); $config["url_newsdata"] = trim($config["url_newsdata"]); $config["upload_path"] = str_replace(array("..", "//"), "", $config["upload_path"]); $config["upload_class"] = trim(str_replace(array("php", "asp", "apsx", "txt", "asax", "ascx", "cdx", "cer", "cgi", "jsp", "html", "html", "htm", ",,"), "", strtolower($config["upload_class"])), ","); $config["upload_thumb"] = (bool) $config["upload_thumb"]; $config["upload_water"] = (bool) $config["upload_water"]; $config["upload_http"] = (bool) $config["upload_http"]; $config["upload_ftp"] = (bool) $config["upload_ftp"]; $config["play_collect"] = (bool) $config["play_collect"]; $config["play_second"] = intval($config["play_second"]); $config["tmpl_cache_on"] = (bool) $config["tmpl_cache_on"]; $config["html_cache_on"] = (bool) $config["html_cache_on"]; $config["user_gbcm"] = (bool) $config["user_gbcm"];
foreach (explode(chr(13), trim($config["play_server"])) as $v ) { list($key, $val) = explode("$\$\$", trim($v)); $arrserver[trim($key)] = trim($val); }
$config["play_server"] = $arrserver;
foreach (explode(chr(13), trim($config["play_collect_content"])) as $v ) { $arrcollect[] = trim($v); }
$config["play_collect_content"] = $arrcollect; $config["html_cache_time"] = $config["html_cache_time"] * 3600;
if (0 < $config["html_cache_index"]) { $config["html_cache_rules"]["home:index:index"] = array("{:action}", $config["html_cache_index"] * 3600); } else { $config["html_cache_rules"]["home:index:index"] = NULL; }
if (0 < $config["html_cache_list"]) { $config["html_cache_rules"]["home:ting:show"] = array("{:controller}_{:action}/{\$_SERVER.REQUEST_URI|md5}", $config["html_cache_list"] * 3600); $config["html_cache_rules"]["home:news:show"] = array("{:controller}_{:action}/{\$_SERVER.REQUEST_URI|md5}", $config["html_cache_list"] * 3600); } else { $config["html_cache_rules"]["home:ting:show"] = NULL; $config["html_cache_rules"]["home:news:show"] = NULL; }
if (0 < $config["html_cache_content"]) { $config["html_cache_rules"]["home:ting:read"] = array("{:controller}_{:action}/{name|get_small_id_by_name}{id|get_small_id}/{name|gettingidmd}{id|getmd5}", $config["html_cache_content"] * 3600); $config["html_cache_rules"]["home:news:read"] = array("{:controller}_{:action}/{\$_SERVER.REQUEST_URI|md5}", $config["html_cache_content"] * 3600); } else { $config["html_cache_rules"]["home:ting:read"] = NULL; $config["html_cache_rules"]["home:news:read"] = NULL; }
if (0 < $config["html_cache_play"]) { $config["html_cache_rules"]["home:ting:play"] = array("{:controller}_{:action}/{name|get_small_id_by_name}{id|get_small_id}/{name|gettingid}{id}/{\$_SERVER.REQUEST_URI|md5}", $config["html_cache_play"] * 3600); } else { $config["html_cache_rules"]["home:ting:play"] = NULL; }
if (0 < $config["html_cache_ajax"]) { $config["html_cache_rules"]["home:my:show"] = array("{:controller}_{:action}/{\$_SERVER.REQUEST_URI|md5}", $config["html_cache_ajax"] * 3600); $config["html_cache_rules"]["home:special:read"] = array("{:controller}_{:action}/{\$_SERVER.REQUEST_URI|md5}", $config["html_cache_ajax"] * 3600); } else { $config["html_cache_rules"]["home:my:show"] = NULL; $config["html_cache_rules"]["home:special:read"] = NULL; }
if (0 < $config["html_cache_juqing"]) { $config["html_cache_rules"]["home:story:read"] = array("{:controller}_{:action}/{name|get_small_id_by_name}{id|get_small_id}/{name|gettingid}{id}/{name|gettingidmd}{id|getmd5}{p}", $config["html_cache_juqing"] * 24 * 3600); } else { $config["html_cache_rules"]["home:story:read"] = NULL; }
if (0 < $config["html_cache_story"]) { $config["html_cache_rules"]["home:story:show"] = array("{:controller}_{:action}/{dir|gediridmd}{id|getmd5}{p}", $config["html_cache_juqing"] * 3600); } else { $config["html_cache_rules"]["home:story:show"] = NULL; }
if (0 < $config["html_cache_actorshow"]) { $config["html_cache_rules"]["home:actor:show"] = array("{:controller}_{:action}/{\$_SERVER.REQUEST_URI|md5}", $config["html_cache_actorshow"] * 3600); } else { $config["html_cache_rules"]["home:actor:show"] = NULL; }
if (0 < $config["html_cache_actor"]) { $config["html_cache_rules"]["home:actor:read"] = array("{:controller}_{:action}/{name|get_small_id_by_name}{id|get_small_id}/{name|gettingidmd}{id|getmd5}", $config["html_cache_actor"] * 24 * 3600); } else { $config["html_cache_rules"]["home:actor:read"] = NULL; } if (0 == $config["url_html"]) { @unlink("./index" . C("html_file_suffix")); } else { $config["html_home_suffix"] = $config["html_file_suffix"]; }
$config_old = require "./Runtime/Conf/config.php"; $config_new = array_merge($config_old, $config); arr2file("./Runtime/Conf/config.php", $config_new); @unlink("./Runtime/common~runtime.php"); $gxl_play .= "var gxl_root=\"" . $config["site_path"] . "\";"; $gxl_play .= "var gxl_width=" . $config["play_width"] . ";"; $gxl_play .= "var gxl_height=" . $config["play_height"] . ";"; admin_gxl_hot_key(C("site_hot")); $this->success("恭喜您,配置信息更新成功!"); }
|
与函数对应的后台功能截图

主要是看这个设置附件上传类型,危害很明显。但这里不能直接添加php后缀,因为有过滤,把”php”, “asp”, “apsx”, “txt”, “asax”, “ascx”, “cdx”, “cer”, “cgi”, “jsp”, “html”, “html”, “htm”等后缀都过滤掉。把这些字符替换为空。这样就很容易绕过了,添加pphphp,就可以绕过。但是,在上传处,还有一次过滤。
漏洞文件:Lib\Admin\Action\UploadAction.class.php
漏洞函数:upload()
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 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| public function upload() { echo "<div style=\"font-size:12px; height:30px; line-height:30px\">"; $uppath = "./" . str_replace(array("..", "//"), "", C("upload_path")) . "/"; $uppath_s = "./" . str_replace(array("..", "//"), "", C("upload_path")) . "-s/"; $sid = trim($_POST["sid"]); $fileback = (!empty($_POST["fileback"]) ? trim($_POST["fileback"]) : "ting_pic");
if ($sid) { $uppath .= $sid . "/"; $uppath_s .= $sid . "/"; mkdirss($uppath); mkdirss($uppath_s); }
$up = new \Org\Net\UploadFile(); $up->savePath = $uppath; $up->saveRule = uniqid; $up->uploadReplace = true; $upload_class = str_replace(array("php", "asp", "apsx", "txt", "asax", "ascx", "cdx", "cer", "cgi", "jsp", "html", "html", "htm", ",,"), "", strtolower(C("upload_class"))); $upload_classs = trim($upload_class, ","); $up->allowExts = explode(",", $upload_classs); $up->autoSub = true; $up->subType = date; $up->dateFormat = C("upload_style");
if (!$up->upload()) { $error = $up->getErrorMsg();
if ($error == "上传文件类型不允许") { $error .= ",可上传<font color=red>" . $upload_classs . "</font>"; }
exit($error . " [<a href=\"?s=Admin-Upload-Show-sid-" . $sid . "-fileback-" . $fileback . "\">重新上传</a>]"); }
$uploadList = $up->getUploadFileInfo();
if (C("upload_water")) { $image = new \Think\Image(); $image->open($uppath . $uploadList[0]["savename"])->water(C("upload_water_img"), C("upload_water_pos"), C("upload_water_pct"))->save($uppath . $uploadList[0]["savename"]); }
if (C("upload_thumb")) { $thumbdir = substr($uploadList[0]["savename"], 0, strrpos($uploadList[0]["savename"], "/")); mkdirss($uppath_s . $thumbdir); $image = new \Think\Image(); $image->open($uppath . $uploadList[0]["savename"]); $image->thumb(C("upload_thumb_w"), C("upload_thumb_h"), C("upload_thumb_pos"))->save($uppath_s . $uploadList[0]["savename"]); }
if (C("upload_ftp")) { $img = D("Img"); $img->ftp_upload($sid . "/" . $uploadList[0]["savename"]); }
echo "<script type='text/javascript'>parent.document.getElementById('" . $fileback . "').value='" . $sid . "/" . $uploadList[0]["savename"] . "';</script>"; echo "文件上传成功 [<a href=\"?s=Admin-Upload-Show-sid-" . $sid . "-fileback-" . $fileback . "\">重新上传</a>]"; echo "</div>"; }
|
这里把”php”, “asp”, “apsx”, “txt”, “asax”, “ascx”, “cdx”, “cer”, “cgi”, “jsp”, “html”, “html”, “htm”这些字符再次过滤为空。
一共过滤两次,所以在添加附件后缀里添加phcdcdxx,后缀就可以了,就可以直接上传拿到shell了。
0x05 鸡肋本地包含漏洞
为什么鸡肋尼?只能包含.html的文件,这个漏洞只能配合后台修改模板后台Getshell(而且只限于老版本)。
漏洞文件:Lib\Action\Home\MapAction.class.php
漏洞函数:show()
1 2 3 4 5 6 7
| public function show(){ $mapname = !empty($_GET['id']) ? trim($_GET['id']):'rss'; $limit = !empty($_GET['limit']) ? intval($_GET['limit']):30; $page = !empty($_GET['p']) ? intval($_GET['p']) : 1; $this->assign('list_map',$this->Lable_Maps($mapname,$limit,$page)); $this->display('./Public/maps/'.$mapname.'.html','utf-8','text/xml'); }
|
看控制变量$id,最后用于display()函数中,所以包含的地址是可控的。
所以包含.html后缀的文件,比如:
1
| http://localhost/?s=Map-show-id-..\..\Tpl\defalut\Home\my_top
|
后台还有一个修改模板的功能,编辑之,添一句话,菜刀连之,然Getshell。
