美文网首页
reGeorg简要分析

reGeorg简要分析

作者: CSeroad | 来源:发表于2020-09-19 14:54 被阅读0次

    前言

    在某次实战中使用reGeorg代理工具时,出现了很多问题,带着这些疑问我打算简单分析一下reGeorg。

    环境搭建

    我这里先以虚拟机phpstudy环境为靶机,用proxifier设置代理程序,pycharm设置reGeorgSocksProxy.py客户端来更好分析reGeorg项目。

    image.png image.png

    这里简要说一下tunnel.nosocket.php和tunnel.php的区别。查看源代码发现tunnel.php多了dl("php_sockets.dll");这行代码。作用是加载socket这个模块,但dl自php 5.3起默认情况下处于禁用状态,所以php 5.3版本以下才可以使用tunnel.php。如果启用,则需配置php.ini。

    reGeorgSocksProxy.py 客户端

    代码分析

    程序入口

    我们从程序的入口__main__来一点点看。

    image.png

    使用argparse模块来接收、解析参数,总共有五个参数。

    -l 本地监听的地址,默认127.0.0.1
    -p 本地监听的端口,默认8888
    -r 每次发送的数据量,默认1024
    -u 目标隧道的地址,需要指定
    -v 详细输出,默认info
    

    askGeorg方法

    配置好相应的参数,脚本先通过askGeorg方法检测远程代理服务器是否正常。

    image.png

    查看askGeorg方法是怎么判断的?

    image.png

    先看一下使用的是http还是https协议,再connect连接到tunnel地址是否为200。如果响应码为200,则提示Georg says, 'All seems fine'

    Socket编程

    再往下,socket编程用来接收本地转发的流量。

    image.png

    bind默认绑定到本地127.0.0.1,8888端口上。servSock.accept() 等待TCP的连接(即Proxifier的流量)。
    将接收到的数据和远程代理服务器建立session连接。

    session类

    image.png

    session类除了初始化还有7个方法。从字面意思大概了解到

    parseSocks5  解析socks5协议
    parseSocks4  解析socks4协议
    handleSocks  使用socks代理
    setupRemoteSession   设置session
    closeRemoteSession   关闭session
    reader  读数据
    writer  写数据
    run     运行程序
    
    image.png

    这是这几个方法依次执行的顺序,我们一个个看。

    初始化
    image.png

    使用urlparse库解析tunnel地址获取各个字段。判断是HTTP还是HTTPS协议。
    urllib3.HTTPConnectionPool用来创建一个连接池。

    run方法

    初始化完成后,运行run方法,首先判断使用的什么socks,即handleSocks方法。

    image.png

    通过sock.recv()接收一字节的数据。判断是socks4还是socks5连接。
    (可以通过wireshark抓取判断是socks4还是socks5)
    判断为socks5,就调用parseSocks5方法。判断socks4,就执行parseSocks4方法。

    parseSocks5方法

    这里proxifier配置的是socks5。
    我们就看parseSocks5方法,首先看到log.debug输出SocksVersion5 detected,提示我们检测到使用的是socks5代理。
    然后sock.recv(1)方法又接收一个字节,然后根据atyp判断target是IPV4还是hostname还是IPV6。
    这里手动输出atype值查看。即print(str(ord(atype)))

    image.png

    然后sock.recv(4)再接收4个字节为IP地址,ord()函数转化为ASCII码拼接为标准的IP地址。即target。接收2个字节,即targetPort。

    image.png

    targetPort也是通过ord()函数返回十进制数,输出标准端口。
    再往下来到connect连接,将target赋值给serverIp,并使用gethostbyname返回主机名IPV4地址。

    image.png

    将serverIp重新变成字节,等待下一步用socks.sendall()发送。在发送之前还需要先设置session。即setupRemoteSession方法。

    image.png

    追踪setupRemoteSession方法。

    image.png

    可以看到是发送POST数据包,并且在headers头设置了{"X-CMD": "CONNECT", "X-TARGET": target, "X-PORT": port} ,以CONNECT为标识,代表和target进行连接。发送该数据包,如果响应吗为200,并且响应头x-status为ok,则获取响应头的set-cookie赋值给cookie。

    image.png image.png

    返回cookie进行connect,然后sock.sendall()发送数据。

    image.png

    之后return到handleSocks方法,再到run方法。

    image.png image.png

    至此连接建立,开始session会话,来保存服务端和客户端的socket会话状态。
    下面就是关键的reader和write。

    reader方法
    image.png

    创建PoolManager对象,发送HTTP数据包。和CONNECT标志相类似。这次使用READ为标识。在headers头添加{"X-CMD": "READ", "Cookie": self.cookie, "Connection": "Keep-Alive"}

    image.png

    POST发送该数据包。如果响应吗为200且x-status为ok,则将响应的data数据以socks发送。

    image.png
    writer方法

    writer方法实现数据包forward转发。和READ方法类似,不过在POST发送数据包时,直接发送了data数据包。标识为forward。

    image.png

    转发给tunnel.nosocks.php
    最后关闭session。即closeRemoteSession方法。

    closeRemoteSession方法
    image.png

    还是POST发送数据包,headers添加disconnect标识,{"X-CMD": "DISCONNECT", "Cookie": self.cookie}
    响应码为200,则Connection Terminated连接终止。

    tunnel.nosocket.php 服务端

    CONNECT

    当接收到客户端的CONNECT连接请求,fsockopen()方法去连接目标地址和端口,如果存在返回X-STATUS: OK,反之则返回X-STATUS: FAIL。

    image.png

    然后进入while循环,fwrite()函数将$writeBuff写进$res,而后一直fgets()读取,将读到的结果赋值给$readBuff,然后输出。

    image.png

    DISCONNECT

    当接收到客户端的DISCONNECT连接请求时,只需要将$_SESSION["run"]致为空,关闭session即可。

    image.png

    READ

    当接收到客户端的READ连接请求时,判断$_SESSION["run"],输出$_SESSION["readbuf"]

    image.png

    FORWARD

    当接收到客户端的FORWARD连接请求时,使用file_get_contents获取php://input内容,并进行输出。

    image.png

    然后将$rawPostData保存在$_SESSION["writebuf"],通过之前的while循环中fgets()读取数据,追加到$readBuff,再用READ请求输出出来。

    debug模式

    以debug模式重新回顾reGeorgSocksProxy.py客户端和tunnel.nosocket.php服务端的代码执行的过程。
    为了更方便总结该过程,做了小小调试。
    设置好profile,代理浏览器访问10.211.55.4的8080端口。
    reGeorgSocksProy.py首先访问tunnel.nosocket.php是否响应正常,然后判断来源协议是socks5还是socks4。浏览器访问10.211.55.4的8080端口,reGeorgSocksProy.py接收到的target就是10.211.55.4,port端口就是8080。并设置session。

    image.png

    接着就是read方法和write方法即forward。

    image.png

    writer()方法携带请求10.211.55.4的8080端口的数据包存在data中然后forward发送,data数据存放在全局变量$_SESSION["writebuf"],通过while循环先fwrite()、fgets()方法获取返回的结果,read()方法再从$_SESSION["readbuf"]结果中打印给客户端。

    image.png image.png

    最后返回closeRemoteSession()方法,关闭session。

    image.png

    wireshark抓包

    wireshark抓取数据包更直观的可以看到整个过程。

    image.png

    connect连接到指定访问的10.211.55.4和8080端口。
    forward 转发10.211.55.4:8080的GET数据包。

    image.png

    read读取返回的内容给客户端。

    image.png

    补充:socks5是怎么判断的?
    因为socks5代理启用在本地的环回地址上,即127.0.0.1。且socks协议工作在TCP链路层。所以wireshark应该抓本地lo网卡
    过滤规则为

    tcp.port == 8888
    
    image.png

    只看发送到8888的这两个数据包就行。
    第一个数据包,leng长度为4。数据内容为十六进制的05020002

    image.png

    第一个字节05即判断使用socks5协议,对应handleSocks方法的if ver == "\x05":
    第二、三个字节0200对应方法的parseSocks5nmethods, methods = (sock.recv(1), sock.recv(1))
    第四个字节02对应parseSocks5方法的if ver == "\x02":

    再看第二个数据包,leng长度10,数据内容十六进制的050100010ad337040050

    image.png

    跟进源代码的parseSocks5方法,继续sock.recv()

    image.png

    接收4个字节长度。即05010001。也对应if atyp == "\x01":

    image.png

    然后再接收4个字节0ad33704为target,2个字节0050为targetPort。
    再用ord()函数从target依次拼接返回十进制数。
    我们可以在console控制台判断一下

    image.png image.png

    实战调试

    大概分析之后,大家应该对整个流程有了一定了解。
    下面结合实战对存在的两个问题进行解决。
    1. proxifier 代理时为什么出现许多莫名其妙的IP?
    其实打开firfox浏览器的一瞬间,firefox就会有多个域名发出请求。

    image.png

    而在reGeorgSocksProxy.py终端里就会解析出多个莫名其妙的IP。

    image.png

    2.什么时候才可以判断确实代理成功?
    从代码层上看,访问远程代理服务器tunnel.nosocket.php返回Georg says, 'All seems fine'就可以代理成功的。因为tunnel.nosocket.php只起到一个中转的作用,转发流量到内网。
    而这次error的原因是目标地址的80端口没有开放,其实不能说明代理是不能使用的。
    比如访问8180端口

    image.png

    最后选择在kali的proxychains和自己编写的端口扫描成功代理。

    image.png

    tunnel.nosocket.php 免杀

    最后还测试某盾查杀了tunnel.nosocket.php,调式发现主要查杀两个位置。

    image.png

    一个fsockopen()函数,对该函数提前引用即可绕过。

    image.png

    一个php输入流,即php://input,使用str_rot13()函数和一些混淆即可绕过。

    $php = str_rot13('c!c!cuc');
    $str = explode('!',$php)[2];
    $pql = $str."://";
    $phpinput = $pql."input"; 
    

    也可以结合webshell免杀的思路,使用简单的编码思路将脚本base64编码之后再解码。

    image.png

    也可成功免杀。

    总结

    大致分析了reGeorg的工作流程,明白是socks编程完成流量的转发,再将结果返回,结合实战成功建立了代理,最后两个姿势进行简单免杀处理。

    相关文章

      网友评论

          本文标题:reGeorg简要分析

          本文链接:https://www.haomeiwen.com/subject/nqulsktx.html