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 SENSITIVE_DATA_REGEX
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 TEXT_TAG_REGEX
from lib.core.settings import TIME_STDEV_COEFF
@ -1165,6 +1166,14 @@ def getHeader(headers, key):
break
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):
"""
Checks for file existence and readability
@ -1178,19 +1187,22 @@ def checkFile(filename, raiseOnError=True):
if filename:
filename = filename.strip('"\'')
try:
if filename is None or not os.path.isfile(filename):
valid = False
except:
valid = False
if valid:
if filename == STDIN_PIPE_DASH:
return checkPipedInput()
else:
try:
with open(filename, "rb"):
pass
if filename is None or not os.path.isfile(filename):
valid = False
except:
valid = False
if valid:
try:
with open(filename, "rb"):
pass
except:
valid = False
if not valid and raiseOnError:
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
"""
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)
if filename == STDIN_PIPE_DASH:
if filename not in kb.cache.content:
kb.cache.content[filename] = sys.stdin.read()
return contextlib.closing(StringIO(readCachedFileContent(filename)))
else:
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):
"""
@ -4797,14 +4815,7 @@ def parseRequestFile(reqFile, checkParams=True):
if not(conf.scope and not re.search(conf.scope, url, re.I)):
yield (url, conf.method or method, data, cookie, tuple(headers))
checkFile(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)
content = readCachedFileContent(reqFile)
if 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"
raise SqlmapFilePathException(errMsg)
if os.path.isfile(conf.logFile):
if checkFile(conf.logFile, False):
for target in parseRequestFile(conf.logFile):
url, _, data, _, _ = target
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)
seen = set()
if not os.path.isfile(conf.requestFile):
if not checkFile(conf.requestFile, False):
errMsg = "specified HTTP request file '%s' " % conf.requestFile
errMsg += "does not exist"
raise SqlmapFilePathException(errMsg)
@ -309,7 +309,7 @@ def _setRequestFromFile():
if 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 += "does not exist"
raise SqlmapFilePathException(errMsg)
@ -411,7 +411,7 @@ def _setBulkMultipleTargets():
infoMsg = "parsing multiple targets list from '%s'" % conf.bulkFile
logger.info(infoMsg)
if not os.path.isfile(conf.bulkFile):
if not checkFile(conf.bulkFile, False):
errMsg = "the specified bulk file "
errMsg += "does not exist"
raise SqlmapFilePathException(errMsg)

View File

@ -19,7 +19,7 @@ from lib.core.enums import DBMS_DIRECTORY_NAME
from lib.core.enums import OS
# 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_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)
@ -222,6 +222,9 @@ try:
except LookupError:
DEFAULT_PAGE_ENCODING = "utf8"
# Marker for program piped input
STDIN_PIPE_DASH = '-'
# URL used in dummy runs
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 checkIntegrity
from lib.core.common import checkPipedInput
from lib.core.common import createGithubIssue
from lib.core.common import dataToStdout
from lib.core.common import getSafeExString
@ -131,6 +132,9 @@ def main():
cmdLineOptions.update(cmdLineParser().__dict__)
initOptions(cmdLineOptions)
if checkPipedInput():
conf.batch = True
if conf.get("api"):
# heavy imports
from lib.utils.api import StdDbOut

View File

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