用Python編寫一個漏洞驗證腳本
前言
我們實戰經常會遇到以下幾個問題:
1、遇到一個利用步驟十分繁瑣的漏洞,中間錯一步就無法利用
2、挖到一個通用漏洞,想要批量刷洞小賺一波,但手動去測試每個網站工作量太大
這個時候編寫一個poc腳本將會將會減輕我們很多工作。本文將以編寫一個高效通用的poc腳本為目的,學習一些必要的python知識,這周也是拒絕做工具小子努力學習的一周
requests模塊使用技巧
Requests是Python中一個常用的HTTP請求庫,使用Requests庫來發起網絡請求非常簡單,具體的使用方法這裡就不多介紹瞭,這裡隻提幾個Requests模塊的使用技巧,請收好
取消重定向
Requests 會自動處理所有重定向,但有時我們並不需要重定向,可以通過allow_redirects
參數禁用重定向處理:
r = requests.get('http://github.com', allow_redirects=False)
SSL 證書驗證
Requests在請求https網站默認會驗證SSL證書,可有些網站並沒有證書,可增加verify=False
參數忽略證書驗證,但此時可能會遇到煩人的InsecureRequestWarning
警告消息。最終能沒有警告消息也能訪問無證書的https網站的方法如下:
import requests from requests.packages.urllib3.exceptions import InsecureRequestWarning requests.packages.urllib3.disable_warnings(InsecureRequestWarning) requests.get('https://github.com', verify=False)
代理
使用代理的目的就不說瞭,使用方法如下:
# http代理,需要指定訪問的http協議和https協議兩種 proxies = { "http": "http://127.0.0.1:8080", "https": "http://127.0.0.1:1080", } # socks5代理 proxies = { 'http': 'socks5://user:pass@host:port', 'https': 'socks5://user:pass@host:port' } requests.get("http://example.org", proxies=proxies)
有個使用技巧就是代理到burp中,檢查一下python發包。如我本地抓到requests請求包如下,可以發現特征十分明顯,所以我們在實戰使用時盡量修改User-Agent
保持cookie
使用session會話對象,向同一主機發送多個請求,底層的 TCP 連接將會被重用,不僅能提性能還能保持cookie
s = requests.Session() s.get('http://httpbin.org/cookies/set/sessioncookie/123456789') r = s.get("http://httpbin.org/cookies")
在編寫poc腳本時我們隻需要利用Requests模塊發送帶有payload的數據即可,配合上這裡的小技巧可能會有更好的體驗
驗證結果
發送帶有payload的請求後,我們需要通過分析響應包判斷是否存在漏洞。往往存在漏洞的響應包都有一些特殊值,我們隻需要在響應包中找到這樣的特殊值即可證明存在漏洞,所以這裡我們通常有兩種寫法
成員運算符 – in
if 'xxx' in r.text: print('存在漏洞') else: print('不存在漏洞')
正則匹配 – re.search()
if re.search('xxx',r.text): print('存在漏洞') else: print('不存在漏洞')
這兩種寫法差不多,不過re.search()有個好處是可以使用正則表達式,在漏洞特征是動態變化的情況時也能有效的捕捉
單線程poc腳本
此時我們已經能寫一個單線程poc腳本瞭,我對單線程的poc腳本的要求十分簡單,就是簡單,在面對不同的漏洞時簡單修改幾行代碼就可以瞭。這裡提供一個我自己寫的單線程poc腳本,大概意思就是這樣
import requests import re from requests.packages.urllib3.exceptions import InsecureRequestWarning requests.packages.urllib3.disable_warnings(InsecureRequestWarning) def Poc(url): proxy = { 'http':'http://127.0.0.1:8080', 'https':'http://127.0.0.1:8080' } headers = { 'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36', 'Connection':'close' } data = {'name':'xxxx','value':'xxxx'} try: response = requests.post(url=url,headers=headers,data=data,verify=False,proxies=proxy,timeout=10) if 'baidu' in response.text: print('存在漏洞') else: print('none') except Exception as e: print(f'請求失敗:{e}') if __name__ == '__main__': url = 'https://www.baidu.com' Poc(url)
使用多線程
當我們想批量驗證數個網站是否存在漏洞時,就需要多線程來提升效率瞭。關於Python多線程的詳細知識這裡就不是這裡的重點瞭。這裡我們將利用Threading和queue做一個多線程poc腳本,我計劃的流程如下
把所有目標url放到queue隊列中;
啟動多線程從queue隊列中獲取目標並執行;
保存執行結果。
具體代碼最後會給出
顏色標記
我在使用多線程時就遇到一個問題,因為多線程處理的數據比較多,終端瞬間會輸出大量信息,很容易就會忽略一些關鍵的信息
然後我就想用顏色來區分不同的信息,在linux終端中使用\033[顯示方式;前景色;背景色m
的格式就能輸出各個顏色的字體。這裡推薦python第三方庫:colorama
colorama是一個可以跨多終端顯示不同顏色字符與背景的第三方庫,在linux終端上,使用ANSI轉義字符來實現彩色字體的輸出。在windows的終端上,通過包裝stdout實現。在windows和linux上有不同的實現方案,從而達到跨平臺的效果
安裝第三方庫的命令各位應該都會吧
pip install colorama
具體使用參考官方文檔:https://pypi.org/project/colorama/
我的使用習慣就是報錯信息的字體使用紅色,發現漏洞的字體使用綠色,此時部分代碼如下:
from colorama import init,Fore init(autoreset=True) print(Fore.GREEN + '[+]存在漏洞') print(Fore.RED + '[!]連接錯誤')
使用顏色後的終端輸出如下,現在使用體驗上明顯會更好一點,大傢也可以根據自己的喜好去設置
添加進度條
我們使用多線程的目的就是為瞭更快的處理更多的url,但目標過多,我們還是免不瞭更長時間的等待。我們經常會把腳本掛在那裡跑,然後呆呆的等著。然後我就想做一個進度條,根據進度條能大概的去預估時間,然後安排自己的工作,提升工作效率,這不就是使用腳本的意義嗎
我首先就找到瞭很多人推薦的第三方庫:tqdm,在多線程中使用時可以使用手動更新進度
import time from tqdm import tqdm with tqdm(total=200) as pbar: pbar.set_description('Processing:') for i in range(20): time.sleep(0.1) pbar.update(10)
但我這裡就遇到一個問題,很多人使用tqdm時隻輸出一個Progress bar任務條,但我們的需求是希望同時輸出每次漏洞探測結果和任務條,這會導致這兩者在終端中顯示的混亂,如下圖所示
有沒有一種辦法能讓任務條一直固定輸出在終端的末尾呢,這樣兩個信息都能很清晰的顯示
我找瞭好久解決方法,但官方似乎說沒有找到在多個平臺上平等使用tqdm的方法,就沒有這個功能。不過我最終找到官方提供瞭一個tqdm.write()方法,似乎能解決這個問題,隻需要把腳本中所有print()方法換成tqdm.write()方法
到這裡我們就成功的擁有瞭一個進度條
多線程poc腳本
我最終寫好的多線程poc腳本如下,中間還有很多可以優化的地方,希望能得到大傢的指點
import requests from requests.packages.urllib3.exceptions import InsecureRequestWarning import threading import queue from colorama import init,Fore from tqdm import tqdm init(autoreset=True) requests.packages.urllib3.disable_warnings(InsecureRequestWarning) global_file_target_url = 'url.txt' global_file_result = 'right.txt' global_threads_num = 12 global_q = queue.Queue() global_list_result = [] # 目標uri global_where = '' # payload 成功時頁面標志信息 global_payload = 'test' global_request_proxy = { 'http':'socks5://127.0.0.1:8080', 'https':'socks5://127.0.0.1:8080' } global_request_headers = { 'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36', 'cookie':'xxxxxxxxxxxxxx', 'Connection':'close' #關閉多餘的連接請求 } global_request_data = {'name':'xxxx','value':'xxxx'} #POST傳遞的數據 global_error = 0 def req(url): global global_error i = 0 while i<3: if i>0: #print(f'[!]第{i}次重試請求{url}') tqdm.write(f'[!]第{i}次重試請求{url}') try: response = requests.get(url=url,headers=global_request_headers,verify=False,timeout=10) response.encoding = response.apparent_encoding text = response.text if global_payload in text: return True else: return False except Exception as e: if i==0: global_error +=1 i = i+1 #print(Fore.RED+f'[!]{url}請求失敗') tqdm.write(Fore.RED+f'[!]{url}請求失敗') def poc(pbar): while not global_q.empty(): target_url = global_q.get() url = target_url+global_where if req(url): #print(Fore.GREEN+'[+]存在漏洞:'+target_url) tqdm.write(Fore.GREEN+'[+]存在漏洞:'+target_url) global_list_result.append(target_url) else: #print('[-]未發現漏洞') tqdm.write('[-]未發現漏洞') pbar.update(1) def main(): # 1、添加目標url隊列 with open(global_file_target_url,'r') as f: urls = f.readlines() for url in urls: url = url.strip() global_q.put(url) num_url = global_q.qsize() pbar = tqdm(total=num_url) pbar.set_description('Processing:') tqdm.write('url總數:'+str(num_url)) # 2、啟動多線程poc驗證 threads = [] for _ in range(global_threads_num): t = threading.Thread(target=poc,args=(pbar,)) threads.append(t) t.start() for t in threads: t.join() # 3、保存結果到文件 global_file_result if global_list_result: file = open(global_file_result,'w') for res in global_list_result: file.write(res+"\n") file.close() tqdm.write(f'失敗請求數{global_error}') if __name__ == '__main__': main()
總結
到此這篇關於用Python編寫一個漏洞驗證腳本的文章就介紹到這瞭,更多相關Python漏洞驗證腳本內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- 教你如何利用python3爬蟲爬取漫畫島-非人哉漫畫
- 基於Python中request請求得到的response的屬性問題
- Python爬蟲之requests庫基本介紹
- Python進度條可視化之監測程序運行速度
- python中response.text 和response.content的區別詳解