滲透&&探測 (之TCP探測篇)

TCP原理

  互聯網由一整套協議構成。TCP 只是其中的一層,有着本身的分工。 瀏覽器

tcp/ip

  來來來,咱們先複習一下TCP/IP五層結構,詳細請參考筆者以前分享的網絡原理篇緩存

  • 以太網協議(Ethernet
    位於數據鏈路層,規定了電子信號如何組成數據包(packet),解決了 子網內部的 點對點 通訊。 服務器

    Ethernet
    可是,以太網協議不能解決多個局域網如何互通,這由 IP 協議解決。

  • IP協議
    IP 協議位於 網絡層 ,定義了一套本身的 地址規則,稱爲 IP 地址。它實現了 路由 功能,容許某個局域網的A主機,向另外一個局域網的B主機發送消息。 網絡

    ip

    路由的原理很簡單。市場上全部的 路由器,背後都有不少 網口,要接入多根 網線。路由器內部有一張 路由表,規定了AIP地址走出口 B段地址走出口,......經過這套 指路牌,實現了數據包的 轉發併發

    router

    IP 協議只是一個 地址協議,並不保證數據包的 完整。若是路由器 丟包,就須要發現 丟了哪個包,以及 如何從新發送 這個包。這就要依靠TCP協議。tcp

TCP 報文

tcp

  • 源端口和目的端口
    分別佔用16bit,表示 源端口號目的端口號 ;用於區別主機中的 不一樣進程,而 IP地址 是用來 區分不一樣的主機的源端口號和目的端口號 配合上IP首部中的源IP地址目的IP地址就能惟一的肯定一個TCP鏈接函數

  • 序號
    Seq 序號,32bit,用來標識從TCP源端向目的端發送的字節流,發起方發送數據時對此進行標記。spa

  • 確認序號
    Ack 序號,32bit,只有ACK標誌位爲1時,確認序號字段纔有效。【確認方Ack=發起方Req+1,兩端配對操作系統

  • 數據偏移
    給出首部中32bit的數目,須要這個值是由於任選字段的長度是可變的。這個字段佔4bit(最多能表示1532bit的的字,即4*15=60個字節的首部長度),所以TCP最多有60字節的首部。然而,沒有任選字段,正常的長度是20字節;計算機網絡

  • 標誌位
    6個,即URGACKPSHRSTSYNFIN等,具體含義以下:

    1. URG:緊急指針(urgent pointer)有效
    2. ACK:確認序號有效
    3. PSH接收方 應該儘快將這個報文交給 應用層
    4. RST:重置鏈接
    5. SYN:發起一個 新鏈接
    6. FIN釋放一個鏈接
  • 窗口
    窗口大小,也就是有名的滑動窗口,用來進行流量控制

TCP 數據包的大小

  簡單說,TCP 協議的做用是,保證數據通訊的 完整性可靠性防止丟包以太網 數據包(packet)的大小是固定的,最初是1518字節,後來增長到1522字節。其中, 1500 字節是負載(payload),22字節是 頭信息head)。

  IP 數據包在以太網數據包的負載裏面,它也有本身的 頭信息,最少須要20字節,因此IP數據包的負載最多爲1480(1500-20)字節。

tcp-data

  TCP 數據包在 IP 數據包的負載裏面。它的 頭信息 最少也須要20字節,所以TCP數據包的最大負載是 1480 - 20 = 1460 字節。因爲 IPTCP 協議每每有 額外的頭信息,因此TCP 負載實際爲1400字節左右。

  所以,一條1500字節的信息須要 兩個 TCP 數據包。HTTP/2 協議的一大改進, 就是壓縮 HTTP 協議的頭信息,使得一個 HTTP 請求能夠放在 一個 TCP 數據包裏面,而不是分紅多個,這樣就提升了速度。

http

TCP 數據包的編號(SEQ

  一個包1400字節,那麼一次性發送 大量數據,就必須分紅多個包。好比,一個 10MB 的文件,須要發送7100多個包。

  發送的時候,TCP 協議爲每一個包 編號sequence number,簡稱 SEQ),以便接收的一方 按照順序還原。萬一發生 丟包,也能夠知道丟失的是哪個包。

  第一個包 的編號是一個 隨機數。爲了便於理解,這裏就把它稱爲 1 號包。假定這個包的負載長度是 100 字節,那麼能夠推算出下一個包的編號應該是 101。這就是說,每一個數據包均可以獲得 兩個 編號:自身的編號,以及 下一個包 的編號。接收方由此知道,應該按照什麼 順序 將它們 還原 成原始文件。

seq

ps :當前包的編號是45943,下一個數據包的編號是46183,由此可知,這個包的負載是240字節。)

TCP 數據包的組裝

  收到TCP數據包之後,組裝還原 是操做系統內核完成的。應用程序 不會 直接處理TCP 數據包。

  對於 應用程序 來講,不用關心 數據通訊 的細節。除非線路異常,收到的老是完整的數據。應用程序須要的數據放在TCP數據包裏面,有本身的 格式(好比HTTP協議)。

  TCP 並無提供任何 機制,表示 原始文件 的大小,這由 應用層 的協議來規定。好比,HTTP 協議就有一個頭信息 Content-Length,表示 信息體 的大小。對於 操做系統 來講,就是持續地 接收 TCP 數據包,將它們按照順序 組裝好,一個包都很多。

  操做系統 不會去處理 TCP 數據包裏面的數據。一旦組裝好 TCP 數據包,就把它們轉交給 應用程序TCP 數據包裏面有一個 端口port)參數,就是用來指定轉交給 監聽該端口 的應用程序。

tcp

(PS:系統根據 TCP 數據包裏面的端口,將組裝好的數據轉交給相應的應用程序。上圖中,21端口是 FTP 服務器,25端口是 SMTP 服務,80端口是 Web 服務器。)

  應用程序 收到組裝好的 原始數據,以 瀏覽器 爲例,就會根據 HTTP 協議的Content-Length字段正確讀出一段段的數據。這也意味着,一次 TCP 通訊能夠包括 多個 HTTP 通訊。

TCP 三次握手

3

  1. 第一次握手
    創建鏈接, 客戶端 發送鏈接 請求報文段,將SYN位置爲1Sequence Numberx
    而後,客戶端進入SYN_SEND狀態,等待 服務器 的確認;

  2. 第二次握手
    服務器 收到SYN報文段。服務器 收到 客戶端SYN報文段,須要對這個SYN報文段進行 確認,設置 Acknowledgment Numberx+1(Sequence Number+1);
    同時,本身本身還要發送SYN請求信息,將SYN位置爲1Sequence Numbery
    ** 服務器端** 將上述全部信息放到一個 報文段(即SYN+ACK報文段)中,一併發送給 客戶端,此時服務器進入SYN_RECV狀態;

  3. 第三次握手
    客戶端 收到 服務器SYN+ACK報文段。而後將Acknowledgment Number設置爲y+1,向服務器發送ACK報文段,這個報文段發送完畢之後,客戶端和服務器端 都進入ESTABLISHED狀態,完成TCP 三次握手

TCP四次分手

客戶端服務器 經過 三次握手 創建了 TCP 鏈接之後,當數據 傳送完畢,確定是要 斷開TCP鏈接 的啊。那對於TCP的斷開鏈接,這裏就有了神祕的 四次分手。(繼續參考上圖)

  1. 第一次分手
    主機A(可使客戶端,也能夠是服務器端),設置Sequence NumberAcknowledgment Number,向 主機B 發送一個FIN報文段;
    此時,主機A 進入FIN_WAIT_1狀態;
    這表示主機1沒有數據要發送給主機2了;

  2. 第二次分手 主機B 收到了 主機A 發送的FIN報文段,向 主機A 回一個ACK報文段,Acknowledgment NumberSequence Number加1;
    主機A 進入FIN_WAIT_2狀態;
    主機B告訴主機A,我贊成你的關閉請求

  3. 第三次分手
    主機B主機A 發送FIN報文段,請求關閉鏈接,同時 主機B 進入 LAST_ACK 狀態;

  4. 第四次分手
    主機A 收到 主機B 發送的FIN報文段,向 主機B 發送ACK報文段,而後主機A進入TIME_WAIT狀態;
    主機B 收到 主機AACK報文段之後,就 關閉鏈接
    此時,主機A 等待2MSL後依然沒有收到回覆,則證實 Server端 已正常關閉,那好,主機A 也能夠關閉鏈接了。

至此,TCP的四次分手就這麼愉快的完成了。

爲何

  • 爲何要三次握手 在謝希仁著《計算機網絡》第四版中講 三次握手 的目的是 爲了防止已失效的鏈接請求報文段忽然又傳送到了服務端,於是產生錯誤 。在另外一部經典的《計算機網絡》一書中講 三次握手 的目的是爲了解決 網絡中存在延遲的重複分組 的問題。

    在謝希仁著《計算機網絡》書中同時舉了一個例子,以下:

    「已失效的鏈接請求報文段」的產生在這樣一種狀況下:client發出的第一個鏈接請求報文段並無丟失,而是在某個網絡結點長時間的滯留了,以至延誤到鏈接釋放之後的某個時間纔到達server。原本這是一個早已失效的報文段。但server收到此失效的鏈接請求報文段後,就誤認爲是client再次發出的一個新的鏈接請求。因而就向client發出確認報文段,贊成創建鏈接。假設不採用「三次握手」,那麼只要server發出確認,新的鏈接就創建了。因爲如今client並無發出創建鏈接的請求,所以不會理睬server的確認,也不會向server發送數據。但server卻覺得新的運輸鏈接已經創建,並一直等待client發來數據。這樣,server的不少資源就白白浪費掉了。採用「三次握手」的辦法能夠防止上述現象發生。例如剛纔那種狀況,client不會向server的確認發出確認。server因爲收不到確認,就知道client並無要求創建鏈接。」

    這就很明白了,防止了服務器端的一直等待而浪費資源。

  • 爲何要四次分手
    那四次分手又是爲什麼呢
    TCP 協議是一種面向 鏈接的可靠的基於字節流 的運輸層通訊協議。
    TCP全雙工 模式,這就意味着,當主機A 發出 FIN 報文段時,只是表示 主機A 已經沒有數據要發送了,主機A 告訴 主機B,它的數據已經 所有發送完畢了
    可是,這個時候 主機A 仍是能夠 接受 來自 主機B 的數據;
    主機B 返回ACK報文段時,表示它已經知道 主機A 沒有數據發送了,可是 主機B 仍是能夠 發送 數據到 主機A 的;
    主機B 也發送了FIN報文段時,這個時候就表示主機B也沒有數據要 發送了,就會告訴 主機B,我也 沒有 數據要發送了。
    以後彼此就會愉快的 中斷 此次TCP鏈接。

    1. FIN_WAIT_1
      這個狀態要好好解釋一下,其實FIN_WAIT_1FIN_WAIT_2狀態的真正含義都是表示 等待對方的FIN報文
      而這兩種狀態的區別是:FIN_WAIT_1狀態其實是當SOCKETESTABLISHED狀態時,它想 主動 關閉鏈接,向對方發送了FIN報文,此時該SOCKET即進入到FIN_WAIT_1狀態。
      而當 對方 迴應ACK報文後,則進入到FIN_WAIT_2狀態。
      固然在實際的正常狀況下,不管對方何種狀況下,都應該 立刻 迴應ACK報文,因此FIN_WAIT_1狀態通常是比較難見到的,而FIN_WAIT_2狀態還有時經常能夠用netstat看到。

    2. FIN_WAIT_2
      上面已經詳細解釋了這種狀態,實際上FIN_WAIT_2狀態下的SOCKET,表示 半鏈接,也即 有一方 要求 close 鏈接,但另外還告訴對方,我暫時還有點數據須要傳送給你(ACK信息),稍後再關閉鏈接。

    3. CLOSE_WAIT
      這種狀態的含義實際上是表示在 等待關閉怎麼理解呢
      當對方close一個SOCKET後發送FIN報文給本身,你係統毫無疑問地會迴應一個ACK報文給對方,此時則進入到CLOSE_WAIT狀態。接下來呢,實際上你真正須要考慮的事情是察看你是否還有數據發送給對方,若是 沒有 的話,那麼你也就能夠 close這個SOCKET,發送FIN報文給對方,也即 關閉鏈接。因此你在CLOSE_WAIT狀態下,須要完成的事情是 等待你去關閉鏈接。

    4. LAST_ACK
      這個狀態仍是比較容易好理解的,它是 被動關閉一方 在發送FIN報文後,最後等待對方的ACK報文。
      當收到ACK報文後,也便可以進入到CLOSED可用狀態了。

    5. TIME_WAIT
      表示收到了對方的FIN報文,併發送出了ACK報文,就等2MSL後便可回到CLOSED可用狀態了。若是FINWAIT1狀態下,收到了對方同時帶FIN標誌和ACK標誌的報文時,能夠直接進入到TIME_WAIT狀態,而無須通過FIN_WAIT_2狀態。

    6. CLOSED 表示鏈接中斷。

慢啓動和 ACK

  服務器 發送數據包,固然越快越好,最好 一次性 全發出去。可是,發得 太快,就有可能 丟包帶寬小路由器過熱緩存溢出 等許多因素都會致使 丟包線路很差的話,發得越快,丟得越多。

  最 理想 的狀態是,在線路 容許 的狀況下,達到 最高速率。可是咱們怎麼知道,對方線路的 理想速率 是多少呢?答案就是 慢慢試

  TCP 協議爲了作到 效率可靠性 的統一,設計了一個 慢啓動slow start)機制。開始 的時候,發送得 較慢,而後根據 丟包 的狀況,調整速率;若是 不丟包,就 加快 發送速度;若是 丟包,就 下降 發送速度。

  Linux 內核裏面設定了(常量TCP_INIT_CWND),剛開始通訊的時候,發送方一次性發送10個數據包,即 發送窗口 的大小爲10。而後停下來,等待 接收方的確認,再 繼續 發送。

  默認狀況下,接收方每收到 兩個 TCP 數據包,就要發送 一個 確認消息。確認 的英語是 acknowledgement,因此這個確認消息就簡稱 ACK

ACK 攜帶 兩個 信息。

  1. 期待要收到下一個數據包的編號
  2. 接收方的接收窗口的剩餘容量

  發送方有了這 兩個 信息,再加上本身 已經發出的數據包的最新編號,就會推測出 接收方大概的接收速度,從而 下降或增長 發送速率。這被稱爲 發送窗口,這個窗口的大小是 可變的

window

(PS:每一個 ACK 都帶有下一個數據包的編號,以及接收窗口的剩餘容量。雙方都會發送 ACK。)

  注意,因爲TCP通訊是 雙向 的,因此 雙方 都須要發送 ACK。兩方的 窗口 大小,極可能是 不同 的。並且 ACK 只是很簡單的幾個字段,一般與 數據 合併在一個 數據包 裏面發送。

send-data

(PS:上圖一共 4 次通訊。第一次 通訊,A 主機發給B 主機的數據包編號是1,長度是100字節。所以 第二次 通訊B主機的 ACK 編號是 1 + 100 = 101第三次通訊 A 主機的數據包編號也是 101。同理,第二次 通訊 B 主機發給 A 主機的數據包編號是1,長度是200字節,所以 第三次通訊 A 主機的 ACK201,第四次通訊 B 主機的數據包編號也是201。)

  即便對於帶寬 很大、線路很好 的鏈接,TCP 也老是從10個數據包開始慢慢試,過了一段時間之後,才達到 最高的傳輸速率。這就是 TCP慢啓動。

數據包的遺失處理

  TCP 協議能夠保證 數據通訊完整性,這是 怎麼作到的

  前面說過,每個數據包都帶有 下一個數據包的編號。若是下一個數據包 沒有收到,那麼 ACK編號 就不會發生變化。

  EG,如今收到了4號包,可是沒有收到5號包。ACK 就會記錄,期待收到5號包。過了一段時間,5號包收到了,那麼下一輪 ACK 會更新編號。若是5號包仍是沒收到,可是收到了6號包或7號包,那麼 ACK 裏面的編號不會變化,老是顯示5號包。這會致使 大量重複內容ACK

  若是 發送方 發現收到 三個 連續的重複 ACK,或者 超時 了還 沒有 收到任何 ACK,就會確認 丟包,即5號包遺失了,從而 再次發送 這個包。經過這種機制,TCP 保證了 不會 有數據包丟失。

missing

(PS:Host B 沒有收到100號數據包,會連續發出相同的 ACK,觸發 Host A 重發100號數據包。)

TCP 探測

  明白了TCP原理,咱們就能夠對TCP監聽的端口進行端口探測。

  其實很簡單,咱們構造一個第一次握手的SYN包給探測主機,若是探測主機回覆咱們一個SYN+ACK的回覆包,咱們就能夠斷定 此端口 爲目標主機開放端口:

  1. 經過以前咱們完成的ping探測主機腳本,判斷目標主機是否可達

  2. 構造一系列待探測端口的SYN TCP網絡數據包

TCP(dport=(int(lport),int(hport)),flags=2)
複製代碼

解釋一下:

lport: 起始探測端口

hport: 截止探測端口

flags:2表示SYN包,來源於SYN位置1,等於2

  1. TCP包封裝到IP包中

  2. 經過sr函數將這一系列包所有發出去,並將結果保存在一個List

  3. 遍歷返回的結果,若是結果中TCP包是SYN+ACK就代表 該端口開放

  連串起來:

  掃描結果:

  發現咱們的虛擬主機對外開放了22端口,那麼咱們就能夠想點歪心思啦

  關注筆者公衆帳號[mindev],並回復tcp,就能獲得tcp掃描源碼喲~~

  願意與你們分享交流各類技術,我的公衆帳號[mindev],以及 知識星球[ 極客世界 ]

geeker
           歡迎訂閱公衆帳號,日更喲~~~
相關文章
相關標籤/搜索