@@ -492,6 +492,65 @@ def _setBulkMultipleTargets():
492492 warnMsg = "no usable links found (with GET parameters)"
493493 logger .warning (warnMsg )
494494
495+ def _setOpenApiTargets ():
496+ if not conf .openApiFile :
497+ return
498+
499+ from lib .parse .openapi import openApiTargets
500+
501+ if conf .method :
502+ warnMsg = "option '--method' will override the HTTP method(s) derived from the OpenAPI/Swagger specification"
503+ logger .warning (warnMsg )
504+
505+ origin = None
506+ if re .match (r"(?i)\Ahttps?://" , conf .openApiFile ):
507+ infoMsg = "fetching OpenAPI/Swagger specification from '%s'" % conf .openApiFile
508+ logger .info (infoMsg )
509+ from lib .request .connect import Connect as Request
510+ content = Request .getPage (url = conf .openApiFile , raise404 = True )[0 ]
511+ match = re .match (r"(?i)(https?://[^/]+)" , conf .openApiFile )
512+ origin = match .group (1 ) if match else None
513+ else :
514+ conf .openApiFile = safeExpandUser (conf .openApiFile )
515+ checkFile (conf .openApiFile )
516+ infoMsg = "parsing OpenAPI/Swagger specification from '%s'" % conf .openApiFile
517+ logger .info (infoMsg )
518+ content = openFile (conf .openApiFile ).read ()
519+
520+ try :
521+ targets = openApiTargets (content , origin )
522+ except ValueError as ex :
523+ errMsg = "unable to parse the OpenAPI/Swagger specification ('%s')" % getSafeExString (ex )
524+ raise SqlmapSyntaxException (errMsg )
525+
526+ if re .search (r"(?i)securitySchemes|securityDefinitions" , content ) and not any ((conf .authType , conf .authCred , conf .authFile )) and not any ((_ [0 ] or "" ).lower () == HTTP_HEADER .AUTHORIZATION .lower () for _ in (conf .httpHeaders or [])):
527+ warnMsg = "the OpenAPI/Swagger specification declares authentication (security schemes) but no credentials were provided. "
528+ warnMsg += "If the API requires authentication, requests are likely to be rejected. Provide credentials with "
529+ warnMsg += "'--auth-type'/'--auth-cred' or a header (e.g. --headers=\" Authorization: Bearer ...\" )"
530+ logger .warning (warnMsg )
531+
532+ before = len (kb .targets ) # openapi carries per-target bodies -> no conf.data fallback
533+ mutating = 0
534+ for url , method , data , headers in targets :
535+ if conf .scope and not re .search (conf .scope , url , re .I ):
536+ continue
537+ if method not in ("GET" , "HEAD" , "OPTIONS" ):
538+ mutating += 1
539+ kb .targets .add ((url , method , data , conf .cookie , tuple (headers ) if headers else None ))
540+
541+ added = len (kb .targets ) - before
542+ if added :
543+ conf .multipleTargets = True
544+ infoMsg = "derived %d target(s) from the OpenAPI/Swagger specification" % added
545+ logger .info (infoMsg )
546+ if mutating :
547+ warnMsg = "%d of the derived target(s) use state-changing HTTP methods (e.g. POST/PUT/PATCH/DELETE). " % mutating
548+ warnMsg += "Scanning them may create, modify or delete server-side data"
549+ logger .warning (warnMsg )
550+ else :
551+ warnMsg = "no usable targets derived from the OpenAPI/Swagger specification"
552+ logger .warning (warnMsg )
553+
495554def _findPageForms ():
496555 if not conf .forms or conf .crawlDepth :
497556 return
@@ -1852,7 +1911,7 @@ def _cleanupOptions():
18521911 if conf .tmpPath :
18531912 conf .tmpPath = ntToPosixSlashes (normalizePath (conf .tmpPath ))
18541913
1855- if any ((conf .googleDork , conf .logFile , conf .bulkFile , conf .forms , conf .crawlDepth , conf .stdinPipe )):
1914+ if any ((conf .googleDork , conf .logFile , conf .bulkFile , conf .forms , conf .crawlDepth , conf .stdinPipe , conf . openApiFile )):
18561915 conf .multipleTargets = True
18571916
18581917 if conf .optimize :
@@ -2728,8 +2787,8 @@ def _basicOptionValidation():
27282787 errMsg += "'SQLMAP_UNSAFE_EVAL=1' to be explicitly set"
27292788 raise SqlmapSystemException (errMsg )
27302789
2731- if conf .chunked and not any ((conf .data , conf .requestFile , conf .forms )):
2732- errMsg = "switch '--chunked' requires usage of (POST) options/switches '--data', '-r' or '--forms '"
2790+ if conf .chunked and not any ((conf .data , conf .requestFile , conf .forms , conf . openApiFile )):
2791+ errMsg = "switch '--chunked' requires usage of (POST) options/switches '--data', '-r', '--forms' or '--openapi '"
27332792 raise SqlmapSyntaxException (errMsg )
27342793
27352794 if conf .api and not conf .configFile :
@@ -3022,7 +3081,7 @@ def init():
30223081
30233082 parseTargetDirect ()
30243083
3025- if any ((conf .url , conf .logFile , conf .bulkFile , conf .requestFile , conf .googleDork , conf .stdinPipe )):
3084+ if any ((conf .url , conf .logFile , conf .bulkFile , conf .requestFile , conf .googleDork , conf .stdinPipe , conf . openApiFile )):
30263085 _setHostname ()
30273086 _setHTTPTimeout ()
30283087 _setHTTPExtraHeaders ()
@@ -3038,6 +3097,7 @@ def init():
30383097 _doSearch ()
30393098 _setStdinPipeTargets ()
30403099 _setBulkMultipleTargets ()
3100+ _setOpenApiTargets ()
30413101 _checkTor ()
30423102 _setCrawler ()
30433103 _findPageForms ()
0 commit comments