內網穿透工具的原理與開發實戰

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

前言

在我國,由於網民眾多,電訊廠商無法保證為每一個寬頻使用者提供全球唯一的公網IPv4地址。因此很多使用者會發現通過路由器端查看到的WAN端IP與百度“IP”關鍵詞所得到的IP不一致,並且前者的IP為一個私人IP。

而還有一些情況下,公網IP比較昂貴,企業雖然本身也持有少量的獨立的公網IP,但是由於成本限制無法為企業內每一台主機都提供一個公網IP,或者內網並不是所有服務都需要暴露到公網中進行訪問,那麼企業有可能就會使用NAT技術將大量的內網IP通過一定規則映射到公網IP上。而最常見的其中一種技術就是NAPT,也叫“網路連接埠地址轉換”。因為一般一個服務都是通過一個連接埠來提供,因此通過這種方式可以將特定的服務通過特定的規則開放到少量的公網IP上。

問題

但是有的時候我們個人寬頻使用者也想將自己的服務發布到公網IP上。比如說我們做了一個很漂亮的網站想發布到互連網上供大家參觀,在沒有公網IP的情況下該怎麼實現呢?

還有的時候我們在對企業做滲透測試的時候,發現企業某台公網伺服器只對公網開放了常見的80連接埠,而我們提權時需要用到的3389等連接埠沒有對公網開放,這個時候又該怎麼辦呢?

解決這些問題的方式就是內網穿透了。

NAPT原理

簡單來說,在NAT Gateway上會有一張映射表,表上記錄了內網向公網哪個IP和連接埠發起了請求,然後如果內網有主機向公網裝置發起了請求,內網主機的請求資料包傳輸到了NAT Gateway上,那麼NAT Gateway會修改該資料包的源IP地址和源連接埠為NAT Gateway自身的IP地址和任意一個不衝突的自身未使用的連接埠,並且把這個修改記錄到那張映射表上。最後把修改之後的資料包發送到請求的目標主機,等目標主機發回了響應包之後,再根據響應包裡面的目的IP地址和目的連接埠去映射表裡面找到該轉寄給哪個內網主機。這樣就實現了內網主機在沒有公網IP的情況下,通過NAPT技術藉助路由器唯一的一個公網IP來訪問公網裝置。

具體原理我到網上找了一張圖片

從這裡我們可以看到,NAPT只解決了內網主機在沒有公網IP的情況下如何訪問公網主機的問題,但是並不能解決公網主機如何主動向內網主機發起請求的問題。

私人地址

在較早以前的 RFC 1918 文檔中對私人地址有相關的說明。

網際網路網域名稱分配組織IANA組織(Internet Assigned Numbers Authority)保留了以下三個IP地址塊用於私人網路。

10.0.0.0 - 10.255.255.255 (10/8位元首碼)

172.16.0.0 - 172.31.255.255 (172.16/12位元首碼)

192.168.0.0 - 192.168.255.255 (192.168/16位元首碼)

我們可以看到其中有1個A類地址塊,32個B類地址塊和256個C類地址塊。主流的家用路由器使用C類私人地址作為路由器LAN端的IP地址較多,所以我們可以看到路由器設定頁面的IP一般都為192.168開頭。

原因

先說說家庭寬頻情況吧。家庭寬頻如果沒有公網IP,那麼意味著你在本機上監聽的任何連接埠,都只能在本機網卡所在的網路中訪問,這個網路一般是路由器LAN端所在的網路。如果沒有做特定的映射規則,那麼路由器WAN端所串連到的網路將無法正常訪問該主機提供的服務。

如果這種情況下想要讓WAN端(如果電訊廠商為你分配了公網IP,那麼WAN端所串連到的網路通常就是公網),那麼需要在路由器上做連接埠映射。比如說路由器的LAN IP為192.168.1.1,WAN IP為23.23.23.23,我想讓內網192.168.1.2主機的80連接埠提供的HTTP伺服器直接能夠在公網中通過 http://23.23.23.23 訪問,那麼就要將192.168.1.2:80 映射到 23.23.23.23:80 上。

但是通常情況下,電訊廠商是不會給普通使用者公網IP的。那麼用這種方法映射,在公網仍然是無法訪問的,因為你的路由器WAN端串連的又是電訊廠商更上一級的路由器LAN端,嚴重一點,甚至是層層串連最後才到公網,這種行為稱作流量穿透。國內某電,某動的寬頻就有大量這種行為。通過流量穿透的方式來提供的寬頻服務,看似便宜,實則影響很大,由於大家公用一個IP,可能會導致很多網站的反SPAM策略傷及無辜,或者內部為了節省頻寬,使用緩衝,導致一些不該緩衝的敏感安全頁面被緩衝起來,甚至導致部分網站緩衝失效完全打不開。

有的人發現,即使自己有公網IP,但是仍然無法通過常規方法架設伺服器,這是怎麼回事呢?這是電訊廠商為了防止個人隨意開設各種非法服務,也防止駭客通過掃描器進行抓雞和批量掃描,將一些常用連接埠進行了封鎖,比如說我們這的中國電信就將80,8080等連接埠封鎖了。這樣封鎖,雖然一定程度上保證了我們的網路安全,比如說前段時間的勒索病毒正因為國內大部分使用者沒有獨立的公網IP,並且作業系統最容易爆發漏洞的一些,135,139等連接埠被電訊廠商封鎖了,使得國內個人家庭電腦中招的機率小了很多;但是導致即使有公網IP,也無法使用常用連接埠向外網提供服務,只能更換到其他連接埠。這樣有什麼不好呢?比較典型的問題就是WEB網站預設使用80連接埠,那麼在輸入網址的時候可以不用帶上連接埠號碼,顯得比較美觀。

解決方案

如果遇到了上述情況,我們該如何解決呢?

如果我們沒有一台公網伺服器,我們可以使用國內大名鼎鼎的“花生殼”,“nat123”等服務來實現,但是他們背後的原理是什麼呢?

我們如果在自己擁有一台具有公網IP伺服器的情況下,我們可以藉助這台公網IP伺服器提供服務。而具體又該怎麼操作呢?

解決方案的實現

先假設我們自己有一台公網伺服器,它的IP為45.45.45.45。我們又有一台內網伺服器IP為23.23.23.23.我們現在想把23.23.23.23:80,即內網伺服器上的HTTP服務開放到45.45.45.45上。

最簡單粗暴的方式就是,我們可以直接將整個內網伺服器環境在公網伺服器上重新搭建一遍。

但是這樣做很麻煩,我們有的時候並不想這樣做,我們只是想簡單的藉助公網伺服器的網路來發布一個內網服務。

前面我們通過NAPT原理得知:NAPT實現了內網主機在沒有公網IP的情況下訪問公網主機。那麼我們可以這樣做:假設公網IP為23.23.23.23,內網IP為192.168.1.2。公網主機先監聽80連接埠,監聽這個連接埠是用於向外部提供一個HTTP服務,80是WEB伺服器的預設連接埠。同時其他任意一個連接埠(這裡我們假設為7777),監聽這個連接埠是用於讓內網伺服器主動串連進來打通一個隧道。接著內網再主動向公網主機的7777發起一個請求,這樣內網就成功與公網主機建立了一個串連通道。然後當有任何用戶端主動串連公網的80連接埠時,公網接收到串連請求之後馬上把這串連請求通過先前建立好的隧道轉寄到內網主機,內網主機接收到來自隧道的資料包後再主動串連內網主機自身的80連接埠,串連成功之後將資料包原封不動地轉寄資料包給80連接埠,待HTTP伺服器程式處理完這個資料包,產生了響應報文之後再原路轉寄回去,最終到達公網的80連接埠,然後返回給最開始請求公網伺服器80連接埠的用戶端。

看起來是不是比較繞呢?事實上大名鼎鼎的花生殼內網版以及nat123等內網穿透工具的原理基本就是如此,但是並不完全是這樣。因為一個運輸層連接埠只能同時提供一種服務,但是我們會發現花生殼這種內網穿透服務是藉助一個公網IP同時給很多使用者提供了服務,這是因為花生殼在流量轉寄這一層上並不是像我之前所說的原封不動的將報文進行轉寄,而是在轉寄之前加了一些控制協議的內容,用於指明該轉寄到哪個花生殼用戶端所在的內網主機上。前者這種原封不動的轉寄方式通常叫做透明傳輸或者透明代理。

穿透防火牆

為了安全起見,通常會在網路中加入防火牆,防火牆有入站規則和出站規則。如果不是非常嚴格的安全管控,通常是不會設定出站規則的,但是入站規則一般都會設定的,比如說外部可以通過80連接埠傳入內網的WEB伺服器訪問網頁,但是不能通過3389連接埠登陸內網的遠端桌面。

而在內網滲透的過程中碰到這種情況,我們也可以藉助上面內網傳統的方式實現穿透防火牆的入站規則。因為防火牆通常只攔截了入站,沒有攔截出站,那麼我們可以讓內網伺服器主動出站(主動串連到駭客的伺服器),與駭客自己的伺服器打通隧道,最終繞過防火牆連上3389遠端桌面。

還有一種情況就是我們已經拿下了內網其中一台並沒有做任何防火牆規則的白名單伺服器,但是我們想連上內網另一台做了入站規則的目標伺服器,那麼我們可以讓這台白名單伺服器作為一個跳板,讓他先監聽自身任意一個連接埠,然後在有任何使用者連上這個連接埠之後,白名單伺服器就主動連上內網的目標伺服器,然後藉助這台白名單伺服器打通駭客和目標伺服器的串連隧道。

而在駭客工具中大名鼎鼎的lcx原理也就是如此,前者的實現是lcx的listen和slave命令,後者的實現是lcx的tran命令。

代碼實現

知道了原理之後,具體該怎麼實現呢?

我這裡選擇了使用Go語言編程實現了這樣一個內網穿透工具。

Golang本身提供了非常多的網路程式庫,並且Golang本身內建的Goroutine能夠很方便的處理網路編程中的非同步IO,而且最重要的是,Golang開發的程式是可以跨平台啟動並執行,意味著寫了一份代碼,我們可以在任何一個作業系統上編譯並使用。

https://github.com/cw1997/NATBypass

初始運行時根據情況輸出歡迎資訊以及文法提示(這裡要重點注意printWelcome函數末尾調用了time.Sleep阻塞一秒,這是因為fmt包輸出是非安全執行緒的,而log包下的輸出都是安全執行緒的,因此為了防止後面執行流中打的日誌會穿插到提示資訊中而使用該函數休息一秒鐘)

首先通過判斷傳入參數決定當前使用何種轉寄策略

然後再判斷傳入參數是否正確,通過Regex等方式驗證IP的合法性以及連接埠範圍

通過port2port函數實現了兩個連接埠同時監聽雙向並且轉寄資料。

在port2host操作中實現了跳板中轉。

在host2host中實現了主動串連打通隧道的功能。

看代碼便可以知道,在Golang中進行socket操作的net包要比C語言中的socket.h操作簡單很多。

轉寄功能的核心就在於forward函數部分。

先輸出一個日誌說明是對哪兩個串連進行雙向轉寄,然後通過sync包下的WaitGroup實現一個條件阻塞功能,防止在Goroutine還未執行完,主線程就已經退出了。

然後發射兩個Goroutine,分別處理串連1到串連2的IO資料包拷貝以及串連2到串連1的IO資料包拷貝。因為要保證兩個連接埠間的通訊是全雙工系統的,也就是兩邊同時都要能夠互相交換資料,所以要用Goroutine來實現這兩個操作的並發。

而IO資料包的拷貝核心代碼在connCopy函數中,根據是否要記錄流量日誌判斷是否要使用io.MultiWriter這個多路寫資料流的函數。

如果開啟記錄檔的檔案流成功,則通過io.MultiWriter函數產生一個多路寫入流,這裡這個多路寫入流的變數名為w,任何寫入到w這個寫入流的資料都會同時寫入先前參與執行多路寫入流建立函數io.MultiWriter的參數中,在這裡參數為conn1和logFile,即為連接埠1和記錄檔流。

接著調用io.Copy將第二參數的讀取流中讀取到的資料來源源不斷地拷貝到第一個參數的寫入流中。

這裡要注意io.Copy函數是同步阻塞的,意味著只要串連沒有斷開,那麼程式執行流將一直卡在這個函數。如果拷貝出錯,那麼io.Copy函數就會返回,也就是執行他下面的代碼。拷貝出錯意味著可能串連已斷開,那麼先把寫入流的串連斷掉。

這裡要重點注意,為什麼是斷開寫入流而不是讀寫流全部斷開呢。因為我們前面發射了兩個Goroutine,如果盲目全部斷開,將會導致另一個Goroutine中可能還有未寫完的資料丟失。具體可以根據TCP四次揮手來分析。

實際執行

如果沒有Golang環境的朋友可以直接下載編譯好的可執行檔,下載地址:https://github.com/cw1997/NATBypass/releases

我們先來看看代碼編譯之後實際運行,左邊為虛擬機器跑的內網伺服器,他已經設定了入站規則,通過直接連接192.168.2.112:3389是無法連上遠端桌面的。

此時此刻右圖開始通過listen命令監聽7777和9999連接埠。

接著內網伺服器再通過slave命令開始雙向串連駭客的主機(右圖的192.168.2.101:7777)以及本地的127.0.0.1:3389。

然後駭客的主機上串連本地監聽的另一個連接埠127.0.0.1:9999即可串連上內網伺服器的遠端桌面。

大家可以根據netstat -an的結果以及控制台日誌輸出來綜合理解這個過程。

寫在最後

這個工具現在實現的仍然只是簡單的透明傳輸,並且存在諸多問題。比如說本地主動串連內網服務是一開始就預串連好的,這樣會導致一些服務如果在連上之後長期沒有資料轉送,會主動斷掉串連,導致公網端偶爾出現無法串連上,要重新斷開重連後才能連上的小BUG,具體在HTTP伺服器要多重新整理幾次頁面,遠端桌面則可能要串連上然後又取消,然後再連才能連上。而且在並發串連上處理還有一些細節沒有做好。並且目前還僅僅支援TCP串連的轉寄等等,當然要實現UDP的轉寄也不是很困難稍加改進即可。大家也可以點個star,提個pull request一起來改進這些問題。目前相關的開源項目也有做的比較成熟的,比如說Golang寫的ngork,大家也可以參考參考。

本文章由 @昌維 原創,在知乎專欄-代碼之美 https://zhuanlan.zhihu.com/codes 首發,轉載請註明出處。大家喜歡和支援我的文章可以點開我的頭像以及專欄名稱進行關注,或是點擊下方的打賞按鈕進行支援,謝謝!

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.