頻道欄目
首頁 > 資訊 > 網絡安全 > 正文

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

16-08-23        來源:[db:作者]  
收藏   我要投稿

玩過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/pythonimport sysimport osimport signalimport threadingfrom 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沒有標準,各行其道)!

我把這個腳本呈給溫州皮鞋廠老板,老板把我罵了,我發誓,以后再也不買他的皮鞋了,而且也不讓別人買他的皮鞋了!

相關TAG標簽
上一篇:SSH框架手動整合——Struts2+Hibernate4+Spring4
下一篇:斯諾登披露絕密文檔證實NSA網絡武器庫被黑
相關文章
圖文推薦

關于我們 | 聯系我們 | 廣告服務 | 投資合作 | 版權申明 | 在線幫助 | 網站地圖 | 作品發布 | Vip技術培訓 | 舉報中心

版權所有: 紅黑聯盟--致力于做實用的IT技術學習網站

美女MM131爽爽爽毛片