Python 實現埠掃描器

假裝我是程式猿發表於2017-10-31

適合有一點Python程式設計基礎的學員學習

實現的原理

最簡單的埠掃描工具使用TCP連線掃描的方式,即利用作業系統原生的網路功能,且通常作為SYN掃描的替代選項。Nmap將這種模式稱為連線掃描,因為使用了類似Unix系統的connect()命令。如果該埠是開放的,作業系統就能完成TCP三次握手,然後埠掃描工具會立即關閉剛建立的該連線,防止拒絕服務攻擊。這種掃描模式的優勢是使用者無需特殊許可權。但使用作業系統原生網路功能不能實現底層控制,因此這種掃描方式並不流行。並且TCP掃描很容易被發現,尤其作為埠清掃的手段:這些服務會記錄傳送者的IP地址,入侵檢測系統可能觸發警報。

還有另外一種掃描方式是SYN掃描,埠掃描工具不使用作業系統原生網路功能,而是自行生成、傳送IP資料包,並監控其迴應。這種掃描模式被稱為“半開放掃描”,因為它從不建立完整的TCP連線。埠掃描工具生成一個SYN包,如果目標埠開放,則會返回SYN-ACK包。掃描端迴應一個RST包,然後在握手完成前關閉連線。如果埠關閉了但未使用過濾,目標埠應該會持續返回RST包。這種粗略的網路利用方式有幾個優點:給掃描工具全權控制資料包傳送和等待迴應時長的權力,允許更詳細的迴應分析。關於哪一種對目標主機的掃描方式更不具備入侵性存在一些爭議,但SYN掃描的優勢是從不會建立完整的連線。然而,RST包可能導致網路堵塞,尤其是一些簡單如印表機之類的網路裝置。

例項中採用的是第一種掃描方式,直接利用作業系統的socket連線介面,初步測試目標伺服器的埠是否可以連線,如果可以則返回埠開啟狀態。

實現單執行緒掃描功能

主要實現這個簡單的掃描器為單執行緒掃描,具體步驟如下:

獲取埠及目標伺服器

新建程式碼如下:

#!/usr/bin/python
# -*- coding: utf-8 -*-

import sys
from socket import *

# port_scan.py <host> <start_port>-<end_port>
host = sys.argv[1]
protstrs = sys.argv[2].splist('-')

start_port = int(portstrs[0])
end_port = int(portstrs[1])

target_ip = gethostbyname(host)
opened_ports = []

for port in range(start_port, end_port):
    sock = socket(AF_INET, SOCK_STREAM)
    sock.settimeout(10)
    result = sock.connect_ex((target_ip, port))
    if result == 0:
        opened_ports.append(port)

print("Opened ports:")

for i in opened_ports:
    print(i)複製程式碼

程式碼解析:

獲取目標ip地址:

target_ip = gethostbyname(host)複製程式碼

進入迴圈連線:

opened_ports = []

for port in range(start_port, end_port):
    sock = socket(AF_INET, SOCK_STREAM)
    sock.settimeout(10)
    result = sock.connect_ex((target_ip, port))
    if result == 0:
        opened_ports.append(port)複製程式碼

列印opened_ports 列表

print i in opened_ports:
        print(i)複製程式碼

測試掃描10-200埠情況

>> python3 scanning_demo.py 127.0.0.1 10-200
Opened ports:
53
80複製程式碼

我們可以看到 53 與 80埠正處於開啟的狀態,你可以使用127.0.0.1:80 檢視開啟了什麼型別的服務

多執行緒掃描

上面程式碼實現了單執行緒掃描埠的測試,但是正常的程式在執行中我們需要考慮執行效率和提升效能,所以需要實現多執行緒程式:

新建程式碼如下:

#!/usr/bin/python
# -*- coding: utf-8 -*-

import sys
import thread
from socket import *

def tcp_test(port):
        sock = socket(AF_INET, SOCK_STREAM)
        sock.settimeout(10)
        result = sock.connect_ex((target_ip, port))
        if result == 0:
                lock.acquire()
                print "Opened Port:", port
                lock.release()
if __name__=='__main__':
    # portscan.py <host> <start_port>-<end_port>
    post = sys.argv[1]
    portstrs = sys.argv[2].split('_')

    start_port = int(portstrs[0])
    end_port = int(portstrsp[1])

    target_ip = gethostbyname(host)

    lock = thread.allocate_lock()

    for port in range(start_port, end_port):
            thread.start_new_thread(tcp_test, (port,))複製程式碼

程式碼解析

引入程式碼包 thread ,這個是實現多執行緒必須要的:

import thread複製程式碼

實現TCP測試函式

需要注意print輸出時候需要加鎖,如果不加鎖可能會出現多個輸出混合在一起的錯誤狀態,而鎖需要在程式啟動時建立,從而能讓新建的執行緒共享這個鎖

def tcp_test(port):
        sock = socket(AF_INET, SOCK_STREAM)
        sock.settimeout(10)
        result = sock.connect_ex((target_ip, port))
        if result == 0:
                lock.acquire()
                print "Opened Port:", port
                lock.release()複製程式碼

當程式碼執行完之後要把鎖釋放掉(釋放lock)

輸入的處理及lock的建立可以放在main函式中:

if __name__=='__main__':
    # portscan.py <host> <start_port>-<end_port>
    host = sys.argv[1]
    portstrs = sys.argv[2].split('-')

    start_port = int(portstrs[0])
    end_port = int(portstrs[1])

    target_ip = gethostbyname(host)

    lock = thread.allocate_lock()複製程式碼

然後修改for迴圈:

for port in range(start_port, end_port):
        thread.start_new_thread(tcp_test, (port,))複製程式碼

thread.start_new_thread 用來建立一個執行緒,該函式的第一個引數是一個執行緒中執行的函式,第二個引數必須是個元組,作為函式的輸入,由於 tcp_test 函式只有一個引數,所以我們使用(port,)這種形式表示這個引數為元組。

最後去掉上一節中的輸出程式碼後我們的多執行緒改造就已經完成了。

測試結果如下:

>> python3 all_scanning_demo.py 127.0.0.1 80-200
Opened ports:80複製程式碼

python-nmap 包

學習Python埠掃描我們必須要接觸的一個非常強大的Python埠掃描包 pyton-nmap 這是一款很有名的安全工具,開源的。它可以在python程式中使用nmap埠掃描的Python包,可以允許開發者對nmap掃描結果進行解析並實現自動化掃描的任務,並輸出報告。還有牛B的是可以支援非同步操作,當執行掃描完成之後呼叫使用者自定義的回撥函式。

install

執行安裝命令

pip install pyton-nmap

Collecting python-nmap
  Downloading python-nmap-0.6.1.tar.gz (41kB)
    100% |████████████████████████████████| 51kB 65kB/s
Building wheels for collected packages: python-nmap
  Running setup.py bdist_wheel for python-nmap ... done
  Stored in directory: /Users/devon/Library/Caches/pip/wheels/d2/20/17/8eb9401fb0fa5ffbd0394c44d9d1c743036896c86029b0a613
Successfully built python-nmap
Installing collected packages: python-nmap
Successfully installed python-nmap-0.6.1複製程式碼

進入到python shell 操作:

載入nmap包

import nmap複製程式碼

建立PortScanner物件

nm = nmap.PortScanner()複製程式碼

掃描 127.0.0.1的 80-200埠:

nm.scan('127.0.0.1','22-100')複製程式碼

檢視使用的命令列和掃描資訊:

nm.command_line()
Nm.scaninfo()複製程式碼

檢視掃描的目標主機資訊:

nm.all_hosts()
nm['127.0.0.1'].hostname()
nm['127.0.0.1'].state()
nm['127.0.0.1'].all_protocols()
nm['127.0.0.1']['tcp'].keys()複製程式碼

擴充套件

通過nmap我們可以實現比較複雜的一些掃描程式,你可以給予我們上面寫的程式嘗試引入python-nmap包並將其擴充改版,實現一些有用的功能:

  • 1.增加GUI,手動新增掃描的埠範圍和主機
  • 2.生成csv格式的掃描報告
  • 3.後臺進行掃描,完成後吧掃描報告已郵件的形式傳送給管理員

常動手,常思考 祝進步!

覺得我分享的文章對你有幫助或者異議,請聯絡微信公眾號:假裝我是程式猿

相關文章