Python 實現端口掃描器

適合有一點Python編程基礎的學員學習python

實現的原理

最簡單的端口掃描工具使用TCP鏈接掃描的方式,即利用操做系統原生的網絡功能,且一般做爲SYN掃描的替代選項。Nmap將這種模式稱爲鏈接掃描,由於使用了相似Unix系統的connect()命令。若是該端口是開放的,操做系統就能完成TCP三次握手,而後端口掃描工具會當即關閉剛創建的該鏈接,防止拒絕服務攻擊。這種掃描模式的優點是用戶無需特殊權限。但使用操做系統原生網絡功能不能實現底層控制,所以這種掃描方式並不流行。而且TCP掃描很容易被發現,尤爲做爲端口清掃的手段:這些服務會記錄發送者的IP地址,入侵檢測系統可能觸發警報。shell

還有另一種掃描方式是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 列表bash

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.後臺進行掃描,完成後吧掃描報告已郵件的形式發送給管理員

常動手,常思考 祝進步!

以爲我分享的文章對你有幫助或者異議,請聯繫微信公衆號:僞裝我是程序猿

相關文章
相關標籤/搜索