1-編寫一個端口掃描器

任何一個靠譜的網(wǎng)絡攻擊都是起步于偵察的。
攻擊者必須在挑選并確定利用目標中的漏洞之前找到目標在哪里有漏洞氏涩。
編寫一個掃描目標主機開放的TCP端口的偵察小腳本腕扶。
為了與TCP端口進行交互啥寇,我們要先建立TCP套接字笨篷。

Python提供了BSD套接字的接口。
BSD套接字提供了一個應用編程接口联予,使程序員能編寫在主機之間進行網(wǎng)絡通信的應用程序啼县。
通過一系列套接字API函數(shù)材原,我們可以創(chuàng)建、綁定監(jiān)聽季眷、連接余蟹,或在TCP/IP套接字上發(fā)送數(shù)據(jù)。

大多數(shù)能訪問互聯(lián)網(wǎng)的應用使用的都是TCP協(xié)議子刮。
例如威酒,在目標組織中,Web服務器可能位于TCP80端口挺峡,電子郵件服務器在TCP25端口葵孤,F(xiàn)TP服務器在TCP21端口。
要連接目標組織中的任一服務器沙郭,攻擊者必須知道與服務器相關(guān)聯(lián)的IP地址和TCP端口佛呻。

所有成功的網(wǎng)絡攻擊一般都是從端口掃描來開序幕的。
有一種類型的端口掃描會向一系列常用的端口發(fā)送TCP SYN數(shù)據(jù)包病线,并等待TCP ACK響應——這能讓我們確定這個端口是開放的。
與此相反鲤嫡,TCP連接掃描是使用完整的三次握手來確定服務器或端口是否可用的送挑。

TCP全連接掃描

開始編寫自己用的TCP全連接掃描來識別主機的TCP端口掃描器。
要導入Python的BSD套接字API實現(xiàn)暖眼。
套接字API會為我們提供一些在實現(xiàn)TCP端口掃描程序時有用的函數(shù)惕耕。
要深入的了解請查看文檔.

為了更好的了解TCP端口掃描器的工作原理,我們將腳本分成五個獨立的步驟诫肠,分別為它們編寫Python代碼司澎。
首先輸入一個主機名和用逗號分割的端口列表,并予以掃描栋豫。
接下來將主機轉(zhuǎn)換成IPv4互聯(lián)網(wǎng)地址挤安。對列表中的每個端口,我們都會鏈接目標地址和該端口丧鸯。
最后蛤铜,為了確定在該端口上運行什么服務,我們將發(fā)送垃圾數(shù)據(jù)并讀取由具體應用發(fā)回的Banner丛肢。

在第一步中围肥,從用戶那里獲得主機名和端口。
為了做到這一點蜂怎,我們在程序中使用optparse庫解析命令行參數(shù)穆刻。
調(diào)用optparse.OptionParser([usage message])會生成一個參數(shù)解析器(option parser)類的實例。
接著杠步,在parser.add_option中指定這個腳本具體要解析哪個命令行參數(shù)氢伟。

e.g. 一個快速解析要掃描的目標主機名和端口的方法

import optparse

parser = optparse.OptionParser('usage %prog -H <target host> -p <target port>')
parser.add_option('-H', dest='tgtHost', type='string', help='specify target host')
parser.add_option('-p', dest='tgtPort', type='string', help='specify target port')

(options, args) = parser.parse_args()
tgtHost = options.tgtHost
tgtPort = options.tgtPort
if tgtHost == None or tgtPort == None:
    print(parser.usage)
    exit(0)
else:
    print(tgtHost)
    print(tgtPort)

接下來我么要生成倆個個函數(shù): connScan和portScan.
portScan函數(shù)以參數(shù)的形式接受主機名和目標端口列表榜轿。
它首先會嘗試用gethostbyname()函數(shù)確定主機名對應的IP地址。
接下來腐芍,它會使用connScan函數(shù)輸出主機名字(或IP地址)差导,并使用connScan()函數(shù)嘗試逐個連接我們要連接的每個端口。
connScan函數(shù)接受兩個參數(shù):tgtHost和tgtPort猪勇,它會去嘗試建立與目標主機端口的連接设褐。
如果成功,connScan將打印出一個端口開放的消息泣刹。如果不成功助析,它會打印出端口關(guān)閉的消息。

from socket import *


def connScan(tgtHost, tgtPort):
    try:
        connSkt = socket(AF_INET, SOCK_STREAM)
        connSkt.connect((tgtHost, tgtPort))
        print('[+] %d/tcp open' % tgtPort)
        connSkt.close()
    except Exception:
        print('[-] %d/tcp closed' % tgtPort)


def portScan(tgtHost, tgtPorts):
    try:
        tgtIP = gethostbyname(tgtHost)
    except:
        print("[-] Cannot resolve '%s': Unknown host" % tgtHost)
        return

    try:
        tgtName = gethostbyaddr(tgtHost)
        print("\n[+] Scan Results for: " + tgtName[0])
    except:
        print("\n[-] Scan Results for: " + tgtIP)

    setdefaulttimeout(1)
    for tgtPost in tgtPorts:
        print("Scannint port " + tgtPost)
        connScan(tgtHost, tgtPost)

抓取應用的Banner

為了抓取目標主機上應用的Banner椅您,必須現(xiàn)在connScan函數(shù)中插入一些新增的代碼外冀。
找到開放端口后,我們向它發(fā)送一個數(shù)據(jù)傳并等待響應掀泳。
根據(jù)收集到的響應雪隧,就能推斷出目標主機和端口上運行的應用。

from socket import *


def connScan(tgtHost, tgtPort):
    try:
        connSkt = socket(AF_INET, SOCK_STREAM)
        connSkt.connect((tgtHost, tgtPort))
        connSkt.send('Hello Python\r\n')
        results = connSkt.recv(1024)
        print('[+] {}/tcp open'.format(tgtPort))
        print('[+] ' + str(results))
        connSkt.close()
    except:
        print('[-] {}/tcp closed'.format(tgtPort))


def portScan(tgtHost, tgtPorts):
    try:
        tgtIP = gethostbyname(tgtHost)
    except:
        print("[-] Cannot resolve '{}': Unknown host".format(tgtHost))
        return

    try:
        tgtName = gethostbyaddr(tgtIP)
        print("\n[+] Scan Results for: " + tgtName[0])
    except:
        print('\n[+] Scan Results for: ' + tgtIP)

    setdefaulttimeout(1)
    for tgtPort in tgtPorts:
        print('Scanning port ' + tgtPort)
        connScan(tgtHost, tgtPort)


def main():
    import optparse
    parser = optparse.OptionParser('usage %prog -H <target host> -p <target port>')
    parser.add_option('-H', dest='tgtHost', type='string', help='specify target host')
    parser.add_option('-p', dest='tgtPort', type='string', help='specify target port')

    (options, args) = parser.parse_args()
    tgtHost = options.tgtHost
    tgtPorts = (options.tgtPort).split(' ')
    if tgtPorts[0] == None or tgtHost == None:
        print('[-] You must specify a target host and port[s].')
        exit(0)
    portScan(tgtHost, tgtPorts)


if __name__ == '__main__':
    main()
<<<<<<< HEAD
=======

>>>>>>> origin/master

線程掃描

根據(jù)套接字中timeout變量的值员舵,每掃描一個套接字都會花費幾秒鐘脑沿。
這看上去微不足道,但如果我們要掃描多個主機端口马僻,時間總量就會成倍增加庄拇。
理想情況下,我們希望能同時掃描多個套接字韭邓,而不是一個一個地進行掃描措近。
這時,我們必須引入Python線程女淑,線程是一種能提供這類同時執(zhí)行多項任務的方法瞭郑。
具體到我們這個掃描器,我們要修改的是portScann()函數(shù)中迭代循環(huán)里的代碼诗力。

from threading import *
for tgtPort in tgtPorts:
    t = Thread(target=connScan, args=(tgtHost, int(tgtPort)))
    t.start()

這讓我們的速度有了顯著的提升凰浮,但這又有一個缺點。connScan()函數(shù)會在屏幕上打印一個輸出苇本。
如果多個線程同時打印輸出袜茧,就可能會出現(xiàn)亂碼和失序。
為了讓一個函數(shù)獲得完整的屏幕控制前瓣窄,我們需要使用一個信號量(semaphore)笛厦。
一個簡單的信號量就能阻止其他線程的運行。
注意俺夕,在打印輸出前裳凸,我們用screenLock贱鄙。acquire()執(zhí)行一個加鎖操作。
如果信號量還沒被鎖上姨谷,線程就有權(quán)繼續(xù)運行逗宁,并輸出到屏幕上。
如果信號量已經(jīng)被鎖定梦湘,我們只能等待瞎颗,直到持有信號量的線程釋放信號量。
通過利用信號量捌议,我們現(xiàn)在能夠確保在任何給定時間上只有一個線程可以打印屏幕哼拔。
在異常處理代碼中,位于finally關(guān)鍵字的是在終止阻塞(其他線程)之前需要執(zhí)行的代碼瓣颅。

from threading import *
from socket import *

screenLock = Semaphore(value=1)
def connScan(tgtHost, tgtPOrt):
    try:
        connSkt = socket(AF_INET, SOCK_STREAM)
        connSkt.connect((tgtHost, tgtPOrt))
        connSkt.send('something')
        results = connSkt.recv(1024)
        screenLock.acquire()
        print('[+] {}/tcp open'.format(tgtPOrt))
        print('[-] ' + str(results))
    except:
        screenLock.acquire()
        print('[-] {}/tcp closed'.format(tgtPOrt))
    finally:
        screenLock.release()
<<<<<<< HEAD
        connSkt.close()        
=======
        connSkt.close()
        
>>>>>>> origin/master

把其他所有的函數(shù)放入同一個腳本中倦逐,并添加一些參數(shù)解析代碼,就有了最終的端口掃描腳本宫补。

#!/usr/bin/python3
# -*- coding: utf-8 -*-
from socket import *
from threading import *

screenLock = Semaphore(value=1)


def connScan(tgtHost, tgtPort):
    try:
        connSkt = socket(AF_INET, SOCK_STREAM)
        connSkt.connect((tgtHost, tgtPort))
        connSkt.send('some information\r\n')
        results = connSkt.recv(1024)
        screenLock.acquire()
        print('[+] {}/tcp open'.format(tgtPort))
        print('[+] ' + str(results))
    except:
        screenLock.acquire()
        print('[-] {}/tcp closed'.format(tgtPort))
    finally:
        screenLock.release()
        connSkt.close()

def portScan(tgtHost, tgtPorts):
    try:
        tgtIP = gethostbyname(tgtHost)
    except:
        print("[-] Cannot resolve '{}': Unknown host".format(tgtHost))
        return

    try:
        tgtName = gethostbyaddr(tgtIP)
        print("\n[+] Scan Results for: " + tgtName[0])
    except:
        print('\n[+] Scan Results for: ' + tgtIP)

    setdefaulttimeout(1)
    for tgtPort in tgtPorts:
        t = Thread(target=connScan, args=(tgtHost, tgtPort))
        t.start()

def main():
    import optparse
    parser = optparse.OptionParser('usage %prog -H <target host> -p <target port>')
    parser.add_option('-H', dest='tgtHost', type='string', help='specify target host')
    parser.add_option('-p', dest='tgtPort', type='string', help='specify target port[s] separated by comma')

    (options, args) = parser.parse_args()

    tgtHost = options.tgtHost
    tgtPorts = str(options.tgtPort).split(', ')

    if tgtPorts[0] == None or tgtHost == None:
        print(parser.usage)
        exit(0)

    portScan(tgtHost, tgtPorts)


if __name__ == '__main__':
    main()

使用NMAP端口掃描代碼

前面的例子是快速編寫能進行TCP鏈接掃描的一個腳本檬姥。
這可能還不能夠用,因為我們可能還要進行其他類型的掃描粉怕,例如穿铆,由Nmap工具包提供的ACK、RST斋荞、FIN或SYN-ACK掃描等。
實際的工業(yè)標準——Namp端口掃描工具包提供了大量功能虐秦。
這也引出一個問題平酿,為什么不直接使用Nmap?這就是Python真正美妙的地方悦陋。
雖然Fyodor Vaskovich編寫的Nmap中也能使用C和Lua編寫的腳本蜈彼,但是Nmap還能被非常好的很合到Python中。
Nmap可以生成基于XML的輸出俺驶。這讓我們能在Python腳本中使用Nmap的全部功能幸逆。在編寫代碼之前,你必須安裝Python-Nmap暮现。

安裝好Python-Nmap之后还绘,我們就可以將Nmap導入到現(xiàn)有的腳本中。
創(chuàng)建一個PortScanner()類對象栖袋,這使我們能用這個對象完成掃描操作拍顷。
PortScanner類有一個scan()函數(shù),它可將目標和端口的列表作為參數(shù)輸入塘幅,并對它們進行基本的Nmap掃描昔案。
另外還可以把目標主機的地址/端口放入數(shù)組中備查尿贫,并打印出端口狀態(tài)。

def nmapScan(tgtHost, tgtPort):
    import nmap
    nmScan = nmap.PortScanner()
    nmScan.scan(tgtHost, tgtPort)
    state = nmScan[tgtHost]['tcp'][int(tgtPort)]['state']
    print('[+] ' + tgtHost + ' tcp/' + tgtPort + " " + state)

def main():
    import optparse
    parser = optparse.OptionParser('usage %prog -H <target host> -p <target port>')
    parser.add_option('-H', dest='tgtHost', type='string', help='specify target host')
    parser.add_option('-p', dest='tgtPort', type='string', help='specify target port[s] separated by comma')

    (options, args) = parser.parse_args()

    tgtHost = options.tgtHost
    tgtPorts = str(options.tgtPort).split(', ')

    if tgtPorts[0] == None or tgtHost == None:
        print(parser.usage)
        exit(0)

    for tgtPort in tgtPorts:
        nmapScan(tgtHost, tgtPort)

if __name__ == '__main__':
    main()

more

  • TCP SYN SCAN —— 也稱為半開放掃描踏揣,這種類型的掃描發(fā)送一個SYN包庆亡,啟動一個TCP會話,并等待響應的數(shù)據(jù)包捞稿。
    如果收到的是一個reset包又谋,表明端口是關(guān)閉的,而如果收到的是一個SYN/ACK包括享,則表示響應的端口是開放的搂根。
  • TCP NULL SCAN —— NULL掃描把TCP頭中的所有標志位都設為NULL。如果受到的是一個RST包铃辖,則表示響應的端口是關(guān)閉的剩愧。
  • TCP FIN SCAN —— TCP FIN 掃描發(fā)送一個表示拆除一個活動的TCP連接的FIN包,讓對方關(guān)閉連接娇斩。
    如果收到了一個RST包仁卷,則表示相應的端口是關(guān)閉的。
  • TCP XMAS SCAN —— TCP XMAS掃描發(fā)送PSH犬第、FIN锦积、URG和TCP標志為被設為1的數(shù)據(jù)包。
    如果受到了一個RST包歉嗓,則表示響應的端口是關(guān)閉的丰介。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市鉴分,隨后出現(xiàn)的幾起案子哮幢,更是在濱河造成了極大的恐慌,老刑警劉巖志珍,帶你破解...
    沈念sama閱讀 216,651評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件橙垢,死亡現(xiàn)場離奇詭異,居然都是意外死亡伦糯,警方通過查閱死者的電腦和手機柜某,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來敛纲,“玉大人喂击,你說我怎么就攤上這事≡卮龋” “怎么了惭等?”我有些...
    開封第一講書人閱讀 162,931評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長办铡。 經(jīng)常有香客問我辞做,道長琳要,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,218評論 1 292
  • 正文 為了忘掉前任秤茅,我火速辦了婚禮稚补,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘框喳。我一直安慰自己课幕,他們只是感情好,可當我...
    茶點故事閱讀 67,234評論 6 388
  • 文/花漫 我一把揭開白布五垮。 她就那樣靜靜地躺著乍惊,像睡著了一般。 火紅的嫁衣襯著肌膚如雪放仗。 梳的紋絲不亂的頭發(fā)上润绎,一...
    開封第一講書人閱讀 51,198評論 1 299
  • 那天,我揣著相機與錄音诞挨,去河邊找鬼莉撇。 笑死,一個胖子當著我的面吹牛惶傻,可吹牛的內(nèi)容都是我干的棍郎。 我是一名探鬼主播,決...
    沈念sama閱讀 40,084評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼银室,長吁一口氣:“原來是場噩夢啊……” “哼涂佃!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起蜈敢,我...
    開封第一講書人閱讀 38,926評論 0 274
  • 序言:老撾萬榮一對情侶失蹤巡李,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后扶认,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,341評論 1 311
  • 正文 獨居荒郊野嶺守林人離奇死亡殊橙,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,563評論 2 333
  • 正文 我和宋清朗相戀三年辐宾,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片膨蛮。...
    茶點故事閱讀 39,731評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡叠纹,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出敞葛,到底是詐尸還是另有隱情誉察,我是刑警寧澤,帶...
    沈念sama閱讀 35,430評論 5 343
  • 正文 年R本政府宣布惹谐,位于F島的核電站持偏,受9級特大地震影響驼卖,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜鸿秆,卻給世界環(huán)境...
    茶點故事閱讀 41,036評論 3 326
  • 文/蒙蒙 一酌畜、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧卿叽,春花似錦桥胞、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至沥阱,卻和暖如春缎罢,著一層夾襖步出監(jiān)牢的瞬間逐哈,已是汗流浹背寒跳。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評論 1 269
  • 我被黑心中介騙來泰國打工冕广, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留宋雏,地道東北人瀑罗。 一個月前我還...
    沈念sama閱讀 47,743評論 2 368
  • 正文 我出身青樓先嬉,卻偏偏與公主長得像著洼,于是被迫代替她去往敵國和親驮吱。 傳聞我的和親對象是個殘疾皇子易茬,可洞房花燭夜當晚...
    茶點故事閱讀 44,629評論 2 354

推薦閱讀更多精彩內(nèi)容