黑客程式設計,基於Python+協程+多程序的弱密碼掃描器!
聽說不想扯淡的程式猿,不是一隻好猿。所以今天來扯扯淡,不貼程式碼,只講設計思想。
0×00 起 – 初始設計
我們的目標是設計一枚通用的弱密碼掃描器,基本功能是針對不同型別的弱密碼,可方便的擴充套件,比如新增SSH、SVN、phpmyadmin的弱密碼掃描功能。我們設定啟動方法是命令列,可以通過命令列指定掃描物件,以及掃描哪些弱密碼。
既然是要求可擴充套件,那我們首先來編寫一個通用的框架,然後通過新增POC的方法來實現擴充套件。在這個框架中,我們需要處理的事情包括:
初始化掃描物件(格式化URL、從檔案或資料庫中讀取URL) 載入弱密碼掃描指令碼(載入一種或者多種掃描指令碼)
同時為了易用性,框架還要提供一些額外的功能:
提供一些公用的函式(如埠掃描、URL去格式化以及格式化等)
顯示當前可用的POC以及POC的相關資訊
我們預期的呼叫方法應該是這樣:
python base.py -p ssh_weak,mysql_weak -t test.txt --run
這樣,讓我們畫個簡圖:
具體講解一下:
base.py是掃描器的入口檔案
poc處理流程:init_poc()將輸入 ssh_weak,mysql_weak格式化,通過load_poc()載入到記憶體中。
target處理流程: init_target()將輸入 test.txt 內容讀取到記憶體中,同時應該支援直接指定引數,以及從資料庫中讀取引數。
POC管理: show_poc_info()呼叫load_poc(),載入所有POC,並print poc_info。
poc_base.py是所有POC的父類,POC通過繼承poc_base,來實現常用函式的繼承,以及POC引擎。
0×10 承 – 功能抽象
通過上述描述,我們得到了一個簡單的框架,通過這個框架提供的功能,我們來試著寫一個標準的POC:
from poc_base import PocBase class MyPOC(PocBase): poc_info = { 'author': 'Friday', 'title': 'svn_weak', } def svn_burst(self, url, user, password): pass def save(): # 向資料庫或檔案中儲存結果 pass def verify(self, target): count = 0 for url in target: for user in ['root', 'work']: for passwd in ['test', '123456']: count += 1 if port_open(22) and svn_burst(): print "Success" save() if count % 10 == 0: print "當前進度:%d" % count
有幾個地方可以優化:
資料儲存模組,每次掃描完儲存一次,太浪費資源,有什麼解決方法?
資料儲存模組,是否能整合到框架中?
掃描數量較大的時候,應該有掃描成功的提醒,以及掃描進度的提醒,是否能整合到框架中?
這其實是一個問題,資料定時儲存(掃描過程中多次儲存)和進度提醒功能,如何整合到框架中?本來的邏輯是,呼叫一次POC,掃描多個URL,然後直接由POC輸出結果。如果想實現資料儲存和進度提醒,看起來要把更多的控制權交到框架手中。所以,將POC的功能簡化到判斷某一個URL是否存在弱密碼,返回true or false。將POC的呼叫許可權,交到Poc_Base中,多次呼叫POC,虛擬碼如下:
class Poc_Base(object):
count = 0
progress = 100 # 進度提醒的單位
@ overide
def verify():
pass
def run():
for url in url_list:
count += 1
if count % progress == 0:
save() # 資料儲存
print "progress %d " % (count) # 進度提醒
if self.verify():
print "success"
經過優化之後,POC的基本模式,更簡單了:
from poc_base import PocBase
class MyPOC(PocBase):
poc_info = {
'author': 'Friday',
'title': 'svn_weak',
}
def svn_burst(self, url, user, password):
pass
def verify(self, url):
for user in ['root', 'work']:
for passwd in ['test', '123456']:
if port_open(22) and svn_burst():
return True
在beebeeto提交過POC的同學,應該驚呼了“除了結果自動儲存的模組,這不和beebeeto的框架一樣麼!”,是的,在一開始寫框架的時候,參考了beebeeto-frame,後來獨立編寫完成/優化完成後,發現殊途同歸了 : )
0×20 轉 – 效能提升
在實現基本功能之後,我又開始蠢蠢欲動了。作為一個有尊(xing)嚴(neng)的框架,怎麼能滿足於一條線的模式!所以,為了效率,我們要在框架層面新增協程和多程序支援,讓多核CPU每個都能跑到100%是我們的目標!
但應該怎麼新增程序和協程的支援呢?有之前新增資料儲存和進度提醒的經驗,實現不難想象。難點在於,在新增程序和協程支援的時候,不影響正常的資料儲存和進度提醒。虛擬碼如下:
class Poc_Base(object):
gevent_num = 100 # 協程數
process_num = 4 # 程序數
count = [0] * process_num # 每個程序,單獨計數
progress = 100 # 進度提醒的單位
@ overide def verify(): pass
def verify_count():
count[progress_number] += 1 if count[progress_number] % progress == 0:
save() # 資料儲存
print "progress %d " % (count[progress_number]) # 進度提醒
if self.verify(): print "success"
# 協程排程函式,分配任務到協程
def run_in_gevent(url_list): # url_list 每個程序分配到一定量的url
pool = Pool(self.gevent_num) for target in url_list:
pool.add(gevent.spawn(self.verify_count, url))
pool.join() # 程序排程函式,分配任務到各個程序
def run():
url_each_process = len(url_list)/process_num for process_number in range(process_num):
multiprocessing.Process(target=run_in_gevent, args=(url_list[*:*],)).start()
multiprocessing.join()
這樣,我們就能在跑POC的時候,用到高階的協程和程序了。
0×30 合
實際執行過程中,協程開了150,程序開了2(8核CPU),可以把兩個核的CPU都跑到90+%。
執行截圖:
雖然一開始說,不會貼程式碼,但還是貼了不少虛擬碼。內容並不深奧,如果你看過beebeeto-frame和beehive的原始碼,覺得這是簡化版的beehive,是高度定製版的beebeeto-frame,我也會覺得很開心: ) ,學習借鑑就是開源軟體對於我的意義。
因為涉及公司的一些制度,不方便公開原始碼,但感興趣的同學,或者想自己實現一個簡單的掃描器的同學,可以參考上文提到的兩種開源軟體