前言最近看到由有分析梦想 cms 的然后也去搭建了一个环境看了一看发现了一个文件包含漏洞的点很有意思下面是详细的复现和分析以后代码审计又多了一中挖掘文件包含漏洞的新思路环境搭建下载https://gitee.com/iteachyou/dreamer_cms然后各种配置都可以看到JDKJdk8IDESpring Tool Suite 4STS或 IntelliJ IDEADBMysql 5.7Windows配置安装Mysql5.7请参考https://www.iteachyou.cc/article/a1db138b4a89402ab50f3499edeb30c2Redis3.2Windows配置安装Redis教程请参考https://www.iteachyou.cc/article/4b0a638f65fa4fb1b9644cf461dba602修改一下配置文件中的 resource-path 和 mysql 的连接漏洞寻找过程进入后台后发现可以编辑模板文件然后这时候我们就需要注意常见的可以触发漏洞的点了首先就是 xss加入我们的 xss 代码然后访问首页成功 xss当然我们真实使用的话可以利用我们的 xss 平台这里推荐与一个https://xssaq.com/点击配置代码后会有很多 payload随便复制一个这里我们简单弹个 cookiexss 的话还是国外使用比较多当然这样并不能达到我们 getshell 的目的漏洞深入利用这里就不得不提到我们的一些标签了一般常见的我们可以尝试 include 标签这里我们先复现一下这个标签是 cms 的专属的标签然后我们根据目录关系创建一个文件尝试一下然后我们访问首页可以看到成功了调试分析我们调试分析一下抓个包看看路由定位到代码Log(operType OperatorType.UPDATE, module 模板管理, content 修改模板) PostMapping(save) RequiresPermissions(5n6ta53y) public String save(TemplateVo template) throws IOException, CmsException { String fileName template.getPath() File.separator template.getFile(); File templateFile newFile(fileName); /** * 查询当前模版目录判断是否为模版目录如不是则报错 */ Theme currentTheme themeService.getCurrentTheme(); String resourceDir fileConfiguration.getResourceDir(); String themePath resourceDir File.separator templates File.separator currentTheme.getThemePath() File.separator; themePath themePath.replaceAll(\\*, /); File themeDir newFile(themePath); // 检查当前编辑文件是否有权限 if(!templateFile.getCanonicalPath().startsWith(themeDir.getCanonicalPath())) { thrownewTemplatePermissionDeniedException(StateCodeEnum.HTTP_FORBIDDEN.getCode(), StateCodeEnum.HTTP_FORBIDDEN.getDescription(), 您没有操作权限); } if(!templateFile.exists()) { thrownewTemplateNotFoundException(StateCodeEnum.HTTP_NOTFOUND.getCode(), StateCodeEnum.HTTP_NOTFOUND.getDescription(), 模板文件不存在); } String filePath template.getPath() File.separator template.getFile(); filePath filePath.replaceAll(\\*, /); File file newFile(filePath); FileUtils.writeStringToFile(file, template.getContent(), UTF-8); returnredirect:/admin/templates/toIndex; }这里就是就简单的写一下模板然后重点关注解析的部分这里有各种各样的标签看到我们的 Include 标签Tag(beginTag{dreamer-cms:include /},endTag{/dreamer-cms:include},regexp(\\{dreamer-cms:include[ \\t].*/\\})|(\\{dreamer-cms:include[ \\t].*\\}\\{/dreamer-cms:include\\}), attributes{ Attribute(name file,regex [ \t]file[\\].*?[\\]), })格式我们看一下解析过程首先是解析我们的模板识别我们的模板内容后开始解析各种标签然后是我们的 includepublic String parse(String html) { Tag annotations IncludeTag.class.getAnnotation(Tag.class); Attribute[] attributes annotations.attributes(); ListString all RegexUtil.parseAll(html, annotations.regexp(), 0); if(StringUtil.isBlank(all)) { return html; } String newHtml html; String resourceDir fileConfiguration.getResourceDir() templates/; Theme currentTheme themeService.getCurrentTheme(); String templatePath currentTheme.getThemePath() /; String basePath resourceDir templatePath; for (int i 0; i all.size(); i) { MapString,Object entity newHashMapString,Object(); String includeTag all.get(i); for (Attribute attribute : attributes) { String condition RegexUtil.parseFirst(includeTag, attribute.regex(), 0); if(StringUtil.isBlank(condition)) { continue; } String key condition.split()[0]; String value condition.split()[1]; key key.trim(); value value.replace(\, ).replace(\, ); entity.put(key, value); } if(entity.keySet() ! null entity.keySet().size() 0) { String path basePath entity.get(file).toString(); File includeFile newFile(path); String includeHtml; try { includeHtml FileUtils.readFileToString(includeFile, UTF-8); newHtml newHtml.replaceFirst(annotations.regexp(), includeHtml); } catch (IOException e) { e.printStackTrace(); } } } return newHtml; }可以目录穿越读取我们任意文件的内容
精准定位文件包含漏洞:代码审计中的实战思维
前言最近看到由有分析梦想 cms 的然后也去搭建了一个环境看了一看发现了一个文件包含漏洞的点很有意思下面是详细的复现和分析以后代码审计又多了一中挖掘文件包含漏洞的新思路环境搭建下载https://gitee.com/iteachyou/dreamer_cms然后各种配置都可以看到JDKJdk8IDESpring Tool Suite 4STS或 IntelliJ IDEADBMysql 5.7Windows配置安装Mysql5.7请参考https://www.iteachyou.cc/article/a1db138b4a89402ab50f3499edeb30c2Redis3.2Windows配置安装Redis教程请参考https://www.iteachyou.cc/article/4b0a638f65fa4fb1b9644cf461dba602修改一下配置文件中的 resource-path 和 mysql 的连接漏洞寻找过程进入后台后发现可以编辑模板文件然后这时候我们就需要注意常见的可以触发漏洞的点了首先就是 xss加入我们的 xss 代码然后访问首页成功 xss当然我们真实使用的话可以利用我们的 xss 平台这里推荐与一个https://xssaq.com/点击配置代码后会有很多 payload随便复制一个这里我们简单弹个 cookiexss 的话还是国外使用比较多当然这样并不能达到我们 getshell 的目的漏洞深入利用这里就不得不提到我们的一些标签了一般常见的我们可以尝试 include 标签这里我们先复现一下这个标签是 cms 的专属的标签然后我们根据目录关系创建一个文件尝试一下然后我们访问首页可以看到成功了调试分析我们调试分析一下抓个包看看路由定位到代码Log(operType OperatorType.UPDATE, module 模板管理, content 修改模板) PostMapping(save) RequiresPermissions(5n6ta53y) public String save(TemplateVo template) throws IOException, CmsException { String fileName template.getPath() File.separator template.getFile(); File templateFile newFile(fileName); /** * 查询当前模版目录判断是否为模版目录如不是则报错 */ Theme currentTheme themeService.getCurrentTheme(); String resourceDir fileConfiguration.getResourceDir(); String themePath resourceDir File.separator templates File.separator currentTheme.getThemePath() File.separator; themePath themePath.replaceAll(\\*, /); File themeDir newFile(themePath); // 检查当前编辑文件是否有权限 if(!templateFile.getCanonicalPath().startsWith(themeDir.getCanonicalPath())) { thrownewTemplatePermissionDeniedException(StateCodeEnum.HTTP_FORBIDDEN.getCode(), StateCodeEnum.HTTP_FORBIDDEN.getDescription(), 您没有操作权限); } if(!templateFile.exists()) { thrownewTemplateNotFoundException(StateCodeEnum.HTTP_NOTFOUND.getCode(), StateCodeEnum.HTTP_NOTFOUND.getDescription(), 模板文件不存在); } String filePath template.getPath() File.separator template.getFile(); filePath filePath.replaceAll(\\*, /); File file newFile(filePath); FileUtils.writeStringToFile(file, template.getContent(), UTF-8); returnredirect:/admin/templates/toIndex; }这里就是就简单的写一下模板然后重点关注解析的部分这里有各种各样的标签看到我们的 Include 标签Tag(beginTag{dreamer-cms:include /},endTag{/dreamer-cms:include},regexp(\\{dreamer-cms:include[ \\t].*/\\})|(\\{dreamer-cms:include[ \\t].*\\}\\{/dreamer-cms:include\\}), attributes{ Attribute(name file,regex [ \t]file[\\].*?[\\]), })格式我们看一下解析过程首先是解析我们的模板识别我们的模板内容后开始解析各种标签然后是我们的 includepublic String parse(String html) { Tag annotations IncludeTag.class.getAnnotation(Tag.class); Attribute[] attributes annotations.attributes(); ListString all RegexUtil.parseAll(html, annotations.regexp(), 0); if(StringUtil.isBlank(all)) { return html; } String newHtml html; String resourceDir fileConfiguration.getResourceDir() templates/; Theme currentTheme themeService.getCurrentTheme(); String templatePath currentTheme.getThemePath() /; String basePath resourceDir templatePath; for (int i 0; i all.size(); i) { MapString,Object entity newHashMapString,Object(); String includeTag all.get(i); for (Attribute attribute : attributes) { String condition RegexUtil.parseFirst(includeTag, attribute.regex(), 0); if(StringUtil.isBlank(condition)) { continue; } String key condition.split()[0]; String value condition.split()[1]; key key.trim(); value value.replace(\, ).replace(\, ); entity.put(key, value); } if(entity.keySet() ! null entity.keySet().size() 0) { String path basePath entity.get(file).toString(); File includeFile newFile(path); String includeHtml; try { includeHtml FileUtils.readFileToString(includeFile, UTF-8); newHtml newHtml.replaceFirst(annotations.regexp(), includeHtml); } catch (IOException e) { e.printStackTrace(); } } } return newHtml; }可以目录穿越读取我们任意文件的内容