Notice
前两篇直接站内搜索即可
定向功能点审计
更像是黑盒白盒的结合体,通过去浏览网站的功能,对可能存在问题的功能点的代码进行审计,检查是否存在问题。例如,发表留言、发送站内信这些功能,比较容易产生跨站脚本漏洞,审计时可以优先关注php代码中,数据在输入输出时是否有被html编码,如果没有,那就看下,有没有xss代码过滤,如果两者都没有,那很大可能就存在xss,如果有xss过滤,则可以通过分析过滤了那些特殊字符或关键字,如果能找到没有过滤的关键字,就能绕过过滤。前面分析框架运行流程时,对控制器和模型的存放位置,以及调用方式都有所了解,但mvc,除了m和c,还有个v。视图解析,这个贯穿全局的功能,一般情况下是不太容易出问题,但如果存在二次解析,那出现漏洞的概率就要高上不少。
还是跟着文章中跟一遍
思路是选取一个功能点作为切入点,一步步定位到模板解析类,例如,首页。
直接在系统函数库中定位 template
$template_cache = pc_base::load_sys_class('template_cache');
在这里加载模板缓存类
到/caches/caches_template/下找模版
$compiledtplfile如果存在,直接取出路径返回,如果不存在就用template_compile函数编译好模板再返回
继续跟进template_compile 类在template_cache.class.php
调用template_parse来解析内容
可以看到解析代码非常的多 一般直接解析成php我们都不会关注,因为不可控
把注意力放在,那些将解析后的结果交给其他方法再进行一次处理的的解析规则上。
91行,93行。91行将从模板中匹配到交给$this->addquote进行处理,但$this->addquote方法仅仅是将传入的内容再转义一下,没什么特别的地方
看93行处的self::pc_tag方法。
case 'block':
$str .= '$block_tag = pc_base::load_app_class(\'block_tag\', \'block\');';
$str .= 'echo $block_tag->pc_tag('.self::arr_to_html($datas).');';
break;
当上述生成的模板缓存被包含时,会去调用应用类block_tag的pc_tag方法,跟进block_tag->pc_tag方法。
把查询结果变成变量,继续走string2array 这里面的$data是模版中的 所以我们并不可控
走进template_url函数
如果$template的值为空,则根据$id到数据库中取出template字段的内容,并写入/caches/caches_template/block/$id.php文件中,如果能同时控制$id和$template,或者能控制数据库中的内容,就可以构造一个恶意文件,然后利用上面的pc标签解析功能包含该文件,实现代码执行
if ($template) {
if(!is_dir($dir)) {
mkdir($dir, 0777, true);
}
$tpl = pc_base::load_sys_class('template_cache');
$str = $tpl->template_parse(new_stripslashes($template));
@file_put_contents($filepath, $str);
} else {
if (!file_exists($filepath)) {
if(!is_dir($dir)) {
mkdir($dir, 0777, true);
}
$tpl = pc_base::load_sys_class('template_cache');
$str = $this->db->get_one(array('id'=>$id), 'template');
$str = $tpl->template_parse($str['template']);
@file_put_contents($filepath, $str);
}
}
return $filepath;
}
在self::pc_tag方法中将$data按照116行的正则再进行一次提取,将提取的结果通过循环,写到$datas数组中。所以,pc标签的格式应该为{pc:xx xx=xx}。
当$op等于block时,将前面提取的$datas传入arr_to_html方法,转成array(key=>value)这种格式,然后生成以下代码。所以,如果想进入以下分支,pc标签的格式应该为{pc:block xx=xx}。
跟进$block_tag->tag方法
将$data[‘pos’]带入数据库查询,如果结果为空,就不会进入到包含点。所以,pc标签的格式应该为{pc:block pos=xx},通过搜索pc标签找到相关触发点。
利用phpstorm的全局搜索 成功找到在link
link模块的index控制器中找到的register方法。
但仅有触发点还不够,前面提到,被包含的文件的内容从数据库中获取,所以还需要找到一个讲恶意代码写入数据库的点,或者找一处调用了block_tag->template_url方法的点,但id和template参数需可控。如果想找写入数据库的点,可以优先到与block_tag类位于同一个模块的block_admin类下找。
在block_update方法中执行了update操作,还会将template写入数据库,同时template还是从post传入。146行处虽然有调用template_url方法,但$id并不可控,原因是,在128行将id带入到数据库中查询,如果查询结果为空,则不会进入到下面的操作。而id在数据库中是递增的,未必能控制在[1、2、3]中。
先利用add方法添加一条记录,然后利用block_update将恶意代码写入数据库,最后通过访问相关页面触发pc标签解析,生成并包含恶意文件。
后记
文章难度对初学者难度偏高,加上文章内的cms版本过老,所以明白大概方法回溯过程即可