Adding support for STDIN pipe (e.g. '... -r - ...')

This commit is contained in:
Miroslav Stampar 2019-03-15 15:36:13 +01:00
parent bf83a4d1f8
commit e7ffc8f9b1
5 changed files with 51 additions and 33 deletions

View File

@ -160,6 +160,7 @@ from lib.core.settings import REFLECTIVE_MISS_THRESHOLD
from lib.core.settings import SAFE_VARIABLE_MARKER from lib.core.settings import SAFE_VARIABLE_MARKER
from lib.core.settings import SENSITIVE_DATA_REGEX from lib.core.settings import SENSITIVE_DATA_REGEX
from lib.core.settings import SENSITIVE_OPTIONS from lib.core.settings import SENSITIVE_OPTIONS
from lib.core.settings import STDIN_PIPE_DASH
from lib.core.settings import SUPPORTED_DBMS from lib.core.settings import SUPPORTED_DBMS
from lib.core.settings import TEXT_TAG_REGEX from lib.core.settings import TEXT_TAG_REGEX
from lib.core.settings import TIME_STDEV_COEFF from lib.core.settings import TIME_STDEV_COEFF
@ -1165,6 +1166,14 @@ def getHeader(headers, key):
break break
return retVal return retVal
def checkPipedInput():
"""
Checks whether input to program has been provided via standard input (e.g. cat /tmp/req.txt | python sqlmap.py -r -)
# Reference: https://stackoverflow.com/a/33873570
"""
return not os.isatty(sys.stdin.fileno())
def checkFile(filename, raiseOnError=True): def checkFile(filename, raiseOnError=True):
""" """
Checks for file existence and readability Checks for file existence and readability
@ -1178,19 +1187,22 @@ def checkFile(filename, raiseOnError=True):
if filename: if filename:
filename = filename.strip('"\'') filename = filename.strip('"\'')
try: if filename == STDIN_PIPE_DASH:
if filename is None or not os.path.isfile(filename): return checkPipedInput()
valid = False else:
except:
valid = False
if valid:
try: try:
with open(filename, "rb"): if filename is None or not os.path.isfile(filename):
pass valid = False
except: except:
valid = False valid = False
if valid:
try:
with open(filename, "rb"):
pass
except:
valid = False
if not valid and raiseOnError: if not valid and raiseOnError:
raise SqlmapSystemException("unable to read file '%s'" % filename) raise SqlmapSystemException("unable to read file '%s'" % filename)
@ -3305,13 +3317,19 @@ def openFile(filename, mode='r', encoding=UNICODE_ENCODING, errors="replace", bu
Returns file handle of a given filename Returns file handle of a given filename
""" """
try: if filename == STDIN_PIPE_DASH:
return codecs.open(filename, mode, encoding, errors, buffering) if filename not in kb.cache.content:
except IOError: kb.cache.content[filename] = sys.stdin.read()
errMsg = "there has been a file opening error for filename '%s'. " % filename
errMsg += "Please check %s permissions on a file " % ("write" if mode and ('w' in mode or 'a' in mode or '+' in mode) else "read") return contextlib.closing(StringIO(readCachedFileContent(filename)))
errMsg += "and that it's not locked by another process." else:
raise SqlmapSystemException(errMsg) try:
return codecs.open(filename, mode, encoding, errors, buffering)
except IOError:
errMsg = "there has been a file opening error for filename '%s'. " % filename
errMsg += "Please check %s permissions on a file " % ("write" if mode and ('w' in mode or 'a' in mode or '+' in mode) else "read")
errMsg += "and that it's not locked by another process."
raise SqlmapSystemException(errMsg)
def decodeIntToUnicode(value): def decodeIntToUnicode(value):
""" """
@ -4797,14 +4815,7 @@ def parseRequestFile(reqFile, checkParams=True):
if not(conf.scope and not re.search(conf.scope, url, re.I)): if not(conf.scope and not re.search(conf.scope, url, re.I)):
yield (url, conf.method or method, data, cookie, tuple(headers)) yield (url, conf.method or method, data, cookie, tuple(headers))
checkFile(reqFile) content = readCachedFileContent(reqFile)
try:
with openFile(reqFile, "rb") as f:
content = f.read()
except (IOError, OSError, MemoryError) as ex:
errMsg = "something went wrong while trying "
errMsg += "to read the content of file '%s' ('%s')" % (reqFile, getSafeExString(ex))
raise SqlmapSystemException(errMsg)
if conf.scope: if conf.scope:
logger.info("using regular expression '%s' for filtering targets" % conf.scope) logger.info("using regular expression '%s' for filtering targets" % conf.scope)

View File

@ -226,7 +226,7 @@ def _setMultipleTargets():
errMsg = "the specified list of targets does not exist" errMsg = "the specified list of targets does not exist"
raise SqlmapFilePathException(errMsg) raise SqlmapFilePathException(errMsg)
if os.path.isfile(conf.logFile): if checkFile(conf.logFile, False):
for target in parseRequestFile(conf.logFile): for target in parseRequestFile(conf.logFile):
url, _, data, _, _ = target url, _, data, _, _ = target
key = re.sub(r"(\w+=)[^%s ]*" % (conf.paramDel or DEFAULT_GET_POST_DELIMITER), r"\g<1>", "%s %s" % (url, data)) key = re.sub(r"(\w+=)[^%s ]*" % (conf.paramDel or DEFAULT_GET_POST_DELIMITER), r"\g<1>", "%s %s" % (url, data))
@ -292,7 +292,7 @@ def _setRequestFromFile():
conf.requestFile = safeExpandUser(conf.requestFile) conf.requestFile = safeExpandUser(conf.requestFile)
seen = set() seen = set()
if not os.path.isfile(conf.requestFile): if not checkFile(conf.requestFile, False):
errMsg = "specified HTTP request file '%s' " % conf.requestFile errMsg = "specified HTTP request file '%s' " % conf.requestFile
errMsg += "does not exist" errMsg += "does not exist"
raise SqlmapFilePathException(errMsg) raise SqlmapFilePathException(errMsg)
@ -309,7 +309,7 @@ def _setRequestFromFile():
if conf.secondReq: if conf.secondReq:
conf.secondReq = safeExpandUser(conf.secondReq) conf.secondReq = safeExpandUser(conf.secondReq)
if not os.path.isfile(conf.secondReq): if not checkFile(conf.secondReq, False):
errMsg = "specified second-order HTTP request file '%s' " % conf.secondReq errMsg = "specified second-order HTTP request file '%s' " % conf.secondReq
errMsg += "does not exist" errMsg += "does not exist"
raise SqlmapFilePathException(errMsg) raise SqlmapFilePathException(errMsg)
@ -411,7 +411,7 @@ def _setBulkMultipleTargets():
infoMsg = "parsing multiple targets list from '%s'" % conf.bulkFile infoMsg = "parsing multiple targets list from '%s'" % conf.bulkFile
logger.info(infoMsg) logger.info(infoMsg)
if not os.path.isfile(conf.bulkFile): if not checkFile(conf.bulkFile, False):
errMsg = "the specified bulk file " errMsg = "the specified bulk file "
errMsg += "does not exist" errMsg += "does not exist"
raise SqlmapFilePathException(errMsg) raise SqlmapFilePathException(errMsg)

View File

@ -19,7 +19,7 @@ from lib.core.enums import DBMS_DIRECTORY_NAME
from lib.core.enums import OS from lib.core.enums import OS
# sqlmap version (<major>.<minor>.<month>.<monthly commit>) # sqlmap version (<major>.<minor>.<month>.<monthly commit>)
VERSION = "1.3.3.29" VERSION = "1.3.3.30"
TYPE = "dev" if VERSION.count('.') > 2 and VERSION.split('.')[-1] != '0' else "stable" TYPE = "dev" if VERSION.count('.') > 2 and VERSION.split('.')[-1] != '0' else "stable"
TYPE_COLORS = {"dev": 33, "stable": 90, "pip": 34} 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) VERSION_STRING = "sqlmap/%s#%s" % ('.'.join(VERSION.split('.')[:-1]) if VERSION.count('.') > 2 and VERSION.split('.')[-1] == '0' else VERSION, TYPE)
@ -222,6 +222,9 @@ try:
except LookupError: except LookupError:
DEFAULT_PAGE_ENCODING = "utf8" DEFAULT_PAGE_ENCODING = "utf8"
# Marker for program piped input
STDIN_PIPE_DASH = '-'
# URL used in dummy runs # URL used in dummy runs
DUMMY_URL = "http://foo/bar?id=1" DUMMY_URL = "http://foo/bar?id=1"

View File

@ -40,6 +40,7 @@ try:
from lib.core.common import banner from lib.core.common import banner
from lib.core.common import checkIntegrity from lib.core.common import checkIntegrity
from lib.core.common import checkPipedInput
from lib.core.common import createGithubIssue from lib.core.common import createGithubIssue
from lib.core.common import dataToStdout from lib.core.common import dataToStdout
from lib.core.common import getSafeExString from lib.core.common import getSafeExString
@ -131,6 +132,9 @@ def main():
cmdLineOptions.update(cmdLineParser().__dict__) cmdLineOptions.update(cmdLineParser().__dict__)
initOptions(cmdLineOptions) initOptions(cmdLineOptions)
if checkPipedInput():
conf.batch = True
if conf.get("api"): if conf.get("api"):
# heavy imports # heavy imports
from lib.utils.api import StdDbOut from lib.utils.api import StdDbOut

View File

@ -30,7 +30,7 @@ c1da277517c7ec4c23e953a51b51e203 lib/controller/handler.py
fb6be55d21a70765e35549af2484f762 lib/controller/__init__.py fb6be55d21a70765e35549af2484f762 lib/controller/__init__.py
ed7874be0d2d3802f3d20184f2b280d5 lib/core/agent.py ed7874be0d2d3802f3d20184f2b280d5 lib/core/agent.py
a932126e7d80e545c5d44af178d0bc0c lib/core/bigarray.py a932126e7d80e545c5d44af178d0bc0c lib/core/bigarray.py
c775aa0369c9eb044efb5065f60a25cd lib/core/common.py b096680d917729fd9658f9b75d44bb3b lib/core/common.py
de8d27ae6241163ff9e97aa9e7c51a18 lib/core/convert.py de8d27ae6241163ff9e97aa9e7c51a18 lib/core/convert.py
abcb1121eb56d3401839d14e8ed06b6e lib/core/data.py abcb1121eb56d3401839d14e8ed06b6e lib/core/data.py
f89512ef3ebea85611c5dde6c891b657 lib/core/datatype.py f89512ef3ebea85611c5dde6c891b657 lib/core/datatype.py
@ -43,14 +43,14 @@ f89512ef3ebea85611c5dde6c891b657 lib/core/datatype.py
fb6be55d21a70765e35549af2484f762 lib/core/__init__.py fb6be55d21a70765e35549af2484f762 lib/core/__init__.py
18c896b157b03af716542e5fe9233ef9 lib/core/log.py 18c896b157b03af716542e5fe9233ef9 lib/core/log.py
947f41084e551ff3b7ef7dda2f25ef20 lib/core/optiondict.py 947f41084e551ff3b7ef7dda2f25ef20 lib/core/optiondict.py
63c5c71af3fd05cd0a1c97dbbe7216b5 lib/core/option.py 94679a06c134ca5c1db1e435e1cb9fb1 lib/core/option.py
fe370021c6bc99daf44b2bfc0d1effb3 lib/core/patch.py fe370021c6bc99daf44b2bfc0d1effb3 lib/core/patch.py
4b12aa67fbf6c973d12e54cf9cb54ea0 lib/core/profiling.py 4b12aa67fbf6c973d12e54cf9cb54ea0 lib/core/profiling.py
d5ef43fe3cdd6c2602d7db45651f9ceb lib/core/readlineng.py d5ef43fe3cdd6c2602d7db45651f9ceb lib/core/readlineng.py
7d8a22c582ad201f65b73225e4456170 lib/core/replication.py 7d8a22c582ad201f65b73225e4456170 lib/core/replication.py
3179d34f371e0295dd4604568fb30bcd lib/core/revision.py 3179d34f371e0295dd4604568fb30bcd lib/core/revision.py
d6269c55789f78cf707e09a0f5b45443 lib/core/session.py d6269c55789f78cf707e09a0f5b45443 lib/core/session.py
96b86cf1a93128720caa88a22f604ea1 lib/core/settings.py 2d4b155258f2ae85c7f287c58742e1fb lib/core/settings.py
4483b4a5b601d8f1c4281071dff21ecc lib/core/shell.py 4483b4a5b601d8f1c4281071dff21ecc lib/core/shell.py
10fd19b0716ed261e6d04f311f6f527c lib/core/subprocessng.py 10fd19b0716ed261e6d04f311f6f527c lib/core/subprocessng.py
10d7e4f7ba2502cce5cf69223c52eddc lib/core/target.py 10d7e4f7ba2502cce5cf69223c52eddc lib/core/target.py
@ -236,7 +236,7 @@ ec2ba8c757ac96425dcd2b97970edd3a shell/stagers/stager.asp_
0c48ddb1feb7e38a951ef05a0d48e032 shell/stagers/stager.jsp_ 0c48ddb1feb7e38a951ef05a0d48e032 shell/stagers/stager.jsp_
2f9e459a4cf6a58680978cdce5ff7971 shell/stagers/stager.php_ 2f9e459a4cf6a58680978cdce5ff7971 shell/stagers/stager.php_
41522f8ad02ac133ca0aeaab374c36a8 sqlmapapi.py 41522f8ad02ac133ca0aeaab374c36a8 sqlmapapi.py
a436dd078b06bf664637b27f42889a35 sqlmap.py 05fe39a2fbd1cff87cb43c5c36e64365 sqlmap.py
772fb3dd15edc9d4055ab9f9dee0c203 tamper/0x2char.py 772fb3dd15edc9d4055ab9f9dee0c203 tamper/0x2char.py
3d89a5c4c33d4d1d9303f5e3bd11f0ae tamper/apostrophemask.py 3d89a5c4c33d4d1d9303f5e3bd11f0ae tamper/apostrophemask.py
1fd0eec63970728c1e6628b2e4c21d81 tamper/apostrophenullencode.py 1fd0eec63970728c1e6628b2e4c21d81 tamper/apostrophenullencode.py