单线程和多线程 如何编写Python漏洞验证脚本( 二 )

 
使用多线程当我们想批量验证数个网站是否存在漏洞时,就需要多线程来提升效率了 。关于Python多线程的详细知识这里就不是这里的重点了 。这里我们将利用Threading和queue做一个多线程poc脚本,我计划的流程如下
把所有目标url放到queue队列中;
启动多线程从queue队列中获取目标并执行;
保存执行结果 。
具体代码最后会给出
 
颜色标记我在使用多线程时就遇到一个问题,因为多线程处理的数据比较多,终端瞬间会输出大量信息,很容易就会忽略一些关键的信息

单线程和多线程 如何编写Python漏洞验证脚本

文章插图
 
然后我就想用颜色来区分不同的信息,在linux终端中使用 33[显示方式;前景色;背景色m 的格式就能输出各个颜色的字体 。这里推荐python第三方库:colorama
colorama是一个可以跨多终端显示不同颜色字符与背景的第三方库,在linux终端上,使用ANSI转义字符来实现彩色字体的输出 。在windows的终端上,通过包装stdout实现 。在windows和linux上有不同的实现方案,从而达到跨平台的效果
安装第三方库的命令各位应该都会吧
pip install colorama具体使用参考官方文档:
https://pypi.org/project/colorama/
我的使用习惯就是报错信息的字体使用红色,发现漏洞的字体使用绿色,此时部分代码如下:
from colorama import init,Foreinit(autoreset=True)print(Fore.GREEN + '[+]存在漏洞')print(Fore.RED + '[!]连接错误')使用颜色后的终端输出如下,现在使用体验上明显会更好一点,大家也可以根据自己的喜好去设置
单线程和多线程 如何编写Python漏洞验证脚本

文章插图
 
添加进度条我们使用多线程的目的就是为了更快地处理更多的url,但目标过多,我们还是免不了更长时间的等待 。我们经常会把脚本挂在那里跑,然后呆呆的等着 。然后我就想做一个进度条,根据进度条能大概地去预估时间,然后安排自己的工作,提升工作效率,这不就是使用脚本的意义吗
我首先就找到了很多人推荐的第三方库: tqdm ,在多线程中使用时可以使用手动更新进度
import timefrom tqdm import tqdmwith tqdm(total=200) as pbar:pbar.set_description('Processing:')for i in range(20):time.sleep(0.1)pbar.update(10)但我这里就遇到一个问题,很多人使用tqdm时只输出一个Progress bar任务条,但我们的需求是希望同时输出每次漏洞探测结果和任务条,这会导致这两者在终端中显示的混乱,如下图所示
单线程和多线程 如何编写Python漏洞验证脚本

文章插图
 
有没有一种办法能让任务条一直固定输出在终端的末尾呢,这样两个信息都能很清晰地显示
我找了好久解决方法,但官方似乎说没有找到在多个平台上平等使用tqdm的方法,就没有这个功能 。
不过我最终找到官方提供了一个tqdm.write()方法,似乎能解决这个问题,只需要把脚本中所有print()方法换成tqdm.write()方法
单线程和多线程 如何编写Python漏洞验证脚本

文章插图
 
到这里我们就成功地拥有了一个进度条
 
多线程poc脚本我最终写好的多线程poc脚本如下,中间还有很多可以优化的地方,希望能得到大家的指点
import requestsfrom requests.packages.urllib3.exceptions import InsecureRequestWarningimport threadingimport queuefrom colorama import init,Forefrom tqdm import tqdminit(autoreset=True)requests.packages.urllib3.disable_warnings(InsecureRequestWarning)global_file_target_url = 'url.txt'global_file_result = 'right.txt'global_threads_num = 12global_q = queue.Queue()global_list_result = []# 目标uriglobal_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 = https://www.isolves.com/it/cxkf/yy/Python/2022-02-07/{'name':'xxxx','value':'xxxx'}#POST传递的数据global_error = 0def req(url):global global_errori = 0while 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_encodingtext = response.textif global_payload in text:return Trueelse:return Falseexcept Exception as e:if i==0:global_error +=1i = 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_whereif 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_resultif 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()


推荐阅读