千万不要在VMWare的NAT模式下使用nmap

玩过nmap的都知道,很多信息的确认来自于OS的指纹,这些指纹中包括TCP序列号!
        如果你在一个Windows宿主机的VMWare虚拟机中使用nmap,而且这个虚拟机还是使用NAT模式,那么不管你扫哪个机器,得到的guess OS结果都将是Windows,该Windows版本将会与你的宿主机完全一致!这明显是错误的结论!本文的目的是纠正这个错误的结论以及提供一个能让你在NAT模式下使用nmap的方法。
        能让你瞬间知道这是错误的,有一个前提,那就是你对VMWare NAT模式的机制非常理解,我在前面写了两篇文章来阐释VMWare的NAT模式,如果你理解了,就会知道,起码这个NAT模式会影响两个结果:
1.traceroute的结果
由于返回的TTL exceeded消息无法对应到已知的五元组(vmnat能做到,但它没做...),因此无法反向NAT讲消息路由到Guest OS。这个就不多说了。
2.nmap的结果
由于vmnat完全接管NAT,也就是说每个TCP连接都是Host OS代理建立的,因此Guest OS看到的永远是Host OS的TCP连接,实际上对于TCP而言,无论你扫哪个机器,都是在扫Host!TCP序列号在经过Host OS的时候会被替换成Host OS与远端主机之间的序列号。

总之,不要在NAT模式下玩网络,玩不转的。事实上,即便不是你的VMWare NAT在作怪,中间的运营商设备也会作怪。如果它劫持或者说接管了你的TCP连接,那么nmap就到它为止了,任何向前行的企图都会止步于此!鉴于运营商再恶劣,它也不会100%劫持你的连接(它干嘛非要跟你过不去呢,贱人一般都是跟所有人都过不去!)
        在扫描中,指纹不准的后果就是信息混乱!所以,在执行扫描前,要确保本地环境的纯粹,这种纯粹不仅仅包含应用层的纯粹,更多的是包含TCP层甚至IP层的纯粹。举一个简单点的例子,Linux的默认TTL是64,如果你在NAT Guest模式下扫描到某个地址的TTL是64以下的某个值且跳数有限,那就能猜测被扫机器是Linux,这个意义上TTL也算一个轻量级指纹!然而,你得到的结果将会是TTL为128!...一切功败垂成灰飞烟灭。
        我是不是该写篇文章解释一下如何在VMWare NAT模式下使用nmap呢?嗯,本来本文到此为止,然而这个想法让我将本文继续下去...

早在几年前,我在搞NAT的实现,曾经提出三种NAT方案:
1.使用PACKET套接字抓包重注入来实现;
2.使用nf_queue抓取重注入来实现
3.直接在内核中实现双向无状态NAT
关于方案2和3,我都有文章阐述,但是只有方案1,我好像还没有提及,本文正是关于方案1的补充。该方案旨在实现一个单纯的IP层NAT,保持TCP序列号的连续。总的框图如下:




看懂了上面的框图,我给出一个简洁的代码:


#!/usr/local/bin/python

import sys
import os

import signal
import threading
from scapy.all import *

# 1.1.1.1是内部的IP地址
in_addr = '1.1.1.1'
# 192.168.44.100是转换后的公网地址
out_addr = '192.168.44.100'
# 101.254.177.3是令人遗憾的火山云主机地址,作为我们的目标
target = '101.254.177.3'
flt_in = "src " + in_addr + " and dst " + target + " and tcp port 80"
flt_out = "src " + target + " and dst " + out_addr + " and tcp port 80"
# 为了阻滞本机的接收失败而Reset连接,故DROP掉本机流量
ipt_cmd = 'iptables -A INPUT -s ' + target + ' -p tcp --sport 80 -j DROP'

def signal_handler(signal, frame):
        os._exit(0)

class ThreadWraper(threading.Thread):
	def __init__(self,func,args,name=''):
		threading.Thread.__init__(self)
		self.name=name
		self.func=func
		self.args=args

	def run(self):
		apply(self.func,self.args)

# 接收正向包,转换源地址
def recv_in(pktdata):
	if TCP in pktdata and pktdata[TCP]:
		seqno = pktdata[TCP].seq
		ackno = pktdata[TCP].ack
		sp = pktdata[TCP].sport
		dp = pktdata[TCP].dport
		flg = pktdata[TCP].flags
		win = pktdata[TCP].window
		opts = pktdata[TCP].options
		payload = pktdata[TCP].payload
   		sendp(Ether()/IP(src = out_addr, dst = target)/TCP(sport = sp, dport = dp, seq = seqno, ack = ackno, flags = flg, window = win, options = opts)/payload, verbose = 0, iface="eth3")

# 接收反向包,转换目标地址
def recv_out(pktdata):
	if TCP in pktdata and pktdata[TCP]:
		seqno = pktdata[TCP].seq
		ackno = pktdata[TCP].ack
		sp = pktdata[TCP].sport
		dp = pktdata[TCP].dport
		flg = pktdata[TCP].flags
		win = pktdata[TCP].window
		opts = pktdata[TCP].options
		payload = pktdata[TCP].payload
   		sendp(Ether()/IP(src = target, dst = in_addr)/TCP(sport = sp, dport = dp, seq = seqno, ack = ackno, flags = flg, window = win, options = opts)/payload, verbose = 0, iface="eth2")

# 本例中,eth2为内部网口
def recv_packet_in():
	sniff(iface ="eth2", prn = recv_in, store = 0, filter = flt_in)

# 本例中,eth3为外部网口
def recv_packet_out():
	sniff(iface = "eth3", prn = recv_out, store = 0, filter = flt_out)

if __name__ == '__main__':
	signal.signal(signal.SIGINT, signal_handler)

	os.system(ipt_cmd)

	in_thread = ThreadWraper(recv_packet_in,(), recv_packet_in.__name__)
	in_thread.setDaemon(True)  
	in_thread.start()

	out_thread = ThreadWraper(recv_packet_out,(), recv_packet_out.__name__)
	out_thread.setDaemon(True)  
	out_thread.start()
	signal.pause()

关于这个代码,没有什么好说的,在这个代码之外,我想提及几点。

        既然这是一个跑在Windows上的代码,为什么会有eth0/1/2/3呢?因为我的笔记本电脑蓝屏再重启后,Dev-CPP不能用了,用尽洪荒之力也没能编译成功,所以我用两台VMWare虚拟机完成这个构想。道理是一样的,实现就无关紧要了。不管是C语言还是Python,都很好,只是我惧怕计算TCP的校验码,我选择了Python。
        看来我们可以用这种方式来替换vmnat了,值得注意的是,一定要封堵到达本机的常规流量,不然TCP Reset就在所难免了!这个PCAP实现避免了TCP被替代被劫持,它只是转换了IP层的地址信息,名副其实的NAT是也(NAT没有标准,各行其道)!
        我把这个脚本呈给温州皮鞋厂老板,老板把我骂了,我发誓,以后再也不买他的皮鞋了,而且也不让别人买他的皮鞋了!

  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值