tmall代码审计

UWI Lv3

任意文件上传

没有检测后缀 直接上传jsp发现能够解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@ResponseBody
@RequestMapping(value = "admin/uploadAdminHeadImage", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
public String uploadAdminHeadImage(@RequestParam MultipartFile file, HttpSession session) {
String originalFileName = file.getOriginalFilename();
logger.info("获取图片原始文件名:{}", originalFileName);
assert originalFileName != null;
String extension = originalFileName.substring(originalFileName.lastIndexOf('.'));
//生成随机名
String fileName = UUID.randomUUID() + extension;
//获取上传路径
String filePath = session.getServletContext().getRealPath("/") + "res/images/item/adminProfilePicture/" + fileName;

logger.info("文件上传路径:{}", filePath);
JSONObject jsonObject = new JSONObject();
try {
logger.info("文件上传中...");
file.transferTo(new File(filePath));
logger.info("文件上传成功!");
jsonObject.put("success", true);
jsonObject.put("fileName", fileName);
} catch (IOException e) {
logger.warn("文件上传失败!");
e.printStackTrace();
jsonObject.put("success", false);
}
return jsonObject.toJSONString();
}

image-20250720163312274

以此为例所有文件上传接口都没做过滤 均能任意文件上传

sql注入

在mybatis的xml配置文件中我们查询到了一个直接拼接的地方 直接拼接orderUtil.orderBy这个函数名叫select

image-20250720222154395

那么接下来就是查找orderUtil.orderBy 是否可控

查看哪里调用到了这个语句

我们找到了xml 映射的接口类UserMapper

image-20250720222330086

查看哪里调用了UserMapper这个接口类

经过查找 在UserServiceImpl类里面我们发现 UserMapper被依赖注入了

image-20250720222510961

继续观察UserServiceImpl的函数内容发现getList函数调用了我们之前找到的select函数

image-20250720222721908

我们寻找哪里调用了getList 函数

搜索userService.getList关键字

找到了一个位置

image-20250720223141410

我们把这个位置完整的代码扒下来看看

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
@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();
}

可以发现orderUtil 是由 orderUtil = new OrderUtil(orderBy, isDesc);生成的 而传入的orderBy

来自@RequestParam(required = false) String orderBy 也就是我们get传参的内容

所以orderBy 是可控制的

image-20250720223435395

尝试sqlmap 测试sql注入 可以看到注入成功

image-20250720223511648

在RewardMapper.xml里面我还发现了一个用 ${}拼接的代码0

这个sql执行的函数名也是select

image-20250722123606657

我们查看哪里调用了这个函数

同样我们发现在RewardServiceImpl 里面rewardMapper被注入

image-20250722124005274

那么我们查看RewardServiceImpl 在哪里被调用

搜索关键字

1
@Resource(name = "rewardService")

发现 这个地方的orderUtil是写死的我们无法控制参数进行利用

image-20250722124624067

还有一处也是写死的

image-20250722124749998

所以都没法利用

后面虽然又找到了几个用${}进行拼接的sql语句但是但是发现参数都是写死的我们不可控

fastjson漏洞

观察pom.xml我们发现fastjson的版本非常低有洞

检索关键字

1
JSON.parseObject(

image-20250722193037585

image-20250722193125028

1
JSONObject object = JSON.parseObject(propertyJson);

用了fastjson 并且propertyJson可控

发现另一个地方同存在 fastjson解析orderItemMap 而orderItemMap可控

image-20250722193604395

dnslog执行成功

image-20250722200142128

image-20250722200156199

log4j漏洞

pom.xml可以看到log4j也存在漏洞

image-20250722205720379

image-20250722205801054

1
logger.info("提取的关键词有{}", Arrays.toString(product_name_split));

参数可控 dnslog执行成功

image-20250722205835511

image-20250722205846869

  • Title: tmall代码审计
  • Author: UWI
  • Created at : 2025-07-31 11:28:50
  • Updated at : 2025-08-13 14:42:18
  • Link: https://nbwsws.github.io/2025/07/31/代码审计/tmall代码审计/
  • License: This work is licensed under CC BY-NC-SA 4.0.
Comments