0x01
在一次代码审计中发现登录失败后回到登录页面,例如下面请求报文。
POST /user/login?error=error HTTP/1.1
User-Agent: xxx
Content-Type: xxx
...
username=admin&password=123456
在跟读代码逻辑后发现,若登录失败则转发至 error 路由,代码实现大致为下图
在登录失败后请求根据 error 所对应的值转发至相应路由,经查阅文章得知 getRequestDispatcher(xxx).forward 会对请求进行转发,转发在服务器内部完成。
由此立即可以想到一个问题,若请求转发路由为需要鉴权的路由是否可以实现鉴权绕过呢?下面为一个测试demo截图,使用filter过滤器进行权限校验。
使用过滤器进行鉴权
简单的servlet进行登录后页面展示
漏洞触发点
在直接访问 /user/index路由时,显示如下
此时我们使用 /api 接口处转发进行转发至 /user/index 路由,请求显示即可成功绕过
由此可以成功绕过鉴权,直接调用登录后接口,也由此成功挖掘到一个前台RCE,即直接调用后端 upload 接口实现未授权任意文件上传。
0x02
在文章查阅的过程中发现,该函数还有另外一个问题,请求转发时,若转发地址为实体文件且不为 jsp 这种可解析文件时,可以实现文件读取的效果。
只不过该文件读取仅限于部署路径下,无法使用 ../ 进行路径回溯,在使用回溯符时会出现报错
0x03
在时空智友的历史漏洞中也存在该方法利用,payload如下
POST /login HTTP/1.1
Host: xxxxxx
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0.3 Safari/605.1.15
Content-Length: 100
Connection: close
Content-Type: application/x-www-form-urlencoded
Upgrade-Insecure-Requests: 1
Accept-Encoding: gzip
op=verify%7Clogin&targetpage=&errorpage=/WEB-INF/dwr.xml&mark=&tzo=480&username=admin&password=admin
在互联网上对于该漏洞的通报中均为任意文件读取,但是在实际测试中并不能实现该效果,在阅读代码时发现,同样使用该方法对部署路径下文件进行读取,无法实现真正的任意文件读取,仅能对部分文件进行读取,漏洞代码如下
在用友最新通报的漏洞,也有使用类似转发作为业务功能实现的方法(与上述方法不同,仅存在相似点)
在代码中 /pt 使用 nc.uap.lfw.core.servlet.CoreServlet 进行处理
在 nc.uap.lfw.core.servlet.CoreServlet#doPost 中使用自定义的forward进行转发,然后通过反射进行调用
总结
在getRequestDispatcher中所转发路由可控时,可以实现鉴权绕过或(有限)文件读取的效果。