测试系统是否存在shiro漏洞
测试系统是测试否存在shiro漏洞
我花了一个下午,对一个内部测试系统做安全巡检。系统目标很明确:看它有没有shiro反序列化漏洞。否存这活儿不复杂,测试但得细心,系统因为shiro的否存坑藏得深。
先看响应头。测试正常登录页面,系统返回的否存Set-Cookie里没带rememberMe字段。这不算坏事,测试但也不代表安全——很多人以为不启用记住我功能就没事,系统可shiro的否存默认配置有时会把rememberMe的cookie名改成别的,比如JSESSIONID或者自定义的测试token。我翻了翻前端源码,系统发现登录请求是否存POST到/login,参数里有username和password,没有勾选框。按惯例,这时候得手动构造一个带rememberMe的请求试试。
用curl发了个带`Cookie: rememberMe=1`的GET请求到首页。响应头里立刻出现了`Set-Cookie: rememberMe=deleteMe`。这信号太明显了——shiro在尝试解密这个无效的cookie,解密失败后清除它。说明shiro的过滤器确实在跑,而且rememberMe功能没被禁用。
确认存在shiro组件后,下一步是找密钥。shiro的AES密钥是硬编码在配置文件里的,很多开发者图省事直接用网上公开的默认key,比如`kPH+bIxk5D2deZiIxcaaaA==`。我拿这个key去加密一个简单的URLDNS payload,塞进rememberMe里发过去。结果响应头还是`deleteMe`,没触发DNS请求。换个key,再试,还是没动静。接连试了十几个常见key,全部石沉大海。
这时候有点泄气,但转念一想,也许目标系统用的是自定义key。那就换个思路——不猜key了,直接看shiro版本。从响应头里的`X-Powered-By`没泄露版本,但静态资源文件里可能有线索。翻了下登录页的JS,发现引用了`/static/js/shiro.js`,这文件名太刻意了。打开一看,注释里写着`shiro-core-1.4.2`。版本号到手,查了下,1.4.2存在CVE-2016-4437的变种绕过,但前提还是得知道key。
折腾了快两小时,最后我决定用工具硬跑。写了个小脚本,从网上扒了500多个公开的shiro key,逐个加密一个简单的`ping`命令payload,发请求后监听自己的服务器端口。跑到第437个key时,服务器收到了回连请求。那一下,屏幕前的我忍不住拍了下桌子。
漏洞确认了。系统用的是`4A5F2C3D9E8B7A1F6C3D2E4B5A6F7C8D`这个key,攻击者拿到后可以直接执行任意命令。我后续在测试环境里跑了个`whoami`,返回的是`root`权限。这系统挂在内网,但若被外部渗透进来,后果不堪设想。
修复建议其实很简单:升级shiro到1.7.1以上,强制启用动态密钥,并且把rememberMe的cookie名改成随机值。但现实是,很多系统上线后没人管这些细节。你问怎么测?说白了就三步:看响应头、试默认key、查版本。但每一步都可能踩坑,比如目标系统把cookie名改了,或者用了动态密钥轮换。所以别指望一把梭,得根据实际情况调整方法。
最后说句实在话,shiro漏洞测试不是玄学,但也不是死记硬背几个key就能通杀。真正难的是判断业务逻辑里哪些地方能触发反序列化,以及绕过WAF对payload的过滤。我那次运气好,系统没上WAF,直接裸奔。要是遇到防护严格的,还得花时间做编码混淆。测试这活儿,耐心比技术更重要。