前言
强网杯Hard_Penetration题目内网中的cms,当时跟队友在最后一个小时回来看的时候才发现这个cms, 审计到最后也没什么时间了,算是比较可惜。看了几个wp,是搭配着shell写入同名文件来绕过拼接。 不过这个BAOCMS不开源,漏洞应该很多,复现完顺便玩玩。
配置环境
首先到GitHub下载源码,我用的是搜到的(https://github.com/IsCrazyCat/demo-baocms-v17.1/)。

任意文件读取漏洞
拿到源码留一眼控制器路由。

正常安装流程下来,打开主页,发现这里是wap目录为主页。

定位到wap下到common控制器,可以看到这里有show(),功能大概是解析模版, 这个功能点一般都有文件包含漏洞。

跟随一下变量流向,调用display()方法。

从注释中也可以看出来,这里获取传入的文件名并进行解析。

来到解析流程,可以看到有ob_start(),来观察一下它与ob_get_clean()之间的代码段。 (上面的$templateFile不过是规范下路径格式,盲猜tag()对传入的文件名进行了解析,跟进一下)

看一眼上面的$templateFile,果然只是规范路径,直接去看tag()。

重点利用的点来了,这里看到准备加载模版文件了。

跟进一下,发现这里有个include()来包含模版缓存文件,来看一下缓存文件怎么生成的。

可以看到这里用了file_get_contents()来获取文件内容, 然后又在if中用file_put_contents()生成了缓存文件。

构造payload读取文件成功,但上面的file_get_contents()跟include()这个搭配在很多写shell的漏洞中可以看到。 一般实战这种cms也是放在公网上的,那么是否可以尝试获取vps上的内容来include呢。
答案是不可以的,因为这里的利用点先经过了is_file()的判断。

前台ThinkPHP3.X where() sql注入
这里可以得到这个cms基于TP3框架开发,翻了翻笔记发现这个版本有几个sql注入。

果然,这里两个接口都有一样的问题,拿其中一个灰盒测试一下。

构造cid[0]=exp&cid[1]==1 and sleep(5) -- a,确认是个注入点。

常规闭合测列数。

可以得出列数有13。

一套常规流程拿到后台管理员密码。

md5解密是123456。

也可以读文件啦!

sql最高权限。

查询secure_file_priv也符合写shell的条件,并且没有目录限制。

现在来分析一下TP3的where()注入源码。(之前我是觉得TP3的sql注入挺鸡肋的,只是大概看了下就没有去细致分析)

跑了一段,跟随变量来到可疑的parseWhere()方法。 可以看到这里的foreach将payload数组中的内容作为数组,传入parseWhereItem()方法。

跟进一下parseWhereItem()方法,取第一个元素作为表达式(这里表达式即为exp), 如果你输入别的内容页面是会回显表达式错误的。然后进入elseif分支,将数组第二个元素拼接进sql语句。

从这里也可以看到拼接成利用的sql语句。

分析到这里,还是不知道为什么要以数组的形式传payload,从而达到sql注入。 所以,我传了一个cid=1))-- a,康康这个数组到底是绕过哪个地方。
对比了一下代码执行流程,很快发现了问题所在。 这里用is_scalar()函数判断是否进入_parseType()方法。

查了一下手册,当传入的是数组的时候,这个函数返回为false, 所以payload不会进入_parseType()方法。那么肯定在_parseType()方法里有过滤payload的地方。

进入这个函数跑一跑,可以看到这里有个intval()函数来过滤payload。 所以当payload不是数组的时候,构造的恶意语句会被intval()函数变为数字。

文件包含漏洞
从前台的show()方法跟display()方法,再到后台的settings()方法, 都可以进行文件包含。
不过需要注意的是只有前台的show()方法没有经过$this->parseTemplate()方法检查, 才可以任意读取文件,因为其它的几个方法都会被$this->parseTemplate()方法拼接.html后缀导致读取文件失败, 需要搭配一个同名的html文件才能利用。
鸡肋ssrf
这里有个curl_exec()来ssrf攻击,但可惜的是没有回显。 构造payload:/api/user/httpRequest?url=。 这里能打的可能性不是很大,除非是很熟悉目标内网应用架构,或者目标满足php-fpm未授权访问的利用点。

失败的xxe注入
审计了一个xxe的点,很可惜第三个参数为LIBXML_NOCDATA,输出的是对象,也没有对实体进行解析。 (第三个参数是LIBXML_NOENT的话,可以利用)

There Is Nothing Below
