前言
文章主要讲述某次红队攻防项目中,从挖掘某系统0day漏洞拿到shell并通过jfinal框架的某个tips绕过waf,到绕过瑞数6反爬最终构造正向代理漫游内网的过程
漏洞挖掘
前期若干天供应链的艰辛不谈,直接进入到挖洞阶段
拿到手一看代码,发现和目标能对的上的接口少之又少,大概只有两个左右的class中的路由能和目标对的上。扫视一遍lib依赖和web.xml后确定了一些信息:1、目标使用jfinal框架进行开发 2、目标没有能rce的第三方依赖。对目标站点抓包访问了一下,发现了目标的站点不太对劲,因为这个站不能重放包。一开始我以为是银行的那种防重放系统,后面找了专家问了一下,是瑞数反爬虫。这就意味着我们打exp会非常艰难,因为自己构造的exp数据包是过不了瑞数的,打过去会直接返回412的状态码。瑞数反爬的防护下,你的每个请求包都要求带一个cookie,这个cookie都是根据uri动态加密计算的。
到这里为止,环境还是令人绝望的。一两个能对上路由的class文件、有漏洞也不一定打的了的瑞数反爬虫、更恐怖的是就算侥幸rce了,代理应该怎么做。正常人一般就放弃了,但我在上一篇hessian反序列化的博客说过:没有打不死的站,只有不努力的工程师。所以必须梭哈,全力办他!
那么问题来了,在没有第三方能rce依赖下,还能找到什么漏洞呢?我在通篇浏览完少量的代码后,发现了一个上传点,但是这个上传点强制限制了文件内容是jpg,而且后缀使用了白名单。除了这个上传点之外,就没有其他的有用的代码了,其他代码全是业务上的渲染和一些预编译的sql。只能转头看这个上传点,这个上传点和我们平常见的最多的SpringMVC的那种上传很不一样。
上图就是文件上传的一个接口,在后面的代码中我就没看到有文件落地的过程了,那说明从http的请求到文件的写入过程在this.getFiles中
最后一直跟,跟到了jfinal框架里面,在下面的红框中进行了文件写入
那从这里看我好像可以直接写入jsp文件,在我本地环境测试之后发现并没有写进去,然后我就继续看后续的代码,是否做了什么操作
后面发现文件上传完有一个判断isSafeFile的方法
这里检测后缀是不是jsp或者jspx,如果是的话会进行删除
看到这边灵光一现,如果我访问jsp的时机正好在他写入了jsp文件之后,而未来得及删除的时候,那么就能成功的访问到webshell了,从上面代码看显然这个路径是固定的。明显的条件竞争场景。这边漏洞点以及有了,我的exp只要两个数据包,一个数据包上传jsp,一个数据包访问这个jsp即将落地的一个web路径。两个数据包高并发的发出去,在某一时刻就可以获取到shell。
Bypass瑞数反爬虫&&Bypass Waf GetShell
前面说了因为有瑞数,我们的exp是没办法正常的发出去的,后面同事研究了下,如果通过js来调用http的请求,那么这个请求自动会携带瑞数的cookie,这样就能正常的把包发出去了。
通过这个特点,我找chatgpt写了两个js代码
下面的代码的真实url路径我进行了修改
upload.js
1 | fileInput = document.getElementById('fileInput'); |
get.js
1 | function makeRequest(url) { |
打开F12,先运行upload.js,再打开另外一个浏览器运行get.js,这样就可以模拟瑞数的数据包进行发包了
可以注意到我上面访问webshell的路径为:/shell.jsp;
这里参考:https://forum.butian.net/share/1899,因为jfinal做了限制,正常不能访问jsp文件,但某些版本可以通过;绕过
还有个点是upload.js中有一段代码为
1 | xhr.setRequestHeader('Content-Type', 'multipart/form-data; boundary=---'); |
这里是绕过waf使用的,因为我构造了畸形的multipart,所以导致waf不能识别到multipart参数中的值,也就绕过了waf。通过我本地测试,这样写在final中是可以正常解析并把文件写入到本地磁盘的。因此这里利用两者解析的差异性绕过了waf。这个绕过也是极少数能用js表达出来的绕过了,不然如果要更多的修改数据包来绕waf的话,js可能就完不成了,也就没办法过瑞数的同时过waf了。
通过大概几千到一万次的访问,最后我访问到了我上传的jsp文件,这个jsp文件的功能为在同目录写入一个专门做文件上传功能的小马,方便我后续稳定的做上传测试。后面我用上传小马传了个命令执行马上去,至此shell就拿下了
Bypass瑞数做正向代理
经过命令执行的探测,发现目标站不出网无法做反向代理。但做正向代理的话,前面又有瑞数,正向代理可没办法用js去一条一条的发包。这里只能正面去刚了,首先我想到的是用python调用selinium或playwright框架去访问目标站,然后模拟js执行来绕过瑞数。但显然我想的简单了,完全绕不过去,都被检测了。后来实在没办法,开始在网上找专门做瑞数解密的人去弄,经过别人研判是最新的瑞数6代,每一个站的加密都是不一样的,因此没有通用工具能破解,只能一个站一套脚本。最后使用钞能力全款拿下了一套脚本。
有个这个脚本后,我们就能做到先调用脚本,获取一个我们要访问的url的加密cookie,把cookie附加到我们的数据包中,这样我们数据包就经过加密,可以正常的抵达到目标服务器的后端了。
下面就是对于neoreg的改造,说实话,在前面的几天中已经花费很多的时间了,到这个时候我已经没心情再去看neoreg哪里调用了http请求,然后再去调用加密给他赋cookie了,因为这样的话我肯定要花时间去理解neoreg的代码并找到每个http请求的地方。很浪费时间。我想了个折中的办法,也就是我用python写一个flask,这个flask的功能是监听8080端口,然后neoreg把流量发给flask监听的8080端口。flask收到了neoreg的流量后,调用瑞数加密的脚本,获取到一个可用的Cookie,把Cookie塞入到flask收到的neoreg的http包中的Cookie位置,然后把整合完毕的包发给目标站。
最后代码大致如下
1 | #!/usr/bin/env python3 |
最后成功打通了代理,顺利进入了内网
总结
漏洞挖掘和漏洞利用同样重要,有洞打不了在一些大型的攻防中比较常见,重要是的能否有灵活的思路去应对以及有一个死磕到底决心。