开发者

Python编写漏洞验证脚本批量测试繁琐漏洞

开发者 https://www.devze.com 2022-12-11 11:09 出处:网络 作者: kali_Ma
目录前言requests模块使用技巧取消重定向SSL证书验证代理保持cookie验证结果单线程poc脚本使用多线程颜色标记添加进度条多线程poc脚本前言
目录
  • 前言
  • requests模块使用技巧
    • 取消重定向
    • SSL证书验证
    • 代理
    • 保持cookie
  • 验证结果
    • 单线程poc脚本
      • 使用多线程
        • 颜色标记
          • 添加进度条
            • 多线程poc脚本

              前言

              我们实战经常会遇到以下几个问题:

              ​ 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

              Python编写漏洞验证脚本批量测试繁琐漏洞

              保持cookie

              使用session会话对象,向同一主机发送多个请求,底层的 TCP 连接将会被重用,不仅能提性能还能保持cookie

              s = requesthttp://www.cppcns.coms.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)
                    www.cppcns.com  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队列中获取目标并执行;

              保存执行结果。

              具体代码最后会给出

              颜色标记

              我在使用多线程时就遇到一个问题,因为多线程处理的数据比较多,终端瞬间会输出大量信息,很容易就会忽略一些关键的信息

              Python编写漏洞验证脚本批量测试繁琐漏洞

              然后我就想用颜色来区分不同的信息,在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 + '[!]连接错误')

              使用颜色后的终端输出如下,现在使用体验上明显会更好一点,大家也可以根据自己的喜好去设置

              Python编写漏洞验证脚本批量测试繁琐漏洞

              添加进度条

              我们使用多线程的目的就是为了更快的处理更多的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任务条,但我们的需求是希望同时输出每次漏洞探测结果和任务条,这会导致这两者在终端中显示的混乱,如下图所示

              Python编写漏洞验证脚本批量测试繁琐漏洞

              有没有一种办法能让任务条一直固定输出在终端的末尾呢,这样两个信息都能很清晰的显示

              我找了好久解决方法,但官方似乎说没有找到在多个平台上平等使用tqdm的方法,就没有这个功能。不过我最终找到官方提供了一个tqdm.write()方法,似乎能解决这个问题,只需要把脚本中所有print()方法换成tqdm.write()方法

              Python编写漏洞验证脚本批量测试繁琐漏洞

              到这里我们就成功的拥有了一个进度条

              多线程poc脚本

              我最终写好的多线程poc脚本如下,中间还有很多可以优化的地方,希望能得到大家的指点

              import requests
              from requests.packages.urllib3.exceptions import InsecureRequestWarning
              import threading
              import queue
              from colorama import iZlWqgznGRnit,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 ZlWqgznGRe:
                          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验证
                  thrZlWqgznGReads = []
                  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()
              
              

              参考:

              https://mp.weixin.qq.com/s/aWbPUANyglL5kWiiFfSRYw

              https://mp.weixin.qq.com/s/Dwec68-ROfiqWeRUY4wEpg~~~~

              以上就是Python编写漏洞验证脚本批量测试繁琐漏洞的详细内容,更多关于Python漏洞验证脚本的资料请关注我们其它相关文章!

              0

              精彩评论

              暂无评论...
              验证码 换一张
              取 消