Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix 'xpath' is not a valid MatcherType #413

Merged
merged 6 commits into from
Mar 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion pocsuite3/lib/yaml/nuclei/operators/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
match_regex,
match_size,
match_status_code,
match_words)
match_words,
match_xpath)

__all__ = [
"ExtractorType",
Expand All @@ -29,4 +30,5 @@
"match_regex",
"match_binary",
"match_dsl",
"match_xpath",
]
2 changes: 1 addition & 1 deletion pocsuite3/lib/yaml/nuclei/operators/extrators/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ def extract_xpath(e: Extractor, corpus: str) -> dict:
else:
doc = etree.HTML(corpus)

if not doc:
if doc is None:
return results

for x in e.xpath:
Expand Down
42 changes: 42 additions & 0 deletions pocsuite3/lib/yaml/nuclei/operators/matchers/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import binascii
import re
from dataclasses import dataclass, field
from lxml import html
from typing import List

from pocsuite3.lib.yaml.nuclei.model import CaseInsensitiveEnum
Expand All @@ -14,6 +15,7 @@ class MatcherType(CaseInsensitiveEnum):
RegexMatcher = "regex"
BinaryMatcher = "binary"
DSLMatcher = "dsl"
XpathMatcher = "xpath"


@dataclass
Expand Down Expand Up @@ -49,6 +51,9 @@ class Matcher:
# Regex contains Regular Expression patterns required to be present in the response part.
regex: List[str] = field(default_factory=list)

# Xpath contains xpath patterns required to be present in the response part.
xpath: List[str] = field(default_factory=list)

# Binary are the binary patterns required to be present in the response part.
binary: List[str] = field(default_factory=list)

Expand Down Expand Up @@ -181,3 +186,40 @@ def match_dsl(matcher: Matcher, data: dict) -> bool:
if len(matcher.dsl) - 1 == i:
return True
return False


def match_xpath(matcher: Matcher, body: str) -> (bool, list):
"""Matches xpath check against a body.
"""
# Convert the body string to etree.HTML object for xpath manipulations
if body is None:
return False
body_tree = html.fromstring(body)
matched_xpaths = []

for i, xpath_pattern in enumerate(matcher.xpath):
try:
# Applying xpath on the HTML and capturing the result
result = body_tree.xpath(xpath_pattern)
if not result:
# If result is empty, the xpath expression did not match anything in the HTML body
if matcher.condition == 'and':
return False, []
elif matcher.condition == 'or':
continue

if matcher.condition == 'or' and not matcher.match_all:
return True, [result]

matched_xpaths.append(result)

if len(matcher.xpath) - 1 == i and not matcher.match_all:
return True, matched_xpaths

except Exception as e:
print(f"Error while matching with XPath {xpath_pattern}. Error: {str(e)}")

if len(matched_xpaths) > 0 and matcher.match_all:
return True, matched_xpaths

return False, []
5 changes: 4 additions & 1 deletion pocsuite3/lib/yaml/nuclei/protocols/http/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
extract_xpath, match_binary,
match_dsl, match_regex,
match_size, match_status_code,
match_words)
match_words, match_xpath)
from pocsuite3.lib.yaml.nuclei.protocols.common.generators import AttackType, payload_generator
from pocsuite3.lib.yaml.nuclei.protocols.common.interactsh import InteractshClient
from pocsuite3.lib.yaml.nuclei.protocols.common.replacer import (
Expand Down Expand Up @@ -198,6 +198,9 @@ def http_match(request: HttpRequest, resp_data: dict, interactsh=None):
elif matcher.type == MatcherType.DSLMatcher:
matcher_res = match_dsl(matcher, resp_data)

elif matcher.type == MatcherType.XpathMatcher:
matcher_res, _ = match_xpath(matcher, item)

if matcher.negative:
matcher_res = not matcher_res

Expand Down
5 changes: 4 additions & 1 deletion pocsuite3/lib/yaml/nuclei/protocols/network/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
extract_dsl, extract_kval, extract_regex,
match_binary,
match_dsl, match_regex,
match_size, match_words)
match_size, match_words, match_xpath)
from pocsuite3.lib.yaml.nuclei.protocols.common.generators import AttackType, payload_generator
from pocsuite3.lib.yaml.nuclei.protocols.common.interactsh import InteractshClient
from pocsuite3.lib.yaml.nuclei.protocols.common.replacer import (
Expand Down Expand Up @@ -162,6 +162,9 @@ def network_match(request: NetworkRequest, resp_data: dict, interactsh=None):
elif matcher.type == MatcherType.BinaryMatcher:
matcher_res, _ = match_binary(matcher, item)

elif matcher.type == MatcherType.XpathMatcher:
matcher_res, _ = match_xpath(matcher, item)

elif matcher.type == MatcherType.DSLMatcher:
matcher_res = match_dsl(matcher, resp_data)

Expand Down
2 changes: 1 addition & 1 deletion pocsuite3/modules/httpserver/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ class HTTPServerV4(HTTPServer):


class PHTTPServer(threading.Thread, metaclass=PHTTPSingleton):
def __init__(self, bind_ip='0.0.0.0', bind_port=666, is_ipv6=False, use_https=False,
def __init__(self, bind_ip='0.0.0.0', bind_port=6666, is_ipv6=False, use_https=False,
certfile=os.path.join(paths.POCSUITE_TMP_PATH, 'cacert.pem'),
requestHandler=BaseRequestHandler):
threading.Thread.__init__(self)
Expand Down
Loading