0x01、前言
本文仅进行思路分享,漏洞已全部修复【请勿非法测试】。当你看到这篇文章的时候,我可能就已经没什么时间继续写了。即将专升本了,接下来好长一段时间将会投入复习。希望可以上岸
老生常谈,也找了几个getshell的点,但是利用起来有点怪,就先放着,后面再写。这个系统基于springboot来写的,那就直接先拼接路由,如下:
直接访问系统会如上图所示,服务器返回500。抓个正常的登录包看看是什么情况。
可以看到正常业务请求包中是有sign,timestamp,noceid和app-key。
这时候如果直接拷贝过来,会提示非法请求接口。这时候就直接全局搜索报错关键字。尝试破解请求头信息
0x02、请求头破解绕过
![关于我在梦里在EDUSRC刷屏的事 关于我在梦里在EDUSRC刷屏的事]()
image.png
如图查看校验的一个过程,先是通过这行代码获取到sign的配置文件
SignProperties signProperties = (SignProperties)SpringUtils.getBean(SignProperties.class);
看到配置文件前缀是string.sign,那么我们直接去搜索一下,先把能拿到的先拿出来
string.sign.appKey= edu
string.sign.timeout= 10000
string.sign.appSecret= EDUstring@1307
继续返回到上文当中。
获取完配置文件信息之后再去看接下来的代码
public static DcHttpHeader get() {
DcHttpHeader httpHeader = new DcHttpHeader();
HttpServletRequest request = ServletHttpUtils.getRequestAttributes().getRequest();
String parameter = request.getParameter("download_token");
log.info("检测链接参数download_token:{}", parameter);
String token;
if (ObjectUtils.isNotEmpty(parameter)) {
httpHeader = (DcHttpHeader)JSONObject.parseObject(parameter, DcHttpHeader.class);
httpHeader.setUrl(request.getRequestURI());
token = httpHeader.getToken();
if (StringUtils.isNotBlank(token)) {
Map<String, String> header = new HashMap();
header.put("token", token);
if (request instanceof RequestWrapper) {
((RequestWrapper)request).addHeader(header);
} else {
ServletUtils.addHeader(request, header);
}
}
if (StringUtils.isNotEmpty(token)) {
SecurityContextHolder.setUserId(ServletUtils.getHeader(request, "userId"));
SecurityContextHolder.setUserCode(ServletUtils.getHeader(request, "userCode"));
SecurityContextHolder.setUserKey(ServletUtils.getHeader(request, "userKey"));
LoginUser loginUser = AuthUtil.getLoginUser(token);
if (ObjectUtils.isNotEmpty(loginUser)) {
log.info("webtoken值:{}", token);
AuthUtil.verifyLoginUserExpire(loginUser);
SecurityContextHolder.set("login_user", loginUser);
}
}
return httpHeader;
} else {
token = request.getHeader("app-key");
String token = request.getHeader("token");
String sign = request.getHeader("sign");
if (ObjectUtils.isNotEmpty(request.getHeader("timestamp"))) {
Long timestamp = Long.parseLong(request.getHeader("timestamp"));
httpHeader.setTimestamp(timestamp);
}
String noceId = request.getHeader("noceId");
httpHeader.setUrl(request.getRequestURI());
httpHeader.setSign(sign);
httpHeader.setNoceId(noceId);
httpHeader.setAppKey(token);
httpHeader.setToken(token);
return httpHeader;
}
}
有两个条件这边会判断download_token不为空,为空则进入else,去获取app-key,token,sign,timestamp四个请求头。并且判断timestamp也就是时间戳不为空。然后把时间戳给到一个请求头的对象中。
依次是:timestamp -> URI路径 -> sign -> noceId -> token。最后再返回对象
随后if判断app-key不为空, 然后获取数据,与枚举类型中的值进行对比是否正确。这边是没用的,校验还是不通过。继续看下面的代码。
Map<String, String> param = new HashMap();
String url = dcHttpHeader.getUrl();
param.put("url", url);
String sign = dcHttpHeader.getSign();
String noceId = dcHttpHeader.getNoceId();
param.put("sign", sign);
param.put("noceId", noceId);
param.put("timestamp", dcHttpHeader.getTimestamp().toString());
param.put("appKey", signProperties.getAppKey());
flag = SignUtil.verifyTimeStampNotify(param, signProperties.getAppSecret(), SignType.MD5, signProperties.getTimeout());
创建hashmap,随后把URI,sign,noceid,timestamp,服务端的appKey设置进去。其实单看到dcHttpHeader就应该知道,这些是从客户端那边获取的请求头,并没什么卵用。只有一个appKey是从配置文件中获取的,也就是“edu”。
重点看verifyTimeStampNotify()
方法。除了第一个参数是从客户端获取的,其他三个都是从配置文件获取
string.sign.appKey= edu
string.sign.timeout= 10000
string.sign.appSecret= EDUstring@1307
跟尽量查看,先判断时间戳不为空,最后判断时效性。然后再次进行校验。继续跟进来
这边就可以看到是先从客户端获取sign,再本地创建个localSign。最后将两者对比查看是否正确。正确则校验通过。继续跟进createSign(params, appSecret, signType)
方法
第一行就不用看了。主要看下面一行,服务端会把客户端的sign删除掉,然后创建个临时字符串,
回顾上面的方法,其实就是把URI,noceid,timestamp,服务端的appKey使用&串起来。最后再加个&key=" + appSecret
。
return signType == SignType.MD5 ? md5(stringSignTemp).toUpperCase() : hmacSha256(stringSignTemp, appSecret).toUpperCase();
再经过这最后一行判断,通过拦截器就可以知道类型是MD5德,所以是对这一串字符串进行MD5加密,并转换为大写。至此,请求头已经破解了。可以发现一开始的请求头生效的没几个,除了时间戳需要验证时效性,其他的目前是没什么用处了,noceid可以一直用,token默认为null即可
0x03、备份文件下载
数据库备份文件下载就需要用到上面的code了。跟踪Service的实现类如下
会通过code去下载数据库的备份文件,只需要对的code即可。
其实这边解压还有问题,下载解压发现里面需要解密,最后发现原来再备份的时候发现进行了openssl加密了。
密码的话其实就是code,也就是下载下来的文件名。
0x04、任意用户添加
虽然获取到了管理员信息,但是用户密码加密且不可逆。只能去尝试添加用户
这时候会发现创建管理员其实是存在一定的概率,但是虽然管理员有约束,但是其他教育厅用户等等没有限制
如图,图中四个用户权限有限制,但是其他用户不存在限制可以加其他权限的用户。之后再根据权限,去添加相关功能的权限值,比如相关功能点校验
同时添加的用户也有问题,密码也是很神奇。
密码规律是姓名拼音的首字母大写+@
+账号
0x05、结语
感谢看到这里,与君共勉,几个月后见
原文始发于微信公众号(赛博搬砖工):关于我在梦里在EDUSRC刷屏的事
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论