Skip to content

Commit 9a34282

Browse files
committed
get operations with query parameters
1 parent 8f84b74 commit 9a34282

File tree

6 files changed

+96
-5
lines changed

6 files changed

+96
-5
lines changed

lib/core/common.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import time
3737
import types
3838
import unicodedata
39+
import json
3940

4041
from difflib import SequenceMatcher
4142
from math import sqrt
@@ -5362,6 +5363,53 @@ def _parseBurpLog(content):
53625363
if not(conf.scope and not re.search(conf.scope, url, re.I)):
53635364
yield (url, conf.method or method, data, cookie, tuple(headers))
53645365

5366+
def _parseSwagger(content):
5367+
"""
5368+
Parses Swagger OpenAPI 3.x.x JSON documents
5369+
"""
5370+
5371+
try:
5372+
swagger = json.loads(content)
5373+
logger.debug("swagger OpenAPI version '%s'" % swagger["openapi"])
5374+
5375+
for path in swagger["paths"]:
5376+
for operation in swagger["paths"][path]:
5377+
op = swagger["paths"][path][operation]
5378+
5379+
tags = conf.swaggerTags.split(",") if conf.swaggerTags is not None else None
5380+
5381+
if ((tags is None or any(tag in op["tags"] for tag in tags))
5382+
and operation == "get"):
5383+
5384+
url = None
5385+
method = None
5386+
data = None
5387+
cookie = None
5388+
5389+
url = "%s%s" % (swagger["servers"][0]["url"], path)
5390+
method = operation.upper()
5391+
q = list(filter(lambda p: (p["in"] == "query"), op["parameters"]))
5392+
qs = ""
5393+
for qp in q:
5394+
qs += "&%s=%s" %(qp["name"], qp["example"])
5395+
qs = qs.replace('&', '?', 1)
5396+
5397+
if op["parameters"] is not None and len(q) > 0:
5398+
url += qs
5399+
5400+
logger.debug("swagger url '%s', method '%s', data '%s', cookie '%s'" %(url, method, data, cookie))
5401+
yield (url, method, data, cookie, None)
5402+
5403+
else:
5404+
logger.info("excluding url '%s', method '%s' as target since there are no parameters to inject" %(url, method))
5405+
5406+
5407+
except json.decoder.JSONDecodeError:
5408+
errMsg = "swagger file is not valid JSON"
5409+
raise SqlmapSyntaxException(errMsg)
5410+
5411+
5412+
53655413
content = readCachedFileContent(reqFile)
53665414

53675415
if conf.scope:
@@ -5373,6 +5421,9 @@ def _parseBurpLog(content):
53735421
for target in _parseWebScarabLog(content):
53745422
yield target
53755423

5424+
for target in _parseSwagger(content):
5425+
yield target
5426+
53765427
def getSafeExString(ex, encoding=None):
53775428
"""
53785429
Safe way how to get the proper exception represtation as a string

lib/core/option.py

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,31 @@ def _setBulkMultipleTargets():
477477
warnMsg = "no usable links found (with GET parameters)"
478478
logger.warn(warnMsg)
479479

480+
def _setSwaggerMultipleTargets():
481+
if not conf.swaggerFile:
482+
return
483+
484+
infoMsg = "parsing multiple targets from swagger '%s'" % conf.swaggerFile
485+
logger.info(infoMsg)
486+
487+
if not os.path.exists(conf.swaggerFile):
488+
errMsg = "the specified list of targets does not exist"
489+
raise SqlmapFilePathException(errMsg)
490+
491+
if checkFile(conf.swaggerFile, False):
492+
debugMsg = "swagger file '%s' checks out" % conf.swaggerFile
493+
logger.debug(debugMsg)
494+
495+
for target in parseRequestFile(conf.swaggerFile):
496+
kb.targets.add(target)
497+
498+
else:
499+
errMsg = "the specified list of targets is not a file "
500+
errMsg += "nor a directory"
501+
raise SqlmapFilePathException(errMsg)
502+
503+
504+
480505
def _findPageForms():
481506
if not conf.forms or conf.crawlDepth:
482507
return
@@ -2677,7 +2702,7 @@ def _basicOptionValidation():
26772702
errMsg = "maximum number of used threads is %d avoiding potential connection issues" % MAX_NUMBER_OF_THREADS
26782703
raise SqlmapSyntaxException(errMsg)
26792704

2680-
if conf.forms and not any((conf.url, conf.googleDork, conf.bulkFile)):
2705+
if conf.forms and not any((conf.url, conf.googleDork, conf.bulkFile, conf.swaggerFile)):
26812706
errMsg = "switch '--forms' requires usage of option '-u' ('--url'), '-g' or '-m'"
26822707
raise SqlmapSyntaxException(errMsg)
26832708

@@ -2787,7 +2812,7 @@ def _basicOptionValidation():
27872812
errMsg = "value for option '--union-char' must be an alpha-numeric value (e.g. 1)"
27882813
raise SqlmapSyntaxException(errMsg)
27892814

2790-
if conf.hashFile and any((conf.direct, conf.url, conf.logFile, conf.bulkFile, conf.googleDork, conf.configFile, conf.requestFile, conf.updateAll, conf.smokeTest, conf.wizard, conf.dependencies, conf.purge, conf.listTampers)):
2815+
if conf.hashFile and any((conf.direct, conf.url, conf.logFile, conf.bulkFile, conf.swaggerFile, conf.googleDork, conf.configFile, conf.requestFile, conf.updateAll, conf.smokeTest, conf.wizard, conf.dependencies, conf.purge, conf.listTampers)):
27912816
errMsg = "option '--crack' should be used as a standalone"
27922817
raise SqlmapSyntaxException(errMsg)
27932818

@@ -2855,7 +2880,7 @@ def init():
28552880

28562881
parseTargetDirect()
28572882

2858-
if any((conf.url, conf.logFile, conf.bulkFile, conf.requestFile, conf.googleDork, conf.stdinPipe)):
2883+
if any((conf.url, conf.logFile, conf.bulkFile, conf.swaggerFile, conf.requestFile, conf.googleDork, conf.stdinPipe)):
28592884
_setHostname()
28602885
_setHTTPTimeout()
28612886
_setHTTPExtraHeaders()
@@ -2871,6 +2896,7 @@ def init():
28712896
_doSearch()
28722897
_setStdinPipeTargets()
28732898
_setBulkMultipleTargets()
2899+
_setSwaggerMultipleTargets()
28742900
_checkTor()
28752901
_setCrawler()
28762902
_findPageForms()

lib/core/optiondict.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
"requestFile": "string",
1919
"sessionFile": "string",
2020
"googleDork": "string",
21+
"swaggerFile": "string",
22+
"swaggerTags": "string",
2123
"configFile": "string",
2224
},
2325

lib/parse/cmdline.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,12 @@ def cmdLineParser(argv=None):
141141
target.add_argument("-g", dest="googleDork",
142142
help="Process Google dork results as target URLs")
143143

144+
target.add_argument("--swaggerFile", dest="swaggerFile",
145+
help="Parse target(s) from a Swagger OpenAPI 3.x.x JSON file ")
146+
147+
target.add_argument("--swaggerTags", dest="swaggerTags",
148+
help="Only process swagger operations that include one of these tags")
149+
144150
target.add_argument("-c", dest="configFile",
145151
help="Load options from a configuration INI file")
146152

lib/parse/configfile.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,14 +79,14 @@ def configFileParser(configFile):
7979

8080
mandatory = False
8181

82-
for option in ("direct", "url", "logFile", "bulkFile", "googleDork", "requestFile", "wizard"):
82+
for option in ("direct", "url", "logFile", "bulkFile", "googleDork", "requestFile", "wizard", "swaggerFile"):
8383
if config.has_option("Target", option) and config.get("Target", option) or cmdLineOptions.get(option):
8484
mandatory = True
8585
break
8686

8787
if not mandatory:
8888
errMsg = "missing a mandatory option in the configuration file "
89-
errMsg += "(direct, url, logFile, bulkFile, googleDork, requestFile or wizard)"
89+
errMsg += "(direct, url, logFile, bulkFile, googleDork, requestFile, wizard or swaggerFile)"
9090
raise SqlmapMissingMandatoryOptionException(errMsg)
9191

9292
for family, optionData in optDict.items():

sqlmap.conf

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@ requestFile =
3232
# Example: +ext:php +inurl:"&id=" +intext:"powered by "
3333
googleDork =
3434

35+
# Parse target(s) for a Swagger OpenAPI 3.x.x JSON file
36+
swaggerFile =
37+
38+
# Only process swagger operations that have one of these tags (e.g. tagA,tagB)
39+
swaggerTags =
40+
3541

3642
# These options can be used to specify how to connect to the target URL.
3743
[Request]

0 commit comments

Comments
 (0)