mirror of
https://github.com/sqlmapproject/sqlmap.git
synced 2026-07-06 16:36:53 +00:00
Adding support for --xxe
This commit is contained in:
parent
16c8909a0c
commit
5fa2da5eae
14 changed files with 1413 additions and 16 deletions
72
lib/request/webhooksite.py
Normal file
72
lib/request/webhooksite.py
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org)
|
||||
See the file 'LICENSE' for copying permission
|
||||
"""
|
||||
|
||||
import json
|
||||
|
||||
from lib.core.data import logger
|
||||
from lib.core.convert import getText
|
||||
from lib.core.enums import HTTP_HEADER
|
||||
from lib.core.settings import OOB_EXFIL_ENDPOINT
|
||||
from lib.request.connect import Connect as Request
|
||||
|
||||
# webhook.site is used for blind-XXE OOB *exfiltration*: it can both serve a custom
|
||||
# response (our malicious external DTD) AND log the request the target then makes
|
||||
# (carrying the file content). interactsh cannot host arbitrary content, hence the
|
||||
# separate backend. HTTP-only, free tier, no account required for basic tokens.
|
||||
|
||||
|
||||
class WebhookSite(object):
|
||||
"""Thin webhook.site client: mints tokens (optionally serving fixed content)
|
||||
and reads back the requests captured on them. All calls go through sqlmap's
|
||||
request stack (proxy/timeout honoured) straight to the service, not the target."""
|
||||
|
||||
def __init__(self):
|
||||
# Exfil host is the public content-serving endpoint (its token API is
|
||||
# service-specific, so --oob-server, which selects the interactsh *detection*
|
||||
# server, deliberately does not repoint it).
|
||||
self.endpoint = OOB_EXFIL_ENDPOINT.rstrip('/')
|
||||
|
||||
def _api(self, path, post=None):
|
||||
try:
|
||||
headers = {HTTP_HEADER.CONTENT_TYPE: "application/json"} if post is not None else {HTTP_HEADER.ACCEPT: "application/json"}
|
||||
page, _, code = Request.getPage(url="%s%s" % (self.endpoint, path), post=post,
|
||||
auxHeaders=headers, direct=True, silent=True, raise404=False)
|
||||
return page if (code is None or code in (200, 201)) else None
|
||||
except Exception as ex:
|
||||
logger.debug("webhook.site request to '%s' failed: %s" % (path, getText(ex)))
|
||||
return None
|
||||
|
||||
def newToken(self, content=None):
|
||||
"""Create a token. When `content` is given the token serves it verbatim
|
||||
(used to host the external DTD). Returns the token UUID or None."""
|
||||
body = {"default_status": 200}
|
||||
if content is not None:
|
||||
body["default_content"] = content
|
||||
body["default_content_type"] = "application/xml"
|
||||
page = self._api("/token", post=json.dumps(body))
|
||||
if page:
|
||||
try:
|
||||
return json.loads(page).get("uuid")
|
||||
except ValueError:
|
||||
pass
|
||||
return None
|
||||
|
||||
def hostUrl(self, token):
|
||||
"""Target-facing URL for a token. Plain HTTP - XML parsers (libxml) commonly
|
||||
cannot fetch https external entities."""
|
||||
host = self.endpoint.split("://", 1)[-1]
|
||||
return "http://%s/%s" % (host, token)
|
||||
|
||||
def captured(self, token):
|
||||
"""Return the list of request records captured on `token` (newest first)."""
|
||||
page = self._api("/token/%s/requests?sorting=newest&per_page=50" % token)
|
||||
if page:
|
||||
try:
|
||||
return json.loads(page).get("data") or []
|
||||
except ValueError:
|
||||
pass
|
||||
return []
|
||||
Loading…
Add table
Add a link
Reference in a new issue