PHP审计之BEESCMS审计案例

PHP审计之BEESCMS审计案例审计流程任意文件包含文件存在即包含该文件,而包含的这个文件名可控,则需要找这个文件创建的地方functioncreat_inc($fl,$str){if(

大家好,又见面了,我是全栈君,祝每个程序员都可以多学几门语言。

PHP审计之BEESCMS审计案例

审计流程

任意文件包含

PHP审计之BEESCMS审计案例

PHP审计之BEESCMS审计案例

文件存在即包含该文件,而包含的这个文件名可控,则需要找这个文件创建的地方

PHP审计之BEESCMS审计案例

PHP审计之BEESCMS审计案例

function creat_inc($fl,$str){
	if(file_exists($fl)){@unlink($fl);}
	if(!$fp=@fopen($fl,'w')){
		msg('文件打开失败,请检查是否有足够的权限操作文件');
	}
	flock($fp,LOCK_EX);
	if(!fwrite($fp,$str)){
		msg('写入文件失败,请检查是否有足够的权限操作文件');
	}
	flock($fp,LOCK_UN);
	unset($fp);
}

PHP审计之BEESCMS审计案例

lang是request接受过来的值,可控。

PHP审计之BEESCMS审计案例

跟踪到这只要$cate_list可控,那么就是一个妥妥的任意文件包含漏洞。而这里的实际代码是$cate_list =.var_export($rel,true)

发现这个$rel这个参数大部分都是数据库查询获取的值。

找了几个目录可控的,继续来看代码

\admin\admin_db.php

\admin\admin_index.php

\admin\admin_info.php

\admin\admin_sq_code.php

admin_db.php文件

PHP审计之BEESCMS审计案例

elseif($action=='save_back'){
	if(!check_purview('data_backup')){msg('<span style="color:red">操作失败,你的权限不足!</span>');}
	$db = $_POST['db'];
	$init = isset($_POST['init'])?$_POST['init']:0;
	$sql_size = 1048;
	$dir = isset($_GET['dir'])?$_GET['dir']:'';
	//缓存所有表
	if($init){
		if(empty($db)){msg('请选择要备份的表');}
		$str="<?php\n$table_arr=".var_export($db,true).";\n?>";
		$file=DATA_PATH.'cache/db_cache.php';
		creat_inc($file,$str);
		//创建备份目录
		$dir = 'db'.date(YmdHms,time());
		@mkdir(DATA_PATH.'backup/'.$dir);
	}
	@include(DATA_PATH.'cache/db_cache.php');

PHP审计之BEESCMS审计案例

发现转义单引号,代码中并没有发现有过滤函数,看到包含过来的init.php文件

if (!get_magic_quotes_gpc())
{
    if (isset($_REQUEST))
    {
        $_REQUEST  = addsl($_REQUEST);
    }
    $_COOKIE   = addsl($_COOKIE);
	$_POST = addsl($_POST);
	$_GET = addsl($_GET);
}

检测没开启魔术引号,则启用自己的过滤方法进行全局的过滤。

/*
*转义函数
*
*@param   $value   array || string
*@return  array || string
*/
function addsl($value)
{
    if (empty($value))
    {
        return $value;
    }
    else
    {	
        return is_array($value) ? array_map('addsl', $value) : addslashes($value);
    }
}

过滤操作

注入

login.php

elseif($action=='ck_login'){
	global $submit,$user,$password,$_sys,$code;
	$submit=$_POST['submit'];
	$user=fl_html(fl_value($_POST['user']));
	$password=fl_html(fl_value($_POST['password']));
	$code=$_POST['code'];
    
    
   .....
       check_login($user,$password);

fl_html跟踪查看发现是过滤xss的,也就是实例化html。fl_value方法是一个正则过滤sql的方法。

function fl_value($str){
   if(empty($str)){return;}
   return preg_replace('/select|insert | update | and | in | on | left | joins | delete |\%|\=|\/\*|\*|\.\.\/|\.\/| union | from | where | group | into |load_file
|outfile/i','',$str);
}
unction check_login($user,$password){
	$rel=$GLOBALS['mysql']->fetch_asc("select id,admin_name,admin_password,admin_purview,is_disable from ".DB_PRE."admin where admin_name='".$user."' limit 0,1");	
	$rel=empty($rel)?'':$rel[0];

updatexml没被过滤,可以使用updatexml。

session覆盖

Extract()该函数使用数组键名作为变量名,使用数组键值作为变量值。但是当变量中有同名的元素时,该函数默认将原有的值给覆盖掉。这就造成了变量覆盖漏洞。

如果能覆盖(添加)这几个$_SESSION值 就能绕过这个检查

$_SESSION覆盖有个必须前提,session_start()必须出现在覆盖之前,不然就算覆盖了$_SESSION变量,一旦session_start() 变量就会被初始化掉。没有使用EXTR_SKIP参数导致任意变量覆盖,又由于执行的时候已经session_start()了
所以可以覆盖(添加)任意$_SESSION值

if(!is_login()){header('location:login.php');exit;}

查看is_login的方法

function is_login(){
   if($_SESSION['login_in']==1&&$_SESSION['admin']){
      if(time()-$_SESSION['login_time']>3600){
         login_out();
      }else{
         $_SESSION['login_time']=time();
         @session_regenerate_id();
      }

发现验证了三个值,主要伪造着三个值即可登录。

if (!get_magic_quotes_gpc())
{
    if (isset($_REQUEST))
    {
        $_REQUEST  = addsl($_REQUEST);
    }
    $_COOKIE   = addsl($_COOKIE);
	$_POST = addsl($_POST);
	$_GET = addsl($_GET);
}
if (isset($_REQUEST)){$_REQUEST  = fl_value($_REQUEST);}
    $_COOKIE   = fl_value($_COOKIE);
	$_GET = fl_value($_GET);
@extract($_POST);
@extract($_GET);
@extract($_COOKIE);

而在这里,init.php代码中,使用Extract方法未使用EXTR_SKIP参数,并且未过滤_session字符,导致可以同名变量覆盖。

_SESSION[login_in]=1&_SESSION[admin]=1&_SESSION[login_time]=99999999999

结尾

类似这种非MVC的架构,可以省略看路由这步骤,直接定位危险函数/方法,还有的就是鉴权实现。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/119842.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • 数据仓库ods层设计_数据仓库建模的流程有几个

    数据仓库ods层设计_数据仓库建模的流程有几个当我们的数据采集到hdfs层上之后,我们就开开始对数据进行建模以便后来分析,那么我们整体的架构先放在每个建模层级的最前面所以项目1的将行为数据和业务数据导入到hdfs中我们已经完成了,现在需要的是将hdfs的数据通过ODS层数据建模,初步的分析以及改变,那么我们首先介绍下ODS层的作用因为我们的数据刚落到hdfs上,他还只是单纯的数据,并没有能让我们直接操作。所以我们需要将这些数据放入到能够对数据进行操作的框架中,如我们这个项目采取了使用hive的方法。所以我们此次在ODS层需要做到的就是将hdfs

  • LeetCode OJ:Basic Calculator(基础计算器)

    LeetCode OJ:Basic Calculator(基础计算器)

  • toArray()与toArray(T [] a)的区别「建议收藏」

    toArray()与toArray(T [] a)的区别「建议收藏」1、Object[]toArray()原理:将集合转换为Object类型的数组并返回该数组(以首地址的形式)。 调用格式:Object[]a=collecton.toArray() 注意:(1)前面类型必须为Object[]且不能被强制转换。(2)需要在遍历Objecta[]时,再强制转换a[n]的类型。由于编译器在语法上无法检测到类型错误,容易

  • django的orm查询方法_django获取get请求参数

    django的orm查询方法_django获取get请求参数前言查找是数据库操作中一个非常重要的技术。查询一般就是使用filter、exclude以及get三个方法来实现。我们可以在调用这些方法的时候传递不同的参数来实现查询需求。在ORM层面,这些查询条件都

  • 计算机考研复试C语言常见面试题「建议收藏」

    计算机考研复试C语言常见面试题「建议收藏」本文是我2021年考研时准备的复试面试题,现在拿出来给大家分享一下觉得好的点个赞哦,毕竟当初我也是整理了好久,改了好几次版本呢祝大家都上岸!!!!P.S.我当初整理的时候是word,直接复制过来的话代码不会自动变成CSDN的代码块,所以代码我是一段一段重新标记为CSDN代码段的,这样大家看起来舒服点C语言基础目录1、static关键字的作用22、C++和C的区别23、Java的方法重载24、重写和重载25、面向对象编程36、c++可以有多个父类37

  • Node.js REPL模块「建议收藏」

    Node.js REPL模块「建议收藏」repl模块提供了一个”读取-求值-输出-循环”(REPL交互式解释器)的实现,它可以作为一个单独的程序,或者包含在其他程序内部。

    2022年10月26日

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号