快盘下载:好资源、好软件、快快下载吧!
快盘排行|快盘最新
前言
本文研究端口转发 & SOCKS代理工具的一个工具,iox
github:https://github.com/EddieIvan01/iox
一、概述
1、简介
最后更新于2020年,用Go编写,功能类似于lcx/ew,优化了网络逻辑,简化了使用方法
2、原理
就是端口转发和SOCKS代理,与lcx和EW的原理相仿
3、用法
#加密 ./iox fwd -r 192.168.0.100:3389 -r *1.1.1.1:8888 -k 656565 #目标 ./iox fwd -l *8888 -l 33890 -k 656565 #攻击机 # UDP -u ./iox fwd -l 53 -r *127.0.0.1:8888 -k 000102 -u ./iox fwd -l *8888 -l *9999 -k 000102 -u ./iox fwd -r *127.0.0.1:9999 -r 8.8.8.8:53 -k 000102 -u
(1)端口转发
#监听 0.0.0.0:8888 和0.0.0.0:9999,将两个连接间的流量转发 ./iox fwd -l 8888 -l 9999 #监听0.0.0.0:8888,把流量转发到1.1.1.1:9999 ./iox fwd -l 8888 -r 1.1.1.1:9999 #连接1.1.1.1:8888和1.1.1.1:9999, 在两个连接间转发 ./iox fwd -r 1.1.1.1:8888 -r 1.1.1.1:9999
(2)SOCKS代理
#在本地 0.0.0.0:1080启动Socks5服务 ./iox proxy -l 1080 #在被控机开启Socks5服务,将服务转发到公网VPS #在VPS上转发0.0.0.0:9999到0.0.0.0:1080 #你必须将两条命令成对使用,因为它内部包含了一个简单的协议来控制回连 ./iox proxy -r 1.1.1.1:9999 ./iox proxy -l 9999 -l 1080 #注意,这两个端口是有顺序的 #接着连接内网主机 proxychains.conf socks5://1.1.1.1:1080 $ proxychains rdesktop 192.168.0.100:3389
二、实践
1、测试场景
攻击机(服务端):kali 192.168.10.128
目标机(客户端):ubuntu 192.168.10.129
都没有限制TCP连接
2、端口转发
(1)服务端
./iox fwd -l *2222 -l 3333 -k 123456
开启apache
./iox fwd -r 127.0.0.1:80 -r *192.168.10.128:2222 -k 123456
还可以nc、ssh等,根据端口来确定服务
tcp三次握手建立连接,客户端向外发起连接的端口是60614和60618
心跳包
修改/etc/proxychains.conf
socks5 0.0.0.0 1080
监听并映射端口
./iox proxy -l 2222 -l 1080
./iox proxy -r 192.168.10.128:2222
之后通过proxychains可以执行命令
如nmap扫描端口信息
proxychains4 nmap -p 1-1000 -Pn -sT 192.168.10.129
tcp握手
nmap期间
使用方法和调用相应模式
package main import ( "fmt" "iox/operate" "iox/option" "os" ) const VERSION = "0.4" func Usage() { fmt.Printf( "iox v%v "+ "Usage: iox fwd/proxy [-l [*][HOST:]PORT] [-r [*]HOST:PORT] [-k HEX] [-t TIMEOUT] [-u] [-h] [-v] "+ "Options: "+ " -l [*][HOST:]PORT "+ " address to listen on. `*` means encrypted socket "+ " -r [*]HOST:PORT "+ " remote host to connect, HOST can be IP or Domain. `*` means encrypted socket "+ " -k HEX "+ " hexadecimal format key, be used to generate Key and IV "+ " -u "+ " udp forward mode "+ " -t TIMEOUT "+ " set connection timeout(millisecond), default is 5000 "+ " -v "+ " enable log output "+ " -h "+ " print usage then exit ", VERSION, ) } func main() { mode, submode, local, remote, lenc, renc, err := option.ParseCli(os.Args[1:]) if err != nil { if err == option.PrintUsage { Usage() } else { fmt.Println(err.Error()) } return } // 端口转发和代理两种模式 switch mode { case "fwd": switch submode { case option.SUBMODE_L2R: operate.Local2Remote(local[0], remote[0], lenc[0], renc[0]) case option.SUBMODE_L2L: operate.Local2Local(local[0], local[1], lenc[0], lenc[1]) case option.SUBMODE_R2R: operate.Remote2Remote(remote[0], remote[1], renc[0], renc[1]) } case "proxy": switch submode { case option.SUBMODE_LP: operate.ProxyLocal(local[0], lenc[0]) case option.SUBMODE_RP: operate.ProxyRemote(remote[0], renc[0]) case option.SUBMODE_RPL2L: operate.ProxyRemoteL2L(local[0], local[1], lenc[0], lenc[1]) } } }
缺省值
package option const ( TCP_BUFFER_SIZE = 0x8000 // UDP protocol's max capacity UDP_PACKET_MAX_SIZE = 0xFFFF - 28 UDP_PACKET_CHANNEL_SIZE = 0x800 CONNECTING_RETRY_DURATION = 1500 SMUX_KEEPALIVE_INTERVAL = 20 SMUX_KEEPALIVE_TIMEOUT = 60 SMUX_FRAMESIZE = 0x8000 SMUX_RECVBUFFER = 0x400000 SMUX_STREAMBUFFER = 0x10000 ) var ( TIMEOUT = 5000 PROTOCOL = "TCP" // enable log output VERBOSE = false // logic optimization, changed in v0.1.1 FORWARD_WITHOUT_DEC = false )
读取输入参数
package option import ( "encoding/hex" "errors" "iox/crypto" "strconv" ) var ( errUnrecognizedMode = errors.New("Unrecognized mode. Must choose a working mode in [fwd/proxy]") errHexDecodeError = errors.New("KEY must be a hexadecimal string") PrintUsage = errors.New("") errUnrecognizedSubMode = errors.New("Malformed args. Incorrect number of `-l/-r` params") errNoSecretKey = errors.New("Encryption enabled, must specify a KEY by `-k` param") errNotANumber = errors.New("Timeout param must be a number") errUDPMode = errors.New("UDP mode only support fwd mode") ) const ( SUBMODE_L2L = iota SUBMODE_R2R SUBMODE_L2R SUBMODE_LP SUBMODE_RP SUBMODE_RPL2L ) // Dont need flag-lib func ParseCli(args []string) ( mode string, submode int, local []string, remote []string, lenc []bool, renc []bool, err error) { if len(args) == 0 { err = PrintUsage return } mode = args[0] switch mode { case "fwd", "proxy": case "-h", "--help": err = PrintUsage return default: err = errUnrecognizedMode return } args = args[1:] ptr := 0 for { if ptr == len(args) { break } switch args[ptr] { case "-l", "--local": l := args[ptr+1] if l[0] == '*' { lenc = append(lenc, true) l = l[1:] } else { lenc = append(lenc, false) } if _, err := strconv.Atoi(l); err == nil { local = append(local, "0.0.0.0:"+l) //默认监听0.0.0.0 } else { if l[0] == ':' { local = append(local, "0.0.0.0"+l) } else { local = append(local, l) } } ptr++ case "-r", "--remote": r := args[ptr+1] if r[0] == '*' { renc = append(renc, true) r = r[1:] } else { renc = append(renc, false) } remote = append(remote, r) ptr++ case "-u", "--udp": PROTOCOL = "UDP" case "-k", "--key": var key []byte key, err = hex.DecodeString(args[ptr+1]) if err != nil { err = errHexDecodeError return } crypto.ExpandKey(key) ptr++ case "-t", "--timeout": TIMEOUT, err = strconv.Atoi(args[ptr+1]) if err != nil { err = errNotANumber return } ptr++ case "-v", "--verbose": VERBOSE = true case "-h", "--help": err = PrintUsage return } ptr++ } if mode == "fwd" { switch { case len(local) == 0 && len(remote) == 2: submode = SUBMODE_R2R case len(local) == 1 && len(remote) == 1: submode = SUBMODE_L2R case len(local) == 2 && len(remote) == 0: submode = SUBMODE_L2L default: err = errUnrecognizedSubMode return } } else { switch { case len(local) == 0 && len(remote) == 1: submode = SUBMODE_RP case len(local) == 1 && len(remote) == 0: submode = SUBMODE_LP case len(local) == 2 && len(remote) == 0: submode = SUBMODE_RPL2L default: err = errUnrecognizedSubMode return } } if len(lenc) != len(local) || len(renc) != len(remote) { err = errUnrecognizedSubMode return } if crypto.SECRET_KEY == nil { for i, _ := range lenc { if lenc[i] { err = errNoSecretKey return } } for i, _ := range renc { if renc[i] { err = errNoSecretKey return } } } if PROTOCOL == "UDP" && mode == "proxy" { err = errUDPMode return } shouldFwdWithoutDec(lenc, renc) return } func shouldFwdWithoutDec(lenc []bool, renc []bool) { if len(lenc)+len(renc) != 2 { return } var result uint8 for i, _ := range lenc { if lenc[i] { result++ } } for i, _ := range renc { if renc[i] { result++ } } if result == 2 { FORWARD_WITHOUT_DEC = true } }
TCP和UDP的信息的加密写和解密读
package netio import ( "iox/crypto" "iox/option" "net" ) type Ctx interface { DecryptRead(b []byte) (int, error) EncryptWrite(b []byte) (int, error) net.Conn } var _ Ctx = &TCPCtx{} var _ Ctx = &UDPCtx{} type TCPCtx struct { net.Conn encrypted bool // Ensure stream cipher synchronous encCipher *crypto.Cipher decCipher *crypto.Cipher } func NewTCPCtx(conn net.Conn, encrypted bool) (*TCPCtx, error) { // if tc, ok := conn.(*net.TCPConn); ok { // tc.SetLinger(0) // } encrypted = encrypted && !option.FORWARD_WITHOUT_DEC ctx := &TCPCtx{ Conn: conn, encrypted: encrypted, } if encrypted { encCipher, decCipher, err := crypto.NewCipherPair() if err != nil { return nil, err } ctx.encCipher = encCipher ctx.decCipher = decCipher } return ctx, nil } func (c *TCPCtx) DecryptRead(b []byte) (int, error) { n, err := c.Read(b) if err != nil { return n, err } if c.encrypted { c.decCipher.StreamXOR(b[:n], b[:n]) } return n, err } func (c *TCPCtx) EncryptWrite(b []byte) (int, error) { if c.encrypted { c.encCipher.StreamXOR(b, b) } return c.Write(b) } type UDPCtx struct { *net.UDPConn encrypted bool connected bool remoteAddr *net.UDPAddr // sync.Mutex } func NewUDPCtx(conn *net.UDPConn, encrypted bool, connected bool) (*UDPCtx, error) { encrypted = encrypted && !option.FORWARD_WITHOUT_DEC ctx := &UDPCtx{ UDPConn: conn, encrypted: encrypted, connected: connected, } return ctx, nil } // Encryption for packet is different from stream func (c *UDPCtx) DecryptRead(b []byte) (int, error) { var n int var err error if !c.connected { var remoteAddr *net.UDPAddr n, remoteAddr, err = c.ReadFromUDP(b) if err != nil { return n, err } c.remoteAddr = remoteAddr } else { n, err = c.Read(b) if err != nil { return n, err } } if c.encrypted { if len(b) < 0x18 { // no nonce, skip return 0, nil } nonce := b[n-0x18 : n] b = b[:n-0x18] cipher, err := crypto.NewCipher(nonce) if err != nil { return 0, err } n -= 0x18 cipher.StreamXOR(b[:n], b[:n]) } return n, err } func (c *UDPCtx) EncryptWrite(b []byte) (int, error) { if c.encrypted { iv, err := crypto.RandomNonce() cipher, err := crypto.NewCipher(iv) if err != nil { return 0, err } cipher.StreamXOR(b, b) b = append(b, iv...) } if !c.connected { return c.WriteTo(b, c.remoteAddr) } return c.Write(b) } /* func (c UDPCtx) IsRemoteAddrRegistered() bool { return c.remoteAddr != nil } */
读写功能,每个套接字只将数据包写入最近向其发送数据包的地址,而不是广播到所有地址
package netio import ( "io" "iox/logger" "iox/option" ) func CipherCopy(dst Ctx, src Ctx) (int64, error) { buffer := make([]byte, option.TCP_BUFFER_SIZE) var written int64 var err error for { var nr int var er error nr, er = src.DecryptRead(buffer) if nr > 0 { var nw int var ew error nw, ew = dst.EncryptWrite(buffer[:nr]) if nw > 0 { logger.Info("<== [%d bytes] ==> ", nw) written += int64(nw) } if ew != nil { err = ew break } if nr != nw { err = io.ErrShortWrite break } } if er != nil { if er != io.EOF { err = er } break } } return written, err } func PipeForward(ctxA Ctx, ctxB Ctx) { signal := make(chan struct{}, 1) go func() { CipherCopy(ctxA, ctxB) signal <- struct{}{} }() go func() { CipherCopy(ctxB, ctxA) signal <- struct{}{} }() <-signal } // This function will run forever // If need to do performance optimization in future, I will consider a go-routine pool here, // but it will introduce the mutex-lock overhead func ForwardUDP(ctxA Ctx, ctxB Ctx) { go func() { buffer := make([]byte, option.UDP_PACKET_MAX_SIZE) for { nr, _ := ctxA.DecryptRead(buffer) if nr > 0 { if nr == 4 && buffer[0] == 0xCC && buffer[1] == 0xDD && buffer[2] == 0xEE && buffer[3] == 0xFF { continue } nw, _ := ctxB.EncryptWrite(buffer[:nr]) if nw > 0 { logger.Info("<== [%d bytes] ==>", nw) } } } }() go func() { buffer := make([]byte, option.UDP_PACKET_MAX_SIZE) for { nr, _ := ctxB.DecryptRead(buffer) if nr > 0 { if nr == 4 && buffer[0] == 0xCC && buffer[1] == 0xDD && buffer[2] == 0xEE && buffer[3] == 0xFF { continue } nw, _ := ctxA.EncryptWrite(buffer[:nr]) if nw > 0 { logger.Info("<== [%d bytes] ==>", nw) } } } }() select {} } var UDP_INIT_PACKET = []byte{ 0xCC, 0xDD, 0xEE, 0xFF, } // Each socket only writes the packet to the address which last sent packet to it recently, // instead of broadcasting to all the address func ForwardUnconnectedUDP(ctxA Ctx, ctxB Ctx) { addrRegistedA := false addrRegistedB := false addrRegistedSignalA := make(chan struct{}) addrRegistedSignalB := make(chan struct{}) packetChannelA := make(chan []byte, option.UDP_PACKET_CHANNEL_SIZE) packetChannelB := make(chan []byte, option.UDP_PACKET_CHANNEL_SIZE) // A read go func() { for { buffer := make([]byte, option.UDP_PACKET_MAX_SIZE) nr, _ := ctxA.DecryptRead(buffer) if nr > 0 { if !addrRegistedA { addrRegistedA = true addrRegistedSignalA <- struct{}{} } if !(nr == 4 && buffer[0] == 0xCC && buffer[1] == 0xDD && buffer[2] == 0xEE && buffer[3] == 0xFF) { packetChannelB <- buffer[:nr] } } } }() // B read go func() { for { buffer := make([]byte, option.UDP_PACKET_MAX_SIZE) nr, _ := ctxB.DecryptRead(buffer) if nr > 0 { if !addrRegistedB { addrRegistedB = true addrRegistedSignalB <- struct{}{} } if !(nr == 4 && buffer[0] == 0xCC && buffer[1] == 0xDD && buffer[2] == 0xEE && buffer[3] == 0xFF) { packetChannelA <- buffer[:nr] } } } }() // A write go func() { <-addrRegistedSignalA var n int for { packet := <-packetChannelA n, _ = ctxA.EncryptWrite(packet) if n > 0 { logger.Info("<== [%d bytes] ==>", n) } } }() // B write go func() { <-addrRegistedSignalB var n int for { packet := <-packetChannelB n, _ = ctxB.EncryptWrite(packet) if n > 0 { logger.Info("<== [%d bytes] ==>", n) } } }() select {} }
写socks5
// code from https://github.com/ring04h/s5.go package socks5 import ( "errors" "io" "iox/logger" "iox/netio" "iox/option" "net" "strconv" "time" ) var ( Commands = []string{"CONNECT", "BIND", "UDP ASSOCIATE"} AddrType = []string{"", "IPv4", "", "Domain", "IPv6"} Verbose = false errAddrType = errors.New("socks addr type not supported") errVer = errors.New("socks version not supported") errMethod = errors.New("socks only support noauth method") errAuthExtraData = errors.New("socks authentication get extra data") errReqExtraData = errors.New("socks request get extra data") errCmd = errors.New("socks only support connect command") ) const ( socksVer5 = 0x05 socksCmdConnect = 0x01 ) func readAtLeast(r netio.Ctx, buf []byte, min int) (n int, err error) { if len(buf) < min { return 0, io.ErrShortBuffer } for n < min && err == nil { var nn int nn, err = r.DecryptRead(buf[n:]) n += nn } if n >= min { err = nil } else if n > 0 && err == io.EOF { err = io.ErrUnexpectedEOF } return } func handShake(conn netio.Ctx) (err error) { const ( idVer = 0 idNmethod = 1 ) buf := make([]byte, 258) var n int // make sure we get the nmethod field if n, err = readAtLeast(conn, buf, idNmethod+1); err != nil { return } if buf[idVer] != socksVer5 { return errVer } nmethod := int(buf[idNmethod]) // client support auth mode msgLen := nmethod + 2 // auth msg length if n == msgLen { // handshake done, common case // do nothing, jump directly to send confirmation } else if n < msgLen { // has more methods to read, rare case if _, err = readAtLeast(conn, buf[n:msgLen], len(buf[n:msgLen])); err != nil { return } } else { // error, should not get extra data return errAuthExtraData } /* X'00' NO AUTHENTICATION REQUIRED X'01' GSSAPI X'02' USERNAME/PASSWORD X'03' to X'7F' IANA ASSIGNED X'80' to X'FE' RESERVED FOR PRIVATE METHODS X'FF' NO ACCEPTABLE METHODS */ // send confirmation: version 5, no authentication required _, err = conn.EncryptWrite([]byte{socksVer5, 0}) return } func parseTarget(conn netio.Ctx) (host string, err error) { const ( idVer = 0 idCmd = 1 idType = 3 // address type index idIP0 = 4 // ip addres start index idDmLen = 4 // domain address length index idDm0 = 5 // domain address start index typeIPv4 = 1 // type is ipv4 address typeDm = 3 // type is domain address typeIPv6 = 4 // type is ipv6 address lenIPv4 = 3 + 1 + net.IPv4len + 2 // 3(ver+cmd+rsv) + 1addrType + ipv4 + 2port lenIPv6 = 3 + 1 + net.IPv6len + 2 // 3(ver+cmd+rsv) + 1addrType + ipv6 + 2port lenDmBase = 3 + 1 + 1 + 2 // 3 + 1addrType + 1addrLen + 2port, plus addrLen ) // refer to getRequest in server.go for why set buffer size to 263 buf := make([]byte, 263) var n int // read till we get possible domain length field if n, err = readAtLeast(conn, buf, idDmLen+1); err != nil { return } // check version and cmd if buf[idVer] != socksVer5 { err = errVer return } /* CONNECT X'01' BIND X'02' UDP ASSOCIATE X'03' */ if buf[idCmd] > 0x03 || buf[idCmd] == 0x00 { logger.Info("Unknown Command: %d", buf[idCmd]) } if buf[idCmd] != socksCmdConnect { // only support CONNECT mode err = errCmd return } // read target address reqLen := -1 switch buf[idType] { case typeIPv4: reqLen = lenIPv4 case typeIPv6: reqLen = lenIPv6 case typeDm: // domain name reqLen = int(buf[idDmLen]) + lenDmBase default: err = errAddrType return } if n == reqLen { // common case, do nothing } else if n < reqLen { // rare case if _, err = readAtLeast(conn, buf[n:reqLen], len(buf[n:reqLen])); err != nil { return } } else { err = errReqExtraData return } switch buf[idType] { case typeIPv4: host = net.IP(buf[idIP0 : idIP0+net.IPv4len]).String() case typeIPv6: host = net.IP(buf[idIP0 : idIP0+net.IPv6len]).String() case typeDm: host = string(buf[idDm0 : idDm0+buf[idDmLen]]) } port := bigEndianUint16(buf[reqLen-2 : reqLen]) host = net.JoinHostPort(host, strconv.Itoa(int(port))) return } func bigEndianUint16(b []byte) uint16 { _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808 return uint16(b[1]) | uint16(b[0])<<8 } func pipeWhenClose(conn netio.Ctx, target string) { remoteConn, err := net.DialTimeout( "tcp", target, time.Millisecond*time.Duration(option.TIMEOUT), ) if err != nil { logger.Info("Connect remote :" + err.Error()) return } defer remoteConn.Close() tcpAddr := remoteConn.LocalAddr().(*net.TCPAddr) if tcpAddr.Zone == "" { if tcpAddr.IP.Equal(tcpAddr.IP.To4()) { tcpAddr.Zone = "ip4" } else { tcpAddr.Zone = "ip6" } } rep := make([]byte, 256) rep[0] = 0x05 rep[1] = 0x00 // success rep[2] = 0x00 //RSV //IP if tcpAddr.Zone == "ip6" { rep[3] = 0x04 //IPv6 } else { rep[3] = 0x01 //IPv4 } var ip net.IP if "ip6" == tcpAddr.Zone { ip = tcpAddr.IP.To16() } else { ip = tcpAddr.IP.To4() } pindex := 4 for _, b := range ip { rep[pindex] = b pindex += 1 } rep[pindex] = byte((tcpAddr.Port >> 8) & 0xff) rep[pindex+1] = byte(tcpAddr.Port & 0xff) conn.EncryptWrite(rep[0 : pindex+2]) // Transfer data remoteConnCtx, err := netio.NewTCPCtx(remoteConn, false) if err != nil { logger.Info("Socks5 remote connect error: %s", err.Error()) return } netio.PipeForward(conn, remoteConnCtx) } func HandleConnection(conn netio.Ctx) { if err := handShake(conn); err != nil { logger.Info("Socks5 handshake error: %s", err.Error()) return } addr, err := parseTarget(conn) if err != nil { logger.Info("socks consult transfer mode or parse target: %s", err.Error()) return } pipeWhenClose(conn, addr) }
TCP和UDP的三种端口转发
package operate import ( "iox/crypto" "iox/logger" "iox/netio" "iox/option" "net" "time" ) func local2RemoteTCP(local string, remote string, lenc bool, renc bool) { listener, err := net.Listen("tcp", local) if err != nil { logger.Warn("Listen on %s error: %s", local, err.Error()) return } defer listener.Close() for { logger.Info("Wait for connection on %s", local) localConn, err := listener.Accept() if err != nil { logger.Warn("Handle local connect error: %s", err.Error()) continue } go func() { defer localConn.Close() logger.Info("Connection from %s", localConn.RemoteAddr().String()) logger.Info("Connecting " + remote) localConnCtx, err := netio.NewTCPCtx(localConn, lenc) if err != nil { logger.Warn("Handle local connect error: %s", err.Error()) return } remoteConn, err := net.DialTimeout( "tcp", remote, time.Millisecond*time.Duration(option.TIMEOUT), ) if err != nil { logger.Warn("Connect remote %s error: %s", remote, err.Error()) return } defer remoteConn.Close() remoteConnCtx, err := netio.NewTCPCtx(remoteConn, renc) if err != nil { logger.Warn("Connect remote %s error: %s", remote, err.Error()) return } logger.Info("Open pipe: %s <== FWD ==> %s", localConn.RemoteAddr().String(), remoteConn.RemoteAddr().String()) netio.PipeForward(localConnCtx, remoteConnCtx) logger.Info("Close pipe: %s <== FWD ==> %s", localConn.RemoteAddr().String(), remoteConn.RemoteAddr().String()) }() } } func local2RemoteUDP(local string, remote string, lenc bool, renc bool) { localAddr, err := net.ResolveUDPAddr("udp", local) if err != nil { logger.Warn("Parse udp address %s error: %s", local, err.Error()) return } listener, err := net.ListenUDP("udp", localAddr) if err != nil { logger.Warn("Listen udp on %s error: %s", local, err.Error()) return } defer listener.Close() remoteAddr, err := net.ResolveUDPAddr("udp", remote) if err != nil { logger.Warn("Parse udp address %s error: %s", local, err.Error()) return } remoteConn, err := net.DialUDP("udp", nil, remoteAddr) if err != nil { logger.Warn("Dial remote udp %s error: %s", local, err.Error()) return } defer remoteConn.Close() listenerCtx, err := netio.NewUDPCtx(listener, lenc, false) if err != nil { return } remoteCtx, err := netio.NewUDPCtx(remoteConn, renc, true) if err != nil { return } netio.ForwardUDP(listenerCtx, remoteCtx) } func Local2Remote(local string, remote string, lenc bool, renc bool) { if option.PROTOCOL == "TCP" { logger.Success("Forward TCP traffic between %s (encrypted: %v) and %s (encrypted: %v)", local, lenc, remote, renc) local2RemoteTCP(local, remote, lenc, renc) } else { logger.Success("Forward UDP traffic between %s (encrypted: %v) and %s (encrypted: %v)", local, lenc, remote, renc) local2RemoteUDP(local, remote, lenc, renc) } } func local2LocalTCP(localA string, localB string, laenc bool, lbenc bool) { var listenerA net.Listener var listenerB net.Listener for { signal := make(chan byte) var localConnA net.Conn var localConnB net.Conn go func() { var err error listenerA, err = net.Listen("tcp", localA) if err != nil { logger.Warn("Listen on %s error: %s", localA, err.Error()) return } defer listenerA.Close() for { logger.Info("Wait for connection on %s", localA) var err error localConnA, err = listenerA.Accept() if err != nil { logger.Warn("Handle connection error: %s", err.Error()) continue } break } signal <- 'A' }() go func() { var err error listenerB, err = net.Listen("tcp", localB) if err != nil { logger.Warn("Listen on %s error: %s", localB, err.Error()) return } defer listenerB.Close() for { logger.Info("Wait for connection on %s", localB) var err error localConnB, err = listenerB.Accept() if err != nil { logger.Warn("Handle connection error: %s", err.Error()) continue } break } signal <- 'B' }() switch <-signal { case 'A': logger.Info("%s connected, waiting for %s", localA, localB) case 'B': logger.Info("%s connected, waiting for %s", localB, localA) } <-signal go func() { defer func() { if localConnA != nil { localConnA.Close() } if localConnB != nil { localConnB.Close() } }() //找了中间端口转发 localConnCtxA, err := netio.NewTCPCtx(localConnA, laenc) if err != nil { logger.Warn("handle local %s error: %s", localA, err.Error()) } localConnCtxB, err := netio.NewTCPCtx(localConnB, lbenc) if err != nil { logger.Warn("handle local %s error: %s", localB, err.Error()) } logger.Info("Open pipe: %s <== FWD ==> %s", localConnA.RemoteAddr().String(), localConnB.RemoteAddr().String()) netio.PipeForward(localConnCtxA, localConnCtxB) logger.Info("Close pipe: %s <== FWD ==> %s", localConnA.RemoteAddr().String(), localConnB.RemoteAddr().String()) }() } } func local2LocalUDP(localA string, localB string, laenc bool, lbenc bool) { localAddrA, err := net.ResolveUDPAddr("udp", localA) if err != nil { logger.Warn("Parse udp address %s error: %s", localA, err.Error()) return } listenerA, err := net.ListenUDP("udp", localAddrA) if err != nil { logger.Warn("Listen udp on %s error: %s", localA, err.Error()) return } defer listenerA.Close() localAddrB, err := net.ResolveUDPAddr("udp", localB) if err != nil { logger.Warn("Parse udp address %s error: %s", localB, err.Error()) return } listenerB, err := net.ListenUDP("udp", localAddrB) if err != nil { logger.Warn("Listen udp on %s error: %s", localB, err.Error()) return } defer listenerB.Close() listenerCtxA, err := netio.NewUDPCtx(listenerA, laenc, false) if err != nil { return } listenerCtxB, err := netio.NewUDPCtx(listenerB, lbenc, false) if err != nil { return } netio.ForwardUnconnectedUDP(listenerCtxA, listenerCtxB) } func Local2Local(localA string, localB string, laenc bool, lbenc bool) { if option.PROTOCOL == "TCP" { logger.Success("Forward TCP traffic between %s (encrypted: %v) and %s (encrypted: %v)", localA, laenc, localB, lbenc) local2LocalTCP(localA, localB, laenc, lbenc) } else { logger.Success("Forward UDP traffic between %s (encrypted: %v) and %s (encrypted: %v)", localA, laenc, localB, lbenc) local2LocalUDP(localA, localB, laenc, lbenc) } } func remote2remoteTCP(remoteA string, remoteB string, raenc bool, rbenc bool) { for { var remoteConnA net.Conn var remoteConnB net.Conn signal := make(chan struct{}) go func() { for { var err error logger.Info("Connecting remote %s", remoteA) remoteConnA, err = net.DialTimeout( "tcp", remoteA, time.Millisecond*time.Duration(option.TIMEOUT), ) if err != nil { logger.Info("Connect remote %s error, retrying", remoteA) time.Sleep(option.CONNECTING_RETRY_DURATION * time.Millisecond) continue } break } signal <- struct{}{} }() go func() { for { var err error logger.Info("Connecting remote %s", remoteB) remoteConnB, err = net.DialTimeout( "tcp", remoteB, time.Millisecond*time.Duration(option.TIMEOUT), ) if err != nil { logger.Info("Connect remote %s error, retrying", remoteB) time.Sleep(option.CONNECTING_RETRY_DURATION * time.Millisecond) continue } break } signal <- struct{}{} }() <-signal <-signal go func() { defer func() { if remoteConnA != nil { remoteConnA.Close() } if remoteConnB != nil { remoteConnB.Close() } }() if remoteConnA != nil && remoteConnB != nil { remoteConnCtxA, err := netio.NewTCPCtx(remoteConnA, raenc) if err != nil { logger.Warn("Handle remote %s error: %s", remoteA, err.Error()) } remoteConnCtxB, err := netio.NewTCPCtx(remoteConnB, rbenc) if err != nil { logger.Warn("Handle remote %s error: %s", remoteB, err.Error()) } logger.Info("Start pipe: %s <== FWD ==> %s", remoteConnA.RemoteAddr().String(), remoteConnB.RemoteAddr().String()) netio.PipeForward(remoteConnCtxA, remoteConnCtxB) logger.Info("Close pipe: %s <== FWD ==> %s", remoteConnA.RemoteAddr().String(), remoteConnB.RemoteAddr().String()) } }() } } func remote2remoteUDP(remoteA string, remoteB string, raenc bool, rbenc bool) { remoteAddrA, err := net.ResolveUDPAddr("udp", remoteA) if err != nil { logger.Warn("Parse udp address %s error: %s", remoteA, err.Error()) return } remoteConnA, err := net.DialUDP("udp", nil, remoteAddrA) if err != nil { logger.Warn("Dial remote udp %s error: %s", remoteA, err.Error()) return } defer remoteConnA.Close() remoteAddrB, err := net.ResolveUDPAddr("udp", remoteB) if err != nil { logger.Warn("Parse udp address %s error: %s", remoteB, err.Error()) return } remoteConnB, err := net.DialUDP("udp", nil, remoteAddrB) if err != nil { logger.Warn("Dial remote udp %s error: %s", remoteB, err.Error()) return } defer remoteConnB.Close() remoteCtxA, err := netio.NewUDPCtx(remoteConnA, raenc, true) if err != nil { return } remoteCtxB, err := netio.NewUDPCtx(remoteConnB, rbenc, true) if err != nil { return } { // Need to send init packet to register the remote address, it doesn't matter even tough target is not `iox` // // There is a design fault here, and I need to consider the case where the FORWARD_WITHOUT_DEC flag is set // but actually needs to be encrypted, otherwise there is no IV in the ciphertext if raenc { iv, err := crypto.RandomNonce() cipher, err := crypto.NewCipher(iv) if err != nil { return } b := make([]byte, 4, 20) copy(b, netio.UDP_INIT_PACKET) cipher.StreamXOR(b, b) b = append(b, iv...) remoteCtxA.Write(b) } else { remoteCtxA.Write(netio.UDP_INIT_PACKET) } if rbenc { iv, err := crypto.RandomNonce() cipher, err := crypto.NewCipher(iv) if err != nil { return } b := make([]byte, 4, 20) copy(b, netio.UDP_INIT_PACKET) cipher.StreamXOR(b, b) b = append(b, iv...) remoteCtxB.Write(b) } else { remoteCtxB.Write(netio.UDP_INIT_PACKET) } } netio.ForwardUDP(remoteCtxA, remoteCtxB) } func Remote2Remote(remoteA string, remoteB string, raenc bool, rbenc bool) { if option.PROTOCOL == "TCP" { logger.Success("Forward TCP traffic between %s (encrypted: %v) and %s (encrypted: %v)", remoteA, raenc, remoteB, rbenc) remote2remoteTCP(remoteA, remoteB, raenc, rbenc) } else { logger.Success("Forward UDP traffic between %s (encrypted: %v) and %s (encrypted: %v)", remoteA, raenc, remoteB, rbenc) remote2remoteUDP(remoteA, remoteB, raenc, rbenc) } }
package operate import ( "iox/logger" "iox/netio" "iox/socks5" "net" "os" "os/signal" ) func ProxyLocal(local string, encrypted bool) { listener, err := net.Listen("tcp", local) if err != nil { logger.Warn("Socks5 listen on %s error: %s", local, err.Error()) return } logger.Success("Start socks5 server on %s (encrypted: %v)", local, encrypted) for { conn, err := listener.Accept() if err != nil { logger.Warn("Socks5 handle local connect error: %s", err.Error()) continue } go func() { defer conn.Close() connCtx, err := netio.NewTCPCtx(conn, encrypted) if err != nil { return } socks5.HandleConnection(connCtx) }() } } func ProxyRemote(remote string, encrypted bool) { session, ctlStream, err := clientHandshake(remote) if err != nil { logger.Warn(err.Error()) return } defer session.Close() logger.Success("Remote socks5 handshake ok (encrypted: %v)", encrypted) connectRequest := make(chan uint8, MAX_CONNECTION) defer close(connectRequest) endSignal := make(chan struct{}) // handle ctrl+C { sigs := make(chan os.Signal) signal.Notify(sigs, os.Interrupt) go func() { <-sigs ctlStream.Write(marshal(Protocol{ CMD: CTL_CLEANUP, N: 0, })) logger.Success("Recv Ctrl+C, exit now") os.Exit(0) }() } // handle ctl stream go func() { defer ctlStream.Close() for { pb, err := readUntilEnd(ctlStream) if err != nil { logger.Warn("Control connection has been closed, exit now") os.Exit(-1) } p := unmarshal(pb) switch p.CMD { case CTL_CONNECT_ME: connectRequest <- p.N case CTL_CLEANUP: endSignal <- struct{}{} return } } }() // handle CONNECT_ME request for { select { case <-endSignal: logger.Success("Recv exit signal from remote, exit now") return case n := <-connectRequest: for n > 0 { go func() { stream, err := session.OpenStream() if err != nil { logger.Info(err.Error()) return } defer stream.Close() connCtx, err := netio.NewTCPCtx(stream, encrypted) if err != nil { return } socks5.HandleConnection(connCtx) }() n-- } } } } func ProxyRemoteL2L(control string, local string, cenc bool, lenc bool) { masterListener, err := net.Listen("tcp", control) if err != nil { logger.Warn("Listen on %s error", control) return } defer masterListener.Close() logger.Info("Listen on %s for reverse socks5", control) localListener, err := net.Listen("tcp", local) if err != nil { logger.Warn("Listen on %s error", local) return } defer localListener.Close() session, ctlStream, err := serverHandshake(masterListener) if err != nil { logger.Warn(err.Error()) return } defer session.Close() defer ctlStream.Close() logger.Success("Reverse socks5 server handshake ok from %s (encrypted: %v)", session.RemoteAddr().String(), cenc) logger.Success("Socks5 server is listening on %s (encrypted: %v)", local, lenc) // handle ctrl+C { sigs := make(chan os.Signal) signal.Notify(sigs, os.Interrupt) go func() { <-sigs ctlStream.Write(marshal(Protocol{ CMD: CTL_CLEANUP, N: 0, })) logger.Success("Recv Ctrl+C, exit now") os.Exit(0) }() } localConnBuffer := make(chan net.Conn, MAX_CONNECTION) defer close(localConnBuffer) // handle ctl stream read go func() { for { pb, err := readUntilEnd(ctlStream) if err != nil { logger.Warn("Control connection has been closed, exit now") os.Exit(-1) } p := unmarshal(pb) switch p.CMD { case CTL_CLEANUP: logger.Success("Recv exit signal from remote, exit now") os.Exit(0) } } }() // handle local connection go func() { for { localConn, err := localListener.Accept() if err != nil { continue } localConnBuffer <- localConn _, err = ctlStream.Write(marshal(Protocol{ CMD: CTL_CONNECT_ME, N: 1, })) if err != nil { logger.Warn("Control connection has been closed, exit now") os.Exit(-1) } } }() for { remoteStream, err := session.AcceptStream() if err != nil { continue } localConn := <-localConnBuffer go func() { defer remoteStream.Close() defer localConn.Close() remoteConnCtx, err := netio.NewTCPCtx(remoteStream, cenc) if err != nil { return } localConnCtx, err := netio.NewTCPCtx(localConn, lenc) if err != nil { return } netio.PipeForward(remoteConnCtx, localConnCtx) }() } }
2、检测与绕过
(1)特征字符串和特征码
命令和log里的特征字符串可以作为检测特征
然后是代码里的特征码
绕过方法:修改掉相应的特征
(2)端口控制
这类端口转发的工具,如果端口限制死就失去作用了
绕过方法:无
(3)进程和库调用
通过终端的进程链控制和第三方库的调用情况在做检测
绕过方法:白进程利用,尽可能不调用库,加壳,主要是木马免杀那套
(4)SOCKS代理的检测
这是IDS这块,具体原理不清
结语
iox主要是比较新
红客突击队于2019年由队长k龙牵头,联合国内多位顶尖高校研究生成立。其团队从成立至今多次参加国际网络安全竞赛并取得良好成绩,积累了丰富的竞赛经验。团队现有三十多位正式成员及若干预备人员,下属联合分队数支。红客突击队始终秉承先做人后技术的宗旨,旨在打造国际顶尖网络安全团队。
脑叶公司EGO防具怎么排名?-脑叶公司EGO防具排名教程攻略
使用Sublime开发微信小程序实现wxml, wxss代码高亮和语法提示
海康威视iVMS-4200校时、手动校时、定位校时、NTP校时四种方法任你选
网络水晶头标准制作线序和直通线、交叉线的检测方法
单模光纤和多模光纤都有哪些形状的接头
常说的E太网中的网线都哪些规格,怎么区别?
virtual box虚拟机安装Centos7教程
virtual box安装Centos7教程和常见问题说明
小马PE统维护工具制作与使用教程
JMAG-Designer 18安装破解教程
curl访问非安全的ssl证书问题
关于我们| 广告联络| 联系我们| 网站帮助| 免责声明| 软件发布
Copyright 2019-2029 【快快下载吧】 版权所有 快快下载吧 | 豫ICP备10006759号公安备案:41010502004165
声明: 快快下载吧上的所有软件和资料来源于互联网,仅供学习和研究使用,请测试后自行销毁,如有侵犯你版权的,请来信指出,本站将立即改正。