reverst:通过QUIC建立HTTP反向隧道的开源工具


Reverst 是一个基于 QUIC 和 HTTP/3 构建的(负载平衡)反向隧道服务器和 Go 服务器-客户端库。

  • Go Powered:使用quic-go以 Go 编写
  • 兼容性:Goclient包建立在net/http标准库抽象之上
  • 负载平衡:在同一隧道后面运行多个服务实例
  • 性能卓越:基于 QUIC 和 HTTP/3 构建

Reverst 用于在受限网络(例如 NAT 网关后面)内公开公共互联网上的服务。隧道二进制文件旨在部署在公共互联网上。然后,客户端服务器拨出到隧道并在目标隧道组上注册自己。隧道组是一组负载平衡的客户端服务器,通过 reverst 隧道 HTTP 接口公开。

Reverst是一个创新的反向隧道解决方案,利用QUIC和HTTP/3协议的高速和安全性,可以在受限网络内部向公网公开服务。它的主要特点包括:

  • 使用QUIC和HTTP/3协议,提供更快的连接建立和更高的吞吐量
  • 支持多路复用,单个连接可传输多个流
  • 支持连接迁移,可在网络环境变化时无缝切换网络
  • 支持0-RTT连接恢复,提高重连效率

反向隧道服务器和客户端库
Reverst 是一个反向隧道服务器,允许通过 QUIC 和 HTTP/3 从 NAT 或防火墙后面的客户端机器到服务器建立安全隧道。它还提供了一个 Go 客户端库,用于从 Go 应用程序创建这些反向隧道。

负载均衡
reverst 服务器支持跨多个后端服务器平衡传入隧道连接的负载。这允许扩展服务器端来处理更多的客户端连接。

用 Go 编写
整个 reverst 项目,包括服务器和客户端库,都是用 Go 编写的,并建立在 quic-go 库之上以支持 QUIC。

其他项目:
1、GOST是一个功能丰富的Go反向代理和隧道工具。它支持多种代理和隧道协议,包括反向代理隧道。主要特点有:

  • 支持反向代理隧道将内网服务暴露到公网
  • 提供公共反向代理测试服务GOST.PLUS
  • 支持串口重定向,实现串口远程通讯和数据监控
  • 支持各种代理协议:HTTP(S)、SOCKS5、Shadowsocks等

2、Supershell是一个基于反向SSH隧道的C2远控平台,通过在目标主机建立反向SSH隧道获取完全交互式Shell。主要特点包括:

  • 支持多平台架构Payload生成,集成压缩和免杀
  • 支持全平台完全交互式Shell,可分享Shell
  • 支持文件管理、内存注入、安装服务等功能
  • 支持客户端监听实现内网渗透

综上所述,Go语言提供了多种优秀的反向隧道解决方案,可满足不同场景的需求,如公网暴露内网服务、远程控制、内网渗透等。

在Go中实现反向隧道思路
在Go中实现反向隧道的基本思路是:

  1. 客户端主动连接公网服务器,建立TCP连接。
  2. 服务端接受客户端连接,作为代理服务器。
  3. 客户端通过该TCP连接将内网服务数据传输给代理服务器。
  4. 代理服务器接收数据后,将其转发给需要访问的公网客户端。

具体实现步骤如下:
客户端
  1. 使用net包建立与公网服务器的TCP连接。
  2. 启动本地HTTP服务,监听内网端口。
  3. 将本地HTTP服务接收到的请求数据通过之前建立的TCP连接发送给服务端。

// 建立与服务端的连接
conn, err := net.Dial(
"tcp", "服务器IP:端口")
if err != nil {
   
// 错误处理
}

// 启动本地HTTP服务
http.HandleFunc(
"/", func(w http.ResponseWriter, r *http.Request) {
   
// 读取请求数据
    data, err := ioutil.ReadAll(r.Body)
    if err != nil {
       
// 错误处理
    }
    
   
// 通过TCP连接发送数据给服务端
    conn.Write(data)
})

// 监听本地端口
http.ListenAndServe(
":8080", nil)

服务端

  1. 监听公网端口,接受客户端连接。
  2. 对每个连接,启动一个goroutine处理。
  3. 在goroutine中,从TCP连接读取客户端发来的数据。
  4. 将读取到的数据作为请求发送给需要访问的公网服务。
  5. 将公网服务的响应数据通过TCP连接返回给客户端。

// 监听端口
listener, err := net.Listen(
"tcp", ":8000")
if err != nil {
   
// 错误处理
}

// 循环接受连接
for {
    conn, err := listener.Accept()
    if err != nil {
       
// 错误处理
        continue
    }
    
   
// 启动goroutine处理连接
    go handleConn(conn)
}

func handleConn(conn net.Conn) {
    defer conn.Close()
    
   
// 读取客户端发来的数据
    data := make([]byte, 1024)
    n, err := conn.Read(data)
    if err != nil {
       
// 错误处理
        return
    }
    
   
// 将数据作为请求发送给公网服务
    resp, err := http.Post(
"http://公网服务地址", "binary/data", bytes.NewReader(data[:n]))
    if err != nil {
       
// 错误处理
        return  
    }
    defer resp.Body.Close()
    
   
// 读取公网服务响应
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
       
// 错误处理
        return
    }
    
   
// 将响应返回给客户端
    conn.Write(body)
}

在Go中实现内网穿透
客户端运行在内网中,主要职责是:

  1. 主动连接公网服务器,建立TCP连接作为隧道。
  2. 启动本地HTTP服务,监听需要穿透的内网端口。
  3. 将本地HTTP服务接收到的请求数据通过隧道TCP连接发送给服务端。
  4. 定期发送心跳包保持与服务端的连接。
  5. 如果与服务端连接断开,则重新连接。

// 建立与服务端的连接
conn, err := net.Dial(
"tcp", "服务器IP:端口")
if err != nil {
   
// 错误处理
}

// 启动本地HTTP服务
http.HandleFunc(
"/", func(w http.ResponseWriter, r *http.Request) {
   
// 读取请求数据
    data, err := ioutil.ReadAll(r.Body)
    if err != nil {
       
// 错误处理
    }
    
   
// 通过TCP连接发送数据给服务端
    conn.Write(data)
})

// 监听本地端口
http.ListenAndServe(
":8080", nil)

// 定期发送心跳包
go keepAlive(conn)

// 重连机制
go reconnect(conn)

服务端
服务端运行在公网服务器上,主要职责是:

  1. 监听公网端口,接受客户端连接。
  2. 对每个连接,启动一个goroutine处理。
  3. 在goroutine中,从TCP连接读取客户端发来的数据。
  4. 将读取到的数据作为请求发送给需要访问的公网服务。
  5. 将公网服务的响应数据通过TCP连接返回给客户端。
  6. 处理客户端断开连接的情况。

// 监听端口
listener, err := net.Listen(
"tcp", ":8000"
if err != nil {
   
// 错误处理
}

// 循环接受连接
for {
    conn, err := listener.Accept()
    if err != nil {
       
// 错误处理
        continue
    }
    
   
// 启动goroutine处理连接
    go handleConn(conn)
}

func handleConn(conn net.Conn) {
    defer conn.Close()
    
   
// 读取客户端发来的数据
    data := make([]byte, 1024)
    n, err := conn.Read(data)
    if err != nil {
       
// 错误处理
        return
    }
    
   
// 将数据作为请求发送给公网服务
    resp, err := http.Post(
"http://公网服务地址", "binary/data", bytes.NewReader(data[:n]))
    if err != nil {
       
// 错误处理
        return  
    }
    defer resp.Body.Close()
    
   
// 读取公网服务响应
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
       
// 错误处理
        return
    }
    
   
// 将响应返回给客户端
    conn.Write(body)
}