def _saveToResultsFile(): if not conf.resultsFP: return results = {} techniques = dict((_[1], _[0]) for _ in getPublicTypeMembers(PAYLOAD.TECHNIQUE)) for injection in kb.injections + kb.falsePositives: if injection.place is None or injection.parameter is None: continue key = (injection.place, injection.parameter, ';'.join(injection.notes)) if key not in results: results[key] = [] results[key].extend(injection.data.keys()) try: for key, value in results.items(): place, parameter, notes = key line = "%s,%s,%s,%s,%s%s" % (safeCSValue(kb.originalUrls.get(conf.url) or conf.url), place, parameter, "".join(techniques[_][0].upper() for _ in sorted(value)), notes, os.linesep) conf.resultsFP.write(line) if not results: line = "%s,,,,%s" % (conf.url, os.linesep) conf.resultsFP.write(line) conf.resultsFP.flush() except IOError, ex: errMsg = "unable to write to the results file '%s' ('%s'). " % (conf.resultsFilename, getSafeExString(ex)) raise SqlmapSystemException(errMsg)
def dbTableValues(self, tableValues): replication = None rtable = None dumpFP = None appendToFile = False warnFile = False if tableValues is None: return db = tableValues["__infos__"]["db"] if not db: db = "All" table = tableValues["__infos__"]["table"] if conf.api: self._write(tableValues, content_type=CONTENT_TYPE.DUMP_TABLE) return dumpDbPath = os.path.join(conf.dumpPath, unsafeSQLIdentificatorNaming(db)) if conf.dumpFormat == DUMP_FORMAT.SQLITE: replication = Replication( os.path.join(conf.dumpPath, "%s.sqlite3" % unsafeSQLIdentificatorNaming(db))) elif conf.dumpFormat in (DUMP_FORMAT.CSV, DUMP_FORMAT.HTML): if not os.path.isdir(dumpDbPath): try: os.makedirs(dumpDbPath) except: warnFile = True _ = unicodeencode( re.sub(r"[^\w]", UNSAFE_DUMP_FILEPATH_REPLACEMENT, unsafeSQLIdentificatorNaming(db))) dumpDbPath = os.path.join( conf.dumpPath, "%s-%s" % (_, hashlib.md5(unicodeencode(db)).hexdigest()[:8])) if not os.path.isdir(dumpDbPath): try: os.makedirs(dumpDbPath) except Exception, ex: try: tempDir = tempfile.mkdtemp(prefix="sqlmapdb") except IOError, _: errMsg = "unable to write to the temporary directory ('%s'). " % _ errMsg += "Please make sure that your disk is not full and " errMsg += "that you have sufficient write permissions to " errMsg += "create temporary files and/or directories" raise SqlmapSystemException(errMsg) warnMsg = "unable to create dump directory " warnMsg += "'%s' (%s). " % (dumpDbPath, getSafeExString(ex)) warnMsg += "Using temporary directory '%s' instead" % tempDir logger.warn(warnMsg) dumpDbPath = tempDir
def _createTargetDirs(): """ Create the output directory. """ if not os.path.isdir(paths.SQLMAP_OUTPUT_PATH): try: if not os.path.isdir(paths.SQLMAP_OUTPUT_PATH): os.makedirs(paths.SQLMAP_OUTPUT_PATH, 0755) warnMsg = "using '%s' as the output directory" % paths.SQLMAP_OUTPUT_PATH logger.warn(warnMsg) except (OSError, IOError), ex: try: tempDir = tempfile.mkdtemp(prefix="sqlmapoutput") except Exception, _: errMsg = "unable to write to the temporary directory ('%s'). " % _ errMsg += "Please make sure that your disk is not full and " errMsg += "that you have sufficient write permissions to " errMsg += "create temporary files and/or directories" raise SqlmapSystemException(errMsg) warnMsg = "unable to create regular output directory " warnMsg += "'%s' (%s). " % (paths.SQLMAP_OUTPUT_PATH, getUnicode(ex)) warnMsg += "Using temporary directory '%s' instead" % tempDir logger.warn(warnMsg) paths.SQLMAP_OUTPUT_PATH = tempDir
def _createTargetDirs(): """ Create the output directory. """ for context in "output", "history": directory = paths["SQLMAP_%s_PATH" % context.upper()] try: if not os.path.isdir(directory): os.makedirs(directory) _ = os.path.join(directory, randomStr()) open(_, "w+b").close() os.remove(_) if conf.outputDir and context == "output": warnMsg = "using '%s' as the %s directory" % (directory, context) logger.warn(warnMsg) except (OSError, IOError), ex: try: tempDir = tempfile.mkdtemp(prefix="sqlmap%s" % context) except Exception, _: errMsg = "unable to write to the temporary directory ('%s'). " % _ errMsg += "Please make sure that your disk is not full and " errMsg += "that you have sufficient write permissions to " errMsg += "create temporary files and/or directories" raise SqlmapSystemException(errMsg) warnMsg = "unable to %s %s directory " % ("create" if not os.path.isdir(directory) else "write to the", context) warnMsg += "'%s' (%s). " % (directory, getUnicode(ex)) warnMsg += "Using temporary directory '%s' instead" % getUnicode(tempDir) logger.warn(warnMsg) paths["SQLMAP_%s_PATH" % context.upper()] = tempDir
def _setResultsFile(): """ Create results file for storing results of running in a multiple target mode. """ if not conf.multipleTargets: return if not conf.resultsFP: conf.resultsFile = conf.resultsFile or os.path.join(paths.SQLMAP_OUTPUT_PATH, time.strftime(RESULTS_FILE_FORMAT).lower()) found = os.path.exists(conf.resultsFile) try: conf.resultsFP = openFile(conf.resultsFile, "a", UNICODE_ENCODING, buffering=0) except (OSError, IOError) as ex: try: warnMsg = "unable to create results file '%s' ('%s'). " % (conf.resultsFile, getUnicode(ex)) handle, conf.resultsFile = tempfile.mkstemp(prefix=MKSTEMP_PREFIX.RESULTS, suffix=".csv") os.close(handle) conf.resultsFP = openFile(conf.resultsFile, "w+", UNICODE_ENCODING, buffering=0) warnMsg += "Using temporary file '%s' instead" % conf.resultsFile logger.warn(warnMsg) except IOError as _: errMsg = "unable to write to the temporary directory ('%s'). " % _ errMsg += "Please make sure that your disk is not full and " errMsg += "that you have sufficient write permissions to " errMsg += "create temporary files and/or directories" raise SqlmapSystemException(errMsg) if not found: conf.resultsFP.writelines("Target URL,Place,Parameter,Technique(s),Note(s)%s" % os.linesep) logger.info("using '%s' as the CSV results file in multiple targets mode" % conf.resultsFile)
def checkFile(filename, raiseOnError=True): """ Checks for file existence and readability >>> checkFile(__file__) True """ valid = True if filename: filename = filename.strip('"\'') if filename == STDIN_PIPE_DASH: return checkPipedInput() else: try: 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) return valid
def _createTargetDirs(): """ Create the output directory. """ try: if not os.path.isdir(paths.SQLMAP_OUTPUT_PATH): os.makedirs(paths.SQLMAP_OUTPUT_PATH, 0755) _ = os.path.join(paths.SQLMAP_OUTPUT_PATH, randomStr()) open(_, "w+b").close() os.remove(_) if conf.outputDir: warnMsg = "using '%s' as the output directory" % paths.SQLMAP_OUTPUT_PATH logger.warn(warnMsg) except (OSError, IOError), ex: try: tempDir = tempfile.mkdtemp(prefix="sqlmapoutput") except Exception, _: errMsg = "unable to write to the temporary directory ('%s'). " % _ errMsg += "Please make sure that your disk is not full and " errMsg += "that you have sufficient write permissions to " errMsg += "create temporary files and/or directories" raise SqlmapSystemException(errMsg)
def _setResultsFile(): """ Create results file for storing results of running in a multiple target mode. """ if not conf.multipleTargets: return if not conf.resultsFP: conf.resultsFilename = os.path.join(paths.SQLMAP_OUTPUT_PATH, time.strftime(RESULTS_FILE_FORMAT).lower()) try: conf.resultsFP = openFile(conf.resultsFilename, "w+", UNICODE_ENCODING, buffering=0) except (OSError, IOError), ex: try: warnMsg = "unable to create results file '%s' ('%s'). " % (conf.resultsFilename, getUnicode(ex)) handle, conf.resultsFilename = tempfile.mkstemp(prefix=MKSTEMP_PREFIX.RESULTS, suffix=".csv") os.close(handle) conf.resultsFP = openFile(conf.resultsFilename, "w+", UNICODE_ENCODING, buffering=0) warnMsg += "Using temporary file '%s' instead" % conf.resultsFilename logger.warn(warnMsg) except IOError, _: errMsg = "unable to write to the temporary directory ('%s'). " % _ errMsg += "Please make sure that your disk is not full and " errMsg += "that you have sufficient write permissions to " errMsg += "create temporary files and/or directories" raise SqlmapSystemException(errMsg)
def dbTableValues(self, tableValues): replication = None rtable = None dumpFP = None appendToFile = False warnFile = False if tableValues is None: return db = tableValues["__infos__"]["db"] if not db: db = "All" table = tableValues["__infos__"]["table"] if conf.api: self._write(tableValues, content_type=CONTENT_TYPE.DUMP_TABLE) return dumpDbPath = os.path.join(conf.dumpPath, unsafeSQLIdentificatorNaming(db)) if conf.dumpFormat == DUMP_FORMAT.SQLITE: replication = Replication( os.path.join(conf.dumpPath, "%s.sqlite3" % unsafeSQLIdentificatorNaming(db))) elif conf.dumpFormat in (DUMP_FORMAT.CSV, DUMP_FORMAT.HTML): if not os.path.isdir(dumpDbPath): try: os.makedirs(dumpDbPath, 0755) except: warnFile = True _ = unicodeencode( re.sub(r"[^\w]", "_", unsafeSQLIdentificatorNaming(db))) dumpDbPath = os.path.join( conf.dumpPath, "%s-%s" % (_, hashlib.md5(unicodeencode(db)).hexdigest()[:8])) if not os.path.isdir(dumpDbPath): try: os.makedirs(dumpDbPath, 0755) except Exception, ex: try: tempDir = tempfile.mkdtemp(prefix="sqlmapdb") except IOError, _: errMsg = u"无法写入临时目录 ('%s').请确保您的磁盘未满,并且您具有足够的写权限来创建临时文件或目录 " % _ raise SqlmapSystemException(errMsg) warnMsg = u"无法创建转储目录 " warnMsg += u"'%s' (%s). " % (dumpDbPath, getSafeExString(ex)) warnMsg += u"使用临时目录'%s'代替" % tempDir logger.warn(warnMsg) dumpDbPath = tempDir
def dbTableValues(self, tableValues): replication = None rtable = None dumpFP = None appendToFile = False warnFile = False if tableValues is None: return db = tableValues["__infos__"]["db"] if not db: db = "All" table = tableValues["__infos__"]["table"] if hasattr(conf, "api"): self._write(tableValues, content_type=CONTENT_TYPE.DUMP_TABLE) return _ = re.sub(r"[^\w]", "_", normalizeUnicode(unsafeSQLIdentificatorNaming(db))) if len(_) < len(db) or IS_WIN and db.upper() in WINDOWS_RESERVED_NAMES: _ = unicodeencode( re.sub(r"[^\w]", "_", unsafeSQLIdentificatorNaming(db))) dumpDbPath = os.path.join( conf.dumpPath, "%s-%s" % (_, hashlib.md5(unicodeencode(db)).hexdigest()[:8])) warnFile = True else: dumpDbPath = os.path.join(conf.dumpPath, _) if conf.dumpFormat == DUMP_FORMAT.SQLITE: replication = Replication( os.path.join(conf.dumpPath, "%s.sqlite3" % unsafeSQLIdentificatorNaming(db))) elif conf.dumpFormat in (DUMP_FORMAT.CSV, DUMP_FORMAT.HTML): if not os.path.isdir(dumpDbPath): try: os.makedirs(dumpDbPath, 0755) except (OSError, IOError), ex: try: tempDir = tempfile.mkdtemp(prefix="sqlmapdb") except IOError, _: errMsg = "unable to write to the temporary directory ('%s'). " % _ errMsg += "Please make sure that your disk is not full and " errMsg += "that you have sufficient write permissions to " errMsg += "create temporary files and/or directories" raise SqlmapSystemException(errMsg) warnMsg = "unable to create dump directory " warnMsg += "'%s' (%s). " % (dumpDbPath, ex) warnMsg += "Using temporary directory '%s' instead" % tempDir logger.warn(warnMsg) dumpDbPath = tempDir
def _createTargetDirs(): """ Create the output directory. """ conf.outputPath = os.path.join(getUnicode(paths.SQLMAP_OUTPUT_PATH), normalizeUnicode(getUnicode(conf.hostname))) try: if not os.path.isdir(conf.outputPath): os.makedirs(conf.outputPath) except (OSError, IOError, TypeError) as ex: try: tempDir = tempfile.mkdtemp(prefix="sqlmapoutput") except Exception as _: errMsg = "unable to write to the temporary directory ('%s'). " % _ errMsg += "Please make sure that your disk is not full and " errMsg += "that you have sufficient write permissions to " errMsg += "create temporary files and/or directories" raise SqlmapSystemException(errMsg) warnMsg = "unable to create output directory " warnMsg += "'%s' (%s). " % (conf.outputPath, getUnicode(ex)) warnMsg += "Using temporary directory '%s' instead" % getUnicode( tempDir) logger.warn(warnMsg) conf.outputPath = tempDir conf.outputPath = getUnicode(conf.outputPath) try: with openFile(os.path.join(conf.outputPath, "target.txt"), "w+") as f: f.write(kb.originalUrls.get(conf.url) or conf.url or conf.hostname) f.write(" (%s)" % (HTTPMETHOD.POST if conf.data else HTTPMETHOD.GET)) f.write(" # %s" % getUnicode(subprocess.list2cmdline(sys.argv), encoding=sys.stdin.encoding)) if conf.data: f.write("\n\n%s" % getUnicode(conf.data)) except IOError as ex: if "denied" in getUnicode(ex): errMsg = "you don't have enough permissions " else: errMsg = "something went wrong while trying " errMsg += "to write to the output directory '%s' (%s)" % ( paths.SQLMAP_OUTPUT_PATH, getSafeExString(ex)) raise SqlmapMissingPrivileges(errMsg) _createDumpDir() _createFilesDir() _configureDumper()
def pop(self): if len(self.chunks[-1]) < 1: self.chunks.pop() try: with open(self.chunks[-1], "rb") as f: self.chunks[-1] = pickle.loads(zlib.decompress(f.read())) except IOError as ex: errMsg = "exception occurred while retrieving data " errMsg += "from a temporary file ('%s')" % ex raise SqlmapSystemException(errMsg) return self.chunks[-1].pop()
def _checkcache(self, index): if (self.cache and self.cache.index != index and self.cache.dirty): filename = self._dump(self.cache.data) self.chunks[self.cache.index] = filename if not (self.cache and self.cache.index == index): try: with open(self.chunks[index], "rb") as f: self.cache = Cache(index, pickle.loads(zlib.decompress(f.read())), False) except Exception as ex: errMsg = "exception occurred while retrieving data " errMsg += "from a temporary file ('%s')" % ex raise SqlmapSystemException(errMsg)
def _dump(self, chunk): try: handle, filename = tempfile.mkstemp(prefix=MKSTEMP_PREFIX.BIG_ARRAY) self.filenames.add(filename) os.close(handle) with open(filename, "w+b") as f: f.write(zlib.compress(pickle.dumps(chunk, pickle.HIGHEST_PROTOCOL), BIGARRAY_COMPRESS_LEVEL)) return filename except (OSError, IOError) as ex: errMsg = "exception occurred while storing data " errMsg += "to a temporary file ('%s'). Please " % ex errMsg += "make sure that there is enough disk space left. If problem persists, " errMsg += "try to set environment variable 'TEMP' to a location " errMsg += "writeable by the current user" raise SqlmapSystemException(errMsg)
conf.outputPath = os.path.join(getUnicode(paths.SQLMAP_OUTPUT_PATH), normalizeUnicode(getUnicode(conf.hostname))) try: if not os.path.isdir(conf.outputPath): os.makedirs(conf.outputPath) except (OSError, IOError, TypeError), ex: try: tempDir = tempfile.mkdtemp(prefix="sqlmapoutput") except Exception, _: errMsg = "unable to write to the temporary directory ('%s'). " % _ errMsg += "Please make sure that your disk is not full and " errMsg += "that you have sufficient write permissions to " errMsg += "create temporary files and/or directories" raise SqlmapSystemException(errMsg) warnMsg = "unable to create output directory " warnMsg += "'%s' (%s). " % (conf.outputPath, getUnicode(ex)) warnMsg += "Using temporary directory '%s' instead" % getUnicode( tempDir) logger.warn(warnMsg) conf.outputPath = tempDir conf.outputPath = getUnicode(conf.outputPath) try: with openFile(os.path.join(conf.outputPath, "target.txt"), "w+") as f: f.write(kb.originalUrls.get(conf.url) or conf.url or conf.hostname) f.write(" (%s)" %
def dbTableValues(self, tableValues): replication = None rtable = None dumpFP = None appendToFile = False warnFile = False if tableValues is None: return db = tableValues["__infos__"]["db"] if not db: db = "All" table = tableValues["__infos__"]["table"] if conf.api: self._write(tableValues, content_type=CONTENT_TYPE.DUMP_TABLE) return dumpDbPath = os.path.join(conf.dumpPath, unsafeSQLIdentificatorNaming(db)) if conf.dumpFormat == DUMP_FORMAT.SQLITE: replication = Replication( os.path.join(conf.dumpPath, "%s.sqlite3" % unsafeSQLIdentificatorNaming(db))) elif conf.dumpFormat in (DUMP_FORMAT.CSV, DUMP_FORMAT.HTML): if not os.path.isdir(dumpDbPath): try: os.makedirs(dumpDbPath) except: warnFile = True _ = re.sub(r"[^\w]", UNSAFE_DUMP_FILEPATH_REPLACEMENT, unsafeSQLIdentificatorNaming(db)) dumpDbPath = os.path.join( conf.dumpPath, "%s-%s" % (_, hashlib.md5(getBytes(db)).hexdigest()[:8])) if not os.path.isdir(dumpDbPath): try: os.makedirs(dumpDbPath) except Exception as ex: try: tempDir = tempfile.mkdtemp(prefix="sqlmapdb") except IOError as _: errMsg = "unable to write to the temporary directory ('%s'). " % _ errMsg += "Please make sure that your disk is not full and " errMsg += "that you have sufficient write permissions to " errMsg += "create temporary files and/or directories" raise SqlmapSystemException(errMsg) warnMsg = "unable to create dump directory " warnMsg += "'%s' (%s). " % (dumpDbPath, getSafeExString(ex)) warnMsg += "Using temporary directory '%s' instead" % tempDir logger.warn(warnMsg) dumpDbPath = tempDir dumpFileName = os.path.join( dumpDbPath, re.sub( r'[\\/]', UNSAFE_DUMP_FILEPATH_REPLACEMENT, "%s.%s" % (unsafeSQLIdentificatorNaming(table), conf.dumpFormat.lower()))) if not checkFile(dumpFileName, False): try: openFile(dumpFileName, "w+b").close() except SqlmapSystemException: raise except: warnFile = True _ = re.sub( r"[^\w]", UNSAFE_DUMP_FILEPATH_REPLACEMENT, normalizeUnicode(unsafeSQLIdentificatorNaming(table))) if len(_) < len(table) or IS_WIN and table.upper( ) in WINDOWS_RESERVED_NAMES: _ = re.sub(r"[^\w]", UNSAFE_DUMP_FILEPATH_REPLACEMENT, unsafeSQLIdentificatorNaming(table)) dumpFileName = os.path.join( dumpDbPath, "%s-%s.%s" % (_, hashlib.md5(getBytes(table)).hexdigest()[:8], conf.dumpFormat.lower())) else: dumpFileName = os.path.join( dumpDbPath, "%s.%s" % (_, conf.dumpFormat.lower())) else: appendToFile = any((conf.limitStart, conf.limitStop)) if not appendToFile: count = 1 while True: candidate = "%s.%d" % (dumpFileName, count) if not checkFile(candidate, False): try: shutil.copyfile(dumpFileName, candidate) except IOError: pass finally: break else: count += 1 dumpFP = openFile(dumpFileName, "wb" if not appendToFile else "ab", buffering=DUMP_FILE_BUFFER_SIZE) count = int(tableValues["__infos__"]["count"]) separator = str() field = 1 fields = len(tableValues) - 1 columns = prioritySortColumns(tableValues.keys()) if conf.col: cols = conf.col.split(',') columns = sorted(columns, key=lambda _: cols.index(_) if _ in cols else 0) for column in columns: if column != "__infos__": info = tableValues[column] lines = "-" * (int(info["length"]) + 2) separator += "+%s" % lines separator += "+" self._write( "Database: %s\nTable: %s" % (unsafeSQLIdentificatorNaming(db) if db else "Current database", unsafeSQLIdentificatorNaming(table))) if conf.dumpFormat == DUMP_FORMAT.SQLITE: cols = [] for column in columns: if column != "__infos__": colType = Replication.INTEGER for value in tableValues[column]['values']: try: if not value or value == " ": # NULL continue int(value) except ValueError: colType = None break if colType is None: colType = Replication.REAL for value in tableValues[column]['values']: try: if not value or value == " ": # NULL continue float(value) except ValueError: colType = None break cols.append((unsafeSQLIdentificatorNaming(column), colType if colType else Replication.TEXT)) rtable = replication.createTable(table, cols) elif conf.dumpFormat == DUMP_FORMAT.HTML: dataToDumpFile(dumpFP, "<!DOCTYPE html>\n<html>\n<head>\n") dataToDumpFile( dumpFP, "<meta http-equiv=\"Content-type\" content=\"text/html;charset=%s\">\n" % UNICODE_ENCODING) dataToDumpFile( dumpFP, "<meta name=\"generator\" content=\"%s\" />\n" % VERSION_STRING) dataToDumpFile( dumpFP, "<title>%s</title>\n" % ("%s%s" % ("%s." % db if METADB_SUFFIX not in db else "", table))) dataToDumpFile(dumpFP, HTML_DUMP_CSS_STYLE) dataToDumpFile(dumpFP, "\n</head>\n<body>\n<table>\n<thead>\n<tr>\n") if count == 1: self._write("[1 entry]") else: self._write("[%d entries]" % count) self._write(separator) for column in columns: if column != "__infos__": info = tableValues[column] column = unsafeSQLIdentificatorNaming(column) maxlength = int(info["length"]) blank = " " * (maxlength - len(column)) self._write("| %s%s" % (column, blank), newline=False) if not appendToFile: if conf.dumpFormat == DUMP_FORMAT.CSV: if field == fields: dataToDumpFile(dumpFP, "%s" % safeCSValue(column)) else: dataToDumpFile( dumpFP, "%s%s" % (safeCSValue(column), conf.csvDel)) elif conf.dumpFormat == DUMP_FORMAT.HTML: dataToDumpFile( dumpFP, "<th>%s</th>" % cgi.escape(column).encode( "ascii", "xmlcharrefreplace")) field += 1 if conf.dumpFormat == DUMP_FORMAT.HTML: dataToDumpFile(dumpFP, "\n</tr>\n</thead>\n<tbody>\n") self._write("|\n%s" % separator) if conf.dumpFormat == DUMP_FORMAT.CSV: dataToDumpFile(dumpFP, "\n" if not appendToFile else "") elif conf.dumpFormat == DUMP_FORMAT.SQLITE: rtable.beginTransaction() if count > TRIM_STDOUT_DUMP_SIZE: warnMsg = "console output will be trimmed to " warnMsg += "last %d rows due to " % TRIM_STDOUT_DUMP_SIZE warnMsg += "large table size" logger.warning(warnMsg) for i in xrange(count): console = (i >= count - TRIM_STDOUT_DUMP_SIZE) field = 1 values = [] if conf.dumpFormat == DUMP_FORMAT.HTML: dataToDumpFile(dumpFP, "<tr>") for column in columns: if column != "__infos__": info = tableValues[column] if len(info["values"]) <= i: continue if info["values"][i] is None: value = u'' else: value = getUnicode(info["values"][i]) value = DUMP_REPLACEMENTS.get(value, value) values.append(value) maxlength = int(info["length"]) blank = " " * (maxlength - len(value)) self._write("| %s%s" % (value, blank), newline=False, console=console) if len(value ) > MIN_BINARY_DISK_DUMP_SIZE and r'\x' in value: try: mimetype = magic.from_buffer(value, mime=True) if any( mimetype.startswith(_) for _ in ("application", "image")): if not os.path.isdir(dumpDbPath): os.makedirs(dumpDbPath) _ = re.sub( r"[^\w]", UNSAFE_DUMP_FILEPATH_REPLACEMENT, normalizeUnicode( unsafeSQLIdentificatorNaming(column))) filepath = os.path.join( dumpDbPath, "%s-%d.bin" % (_, randomInt(8))) warnMsg = "writing binary ('%s') content to file '%s' " % ( mimetype, filepath) logger.warn(warnMsg) with open(filepath, "wb") as f: _ = safechardecode(value, True) f.write(_) except magic.MagicException as ex: logger.debug(getSafeExString(ex)) if conf.dumpFormat == DUMP_FORMAT.CSV: if field == fields: dataToDumpFile(dumpFP, "%s" % safeCSValue(value)) else: dataToDumpFile( dumpFP, "%s%s" % (safeCSValue(value), conf.csvDel)) elif conf.dumpFormat == DUMP_FORMAT.HTML: dataToDumpFile( dumpFP, "<td>%s</td>" % cgi.escape(value).encode( "ascii", "xmlcharrefreplace")) field += 1 if conf.dumpFormat == DUMP_FORMAT.SQLITE: try: rtable.insert(values) except SqlmapValueException: pass elif conf.dumpFormat == DUMP_FORMAT.CSV: dataToDumpFile(dumpFP, "\n") elif conf.dumpFormat == DUMP_FORMAT.HTML: dataToDumpFile(dumpFP, "</tr>\n") self._write("|", console=console) self._write("%s\n" % separator) if conf.dumpFormat == DUMP_FORMAT.SQLITE: rtable.endTransaction() logger.info("table '%s.%s' dumped to sqlite3 database '%s'" % (db, table, replication.dbpath)) elif conf.dumpFormat in (DUMP_FORMAT.CSV, DUMP_FORMAT.HTML): if conf.dumpFormat == DUMP_FORMAT.HTML: dataToDumpFile(dumpFP, "</tbody>\n</table>\n</body>\n</html>") else: dataToDumpFile(dumpFP, "\n") dumpFP.close() msg = "table '%s.%s' dumped to %s file '%s'" % ( db, table, conf.dumpFormat, dumpFileName) if not warnFile: logger.info(msg) else: logger.warn(msg)
def osPwn(self): goUdf = False fallbackToWeb = False setupSuccess = False self.checkDbmsOs() if Backend.isOs(OS.WINDOWS): msg = "how do you want to establish the tunnel?" msg += "\n[1] TCP: Metasploit Framework (default)" msg += "\n[2] ICMP: icmpsh - ICMP tunneling" while True: tunnel = readInput(msg, default='1') if tunnel.isdigit() and int(tunnel) in (1, 2): tunnel = int(tunnel) break else: warnMsg = "invalid value, valid values are '1' and '2'" logger.warn(warnMsg) else: tunnel = 1 debugMsg = "the tunnel can be established only via TCP when " debugMsg += "the back-end DBMS is not Windows" logger.debug(debugMsg) if tunnel == 2: isAdmin = runningAsAdmin() if not isAdmin: errMsg = "you need to run sqlmap as an administrator " errMsg += "if you want to establish an out-of-band ICMP " errMsg += "tunnel because icmpsh uses raw sockets to " errMsg += "sniff and craft ICMP packets" raise SqlmapMissingPrivileges(errMsg) try: __import__("impacket") except ImportError: errMsg = "sqlmap requires 'python-impacket' third-party library " errMsg += "in order to run icmpsh master. You can get it at " errMsg += "http://code.google.com/p/impacket/downloads/list" raise SqlmapMissingDependence(errMsg) filename = "/proc/sys/net/ipv4/icmp_echo_ignore_all" if os.path.exists(filename): try: with open(filename, "wb") as f: f.write("1") except IOError, ex: errMsg = "there has been a file opening/writing error " errMsg += "for filename '%s' ('%s')" % ( filename, getSafeExString(ex)) raise SqlmapSystemException(errMsg) else: errMsg = "you need to disable ICMP replies by your machine " errMsg += "system-wide. For example run on Linux/Unix:\n" errMsg += "# sysctl -w net.ipv4.icmp_echo_ignore_all=1\n" errMsg += "If you miss doing that, you will receive " errMsg += "information from the database server and it " errMsg += "is unlikely to receive commands sent from you" logger.error(errMsg) if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL): self.sysUdfs.pop("sys_bineval")
def osPwn(self): goUdf = False fallbackToWeb = False setupSuccess = False self.checkDbmsOs() if Backend.isOs(OS.WINDOWS): msg = "how do you want to establish the tunnel?" msg += "\n[1] TCP: Metasploit Framework (default)" msg += "\n[2] ICMP: icmpsh - ICMP tunneling" while True: tunnel = readInput(msg, default='1') if tunnel.isdigit() and int(tunnel) in (1, 2): tunnel = int(tunnel) break else: warnMsg = "invalid value, valid values are '1' and '2'" logger.warn(warnMsg) else: tunnel = 1 debugMsg = "the tunnel can be established only via TCP when " debugMsg += "the back-end DBMS is not Windows" logger.debug(debugMsg) if tunnel == 2: isAdmin = runningAsAdmin() if not isAdmin: errMsg = "you need to run sqlmap as an administrator " errMsg += "if you want to establish an out-of-band ICMP " errMsg += "tunnel because icmpsh uses raw sockets to " errMsg += "sniff and craft ICMP packets" raise SqlmapMissingPrivileges(errMsg) try: __import__("impacket") except ImportError: errMsg = "sqlmap requires 'python-impacket' third-party library " errMsg += "in order to run icmpsh master. You can get it at " errMsg += "http://code.google.com/p/impacket/downloads/list" raise SqlmapMissingDependence(errMsg) filename = "/proc/sys/net/ipv4/icmp_echo_ignore_all" if os.path.exists(filename): try: with open(filename, "wb") as f: f.write("1") except IOError as ex: errMsg = "there has been a file opening/writing error " errMsg += "for filename '%s' ('%s')" % ( filename, getSafeExString(ex)) raise SqlmapSystemException(errMsg) else: errMsg = "you need to disable ICMP replies by your machine " errMsg += "system-wide. For example run on Linux/Unix:\n" errMsg += "# sysctl -w net.ipv4.icmp_echo_ignore_all=1\n" errMsg += "If you miss doing that, you will receive " errMsg += "information from the database server and it " errMsg += "is unlikely to receive commands sent from you" logger.error(errMsg) if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL): self.sysUdfs.pop("sys_bineval") self.getRemoteTempPath() if isStackingAvailable() or conf.direct: web = False self.initEnv(web=web) if tunnel == 1: if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL): msg = "how do you want to execute the Metasploit shellcode " msg += "on the back-end database underlying operating system?" msg += "\n[1] Via UDF 'sys_bineval' (in-memory way, anti-forensics, default)" msg += "\n[2] Via 'shellcodeexec' (file system way, preferred on 64-bit systems)" while True: choice = readInput(msg, default='1') if choice.isdigit() and int(choice) in (1, 2): choice = int(choice) break else: warnMsg = "invalid value, valid values are '1' and '2'" logger.warn(warnMsg) if choice == 1: goUdf = True if goUdf: exitfunc = "thread" setupSuccess = True else: exitfunc = "process" self.createMsfShellcode(exitfunc=exitfunc, format="raw", extra="BufferRegister=EAX", encode="x86/alpha_mixed") if not goUdf: setupSuccess = self.uploadShellcodeexec(web=web) if setupSuccess is not True: if Backend.isDbms(DBMS.MYSQL): fallbackToWeb = True else: msg = "unable to mount the operating system takeover" raise SqlmapFilePathException(msg) if Backend.isOs(OS.WINDOWS) and Backend.isDbms( DBMS.MYSQL) and conf.privEsc: debugMsg = "by default MySQL on Windows runs as SYSTEM " debugMsg += "user, no need to privilege escalate" logger.debug(debugMsg) elif tunnel == 2: setupSuccess = self.uploadIcmpshSlave(web=web) if setupSuccess is not True: if Backend.isDbms(DBMS.MYSQL): fallbackToWeb = True else: msg = "unable to mount the operating system takeover" raise SqlmapFilePathException(msg) if not setupSuccess and Backend.isDbms( DBMS.MYSQL) and not conf.direct and (not isStackingAvailable() or fallbackToWeb): web = True if fallbackToWeb: infoMsg = "falling back to web backdoor to establish the tunnel" else: infoMsg = "going to use a web backdoor to establish the tunnel" logger.info(infoMsg) self.initEnv(web=web, forceInit=fallbackToWeb) if self.webBackdoorUrl: if not Backend.isOs(OS.WINDOWS) and conf.privEsc: # Unset --priv-esc if the back-end DBMS underlying operating # system is not Windows conf.privEsc = False warnMsg = "sqlmap does not implement any operating system " warnMsg += "user privilege escalation technique when the " warnMsg += "back-end DBMS underlying system is not Windows" logger.warn(warnMsg) if tunnel == 1: self.createMsfShellcode(exitfunc="process", format="raw", extra="BufferRegister=EAX", encode="x86/alpha_mixed") setupSuccess = self.uploadShellcodeexec(web=web) if setupSuccess is not True: msg = "unable to mount the operating system takeover" raise SqlmapFilePathException(msg) elif tunnel == 2: setupSuccess = self.uploadIcmpshSlave(web=web) if setupSuccess is not True: msg = "unable to mount the operating system takeover" raise SqlmapFilePathException(msg) if setupSuccess: if tunnel == 1: self.pwn(goUdf) elif tunnel == 2: self.icmpPwn() else: errMsg = "unable to prompt for an out-of-band session" raise SqlmapNotVulnerableException(errMsg) if not conf.cleanup: self.cleanup(web=web)
def runGui(parser): try: from thirdparty.six.moves import tkinter as _tkinter from thirdparty.six.moves import tkinter_scrolledtext as _tkinter_scrolledtext from thirdparty.six.moves import tkinter_ttk as _tkinter_ttk from thirdparty.six.moves import tkinter_messagebox as _tkinter_messagebox except ImportError as ex: raise SqlmapMissingDependence("missing dependence ('%s')" % getSafeExString(ex)) # Reference: https://www.reddit.com/r/learnpython/comments/985umy/limit_user_input_to_only_int_with_tkinter/e4dj9k9?utm_source=share&utm_medium=web2x class ConstrainedEntry(_tkinter.Entry): def __init__(self, master=None, **kwargs): self.var = _tkinter.StringVar() self.regex = kwargs["regex"] del kwargs["regex"] _tkinter.Entry.__init__(self, master, textvariable=self.var, **kwargs) self.old_value = '' self.var.trace('w', self.check) self.get, self.set = self.var.get, self.var.set def check(self, *args): if re.search(self.regex, self.get()): self.old_value = self.get() else: self.set(self.old_value) # Reference: https://code.activestate.com/recipes/580726-tkinter-notebook-that-fits-to-the-height-of-every-/ class AutoresizableNotebook(_tkinter_ttk.Notebook): def __init__(self, master=None, **kw): _tkinter_ttk.Notebook.__init__(self, master, **kw) self.bind("<<NotebookTabChanged>>", self._on_tab_changed) def _on_tab_changed(self, event): event.widget.update_idletasks() tab = event.widget.nametowidget(event.widget.select()) event.widget.configure(height=tab.winfo_reqheight()) try: window = _tkinter.Tk() except Exception as ex: errMsg = "unable to create GUI window ('%s')" % getSafeExString(ex) raise SqlmapSystemException(errMsg) window.title(VERSION_STRING) # Reference: https://www.holadevs.com/pregunta/64750/change-selected-tab-color-in-ttknotebook style = _tkinter_ttk.Style() settings = { "TNotebook.Tab": { "configure": { "padding": [5, 1], "background": "#fdd57e" }, "map": { "background": [("selected", "#C70039"), ("active", "#fc9292")], "foreground": [("selected", "#ffffff"), ("active", "#000000")] } } } style.theme_create("custom", parent="alt", settings=settings) style.theme_use("custom") # Reference: https://stackoverflow.com/a/10018670 def center(window): window.update_idletasks() width = window.winfo_width() frm_width = window.winfo_rootx() - window.winfo_x() win_width = width + 2 * frm_width height = window.winfo_height() titlebar_height = window.winfo_rooty() - window.winfo_y() win_height = height + titlebar_height + frm_width x = window.winfo_screenwidth() // 2 - win_width // 2 y = window.winfo_screenheight() // 2 - win_height // 2 window.geometry('{}x{}+{}+{}'.format(width, height, x, y)) window.deiconify() def onKeyPress(event): global line global queue if process: if event.char == '\b': line = line[:-1] else: line += event.char def onReturnPress(event): global line global queue if process: try: process.stdin.write(("%s\n" % line.strip()).encode()) process.stdin.flush() except socket.error: line = "" event.widget.master.master.destroy() return "break" except: return event.widget.insert(_tkinter.END, "\n") return "break" def run(): global alive global process global queue config = {} for key in window._widgets: dest, type = key widget = window._widgets[key] if hasattr(widget, "get") and not widget.get(): value = None elif type == "string": value = widget.get() elif type == "float": value = float(widget.get()) elif type == "int": value = int(widget.get()) else: value = bool(widget.var.get()) config[dest] = value for option in parser.option_list: config[option.dest] = defaults.get(option.dest, None) handle, configFile = tempfile.mkstemp(prefix=MKSTEMP_PREFIX.CONFIG, text=True) os.close(handle) saveConfig(config, configFile) def enqueue(stream, queue): global alive for line in iter(stream.readline, b''): queue.put(line) alive = False stream.close() alive = True process = subprocess.Popen([ sys.executable or "python", os.path.join(paths.SQLMAP_ROOT_PATH, "sqlmap.py"), "-c", configFile ], shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, stdin=subprocess.PIPE, bufsize=1, close_fds=not IS_WIN) # Reference: https://stackoverflow.com/a/4896288 queue = _queue.Queue() thread = threading.Thread(target=enqueue, args=(process.stdout, queue)) thread.daemon = True thread.start() top = _tkinter.Toplevel() top.title("Console") # Reference: https://stackoverflow.com/a/13833338 text = _tkinter_scrolledtext.ScrolledText(top, undo=True) text.bind("<Key>", onKeyPress) text.bind("<Return>", onReturnPress) text.pack() text.focus() center(top) while True: line = "" try: # line = queue.get_nowait() line = queue.get(timeout=.1) text.insert(_tkinter.END, line) except _queue.Empty: text.see(_tkinter.END) text.update_idletasks() if not alive: break menubar = _tkinter.Menu(window) filemenu = _tkinter.Menu(menubar, tearoff=0) filemenu.add_command(label="Open", state=_tkinter.DISABLED) filemenu.add_command(label="Save", state=_tkinter.DISABLED) filemenu.add_separator() filemenu.add_command(label="Exit", command=window.quit) menubar.add_cascade(label="File", menu=filemenu) menubar.add_command(label="Run", command=run) helpmenu = _tkinter.Menu(menubar, tearoff=0) helpmenu.add_command(label="Official site", command=lambda: webbrowser.open(SITE)) helpmenu.add_command(label="Github pages", command=lambda: webbrowser.open(GIT_PAGE)) helpmenu.add_command(label="Wiki pages", command=lambda: webbrowser.open(WIKI_PAGE)) helpmenu.add_command(label="Report issue", command=lambda: webbrowser.open(ISSUES_PAGE)) helpmenu.add_separator() helpmenu.add_command(label="About", command=lambda: _tkinter_messagebox.showinfo( "About", "Copyright (c) 2006-2021\n\n (%s)" % DEV_EMAIL_ADDRESS)) menubar.add_cascade(label="Help", menu=helpmenu) window.config(menu=menubar) window._widgets = {} notebook = AutoresizableNotebook(window) first = None frames = {} for group in parser.option_groups: frame = frames[group.title] = _tkinter.Frame(notebook, width=200, height=200) notebook.add(frames[group.title], text=group.title) _tkinter.Label(frame).grid(column=0, row=0, sticky=_tkinter.W) row = 1 if group.get_description(): _tkinter.Label(frame, text="%s:" % group.get_description()).grid( column=0, row=1, columnspan=3, sticky=_tkinter.W) _tkinter.Label(frame).grid(column=0, row=2, sticky=_tkinter.W) row += 2 for option in group.option_list: _tkinter.Label( frame, text="%s " % parser.formatter._format_option_strings(option)).grid( column=0, row=row, sticky=_tkinter.W) if option.type == "string": widget = _tkinter.Entry(frame) elif option.type == "float": widget = ConstrainedEntry(frame, regex=r"\A\d*\.?\d*\Z") elif option.type == "int": widget = ConstrainedEntry(frame, regex=r"\A\d*\Z") else: var = _tkinter.IntVar() widget = _tkinter.Checkbutton(frame, variable=var) widget.var = var first = first or widget widget.grid(column=1, row=row, sticky=_tkinter.W) window._widgets[(option.dest, option.type)] = widget default = defaults.get(option.dest) if default: if hasattr(widget, "insert"): widget.insert(0, default) _tkinter.Label(frame, text=" %s" % option.help).grid(column=2, row=row, sticky=_tkinter.W) row += 1 _tkinter.Label(frame).grid(column=0, row=row, sticky=_tkinter.W) notebook.pack(expand=1, fill="both") notebook.enable_traversal() first.focus() window.mainloop()