This commit is contained in:
Miroslav Štampar
2026-09-04 09:47:33 +02:00
parent e10092efcd
commit 1ee368f78a
3 changed files with 49 additions and 17 deletions
+19 -11
View File
@@ -1223,6 +1223,14 @@ def heuristicCheckSqlInjection(place, parameter):
if conf.beep:
beep()
def _search(regex):
# Note: on a rare (e.g. huge) response the regex engine itself can fail, and losing one
# advisory heuristic beats losing the whole run (e.g. #5994 and #6105)
try:
return re.search(regex, page or "")
except (SystemError, RuntimeError) as ex:
logger.debug("skipping heuristic check because of a regex engine failure ('%s')" % getSafeExString(ex))
try:
for match in re.finditer(FI_ERROR_REGEX, page or ""):
if randStr1.lower() in match.group(0).lower():
@@ -1234,71 +1242,71 @@ def heuristicCheckSqlInjection(place, parameter):
break
except (SystemError, RuntimeError) as ex:
logger.debug("Skipping FI heuristic due to regex failure: %s", getSafeExString(ex))
logger.debug("skipping heuristic check because of a regex engine failure ('%s')" % getSafeExString(ex))
if not conf.nosql and re.search(NOSQL_ERROR_REGEX, page or ""):
if not conf.nosql and _search(NOSQL_ERROR_REGEX):
infoMsg = "heuristic (NoSQL) test shows that %sparameter '%s' might be vulnerable to NoSQL injection attacks (rerun with switch '--nosql')" % ("%s " % paramType if paramType != parameter else "", parameter)
logger.info(infoMsg)
if conf.beep:
beep()
if not conf.graphql and re.search(GRAPHQL_ERROR_REGEX, page or ""):
if not conf.graphql and _search(GRAPHQL_ERROR_REGEX):
infoMsg = "heuristic (GraphQL) test shows that %sparameter '%s' appears to be a GraphQL endpoint (rerun with switch '--graphql')" % ("%s " % paramType if paramType != parameter else "", parameter)
logger.info(infoMsg)
if conf.beep:
beep()
if not conf.ldap and re.search(LDAP_ERROR_REGEX, page or ""):
if not conf.ldap and _search(LDAP_ERROR_REGEX):
infoMsg = "heuristic (LDAP) test shows that %sparameter '%s' might be vulnerable to LDAP injection (rerun with switch '--ldap')" % ("%s " % paramType if paramType != parameter else "", parameter)
logger.info(infoMsg)
if conf.beep:
beep()
if not conf.xpath and re.search(XPATH_ERROR_REGEX, page or ""):
if not conf.xpath and _search(XPATH_ERROR_REGEX):
infoMsg = "heuristic (XPath) test shows that %sparameter '%s' might be vulnerable to XPath injection (rerun with switch '--xpath')" % ("%s " % paramType if paramType != parameter else "", parameter)
logger.info(infoMsg)
if conf.beep:
beep()
if not conf.ssti and re.search(SSTI_ERROR_REGEX, page or ""):
if not conf.ssti and _search(SSTI_ERROR_REGEX):
infoMsg = "heuristic (SSTI) test shows that %sparameter '%s' might be vulnerable to server-side template injection (rerun with switch '--ssti')" % ("%s " % paramType if paramType != parameter else "", parameter)
logger.info(infoMsg)
if conf.beep:
beep()
if not conf.hql and re.search(HQL_ERROR_REGEX, page or ""):
if not conf.hql and _search(HQL_ERROR_REGEX):
infoMsg = "heuristic (HQL) test shows that %sparameter '%s' might be vulnerable to HQL/JPQL (Hibernate ORM) injection (rerun with switch '--hql')" % ("%s " % paramType if paramType != parameter else "", parameter)
logger.info(infoMsg)
if conf.beep:
beep()
if not conf.xslt and re.search(XSLT_ERROR_REGEX, page or ""):
if not conf.xslt and _search(XSLT_ERROR_REGEX):
infoMsg = "heuristic (XSLT) test shows that %sparameter '%s' might be vulnerable to XSLT injection (rerun with switch '--xslt')" % ("%s " % paramType if paramType != parameter else "", parameter)
logger.info(infoMsg)
if conf.beep:
beep()
if not conf.sparql and re.search(SPARQL_ERROR_REGEX, page or ""):
if not conf.sparql and _search(SPARQL_ERROR_REGEX):
infoMsg = "heuristic (SPARQL) test shows that %sparameter '%s' might be vulnerable to SPARQL injection (rerun with switch '--sparql')" % ("%s " % paramType if paramType != parameter else "", parameter)
logger.info(infoMsg)
if conf.beep:
beep()
if not conf.odata and re.search(ODATA_ERROR_REGEX, page or ""):
if not conf.odata and _search(ODATA_ERROR_REGEX):
infoMsg = "heuristic (OData) test shows that %sparameter '%s' might be vulnerable to OData $filter injection (rerun with switch '--odata')" % ("%s " % paramType if paramType != parameter else "", parameter)
logger.info(infoMsg)
if conf.beep:
beep()
if not conf.xxe and kb.postHint in (POST_HINT.XML, POST_HINT.SOAP) and re.search(XXE_ERROR_REGEX, page or ""):
if not conf.xxe and kb.postHint in (POST_HINT.XML, POST_HINT.SOAP) and _search(XXE_ERROR_REGEX):
infoMsg = "heuristic (XXE) test shows that the XML request body might be vulnerable to XML External Entity injection (rerun with switch '--xxe')"
logger.info(infoMsg)
+9 -6
View File
@@ -20,7 +20,7 @@ from lib.core.enums import OS
from thirdparty import six
# sqlmap version (<major>.<minor>.<month>.<monthly commit>)
VERSION = "1.10.9.3"
VERSION = "1.10.9.4"
TYPE = "dev" if VERSION.count('.') > 2 and VERSION.split('.')[-1] != '0' else "stable"
TYPE_COLORS = {"dev": 33, "stable": 90, "pip": 34}
VERSION_STRING = "sqlmap/%s#%s" % ('.'.join(VERSION.split('.')[:-1]) if VERSION.count('.') > 2 and VERSION.split('.')[-1] == '0' else VERSION, TYPE)
@@ -1193,7 +1193,10 @@ XPATH_ERROR_SIGNATURES = (
("Python ElementTree", r"xml\.etree\.ElementTree\.(?:ParseError|Element)"),
# NOT XSLT: a dedicated '--xslt' engine owns those errors now, and claiming them here made every
# XSLT parser error suggest '--xpath' as well
("Generic XPath", r"XPath.*?(?:error|exception|syntax)"),
# NOTE: the gap has to stay bounded (like in 'Handlebars' below). An unbounded '.*?' turns this
# into a quadratic scan of every long line that merely carries the word 'xpath' (e.g. minified
# JS/JSON), which took ~25s on a 400KB response - and blew up the regex engine itself (#6105)
("Generic XPath", r"XPath[^\n]{0,100}?(?:error|exception|syntax)"),
("Generic XPath", r"Invalid XPath|XPath evaluation failed"),
)
@@ -1337,7 +1340,7 @@ SSTI_ERROR_SIGNATURES = (
("Velocity", r"org\.apache\.velocity\.(?:runtime|exception)\.\w+|ParseErrorException|MethodInvocationException|ResourceNotFoundException"),
("Spring EL / Thymeleaf", r"org\.springframework\.expression\.\w+|org\.thymeleaf\.\w+|SpelEvaluationException|TemplateProcessingException|ExpressionParsingException"),
("Struts2 (OGNL)", r"ognl\.(?:OgnlException|NoSuchPropertyException|MethodFailedException|InappropriateExpressionException|ExpressionSyntaxException)|com\.opensymphony\.xwork2|org\.apache\.struts2|There is no Action mapped for|Struts (?:Problem Report|has detected an unhandled exception)"),
("ERB", r"\(erb\):\d+|NameError.*undefined local variable"),
("ERB", r"\(erb\):\d+|NameError[^\n]{0,100}?undefined local variable"),
# NOTE: these must stay anchored to a diagnostic. The bare product names matched any page that
# carries the word 'pug'/'jade'/'handlebars' (a surname, a colour, a <script src=> of the runtime),
# and the bare 'ParseError' matched lxml.etree.XSLTParseError and ElementTree.ParseError
@@ -1361,7 +1364,7 @@ XXE_ERROR_SIGNATURES = (
("Java (Xerces/JAXP)", r"(?:org\.xml\.sax\.SAXParseException|com\.sun\.org\.apache\.xerces|javax\.xml\.stream\.XMLStreamException|The (?:entity|element type) \"[^\"]*\" was referenced|DOCTYPE is disallowed when the feature|External (?:DTD|parsed entities|Entity): failed|\"[^\"]*\" must be declared|had to be read but the maximum)"),
(".NET System.Xml", r"(?:System\.Xml\.XmlException|For security reasons DTD is prohibited|Reference to undeclared entity|An error occurred while parsing EntityName|XmlTextReaderImpl)"),
("Python expat", r"(?:xml\.parsers\.expat\.ExpatError|undefined entity|not well-formed \(invalid token\)|ExpatError)"),
("Ruby Nokogiri/REXML", r"(?:Nokogiri::XML::SyntaxError|REXML::ParseException|Entity .* not defined)"),
("Ruby Nokogiri/REXML", r"(?:Nokogiri::XML::SyntaxError|REXML::ParseException|Entity [^\n]{0,100}? not defined)"),
("Go encoding/xml", r"XML syntax error on line \d+"),
# NOTE: 'unexpected end of ...' is what every parser says, not what an XML parser says. It matched
# the "Unexpected end of query" of BaseX, the "Unexpected <EOF>" of GraphQL and the "Unexpected end
@@ -1417,7 +1420,7 @@ HQL_ERROR_SIGNATURES = (
("Hibernate", r"(?:unexpected (?:token:|end of subtree|AST node)|Could not (?:resolve|interpret) (?:attribute|root entity|path|property))"),
("EclipseLink / JPQL", r"(?:org\.eclipse\.persistence\.exceptions\.JPQLException|Exception \[EclipseLink|Problem compiling \[|An exception occurred while creating a query)"),
("JPA / JPQL", r"(?:javax|jakarta)\.persistence\.(?:PersistenceException|Query(?:Syntax|Timeout)?Exception)"),
("Generic HQL/JPQL", r"(?:HQL|JPQL|EJBQL)\b.*?(?:error|exception|syntax|not (?:mapped|resolve))"),
("Generic HQL/JPQL", r"(?:HQL|JPQL|EJBQL)\b[^\n]{0,100}?(?:error|exception|syntax|not (?:mapped|resolve))"),
)
HQL_ERROR_REGEX = r"(?i)(?:%s)" % '|'.join(regex for _, regex in HQL_ERROR_SIGNATURES)
@@ -1484,7 +1487,7 @@ SPARQL_ERROR_SIGNATURES = (
# too - matching on it alone mislabelled them as RDF4J, so only the package name is kept
("RDF4J / GraphDB", r"org\.eclipse\.rdf4j|org\.openrdf\.query"),
("Blazegraph", r"com\.bigdata\.rdf|\bBlazegraph\b"),
("rdflib", r"rdflib\.plugins\.sparql|\bParseException\b.*?(?:SPARQL|sparql)"),
("rdflib", r"rdflib\.plugins\.sparql|\bParseException\b[^\n]{0,100}?(?:SPARQL|sparql)"),
("Stardog", r"com\.(?:complexible\.)?stardog"),
)