1、媒介
不知怎的比来甚是忖量校园糊口,忖量食堂的炒饭。那时会往各类安然bbs上刷刷帖子,喜好看他人写的一些关于安然技能或经验的总结;那时BBS上良多文章标题问题都是:成功渗入XXX,成功拿下XXX。这里便以一篇进侵菲律宾某大年夜学的文章引出文章的主题,我们先简要看一下过程。大年夜学网站利用了名为joomla的开源web法度,(1)青年利用一个joomla已公开的缝隙进进web后台(2)青年利用joomla后台上传限制不严的缺点上传了一个webshell(3)节制主机赠予我国国旗。
本来进侵一台主机如斯等闲,治理员判断给web法度打上安然补丁。治理员的工作是结束了,作为安然从业人员再一想是不是是joomla后台这里可以上传webshell是不是是有标题问题呢,假定joomla后台不克不及上传webshell,是不是是可以削减进侵的可能和损掉。下面进进本文的主题:web后台法度的安然性。
2、简介
国内良多站点都是基于开源论坛、cms搭建的,好比discuz、phpwind、dedecms等。这些法度都是国内开源web法度中的佼佼者,也比较重视安然性。平常平凡大年夜家存眷比较多的是sql注进、xss这些可以直接盗取用户数据的缝隙。网上因为弱口令被进侵的案例数不堪数,别的用户数据泄漏事务时而产生,纯真靠暗码防护的后台被冲破,被社工的可能性愈来愈大年夜。获得一个治理后台暗码后,再连络后台法度的肆意代码履行、文件包含或号令注进等缝隙获得一个shell,盗取用户资料不是甚么难事。此时后台法度的安然性成为一个短板。
Discuz是一款风行的论坛法度,笔者这里就以它的后台法度为例简单阐发一下其安然性,下面直接看一些缝隙案例(Discuz最新版本已打补丁,请用户及时进级到最新版-Discuz! X3.1 R20140101)。
3、案例阐发
Tips:下文提到的$settingnew是discuz后台存储表单数据的变量,后台用户可控。
案例一:用户输进数据过滤逻辑不当
缝隙文件:X3\source\admincp\admincp_setting.php
阐发:
// 1、alice点窜$settingnew['extcredits']非数组
if(is_array($settingnew['extcredits'])) {
foreach($settingnew['extcredits'] as $key => $value) {
// 2、给$settingnew['initcredits'][1]传进phpinfo();,非数组绕过intval转换
$settingnew['initcredits'][$i] = intval($settingnew['initcredits'][$i]);
... 省略 ...
for($i = 1; $i <= 8; $i++) {
// 3、 phpinfo();被赋值给$initformula
$initformula = str_replace('extcredits'.$i, $settingnew['initcredits'][$i], $initformula);
}
// 4、phpinfo()带进eval履行
eval("\$_G['setting']['initcredits'] = round($initformula);");
案例二:二次注进
简单介绍一下二次注进,歹意用户alice在A处传进歹意数据并被存储到数据库,在A处不直接导致安然标题问题;B处援引到A处存储的数据,从而触发安然标题问题。
缝隙文件:X3\source\admincp\admincp_setting.php
阐发:
// 1、alice上传一个图片木马假定为1.gif; alice设置$settingnew['seccodedata']['type']值为1.gif\0:xx(按照图片地址做恰当目次跳转);该值未作任何过滤存进数据库
if($settingnew['seccodedata']['type'] == 0 || $settingnew['seccodedata']['type'] == 2) {
$seccoderoot = 'static/image/seccode/font/en/';
} elseif($settingnew['seccodedata']['type'] == 1) {
$seccoderoot = 'static/image/seccode/font/ch/';
}
缝隙文件:source\module\misc\misc_seccode.php
// 2、$_G['setting']['seccodedata']['type']值来自于数据库,即为1处传进的1.gif\0:xx
if(!is_numeric($_G['setting']['seccodedata']['type'])) {
$etype = explode(':', $_G['setting']['seccodedata']['type']);
if(count($etype) >1) {
// 3、 \0截断获得$codefile为图片小马(也可利用././././多个路径符编制截断)
$codefile = DISCUZ_ROOT.'./source/plugin/'.$etype[0].'/seccode/seccode_'.$etype[1].'.php';
... 省略 ...
if(file_exists($codefile)) {
// 4、图片木马被include获得webshell
@include_once $codefile;
案例三:法度进级新增逻辑导致的缝隙
缝隙文件:X3\source\admincp\admincp_adv.php
// 1、alice上传一个图片木马假定为1.gif; alice传进type参数值为1.gif\0:xx(按照图片地址做恰当目次跳转)
$type = $_GET['type'];
... ...
if($type) {
//2、获得$etype为1.gif\0
$etype = explode(':', $type);
if(count($etype) >1) {
//3、$advfile值被\0截断,为图片木马路径1.gif
$advfile = DISCUZ_ROOT.'./source/plugin/'.$etype[0].'/adv/adv_'.$etype[1].'.php';
$advclass = 'adv_'.$etype[1];
}
... 省略 ...
//4、包含图片木马,获得webshell
if(file_exists($advfile)) {
require_once $advfile;
对比下X2.5版本的逻辑,此处缝隙美满是因为新增代码导致的。
$type = $_GET['type'];
$target = $_GET['target'];
$typeadd = '';
if($type) {
$advfile = libfile('adv/'.$type, 'class');
if(file_exists($advfile)) {
require_once $advfile;
案例四:缝隙修补不完美
缝隙文件:X3\api\uc.php
阐发:
//1、config_ucenter.php内容部门截取以下:define('UC_API', 'http://localhost/bbs/uc_server');
$configfile = trim(file_get_contents(DISCUZ_ROOT.'./config/config_ucenter.php'));
... ...
//2、$UC_AP外部可控,alice传进$UC_API的值为xyz');eval($_POST[cmd];
获得$configfile值为define('UC_API', 'xyz\');eval($_POST[cmd];'); xyz后面的引号被转义。
$configfile=preg_replace("/define\('UC_API',\s*'.*?'\);/i",
"define('UC_API','".addslashes($UC_API)."');", $configfile);
//3、将define('UC_API', 'xyz\');eval($_POST[cmd];');写进建设文件
if($fp = @fopen(DISCUZ_ROOT.'./config/config_ucenter.php', 'w')) {
@fwrite($fp, trim($configfile));
@fclose($fp);
}
//4、alice再次传进$UC_API的值为xyz,preg_replace利用的正则表达式是
define\('UC_API',\s*'.*?'\); .*?'非贪婪匹配,匹配到第一个引号结束,
之前的转义符被替代xyz\替代为xyz,从而获得$configfile值为
define('UC_API', 'xyz');eval($_POST[cmd];');写进建设文件获得webshell。
这个标题问题早在2010年外部已公开,官方已及时发出补丁
详情请参考:http://www.oldjun.com/blog/index.php/archives/76/
4、总结
上面这些例子主如果笔者实践经验的一些总结,不必然周全,希看能给大年夜家拓展一些思路;好比上述提到的二次注进,$settingnew['seccodedata']['type']这个变量没过滤,$settingnew的其他数组也可能没过滤,也确切存在多处近似的标题问题,大年夜家可以自行往测验测验一下。关于代码审计的编制首要有两个大年夜标的目标:(1)危险函数向上追踪输进;(2)追踪用户输进是不是进进危险函数;这里的危险函数关于危险函数首要包含代码履行相干:eval、assert,文件包含:include、require等,号令履行:system、exec等,写文件:fwrite、file_put_contents等;
代码审计的编制这里保举两篇文章:
https://code.谷歌.com/p/pasc2at/wiki/SimplifiedChinese
http://wenku.百度.com/view/c85be95a3b3567ec102d8a12.html
5、反思
1、一切输进都是有害的;
后台法度的用户输进比拟前台首要增加了后台表单的数据,别的有些后台撑持上传文件(如dz1.5的自定义sql),上传文件的内容也属于输进;这些输进都属于用户范围。必然要做严格的节制和过滤。
2、安然意识;
其实良多缝隙的产生其实不是手艺标题问题导致的,而是我们贫乏安然意识,不正视安但是变成的悲剧。特别是第三个和第四个,完全不该该产生;需要对开辟人员做安然宣导和根基的安然培训。
3、缝隙Review;
(1)开辟人员收到缝隙后要对缝隙产生的启事做总结,并Review代码中是不是有近似的标题问题。有些时辰开辟人员仅仅是修补了安然人员或白帽子供给的缝隙点,别的一处代码有近似的标题问题没修补继续爆出漏洞,无限无尽。如许做还会带来更大年夜的隐患,黑客是很是甘愿答应并善于总结反思的,每个补丁其实也是给黑客拓展了思路,假定修补不完全后果很严重。
(2)开辟人员修补完成后安然人员需要进行测试确认,上述的案例四就是光鲜的例子。有前提的环境下安然人员应当清算一些常见缝隙修复指引,如许也能够进步工作效力。