1.漏洞复现
PbootCMS 3.0.4,下载仓库 · 星梦/PbootCMS - Gitee.com
复现
漏洞页面:http://127.0.0.1/?search 或 http://127.0.0.1/?keyword
POST请求:1=select 1
2.正向分析
从可见功能点正向分析
index.php
代码语言:javascript复制...
// 引用内核启动文件
require dirname(__FILE__) . '/core/start.php';
/core/start.php
代码语言:javascript复制...
// 启动内核
corebasicKernel::run();
/core/basic/Kernel.php
加密了,之后调用 IndexController类 的 _empty方法
代码语言:javascript复制...
* 翱云科技版权所有,未经许可擅自破解本文件将依法追究法律责任。
...
/apps/home/controller/IndexController.php
在 _empty方法 的开头添加:
代码语言:javascript复制// 空拦截器, 实现文章路由转发
public function _empty()
{
var_dump(debug_backtrace());
访问主页,可以知道是 Kernel.php 调用的
代码语言:javascript复制array(4) {
[0]=>
array(7) {
["file"]=>
string(108) "D:environmentphpstudy_proWWWPbootCMS-V3.0.4corebasicKernel.php(10) : eval()'d code(1) : eval()'d code"
["line"]=>
int(2)
通过对 search 或 keyword 进行 GET请求 都可以调用 SearchController类 的 index方法
代码语言:javascript复制// 空拦截器, 实现文章路由转发
public function _empty()
{ ...
// 路由
switch ($param[0]) {
case 'search':
case 'keyword':
$search = new SearchController();
$search->index();
break;
/apps/home/controller/SearchController.php
调用了 ParserController类 的 parserSearchLabel方法
代码语言:javascript复制class SearchController extends Controller
{
...
public function __construct()
{
$this->parser = new ParserController();
...
}
...
public function index()
{
...
$content = $this->parser->parserSearchLabel($content); // 搜索结果标签
ParserController类
/apps/home/controller/ParserController.php
代码语言:javascript复制class ParserController extends Controller
{
...
public function __construct()
{
$this->model = new ParserModel();
}
...
// 解析内容搜索结果标签
public function parserSearchLabel($content)
{
...
// 数据接收
if ($_POST) {
$receive = $_POST;
} else {
$receive = $_GET;
}
foreach ($receive as $key => $value) {
if (! ! $value = request($key, 'vars')) {
...
$where3[$key] = $value;
...
}
}
// 去除特殊键值
unset($where3['keyword']);
...
$data = $this->model->getLists($scode, $num, $order, $where1, $where2, $where3, $fuzzy, $start, $lfield, $lg);
页面中的搜索框是对 keyword 进行 GET请求 的,但是如果用 keyword 请求,变量会被销毁
所以要自己进行 POST请求(1=select 1),请求会被 request函数 处理后赋值给 $where3,然后处理 SQL语句
/core/function/helper.php
request函数
代码语言:javascript复制function request($name, $type = null, $require = false, $vartext = null, $default = null)
{
if (isset($_POST[$name])) {
$d_source = 'post';
} else {
$d_source = 'get';
}
$condition = array(
'd_source' => $d_source,
'd_type' => $type,
'd_require' => $require,
$name => $vartext,
'd_default' => $default
);
return filter($name, $condition);
}
设置了一个数组,然后通过 filter函数 进行过滤
代码语言:javascript复制array(5) {
["d_source"]=>
string(4) "post"
["d_type"]=>
string(4) "vars"
["d_require"]=>
bool(false)
[1]=>
NULL
["d_default"]=>
NULL
}
filter函数
代码语言:javascript复制function filter($varname, $condition)
{
...
$vartext = $varname;
...
// 数据源
if (array_key_exists('d_source', $condition)) {
switch ($condition['d_source']) {
case 'post':
$data = @$_POST[$varname];
break;
...
// 数据类型检测
if (array_key_exists('d_type', $condition)) {
switch ($condition['d_type']) {
...
case 'vars':
if (! preg_match('/^[x{4e00}-x{9fa5}w-.,s] $/u', $data)) {
$err = '只能包含中文、字母、数字、横线、点、逗号、空格!';
}
break;
...
// 返回收据
return escape_string($data);
}
就是,并且data 只能包含中文、字母、数字、横线、点、逗号、空格,然后通过 escape_string函数 进行过滤
/core/function/handle.php
escape_string函数
Copy
代码语言:javascript复制// 获取转义数据,支持字符串、数组、对象
function escape_string($string)
{
...
$string = htmlspecialchars(trim($string), ENT_QUOTES, 'UTF-8');
$string = addslashes($string);
...
return $string;
}
对 select 1 用 htmlspecialchars函数 和 addslashes函数 进行了转义
ParserModel类
/apps/home/model/ParserModel.php
getLists方法
数据过滤完之后通过 ParserModel类 的 getLists方法 处理 SQL语句
代码语言:javascript复制// 列表内容,带分页,不区分语言,兼容跨语言
public function getLists($scode, $num, $order, $filter = array(), $tags = array(), $select = array(), $fuzzy = true, $start = 1, $lfield = null, $lg = null)
{
...
return parent::table('ay_content a')->field($fields)
...
->where($select, 'AND', 'AND', $fuzzy)
...;
}
就在select数组 中,通过 where方法 进行了 SQL语句 拼接操作
Model类
/core/basic/Model.php
where方法
在 return 上面添加,看看最终的 SQL语句 是什么:
代码语言:javascript复制final public function where($where, $inConnect = 'AND', $outConnect = 'AND', $fuzzy = false)
{
...
var_dump($this->sql['where']);
return $this;
}
看到注入的 SQL语句 拼接到了最后
代码语言:javascript复制string(143) "WHERE(a.scode in ('5','6','7') OR a.subscode='5') AND(a.status=1 AND d.type=2 AND a.date<'2023-05-05 14:09:11' AND a.acode='cn' ) AND(select 1)"
本文为免杀三期学员笔记:https://www.cnblogs.com/Night-Tac/articles/17372836.html