前言:最近两场HW都和某师傅学到了挺多东西,算是对内网不出网以及流量代理做个分析(SOCKS协议,reGeorg原理分析,frp的代理,CS上的代理

SOCKS

SOCKS(Socks:Protocol for sessions traversal across firewall securely)防火墙安全会话转换协议

SOCKS是一种网络传输协议,主要用于客户端和外网服务器之间通讯的中间传输。SOCKS是“socket secure”的缩写

当防火墙后的客户端要访问外部的服务器时,就跟SOCKS代理服务器连接。这个代理服务器控制着客户端访问外网的资格,允许的话,就将客户端的请求发往外部的服务器。

Socks协议定位非常清楚,工作于会话层,就是在防火墙服务器上,提供一种对于TCP会话的转发,允许用户可以透明的穿透防火墙的阻拦。这种协议优势在于,它完全独立于应用层的协议,可以用于telent,http,ftp。且可以在TCP会话开始之前,完成权限的检查,之后只需要做往复的转发即可;常用的防火墙,或代理软件都支持SOCKS

新的协议 SOCKS v5 在 SOCKSV4基础上作了进一步扩展,从而可以支持 UDP ,并对其框架规定作了扩展,以支持安全认证方案。同时它还采用地址解析方案 (addressing scheme) 以支持域名和 IPV6 地址解析

(example:域环境下有DUDU.org.com,Socks5协议就可以支持对地址解析的代理)

现在普遍使用的 SOCKSv5,协议变复杂了很多。首先,因为有强力的验证,而且支持多种验证方法,就有了一个协商验证方法的过程,然后,进行身份验证,最后再进行通信指令

通信流程:

  • 客户端连接上代理服务器之后需要发送请求告知服务器目前的socks协议版本以及支持的认证方式
  • 代理服务器收到请求后根据其设定的认证方式返回给客户端
  • 如果代理服务器不需要认证,客户端将直接向代理服务器发起真实请求
  • 代理服务器收到该请求之后连接客户端请求的目标服务器
  • 代理服务器开始转发客户端与目标服务器之间的流量

加密过程:



 虽然HTTP代理有不同的使用模式,CONNECT方法允许转发TCP连接;然而,socks代理还可以转发UDP流量和反向代理,
而HTTP代理不能。HTTP代理更适合HTTP协议,执行更高层次的过滤;socks不管应用层是什么协议,只要是传输层是
TCP/UDP协议就可以代理------------此协议的强大之处

reGeorg简单分析

一般主要用于服务器已GetShell,想横向但是因为防火墙ACL给你卡死,只允许HTTP进出,无法端口转发
之前HW好几个目标系统都是其他服务器不出网情况,只能搭建reGeorg等工具进行隧道搭建,访问内网其他服务器

Github上关于reGeorg的简介

The successor to reDuh, pwn a bastion webserver and create SOCKS proxies through the DMZ. Pivot and pwn.



使用起来也简单,用蚁剑,哥斯拉,冰蝎,天蝎等拿到shell工具传个服务器对应的tnuuel.XXX

然后CMD下:

$ python reGeorgSocksProxy.py -p 8080 -u http://DUDU.com/tunnel/tunnel.jsp



然后就可以对内网进行探测,扫描

整体流程图:

1.绑定本地的8080端口,起一个SockerServer服务。用来接收本地转发的流量
 servSock = socket(AF_INET, SOCK_STREAM)
servSock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
servSock.bind((args.listen_on, args.listen_port))
servSock.listen(1000)
while True:
try:
sock, addr_info = servSock.accept()
sock.settimeout(SOCKTIMEOUT)
log.debug("Incomming connection")
session(sock, args.url).start()
except KeyboardInterrupt, ex:
break
except Exception, e:
2.用Proxifier将流量代理到本地的8080端口
3.一旦有流量进入后,判断是socks的哪个版本
ver = sock.recv(1)
if ver == "\x05":
return self.parseSocks5(sock)
elif ver == "\x04":
return self.parseSocks4(sock)
获取请求的target + ip
log.debug("SocksVersion5 detected")
nmethods, methods = (sock.recv(1), sock.recv(1))
sock.sendall(VER + METHOD)
ver = sock.recv(1)
if ver == "\x02": # this is a hack for proxychains
ver, cmd, rsv, atyp = (sock.recv(1), sock.recv(1), sock.recv(1), sock.recv(1))
else:
cmd, rsv, atyp = (sock.recv(1), sock.recv(1), sock.recv(1))
target = None
targetPort = None
if atyp == "\x01": # IPv4
# Reading 6 bytes for the IP and Port
target = sock.recv(4)
targetPort = sock.recv(2)
target = "." .join([str(ord(i)) for i in target])
targetPort = ord(targetPort[0]) * 256 + ord(targetPort[1])
if cmd == "\x02": # BIND
raise SocksCmdNotImplemented("Socks5 - BIND not implemented")
elif cmd == "\x03": # UDP
raise SocksCmdNotImplemented("Socks5 - UDP not implemented")
elif cmd == "\x01": # CONNECT
serverIp = target
try:
serverIp = gethostbyname(target)
except:
log.error("oeps")
serverIp = "".join([chr(int(i)) for i in serverIp.split(".")])
4.发送http请求到服务端的脚本,标识符是CONNECT。附带的参数是tagetIP+Port
如果请求成功,会生成的sessionID保存下来(很重要用来保存整个服务端和Target的Socket会话状态)
headers = {"X-CMD": "CONNECT", "X-TARGET": target, "X-PORT": port}
self.target = target
self.port = port
cookie = None
conn = self.httpScheme(host=self.httpHost, port=self.httpPort)
# response = conn.request("POST", self.httpPath, params, headers)
response = conn.urlopen('POST', self.connectString + "?cmd=connect&target=%s&port=%d" % (target, port), headers=headers, body="")
if response.status == 200:
status = response.getheader("x-status")
if status == "OK":
cookie = response.getheader("set-cookie")
log.info("[%s:%d] HTTP [200]: cookie [%s]" % (self.target, self.port, cookie))
else:
if response.getheader("X-ERROR") is not None:
log.error(response.getheader("X-ERROR"))
5.Tunel服务器与Target建立Socket连接
if (cmd.compareTo("CONNECT") == 0) {
try {
String target = request.getHeader("X-TARGET");
int port = Integer.parseInt(request.getHeader("X-PORT"));
SocketChannel socketChannel = SocketChannel.open();
socketChannel.connect(new InetSocketAddress(target, port));
socketChannel.configureBlocking(false);
session.setAttribute("socket", socketChannel);
response.setHeader("X-STATUS", "OK");
}
6.发送http请求到服务端的脚本,标识符是READ
headers = {"X-CMD": "READ", "Cookie": self.cookie, "Connection": "Keep-Alive"}
response = conn.urlopen('POST', self.connectString + "?cmd=read", headers=headers, body="")
data = None
if response.status == 200:
status = response.getheader("x-status")
if status == "OK":
if response.getheader("set-cookie") is not None:
cookie = response.getheader("set-cookie")
data = response.data
# Yes I know this is horrible, but its a quick fix to issues with tomcat 5.x bugs that have been reported, will find a propper fix laters
try:
if response.getheader("server").find("Apache-Coyote/1.1") > 0:
data = data[:len(data) - 1]
except:
pass
if data is None:
data = ""
else:
data = None
log.error("[%s:%d] HTTP [%d]: Status: [%s]: Message [%s] Shutting down" % (self.target, self.port, response.status, status, response.getheader("X-ERROR")))
else:
log.error("[%s:%d] HTTP [%d]: Shutting down" % (self.target, self.port, response.status))
if data is None:
# Remote socket closed
break
if len(data) == 0:
sleep(0.1)
continue
transferLog.info("[%s:%d] <<<< [%d]" % (self.target, self.port, len(data)))
self.pSocket.send(data)
7.Tunel服务器得到Client客户端发送的读取指令后,读取socket数据
SocketChannel socketChannel = (SocketChannel)session.getAttribute("socket");
try {
ByteBuffer buf = ByteBuffer.allocate(512);
int bytesRead = socketChannel.read(buf); }
8.把读到的数据,以二进制流的形式用response写给client
ServletOutputStream so = response.getOutputStream();
while (bytesRead > 0){
so.write(buf.array(),0,bytesRead);
so.flush();
buf.clear();
bytesRead = socketChannel.read(buf);
}
Client接收到数据,把响应数据send给相应的程序
pSocket.send(data)
9.经进行socketServer接受到数据进行解析,取出具体的data
比如我要访问内网的oa.com/admin.do系统,大概会生成如下data
StringBuffer temp = new StringBuffer();
temp.append("GET http://oa.com:8080/admin.do HTTP/1.1\r\n");
temp.append("Host: oa.com:8080\r\n");
temp.append("Connection: keep-alive\r\n");
temp.append("Cache-Control: max-age=0\r\n");
temp
.append("User-Agent: Mozilla/5.0 (Windows NT 5.1) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.47 Safari/536.11\r\n");
temp
.append("Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n");
temp.append("Accept-Encoding: gzip,deflate,sdch\r\n");
temp.append("Accept-Language: zh-CN,zh;q=0.8\r\n");
temp.append("Accept-Charset: GBK,utf-8;q=0.7,*;q=0.3\r\n");
temp.append("\r\n");
request = temp.toString().getBytes();
10.然后会把解析好的data放到http的data里,并将标识符设置成FORWARD。发送给Tunel服务器
self.pSocket.settimeout(1)
data = self.pSocket.recv(READBUFSIZE)
if not data:
break
print("FORWARD---------")
headers = {"X-CMD": "FORWARD", "Cookie": self.cookie, "Content-Type": "application/octet-stream", "Connection": "Keep-Alive"}
response = conn.urlopen('POST', self.connectString + "?cmd=forward", headers=headers, body=data)
if response.status == 200:
status = response.getheader("x-status")
if status == "OK":
if response.getheader("set-cookie") is not None:
self.cookie = response.getheader("set-cookie")
else:
log.error("[%s:%d] HTTP [%d]: Status: [%s]: Message [%s] Shutting down" % (self.target, self.port, response.status, status, response.getheader("x-error")))
break
else:
log.error("[%s:%d] HTTP [%d]: Shutting down" % (self.target, self.port, response.status))
break
transferLog.info("[%s:%d] >>>> [%d]" % (self.target, self.port, len(data)))
11.Tunel服务器接收到数据后,得到标识符FORWARD后,从request获取到二进制数据流。write给前面建立好的SocketChannel
else if (cmd.compareTo("FORWARD") == 0){
SocketChannel socketChannel = (SocketChannel)session.getAttribute("socket");
try { int readlen = request.getContentLength();
byte[] buff = new byte[readlen];
request.getInputStream().read(buff, 0, readlen);
ByteBuffer buf = ByteBuffer.allocate(readlen);
buf.clear();
buf.put(buff);
buf.flip();
while(buf.hasRemaining()) {
socketChannel.write(buf);
}
response.setHeader("X-STATUS", "OK");
//response.getOutputStream().close(); }

流程:

主要是本地起了一个socks代理服务器,而后PC不断的和tunnel sever进行HTTP的交互验证完socks4或者是socks5后,会调用函数解析获取到的目标ip以及端口,而后向自己上传在服务器上的tunnel.jsp发送一个connect请求,请求成功后会保存Socket会话(session ID保存),后续通过循环判断是否有传递的内容,通过socket连接向目标机器发送请求内容,且不断从与目标机器建立的socket连接中获取数据,存在就写入readbuff变量。接着发送forword请求,将真实的数据发送给tunnel,然后tunnel获到post数据转发到socket连接中,发送给目标机器,然后将目标机器返回的数据存放$_SESSION['readbuf']中,等待下一次read请求来获取内容;

frp搭建代理隧道的话,也用到了Socks代理协议去连接frps

CS上的socks4隧道

后渗透神奇CobaltStrike上也自带了Socks4代理,只需要简单的设置端口号,然后本地设置个全局代理,一键梭哈

(之前一直和老师傅用的frp搭建隧道,后来发现CS内置的也很稳定,只不过是socks4罢了)





然后全局代理软件设置端口,设置协议。先去检测一下连通性



最需要注意的点就是内网ip段,因为在被控sever上ipconfig的内网ip不一定是全部,有可能10,172,192三个段都会存在存活主机(血的教训)



为了更仔细一点扫描,还是拿fscan,Ladon等扫描更多的段,说不定柳暗花明又一村

参考文章:

http://screwsec.com/2020/06/05/reGeorg原理分析/#详细细节

https://sexywp.com/socks-protocol.htm

Socks协议以及代理转发工具分析的更多相关文章

  1. 【转】fiddler-http协议调试代理工具

    题目有一些激进.但是在前端界打滚了这么多年,fiddler一直都是陪着我走过来了.它就是一个抓包神奇,代理神器.它的厉害之处,我简单地说一下,希望你们看了以后,能点上32个赞. 1.fiddler为何 ...

  2. 基于SSH协议的端口转发

    [前言] 最近一直在使用ssh协议的端口转发(隧道)功能,完成对内网空透等.这篇文章将主要讲解3种常用的ssh tunnelling使用方法和基本原理. 在介绍具体内容前,我先奉上端口转发的常用情景: ...

  3. HTTP协议属于应用层,而SOCKS协议属于传输层

    HTTP协议属于应用层,而SOCKS协议属于传输层 SOCKS代理 SOCKS代理能在任何端口,任何协议下运行. SOCKS V4只支持 TCP连接,而SOCKS V5在其基础上增加了安全认证以及对U ...

  4. Windows 和 Linux 平台下的端口转发工具

    原文地址: http://unmi.cc/windows-linux-port-forwarding/ 这里记录一下我曾经使用过的几个端口转发工具,即端口映射.端口重定向,和 NAT 也是差不多的概念 ...

  5. netty系列之:netty对SOCKS协议的支持

    目录 简介 SocksMessage Socks4Message Socks5Message 总结 简介 SOCKS是一个优秀的网络协议,主要被用来做代理,它的两个主要版本是SOCKS4和SOCKS5 ...

  6. HTTP协议 (五) 代理

    HTTP协议 (五) 代理 阅读目录 什么是代理服务器 Fiddler就是个典型的代理 代理作用一:FQ 代理作用二:匿名访问 代理作用三:通过代理上网 代理作用四:通过代理缓存,加快上网速度 代理作 ...

  7. windows下使用密钥登录Linux及xshell代理转发

    1.密钥登录原理 一般我们使用xshell访问远程主机(Linux主机)时,都是先请管理员给我们开一个账户,即为我们设置一个一个用户名和对应的密码,然后我们就可以使用下面的方式登录到远程主机了: 在这 ...

  8. JDK动态代理深入理解分析并手写简易JDK动态代理(上)

    原文同步发表至个人博客[夜月归途] 原文链接:http://www.guitu18.com/se/java/2019-01-03/27.html 作者:夜月归途 出处:http://www.guitu ...

  9. Docker Kubernetes hostPort 代理转发

    Docker Kubernetes  hostPort 代理转发 hostPort: 1. 类似docker -p 映射宿主级端口到容器. 2. 容器所在的主机暴露端口转发到指定容器中. 3. hos ...

随机推荐

  1. .Net之Docker部署详细流程

    开篇语 自己从头开始走一遍docker部署.net的流程,作为一种学习总结,以及后续会写一些在该基础之上的文章. 本次示例环境:vs2019.net5.docker.postman 创建项目 本次事例 ...

  2. 异步访问技术Ajax(XMLHttpRequest)

    目录 AJAX XMLHttpRequest Ajax向服务器发送请求 Ajax接收服务器响应 AJAX - onreadystatechange 事件 使用 Callback 函数 一次Ajax请求 ...

  3. Windows PE第九章 线程局部存储

    线程局部存储(TLS) 这个东西并不陌生了,之前写过了一个关于这个的应用,利用静态TLS姿势实现代码段静态加密免杀或者所谓的加壳思路.地址在这:http://blog.csdn.net/u013761 ...

  4. intellij idea的Maven项目运行报程序包找不到的错误

    概括一句话:IDEA的Terminal命令行输入mvn idea:idea或者mvn idea:module , 即可解决 重做过开发环境后在intellij idea中载入java工程,通过mave ...

  5. 【转】风控中的特征评价指标(一)——IV和WOE

    转自:https://zhuanlan.zhihu.com/p/78809853 1.IV值的用途 IV,即信息价值(Information Value),也称信息量. 目前还只是在对LR建模时用到过 ...

  6. Linux下为Calibre书库打中文目录名与文件名补丁

    本文由来 临近下班突然看到知乎上有篇文章是给Calibre打中文目录与文件名补丁的,想起我之前为啥放弃Calibre的--存进书库里书的名称都变成了拼音!手动找起来或者搜索工具找起来太麻烦了(有时想不 ...

  7. 改善c++程序的150个建议(读后总结)-------12-18

    12.优先使用前置操作符 #include <iostream> using namespace std; class A { private: int num; public: A op ...

  8. MySQL5.7升级到8.0过程详解

    前言: 不知不觉,MySQL8.0已经发布好多个GA小版本了.目前互联网上也有很多关于MySQL8.0的内容了,MySQL8.0版本基本已到稳定期,相信很多小伙伴已经在接触8.0了.本篇文章主要介绍从 ...

  9. easy-flows源码研习

    一.项目概述 1.原项目github地址:https://github.com/j-easy/easy-flows.git 2.easy-flows可以用非常简易的api创建常用的可组合的工作流.涵盖 ...

  10. Linux上的Shebang符号(#!)

    使用Linux或者unix系统的同学可能都对#!这个符号并不陌生,但是你真的了解它吗? 本文了将给你简单介绍一下Shebang("#!")这个符号. 首先,这个符号(#!)的名称, ...