PageRenderTime 70ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/core/common.py

https://github.com/filippocld/sqlmap
Python | 3293 lines | 3232 code | 28 blank | 33 comment | 44 complexity | f51f1d2fcb14a527696acb64962097c9 MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause

Large files files are truncated, but you can click here to view the full file

  1. #!/usr/bin/env python
  2. """
  3. Copyright (c) 2006-2012 sqlmap developers (http://sqlmap.org/)
  4. See the file 'doc/COPYING' for copying permission
  5. """
  6. import codecs
  7. import contextlib
  8. import cookielib
  9. import copy
  10. import ctypes
  11. import httplib
  12. import inspect
  13. import logging
  14. import ntpath
  15. import os
  16. import posixpath
  17. import random
  18. import re
  19. import socket
  20. import string
  21. import struct
  22. import sys
  23. import time
  24. import urllib
  25. import urlparse
  26. import unicodedata
  27. from ConfigParser import DEFAULTSECT
  28. from ConfigParser import RawConfigParser
  29. from StringIO import StringIO
  30. from difflib import SequenceMatcher
  31. from math import sqrt
  32. from optparse import OptionValueError
  33. from subprocess import PIPE
  34. from subprocess import Popen as execute
  35. from xml.dom import minidom
  36. from xml.sax import parse
  37. from extra.safe2bin.safe2bin import safecharencode
  38. from lib.core.bigarray import BigArray
  39. from lib.core.data import conf
  40. from lib.core.data import kb
  41. from lib.core.data import logger
  42. from lib.core.data import paths
  43. from lib.core.convert import base64pickle
  44. from lib.core.convert import base64unpickle
  45. from lib.core.convert import hexdecode
  46. from lib.core.convert import htmlunescape
  47. from lib.core.convert import stdoutencode
  48. from lib.core.convert import unicodeencode
  49. from lib.core.convert import utf8encode
  50. from lib.core.decorators import cachedmethod
  51. from lib.core.dicts import DBMS_DICT
  52. from lib.core.dicts import DEPRECATED_HINTS
  53. from lib.core.dicts import SQL_STATEMENTS
  54. from lib.core.enums import ADJUST_TIME_DELAY
  55. from lib.core.enums import CHARSET_TYPE
  56. from lib.core.enums import DBMS
  57. from lib.core.enums import EXPECTED
  58. from lib.core.enums import HEURISTIC_TEST
  59. from lib.core.enums import HTTPHEADER
  60. from lib.core.enums import HTTPMETHOD
  61. from lib.core.enums import OS
  62. from lib.core.enums import PLACE
  63. from lib.core.enums import PAYLOAD
  64. from lib.core.enums import REFLECTIVE_COUNTER
  65. from lib.core.enums import SORT_ORDER
  66. from lib.core.exception import SqlmapDataException
  67. from lib.core.exception import SqlmapFilePathException
  68. from lib.core.exception import SqlmapGenericException
  69. from lib.core.exception import SqlmapNoneDataException
  70. from lib.core.exception import SqlmapMissingDependence
  71. from lib.core.exception import SqlmapSilentQuitException
  72. from lib.core.exception import SqlmapSyntaxException
  73. from lib.core.exception import SqlmapUserQuitException
  74. from lib.core.log import LOGGER_HANDLER
  75. from lib.core.optiondict import optDict
  76. from lib.core.settings import BOLD_PATTERNS
  77. from lib.core.settings import CUSTOM_INJECTION_MARK_CHAR
  78. from lib.core.settings import DBMS_DIRECTORY_DICT
  79. from lib.core.settings import DEFAULT_COOKIE_DELIMITER
  80. from lib.core.settings import DEFAULT_GET_POST_DELIMITER
  81. from lib.core.settings import DEFAULT_MSSQL_SCHEMA
  82. from lib.core.settings import DEPRECATED_OPTIONS
  83. from lib.core.settings import DESCRIPTION
  84. from lib.core.settings import DUMMY_SQL_INJECTION_CHARS
  85. from lib.core.settings import DUMMY_USER_INJECTION
  86. from lib.core.settings import DYNAMICITY_MARK_LENGTH
  87. from lib.core.settings import ERROR_PARSING_REGEXES
  88. from lib.core.settings import FORM_SEARCH_REGEX
  89. from lib.core.settings import GENERIC_DOC_ROOT_DIRECTORY_NAMES
  90. from lib.core.settings import HASHDB_MILESTONE_VALUE
  91. from lib.core.settings import HOST_ALIASES
  92. from lib.core.settings import INFERENCE_UNKNOWN_CHAR
  93. from lib.core.settings import ISSUES_PAGE
  94. from lib.core.settings import IS_WIN
  95. from lib.core.settings import LARGE_OUTPUT_THRESHOLD
  96. from lib.core.settings import MIN_TIME_RESPONSES
  97. from lib.core.settings import ML
  98. from lib.core.settings import NULL
  99. from lib.core.settings import PARAMETER_AMP_MARKER
  100. from lib.core.settings import PARAMETER_SEMICOLON_MARKER
  101. from lib.core.settings import PARTIAL_VALUE_MARKER
  102. from lib.core.settings import PAYLOAD_DELIMITER
  103. from lib.core.settings import PLATFORM
  104. from lib.core.settings import PRINTABLE_CHAR_REGEX
  105. from lib.core.settings import PYVERSION
  106. from lib.core.settings import REFERER_ALIASES
  107. from lib.core.settings import REFLECTED_BORDER_REGEX
  108. from lib.core.settings import REFLECTED_MAX_REGEX_PARTS
  109. from lib.core.settings import REFLECTED_REPLACEMENT_REGEX
  110. from lib.core.settings import REFLECTED_VALUE_MARKER
  111. from lib.core.settings import REFLECTIVE_MISS_THRESHOLD
  112. from lib.core.settings import REVISION
  113. from lib.core.settings import SENSITIVE_DATA_REGEX
  114. from lib.core.settings import SITE
  115. from lib.core.settings import SUPPORTED_DBMS
  116. from lib.core.settings import TEXT_TAG_REGEX
  117. from lib.core.settings import TIME_STDEV_COEFF
  118. from lib.core.settings import UNICODE_ENCODING
  119. from lib.core.settings import UNKNOWN_DBMS_VERSION
  120. from lib.core.settings import URI_QUESTION_MARKER
  121. from lib.core.settings import URLENCODE_CHAR_LIMIT
  122. from lib.core.settings import URLENCODE_FAILSAFE_CHARS
  123. from lib.core.settings import USER_AGENT_ALIASES
  124. from lib.core.settings import VERSION
  125. from lib.core.settings import VERSION_STRING
  126. from lib.core.threads import getCurrentThreadData
  127. from thirdparty.clientform.clientform import ParseResponse
  128. from thirdparty.clientform.clientform import ParseError
  129. from thirdparty.magic import magic
  130. from thirdparty.odict.odict import OrderedDict
  131. from thirdparty.termcolor.termcolor import colored
  132. class UnicodeRawConfigParser(RawConfigParser):
  133. """
  134. RawConfigParser with unicode writing support
  135. """
  136. def write(self, fp):
  137. """
  138. Write an .ini-format representation of the configuration state.
  139. """
  140. if self._defaults:
  141. fp.write("[%s]\n" % DEFAULTSECT)
  142. for (key, value) in self._defaults.items():
  143. fp.write("%s = %s\n" % (key, getUnicode(value, UNICODE_ENCODING).replace('\n', '\n\t')))
  144. fp.write("\n")
  145. for section in self._sections:
  146. fp.write("[%s]\n" % section)
  147. for (key, value) in self._sections[section].items():
  148. if key != "__name__":
  149. if value is None:
  150. fp.write("%s\n" % (key))
  151. else:
  152. fp.write("%s = %s\n" % (key, getUnicode(value, UNICODE_ENCODING).replace('\n', '\n\t')))
  153. fp.write("\n")
  154. class Format(object):
  155. @staticmethod
  156. def humanize(values, chain=" or "):
  157. return chain.join(values)
  158. # Get methods
  159. @staticmethod
  160. def getDbms(versions=None):
  161. """
  162. Format the back-end DBMS fingerprint value and return its
  163. values formatted as a human readable string.
  164. @return: detected back-end DBMS based upon fingerprint techniques.
  165. @rtype: C{str}
  166. """
  167. if versions is None and Backend.getVersionList():
  168. versions = Backend.getVersionList()
  169. return Backend.getDbms() if versions is None else "%s %s" % (Backend.getDbms(), " and ".join(v for v in versions))
  170. @staticmethod
  171. def getErrorParsedDBMSes():
  172. """
  173. Parses the knowledge base htmlFp list and return its values
  174. formatted as a human readable string.
  175. @return: list of possible back-end DBMS based upon error messages
  176. parsing.
  177. @rtype: C{str}
  178. """
  179. htmlParsed = None
  180. if len(kb.htmlFp) == 0 or kb.heuristicTest != HEURISTIC_TEST.POSITIVE:
  181. pass
  182. elif len(kb.htmlFp) == 1:
  183. htmlParsed = kb.htmlFp[0]
  184. elif len(kb.htmlFp) > 1:
  185. htmlParsed = " or ".join(kb.htmlFp)
  186. return htmlParsed
  187. @staticmethod
  188. def getOs(target, info):
  189. """
  190. Formats the back-end operating system fingerprint value
  191. and return its values formatted as a human readable string.
  192. Example of info (kb.headersFp) dictionary:
  193. {
  194. 'distrib': set(['Ubuntu']),
  195. 'type': set(['Linux']),
  196. 'technology': set(['PHP 5.2.6', 'Apache 2.2.9']),
  197. 'release': set(['8.10'])
  198. }
  199. Example of info (kb.bannerFp) dictionary:
  200. {
  201. 'sp': set(['Service Pack 4']),
  202. 'dbmsVersion': '8.00.194',
  203. 'dbmsServicePack': '0',
  204. 'distrib': set(['2000']),
  205. 'dbmsRelease': '2000',
  206. 'type': set(['Windows'])
  207. }
  208. @return: detected back-end operating system based upon fingerprint
  209. techniques.
  210. @rtype: C{str}
  211. """
  212. infoStr = ""
  213. if info and "type" in info:
  214. infoStr += "%s operating system: %s" % (target, Format.humanize(info["type"]))
  215. if "distrib" in info:
  216. infoStr += " %s" % Format.humanize(info["distrib"])
  217. if "release" in info:
  218. infoStr += " %s" % Format.humanize(info["release"])
  219. if "sp" in info:
  220. infoStr += " %s" % Format.humanize(info["sp"])
  221. if "codename" in info:
  222. infoStr += " (%s)" % Format.humanize(info["codename"])
  223. if "technology" in info:
  224. infoStr += "\nweb application technology: %s" % Format.humanize(info["technology"], ", ")
  225. return infoStr.lstrip()
  226. class Backend:
  227. # Set methods
  228. @staticmethod
  229. def setDbms(dbms):
  230. dbms = aliasToDbmsEnum(dbms)
  231. if dbms is None:
  232. return None
  233. # Little precaution, in theory this condition should always be false
  234. elif kb.dbms is not None and kb.dbms != dbms:
  235. msg = "sqlmap previously fingerprinted back-end DBMS "
  236. msg += "%s. However now it has been fingerprinted " % kb.dbms
  237. msg += "to be %s. " % dbms
  238. msg += "Please, specify which DBMS is "
  239. msg += "correct [%s (default)/%s] " % (kb.dbms, dbms)
  240. while True:
  241. _ = readInput(msg, default=kb.dbms)
  242. if aliasToDbmsEnum(_) == kb.dbms:
  243. break
  244. elif aliasToDbmsEnum(_) == dbms:
  245. kb.dbms = aliasToDbmsEnum(_)
  246. break
  247. else:
  248. warnMsg = "invalid value"
  249. logger.warn(warnMsg)
  250. elif kb.dbms is None:
  251. kb.dbms = aliasToDbmsEnum(dbms)
  252. return kb.dbms
  253. @staticmethod
  254. def setVersion(version):
  255. if isinstance(version, basestring):
  256. kb.dbmsVersion = [version]
  257. return kb.dbmsVersion
  258. @staticmethod
  259. def setVersionList(versionsList):
  260. if isinstance(versionsList, list):
  261. kb.dbmsVersion = versionsList
  262. elif isinstance(versionsList, basestring):
  263. Backend.setVersion(versionsList)
  264. else:
  265. logger.error("invalid format of versionsList")
  266. @staticmethod
  267. def forceDbms(dbms, sticky=False):
  268. if not kb.stickyDBMS:
  269. kb.forcedDbms = aliasToDbmsEnum(dbms)
  270. kb.stickyDBMS = sticky
  271. @staticmethod
  272. def flushForcedDbms(force=False):
  273. if not kb.stickyDBMS or force:
  274. kb.forcedDbms = None
  275. kb.stickyDBMS = False
  276. @staticmethod
  277. def setOs(os):
  278. if os is None:
  279. return None
  280. # Little precaution, in theory this condition should always be false
  281. elif kb.os is not None and isinstance(os, basestring) and kb.os.lower() != os.lower():
  282. msg = "sqlmap previously fingerprinted back-end DBMS "
  283. msg += "operating system %s. However now it has " % kb.os
  284. msg += "been fingerprinted to be %s. " % os
  285. msg += "Please, specify which OS is "
  286. msg += "correct [%s (default)/%s] " % (kb.os, os)
  287. while True:
  288. _ = readInput(msg, default=kb.os)
  289. if _ == kb.os:
  290. break
  291. elif _ == os:
  292. kb.os = _.capitalize()
  293. break
  294. else:
  295. warnMsg = "invalid value"
  296. logger.warn(warnMsg)
  297. elif kb.os is None and isinstance(os, basestring):
  298. kb.os = os.capitalize()
  299. return kb.os
  300. @staticmethod
  301. def setOsVersion(version):
  302. if version is None:
  303. return None
  304. elif kb.osVersion is None and isinstance(version, basestring):
  305. kb.osVersion = version
  306. @staticmethod
  307. def setOsServicePack(sp):
  308. if sp is None:
  309. return None
  310. elif kb.osSP is None and isinstance(sp, int):
  311. kb.osSP = sp
  312. @staticmethod
  313. def setArch():
  314. msg = "what is the back-end database management system architecture?"
  315. msg += "\n[1] 32-bit (default)"
  316. msg += "\n[2] 64-bit"
  317. while True:
  318. _ = readInput(msg, default='1')
  319. if isinstance(_, basestring) and _.isdigit() and int(_) in (1, 2):
  320. kb.arch = 32 if int(_) == 1 else 64
  321. break
  322. else:
  323. warnMsg = "invalid value. Valid values are 1 and 2"
  324. logger.warn(warnMsg)
  325. return kb.arch
  326. # Get methods
  327. @staticmethod
  328. def getForcedDbms():
  329. return aliasToDbmsEnum(kb.get("forcedDbms"))
  330. @staticmethod
  331. def getDbms():
  332. return aliasToDbmsEnum(kb.get("dbms"))
  333. @staticmethod
  334. def getErrorParsedDBMSes():
  335. """
  336. Returns array with parsed DBMS names till now
  337. This functions is called to:
  338. 1. Sort the tests, getSortedInjectionTests() - detection phase.
  339. 2. Ask user whether or not skip specific DBMS tests in detection phase,
  340. lib/controller/checks.py - detection phase.
  341. 3. Sort the fingerprint of the DBMS, lib/controller/handler.py -
  342. fingerprint phase.
  343. """
  344. return kb.htmlFp if kb.get("heuristicTest") == HEURISTIC_TEST.POSITIVE else []
  345. @staticmethod
  346. def getIdentifiedDbms():
  347. dbms = None
  348. if not kb:
  349. pass
  350. elif Backend.getForcedDbms() is not None:
  351. dbms = Backend.getForcedDbms()
  352. elif Backend.getDbms() is not None:
  353. dbms = kb.dbms
  354. elif conf.get("dbms"):
  355. dbms = conf.dbms
  356. elif Backend.getErrorParsedDBMSes():
  357. dbms = unArrayizeValue(Backend.getErrorParsedDBMSes())
  358. elif kb.get("injection") and kb.injection.dbms:
  359. dbms = unArrayizeValue(kb.injection.dbms)
  360. return aliasToDbmsEnum(dbms)
  361. @staticmethod
  362. def getVersion():
  363. if len(kb.dbmsVersion) > 0:
  364. return kb.dbmsVersion[0]
  365. else:
  366. return None
  367. @staticmethod
  368. def getVersionList():
  369. if len(kb.dbmsVersion) > 0:
  370. return kb.dbmsVersion
  371. else:
  372. return None
  373. @staticmethod
  374. def getOs():
  375. return kb.os
  376. @staticmethod
  377. def getOsVersion():
  378. return kb.osVersion
  379. @staticmethod
  380. def getOsServicePack():
  381. return kb.osSP
  382. @staticmethod
  383. def getArch():
  384. if kb.arch is None:
  385. Backend.setArch()
  386. return kb.arch
  387. # Comparison methods
  388. @staticmethod
  389. def isDbms(dbms):
  390. if Backend.getDbms() is not None:
  391. return Backend.getDbms() == aliasToDbmsEnum(dbms)
  392. else:
  393. return Backend.getIdentifiedDbms() == aliasToDbmsEnum(dbms)
  394. @staticmethod
  395. def isDbmsWithin(aliases):
  396. return Backend.getDbms() is not None and Backend.getDbms().lower() in aliases
  397. @staticmethod
  398. def isVersion(version):
  399. return Backend.getVersion() is not None and Backend.getVersion() == version
  400. @staticmethod
  401. def isVersionWithin(versionList):
  402. if Backend.getVersionList() is None:
  403. return False
  404. for _ in Backend.getVersionList():
  405. if _ != UNKNOWN_DBMS_VERSION and _ in versionList:
  406. return True
  407. return False
  408. @staticmethod
  409. def isVersionGreaterOrEqualThan(version):
  410. return Backend.getVersion() is not None and str(Backend.getVersion()) >= str(version)
  411. @staticmethod
  412. def isOs(os):
  413. return Backend.getOs() is not None and Backend.getOs().lower() == os.lower()
  414. def paramToDict(place, parameters=None):
  415. """
  416. Split the parameters into names and values, check if these parameters
  417. are within the testable parameters and return in a dictionary.
  418. """
  419. testableParameters = OrderedDict()
  420. if place in conf.parameters and not parameters:
  421. parameters = conf.parameters[place]
  422. parameters = parameters.replace(", ", ",")
  423. parameters = re.sub(r"&(\w{1,4});", r"%s\g<1>%s" % (PARAMETER_AMP_MARKER, PARAMETER_SEMICOLON_MARKER), parameters)
  424. splitParams = parameters.split(conf.pDel or (DEFAULT_COOKIE_DELIMITER if place == PLACE.COOKIE else DEFAULT_GET_POST_DELIMITER))
  425. for element in splitParams:
  426. element = re.sub(r"%s(.+?)%s" % (PARAMETER_AMP_MARKER, PARAMETER_SEMICOLON_MARKER), r"&\g<1>;", element)
  427. elem = element.split("=")
  428. if len(elem) >= 2:
  429. parameter = elem[0].replace(" ", "")
  430. condition = not conf.testParameter
  431. condition |= parameter in conf.testParameter
  432. if condition:
  433. testableParameters[parameter] = "=".join(elem[1:])
  434. if not conf.multipleTargets:
  435. _ = urldecode(testableParameters[parameter], convall=True)
  436. if _.strip(DUMMY_SQL_INJECTION_CHARS) != _\
  437. or re.search(r'\A9{3,}', _) or re.search(DUMMY_USER_INJECTION, _):
  438. warnMsg = "it appears that you have provided tainted parameter values "
  439. warnMsg += "('%s') with most probably leftover " % element
  440. warnMsg += "chars/statements from manual SQL injection test(s). "
  441. warnMsg += "Please, always use only valid parameter values "
  442. warnMsg += "so sqlmap could be able to properly run "
  443. logger.warn(warnMsg)
  444. message = "Are you sure you want to continue? [y/N] "
  445. test = readInput(message, default="N")
  446. if test[0] not in ("y", "Y"):
  447. raise SqlmapSilentQuitException
  448. if conf.testParameter and not testableParameters:
  449. paramStr = ", ".join(test for test in conf.testParameter)
  450. if len(conf.testParameter) > 1:
  451. warnMsg = "provided parameters '%s' " % paramStr
  452. warnMsg += "are not inside the %s" % place
  453. logger.warn(warnMsg)
  454. else:
  455. parameter = conf.testParameter[0]
  456. if not intersect(USER_AGENT_ALIASES + REFERER_ALIASES + HOST_ALIASES, parameter, True):
  457. warnMsg = "provided parameter '%s' " % paramStr
  458. warnMsg += "is not inside the %s" % place
  459. logger.warn(warnMsg)
  460. elif len(conf.testParameter) != len(testableParameters.keys()):
  461. for parameter in conf.testParameter:
  462. if parameter not in testableParameters:
  463. warnMsg = "provided parameter '%s' " % parameter
  464. warnMsg += "is not inside the %s" % place
  465. logger.warn(warnMsg)
  466. return testableParameters
  467. def getDocRoot():
  468. docRoot = None
  469. pagePath = directoryPath(conf.path)
  470. defaultDocRoot = ("C:/xampp/htdocs/", "C:/Inetpub/wwwroot/") if Backend.isOs(OS.WINDOWS) else ("/var/www/",)
  471. if kb.absFilePaths:
  472. for absFilePath in kb.absFilePaths:
  473. if docRoot:
  474. break
  475. if directoryPath(absFilePath) == '/':
  476. continue
  477. absFilePath = normalizePath(absFilePath)
  478. windowsDriveLetter = None
  479. if isWindowsDriveLetterPath(absFilePath):
  480. windowsDriveLetter, absFilePath = absFilePath[:2], absFilePath[2:]
  481. absFilePath = ntToPosixSlashes(posixToNtSlashes(absFilePath))
  482. if any("/%s/" % _ in absFilePath for _ in GENERIC_DOC_ROOT_DIRECTORY_NAMES):
  483. for _ in GENERIC_DOC_ROOT_DIRECTORY_NAMES:
  484. _ = "/%s/" % _
  485. if _ in absFilePath:
  486. docRoot = "%s%s" % (absFilePath.split(_)[0], _)
  487. break
  488. elif pagePath in absFilePath:
  489. docRoot = absFilePath.split(pagePath)[0]
  490. if windowsDriveLetter:
  491. docRoot = "%s/%s" % (windowsDriveLetter, ntToPosixSlashes(docRoot))
  492. docRoot = normalizePath(docRoot)
  493. if docRoot:
  494. infoMsg = "retrieved the web server document root: '%s'" % docRoot
  495. logger.info(infoMsg)
  496. else:
  497. warnMsg = "unable to retrieve the web server document root"
  498. logger.warn(warnMsg)
  499. message = "please provide the web server document root "
  500. message += "[%s]: " % ",".join(root for root in defaultDocRoot)
  501. inputDocRoot = readInput(message, default=defaultDocRoot)
  502. if inputDocRoot:
  503. if isinstance(inputDocRoot, basestring):
  504. docRoot = inputDocRoot.split(',')
  505. else:
  506. docRoot = inputDocRoot
  507. else:
  508. docRoot = defaultDocRoot
  509. return docRoot
  510. def getDirs():
  511. directories = set("/")
  512. if kb.absFilePaths:
  513. infoMsg = "retrieved web server full paths: "
  514. infoMsg += "'%s'" % ", ".join(ntToPosixSlashes(path) for path in kb.absFilePaths)
  515. logger.info(infoMsg)
  516. for absFilePath in kb.absFilePaths:
  517. if absFilePath:
  518. directory = directoryPath(absFilePath)
  519. directory = ntToPosixSlashes(directory)
  520. directories.add(directory)
  521. else:
  522. warnMsg = "unable to retrieve any web server path"
  523. logger.warn(warnMsg)
  524. webDir = extractRegexResult(r"//[^/]+?/(?P<result>.*)/.", conf.url)
  525. if webDir:
  526. directories.add(webDir)
  527. message = "please provide any additional web server full path to try "
  528. message += "to upload the agent [Enter for None]: "
  529. inputDirs = readInput(message)
  530. if inputDirs:
  531. inputDirs = inputDirs.replace(", ", ",")
  532. inputDirs = inputDirs.split(",")
  533. for inputDir in inputDirs:
  534. if inputDir:
  535. directories.add(inputDir)
  536. return list(directories)
  537. def filePathToString(filePath):
  538. strRepl = filePath.replace("/", "_").replace("\\", "_")
  539. strRepl = strRepl.replace(" ", "_").replace(":", "_")
  540. return strRepl
  541. def singleTimeDebugMessage(message):
  542. singleTimeLogMessage(message, logging.DEBUG)
  543. def singleTimeWarnMessage(message):
  544. singleTimeLogMessage(message, logging.WARN)
  545. def singleTimeLogMessage(message, level=logging.INFO, flag=None):
  546. if flag is None:
  547. flag = hash(message)
  548. if flag not in kb.singleLogFlags:
  549. kb.singleLogFlags.add(flag)
  550. logger.log(level, message)
  551. def boldifyMessage(message):
  552. retVal = message
  553. if any(_ in message for _ in BOLD_PATTERNS):
  554. retVal = setColor(message, True)
  555. return retVal
  556. def setColor(message, bold=False):
  557. retVal = message
  558. level = extractRegexResult(r"\[(?P<result>[A-Z ]+)\]", message) or kb.get("stickyLevel")
  559. if message and getattr(LOGGER_HANDLER, "is_tty", False): # colorizing handler
  560. if bold:
  561. retVal = colored(message, color=None, on_color=None, attrs=("bold",))
  562. elif level:
  563. _ = LOGGER_HANDLER.level_map.get(logging.getLevelName(level))
  564. if _:
  565. background, foreground, bold = _
  566. retVal = colored(message, color=foreground, on_color="on_%s" % background if background else None, attrs=("bold",) if bold else None)
  567. kb.stickyLevel = level if message and message[-1] != "\n" else None
  568. return retVal
  569. def dataToStdout(data, forceOutput=False, bold=False):
  570. """
  571. Writes text to the stdout (console) stream
  572. """
  573. message = ""
  574. if not kb.get("threadException"):
  575. if forceOutput or not getCurrentThreadData().disableStdOut:
  576. if kb.get("multiThreadMode"):
  577. logging._acquireLock()
  578. message = stdoutencode(data)
  579. sys.stdout.write(setColor(message, bold))
  580. try:
  581. sys.stdout.flush()
  582. except IOError:
  583. pass
  584. if kb.get("multiThreadMode"):
  585. logging._releaseLock()
  586. kb.prependFlag = len(data) == 1 and data not in ('\n', '\r') or len(data) > 2 and data[0] == '\r' and data[-1] != '\n'
  587. def dataToTrafficFile(data):
  588. if not conf.trafficFile:
  589. return
  590. conf.trafficFP.write(data)
  591. conf.trafficFP.flush()
  592. def dataToDumpFile(dumpFile, data):
  593. dumpFile.write(data)
  594. dumpFile.flush()
  595. def dataToOutFile(filename, data):
  596. if not data:
  597. return "No data retrieved"
  598. retVal = "%s%s%s" % (conf.filePath, os.sep, filePathToString(filename))
  599. with codecs.open(retVal, "wb") as f:
  600. f.write(data)
  601. return retVal
  602. def strToHex(value):
  603. """
  604. Converts string value to it's hexadecimal representation
  605. """
  606. return (value if not isinstance(value, unicode) else value.encode(UNICODE_ENCODING)).encode("hex").upper()
  607. def readInput(message, default=None, checkBatch=True):
  608. """
  609. Reads input from terminal
  610. """
  611. retVal = None
  612. kb.stickyLevel = None
  613. if "\n" in message:
  614. message += "%s> " % ("\n" if message.count("\n") > 1 else "")
  615. elif message[-1] == ']':
  616. message += " "
  617. if conf.answers:
  618. for item in conf.answers.split(','):
  619. question = item.split('=')[0].strip()
  620. answer = item.split('=')[1] if len(item.split('=')) > 1 else None
  621. if answer and question.lower() in message.lower():
  622. retVal = getUnicode(answer, UNICODE_ENCODING)
  623. infoMsg = "%s%s" % (getUnicode(message), retVal)
  624. logger.info(infoMsg)
  625. debugMsg = "used the given answer"
  626. logger.debug(debugMsg)
  627. break
  628. if retVal is None:
  629. if checkBatch and conf.batch:
  630. if isListLike(default):
  631. options = ",".join(getUnicode(opt, UNICODE_ENCODING) for opt in default)
  632. elif default:
  633. options = getUnicode(default, UNICODE_ENCODING)
  634. else:
  635. options = unicode()
  636. infoMsg = "%s%s" % (getUnicode(message), options)
  637. logger.info(infoMsg)
  638. debugMsg = "used the default behaviour, running in batch mode"
  639. logger.debug(debugMsg)
  640. retVal = default
  641. else:
  642. logging._acquireLock()
  643. dataToStdout("\r%s" % message, forceOutput=True, bold=True)
  644. kb.prependFlag = False
  645. try:
  646. retVal = raw_input() or default
  647. retVal = getUnicode(retVal, system=True) if retVal else retVal
  648. except:
  649. time.sleep(0.05) # Reference: http://www.gossamer-threads.com/lists/python/python/781893
  650. kb.prependFlag = True
  651. raise SqlmapUserQuitException
  652. finally:
  653. logging._releaseLock()
  654. return retVal
  655. def randomRange(start=0, stop=1000):
  656. """
  657. Returns random integer value in given range
  658. """
  659. return int(random.randint(start, stop))
  660. def randomInt(length=4):
  661. """
  662. Returns random integer value with provided number of digits
  663. """
  664. return int("".join(random.choice(string.digits if i!=0 else string.digits.replace('0', '')) for i in xrange(0, length)))
  665. def randomStr(length=4, lowercase=False, alphabet=None):
  666. """
  667. Returns random string value with provided number of characters
  668. """
  669. if alphabet:
  670. retVal = "".join(random.choice(alphabet) for _ in xrange(0, length))
  671. elif lowercase:
  672. retVal = "".join(random.choice(string.lowercase) for _ in xrange(0, length))
  673. else:
  674. retVal = "".join(random.choice(string.letters) for _ in xrange(0, length))
  675. return retVal
  676. def sanitizeStr(value):
  677. """
  678. Sanitizes string value in respect to newline and line-feed characters
  679. """
  680. return getUnicode(value).replace("\n", " ").replace("\r", "")
  681. def checkFile(filename):
  682. """
  683. Checks for file existence
  684. """
  685. if not os.path.isfile(filename):
  686. raise SqlmapFilePathException, "unable to read file '%s'" % filename
  687. def banner():
  688. """
  689. This function prints sqlmap banner with its version
  690. """
  691. _ = """\n %s - %s\n %s\n\n""" % (VERSION_STRING, DESCRIPTION, SITE)
  692. dataToStdout(_, forceOutput=True)
  693. def parsePasswordHash(password):
  694. blank = " " * 8
  695. if not password or password == " ":
  696. password = NULL
  697. if Backend.isDbms(DBMS.MSSQL) and password != NULL and isHexEncodedString(password):
  698. hexPassword = password
  699. password = "%s\n" % hexPassword
  700. password += "%sheader: %s\n" % (blank, hexPassword[:6])
  701. password += "%ssalt: %s\n" % (blank, hexPassword[6:14])
  702. password += "%smixedcase: %s\n" % (blank, hexPassword[14:54])
  703. if not Backend.isVersionWithin(("2005", "2008")):
  704. password += "%suppercase: %s" % (blank, hexPassword[54:])
  705. return password
  706. def cleanQuery(query):
  707. retVal = query
  708. for sqlStatements in SQL_STATEMENTS.values():
  709. for sqlStatement in sqlStatements:
  710. sqlStatementEsc = sqlStatement.replace("(", "\\(")
  711. queryMatch = re.search("(%s)" % sqlStatementEsc, query, re.I)
  712. if queryMatch and "sys_exec" not in query:
  713. retVal = retVal.replace(queryMatch.group(1), sqlStatement.upper())
  714. return retVal
  715. def setPaths():
  716. """
  717. Sets absolute paths for project directories and files
  718. """
  719. # sqlmap paths
  720. paths.SQLMAP_EXTRAS_PATH = os.path.join(paths.SQLMAP_ROOT_PATH, "extra")
  721. paths.SQLMAP_PROCS_PATH = os.path.join(paths.SQLMAP_ROOT_PATH, "procs")
  722. paths.SQLMAP_SHELL_PATH = os.path.join(paths.SQLMAP_ROOT_PATH, "shell")
  723. paths.SQLMAP_TAMPER_PATH = os.path.join(paths.SQLMAP_ROOT_PATH, "tamper")
  724. paths.SQLMAP_TXT_PATH = os.path.join(paths.SQLMAP_ROOT_PATH, "txt")
  725. paths.SQLMAP_UDF_PATH = os.path.join(paths.SQLMAP_ROOT_PATH, "udf")
  726. paths.SQLMAP_XML_PATH = os.path.join(paths.SQLMAP_ROOT_PATH, "xml")
  727. paths.SQLMAP_XML_BANNER_PATH = os.path.join(paths.SQLMAP_XML_PATH, "banner")
  728. paths.SQLMAP_OUTPUT_PATH = os.path.join(paths.SQLMAP_ROOT_PATH, "output")
  729. paths.SQLMAP_DUMP_PATH = os.path.join(paths.SQLMAP_OUTPUT_PATH, "%s", "dump")
  730. paths.SQLMAP_FILES_PATH = os.path.join(paths.SQLMAP_OUTPUT_PATH, "%s", "files")
  731. paths.SQLMAP_SEXEC_PATH = os.path.join(paths.SQLMAP_EXTRAS_PATH, "shellcodeexec")
  732. # sqlmap files
  733. paths.SQLMAP_HISTORY = os.path.join(paths.SQLMAP_ROOT_PATH, ".sqlmap_history")
  734. paths.SQLMAP_CONFIG = os.path.join(paths.SQLMAP_ROOT_PATH, "sqlmap-%s.conf" % randomStr())
  735. paths.COMMON_COLUMNS = os.path.join(paths.SQLMAP_TXT_PATH, "common-columns.txt")
  736. paths.COMMON_TABLES = os.path.join(paths.SQLMAP_TXT_PATH, "common-tables.txt")
  737. paths.COMMON_OUTPUTS = os.path.join(paths.SQLMAP_TXT_PATH, 'common-outputs.txt')
  738. paths.SQL_KEYWORDS = os.path.join(paths.SQLMAP_TXT_PATH, "keywords.txt")
  739. paths.SMALL_DICT = os.path.join(paths.SQLMAP_TXT_PATH, "smalldict.txt")
  740. paths.USER_AGENTS = os.path.join(paths.SQLMAP_TXT_PATH, "user-agents.txt")
  741. paths.WORDLIST = os.path.join(paths.SQLMAP_TXT_PATH, "wordlist.zip")
  742. paths.PHPIDS_RULES_XML = os.path.join(paths.SQLMAP_XML_PATH, "phpids_rules.xml")
  743. paths.ERRORS_XML = os.path.join(paths.SQLMAP_XML_PATH, "errors.xml")
  744. paths.PAYLOADS_XML = os.path.join(paths.SQLMAP_XML_PATH, "payloads.xml")
  745. paths.INJECTIONS_XML = os.path.join(paths.SQLMAP_XML_PATH, "injections.xml")
  746. paths.LIVE_TESTS_XML = os.path.join(paths.SQLMAP_XML_PATH, "livetests.xml")
  747. paths.QUERIES_XML = os.path.join(paths.SQLMAP_XML_PATH, "queries.xml")
  748. paths.GENERIC_XML = os.path.join(paths.SQLMAP_XML_BANNER_PATH, "generic.xml")
  749. paths.MSSQL_XML = os.path.join(paths.SQLMAP_XML_BANNER_PATH, "mssql.xml")
  750. paths.MYSQL_XML = os.path.join(paths.SQLMAP_XML_BANNER_PATH, "mysql.xml")
  751. paths.ORACLE_XML = os.path.join(paths.SQLMAP_XML_BANNER_PATH, "oracle.xml")
  752. paths.PGSQL_XML = os.path.join(paths.SQLMAP_XML_BANNER_PATH, "postgresql.xml")
  753. def weAreFrozen():
  754. """
  755. Returns whether we are frozen via py2exe.
  756. This will affect how we find out where we are located.
  757. Reference: http://www.py2exe.org/index.cgi/WhereAmI
  758. """
  759. return hasattr(sys, "frozen")
  760. def parseTargetDirect():
  761. """
  762. Parse target dbms and set some attributes into the configuration singleton.
  763. """
  764. if not conf.direct:
  765. return
  766. details = None
  767. remote = False
  768. for dbms in SUPPORTED_DBMS:
  769. details = re.search("^(?P<dbms>%s)://(?P<credentials>(?P<user>.+?)\:(?P<pass>.*)\@)?(?P<remote>(?P<hostname>.+?)\:(?P<port>[\d]+)\/)?(?P<db>[\w\d\ \:\.\_\-\/\\\\]+?)$" % dbms, conf.direct, re.I)
  770. if details:
  771. conf.dbms = details.group('dbms')
  772. if details.group('credentials'):
  773. conf.dbmsUser = details.group('user')
  774. conf.dbmsPass = details.group('pass')
  775. else:
  776. conf.dbmsUser = unicode()
  777. conf.dbmsPass = unicode()
  778. if not conf.dbmsPass:
  779. conf.dbmsPass = None
  780. if details.group('remote'):
  781. remote = True
  782. conf.hostname = details.group('hostname')
  783. conf.port = int(details.group('port'))
  784. else:
  785. conf.hostname = "localhost"
  786. conf.port = 0
  787. conf.dbmsDb = details.group('db')
  788. conf.parameters[None] = "direct connection"
  789. break
  790. if not details:
  791. errMsg = "invalid target details, valid syntax is for instance "
  792. errMsg += "'mysql://USER:PASSWORD@DBMS_IP:DBMS_PORT/DATABASE_NAME' "
  793. errMsg += "or 'access://DATABASE_FILEPATH'"
  794. raise SqlmapSyntaxException, errMsg
  795. for dbmsName, data in DBMS_DICT.items():
  796. if conf.dbms in data[0]:
  797. try:
  798. if dbmsName in (DBMS.ACCESS, DBMS.SQLITE, DBMS.FIREBIRD):
  799. if remote:
  800. warnMsg = "direct connection over the network for "
  801. warnMsg += "%s DBMS is not supported" % dbmsName
  802. logger.warn(warnMsg)
  803. conf.hostname = "localhost"
  804. conf.port = 0
  805. elif not remote:
  806. errMsg = "missing remote connection details"
  807. raise SqlmapSyntaxException, errMsg
  808. if dbmsName in (DBMS.MSSQL, DBMS.SYBASE):
  809. import _mssql
  810. import pymssql
  811. if not hasattr(pymssql, "__version__") or pymssql.__version__ < "1.0.2":
  812. errMsg = "'%s' third-party library must be " % data[1]
  813. errMsg += "version >= 1.0.2 to work properly. "
  814. errMsg += "Download from '%s'" % data[2]
  815. raise SqlmapMissingDependence, errMsg
  816. elif dbmsName == DBMS.MYSQL:
  817. import pymysql
  818. elif dbmsName == DBMS.PGSQL:
  819. import psycopg2
  820. elif dbmsName == DBMS.ORACLE:
  821. import cx_Oracle
  822. elif dbmsName == DBMS.SQLITE:
  823. import sqlite3
  824. elif dbmsName == DBMS.ACCESS:
  825. import pyodbc
  826. elif dbmsName == DBMS.FIREBIRD:
  827. import kinterbasdb
  828. except ImportError:
  829. errMsg = "sqlmap requires '%s' third-party library " % data[1]
  830. errMsg += "in order to directly connect to the database "
  831. errMsg += "%s. Download from '%s'" % (dbmsName, data[2])
  832. raise SqlmapMissingDependence, errMsg
  833. def parseTargetUrl():
  834. """
  835. Parse target url and set some attributes into the configuration singleton.
  836. """
  837. if not conf.url:
  838. return
  839. originalUrl = conf.url
  840. if re.search("\[.+\]", conf.url) and not socket.has_ipv6:
  841. errMsg = "IPv6 addressing is not supported "
  842. errMsg += "on this platform"
  843. raise SqlmapGenericException, errMsg
  844. if not re.search("^http[s]*://", conf.url, re.I):
  845. if ":443/" in conf.url:
  846. conf.url = "https://" + conf.url
  847. else:
  848. conf.url = "http://" + conf.url
  849. if CUSTOM_INJECTION_MARK_CHAR in conf.url:
  850. conf.url = conf.url.replace('?', URI_QUESTION_MARKER)
  851. urlSplit = urlparse.urlsplit(conf.url)
  852. hostnamePort = urlSplit[1].split(":") if not re.search("\[.+\]", urlSplit[1]) else filter(None, (re.search("\[.+\]", urlSplit[1]).group(0), re.search("\](:(?P<port>\d+))?", urlSplit[1]).group("port")))
  853. conf.scheme = urlSplit[0].strip().lower() if not conf.forceSSL else "https"
  854. conf.path = urlSplit[2].strip()
  855. conf.hostname = hostnamePort[0].strip()
  856. conf.ipv6 = conf.hostname != conf.hostname.strip("[]")
  857. conf.hostname = conf.hostname.strip("[]")
  858. try:
  859. _ = conf.hostname.encode("idna")
  860. except UnicodeError:
  861. _ = None
  862. if any((_ is None, re.search(r'\s', conf.hostname), '..' in conf.hostname, conf.hostname.startswith('.'))):
  863. errMsg = "invalid target url"
  864. raise SqlmapSyntaxException, errMsg
  865. if len(hostnamePort) == 2:
  866. try:
  867. conf.port = int(hostnamePort[1])
  868. except:
  869. errMsg = "invalid target url"
  870. raise SqlmapSyntaxException, errMsg
  871. elif conf.scheme == "https":
  872. conf.port = 443
  873. else:
  874. conf.port = 80
  875. if urlSplit[3]:
  876. conf.parameters[PLACE.GET] = urldecode(urlSplit[3]) if urlSplit[3] and urlencode(DEFAULT_GET_POST_DELIMITER, None) not in urlSplit[3] else urlSplit[3]
  877. conf.url = getUnicode("%s://%s:%d%s" % (conf.scheme, ("[%s]" % conf.hostname) if conf.ipv6 else conf.hostname, conf.port, conf.path))
  878. conf.url = conf.url.replace(URI_QUESTION_MARKER, '?')
  879. if not conf.referer and intersect(REFERER_ALIASES, conf.testParameter, True):
  880. debugMsg = "setting the HTTP Referer header to the target url"
  881. logger.debug(debugMsg)
  882. conf.httpHeaders = filter(lambda (key, value): key != HTTPHEADER.REFERER, conf.httpHeaders)
  883. conf.httpHeaders.append((HTTPHEADER.REFERER, conf.url))
  884. if not conf.host and intersect(HOST_ALIASES, conf.testParameter, True):
  885. debugMsg = "setting the HTTP Host header to the target url"
  886. logger.debug(debugMsg)
  887. conf.httpHeaders = filter(lambda (key, value): key != HTTPHEADER.HOST, conf.httpHeaders)
  888. conf.httpHeaders.append((HTTPHEADER.HOST, getHostHeader(conf.url)))
  889. if originalUrl != conf.url:
  890. kb.originalUrls[conf.url] = originalUrl
  891. def expandAsteriskForColumns(expression):
  892. """
  893. If the user provided an asterisk rather than the column(s)
  894. name, sqlmap will retrieve the columns itself and reprocess
  895. the SQL query string (expression)
  896. """
  897. asterisk = re.search("^SELECT\s+\*\s+FROM\s+([\w\.\_]+)\s*", expression, re.I)
  898. if asterisk:
  899. infoMsg = "you did not provide the fields in your query. "
  900. infoMsg += "sqlmap will retrieve the column names itself"
  901. logger.info(infoMsg)
  902. dbTbl = asterisk.group(1)
  903. if dbTbl and ".." in dbTbl:
  904. dbTbl = dbTbl.replace('..', '.dbo.')
  905. if dbTbl and "." in dbTbl:
  906. conf.db, conf.tbl = dbTbl.split(".", 1)
  907. else:
  908. conf.tbl = dbTbl
  909. columnsDict = conf.dbmsHandler.getColumns(onlyColNames=True)
  910. if columnsDict and conf.db in columnsDict and conf.tbl in columnsDict[conf.db]:
  911. columns = columnsDict[conf.db][conf.tbl].keys()
  912. columns.sort()
  913. columnsStr = ", ".join(column for column in columns)
  914. expression = expression.replace("*", columnsStr, 1)
  915. infoMsg = "the query with column names is: "
  916. infoMsg += "%s" % expression
  917. logger.info(infoMsg)
  918. return expression
  919. def getLimitRange(count, dump=False, plusOne=False):
  920. """
  921. Returns range of values used in limit/offset constructs
  922. """
  923. retVal = None
  924. count = int(count)
  925. limitStart, limitStop = 1, count
  926. if dump:
  927. if isinstance(conf.limitStop, int) and conf.limitStop > 0 and conf.limitStop < limitStop:
  928. limitStop = conf.limitStop
  929. if isinstance(conf.limitStart, int) and conf.limitStart > 0 and conf.limitStart <= limitStop:
  930. limitStart = conf.limitStart
  931. retVal = xrange(limitStart, limitStop + 1) if plusOne else xrange(limitStart - 1, limitStop)
  932. return retVal
  933. def parseUnionPage(page):
  934. """
  935. Returns resulting items from UNION query inside provided page content
  936. """
  937. if page is None:
  938. return None
  939. if page.startswith(kb.chars.start) and page.endswith(kb.chars.stop):
  940. if len(page) > LARGE_OUTPUT_THRESHOLD:
  941. warnMsg = "large output detected. This might take a while"
  942. logger.warn(warnMsg)
  943. data = BigArray()
  944. keys = set()
  945. for match in re.finditer("%s(.*?)%s" % (kb.chars.start, kb.chars.stop), page, re.DOTALL | re.IGNORECASE):
  946. entry = match.group(1)
  947. if kb.chars.start in entry:
  948. entry = entry.split(kb.chars.start)[-1]
  949. if kb.unionDuplicates:
  950. key = entry.lower()
  951. if key not in keys:
  952. keys.add(key)
  953. else:
  954. continue
  955. entry = entry.split(kb.chars.delimiter)
  956. if conf.hexConvert:
  957. entry = applyFunctionRecursively(entry, decodeHexValue)
  958. if kb.safeCharEncode:
  959. entry = applyFunctionRecursively(entry, safecharencode)
  960. data.append(entry[0] if len(entry) == 1 else entry)
  961. else:
  962. data = page
  963. if len(data) == 1 and isinstance(data[0], basestring):
  964. data = data[0]
  965. return data
  966. def parseFilePaths(page):
  967. """
  968. Detects (possible) absolute system paths inside the provided page content
  969. """
  970. if page:
  971. for regex in (r" in <b>(?P<result>.*?)</b> on line", r"(?:>|\s)(?P<result>[A-Za-z]:[\\/][\w.\\/]*)", r"(?:>|\s)(?P<result>/\w[/\w.]+)"):
  972. for match in re.finditer(regex, page):
  973. absFilePath = match.group("result").strip()
  974. page = page.replace(absFilePath, "")
  975. if isWindowsDriveLetterPath(absFilePath):
  976. absFilePath = posixToNtSlashes(absFilePath)
  977. if absFilePath not in kb.absFilePaths:
  978. kb.absFilePaths.add(absFilePath)
  979. def getLocalIP():
  980. retVal = None
  981. try:
  982. s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  983. s.connect((conf.hostname, conf.port))
  984. retVal, _ = s.getsockname()
  985. s.close()
  986. except:
  987. debugMsg = "there was an error in opening socket "
  988. debugMsg += "connection toward '%s'" % conf.hostname
  989. logger.debug(debugMsg)
  990. return retVal
  991. def getRemoteIP():
  992. return socket.gethostbyname(conf.hostname)
  993. def getFileType(filePath):
  994. try:
  995. _ = magic.from_file(filePath)
  996. except:
  997. return "unknown"
  998. return "text" if "ASCII" in _ or "text" in _ else "binary"
  999. def getCharset(charsetType=None):
  1000. asciiTbl = []
  1001. if charsetType is None:
  1002. asciiTbl.extend(xrange(0, 128))
  1003. # 0 or 1
  1004. elif charsetType == CHARSET_TYPE.BINARY:
  1005. asciiTbl.extend([0, 1])
  1006. asciiTbl.extend(xrange(47, 50))
  1007. # Digits
  1008. elif charsetType == CHARSET_TYPE.DIGITS:
  1009. asciiTbl.extend([0, 1])
  1010. asciiTbl.extend(xrange(47, 58))
  1011. # Hexadecimal
  1012. elif charsetType == CHARSET_TYPE.HEXADECIMAL:
  1013. asciiTbl.extend([0, 1])
  1014. asciiTbl.extend(xrange(47, 58))
  1015. asciiTbl.extend(xrange(64, 71))
  1016. asciiTbl.extend([87, 88]) # X
  1017. asciiTbl.extend(xrange(96, 103))
  1018. asciiTbl.extend([119, 120]) # x
  1019. # Characters
  1020. elif charsetType == CHARSET_TYPE.ALPHA:
  1021. asciiTbl.extend([0, 1])
  1022. asciiTbl.extend(xrange(64, 91))
  1023. asciiTbl.extend(xrange(96, 123))
  1024. # Characters and digits
  1025. elif charsetType == CHARSET_TYPE.ALPHANUM:
  1026. asciiTbl.extend([0, 1])
  1027. asciiTbl.extend(xrange(47, 58))
  1028. asciiTbl.extend(xrange(64, 91))
  1029. asciiTbl.extend(xrange(96, 123))
  1030. return asciiTbl
  1031. def searchEnvPath(filename):
  1032. retVal = None
  1033. path = os.environ.get("PATH", "")
  1034. paths = path.split(";") if IS_WIN else path.split(":")
  1035. for _ in paths:
  1036. _ = _.replace(";", "")
  1037. retVal = os.path.exists(os.path.normpath(os.path.join(_, filename)))
  1038. if retVal:
  1039. break
  1040. return retVal
  1041. def directoryPath(filepath):
  1042. """
  1043. Returns directory path for a given filepath
  1044. """
  1045. retVal = filepath
  1046. if filepath:
  1047. retVal = ntpath.dirname(filepath) if isWindowsDriveLetterPath(filepath) else posixpath.dirname(filepath)
  1048. return retVal
  1049. def normalizePath(filepath):
  1050. """
  1051. Returns normalized string representation of a given filepath
  1052. """
  1053. retVal = filepath
  1054. if filepath:
  1055. retVal = ntpath.normpath(filepath) if isWindowsDriveLetterPath(filepath) else posixpath.normpath(filepath)
  1056. return retVal
  1057. def safeStringFormat(format_, params):
  1058. """
  1059. Avoids problems with inappropriate string format strings
  1060. """
  1061. retVal = format_.replace("%d", "%s")
  1062. if isinstance(params, basestring):
  1063. retVal = retVal.replace("%s", params)
  1064. else:
  1065. count, index = 0, 0
  1066. while index != -1:
  1067. index = retVal.find("%s")
  1068. if index != -1:
  1069. if count < len(params):
  1070. retVal = retVal[:index] + getUnicode(params[count]) + retVal[index + 2:]
  1071. else:
  1072. raise SqlmapNoneDataException, "wrong number of parameters during string formatting"
  1073. count += 1
  1074. return retVal
  1075. def getFilteredPageContent(page, onlyText=True):
  1076. """
  1077. Returns filtered page content without script, style and/or comments
  1078. or all HTML tags
  1079. """
  1080. retVal = page
  1081. # only if the page's charset has been successfully identified
  1082. if isinstance(page, unicode):
  1083. retVal = re.sub(r"(?si)<script.+?</script>|<!--.+?-->|<style.+?</style>%s" % (r"|<[^>]+>|\t|\n|\r" if onlyText else ""), " ", page)
  1084. while retVal.find(" ") != -1:
  1085. retVal = retVal.replace(" ", " ")
  1086. retVal = htmlunescape(retVal)
  1087. return retVal
  1088. def getPageWordSet(page):
  1089. """
  1090. Returns word set used in page content
  1091. """
  1092. retVal = set()
  1093. # only if the page's charset has been successfully identified
  1094. if isinstance(page, unicode):
  1095. _ = getFilteredPageContent(page)
  1096. retVal = set(re.findall(r"\w+", _))
  1097. return retVal
  1098. def showStaticWords(firstPage, secondPage):
  1099. infoMsg = "finding static words in longest matching part of dynamic page content"
  1100. logger.info(infoMsg)
  1101. firstPage = getFilteredPageContent(firstPage)
  1102. secondPage = getFilteredPageContent(secondPage)
  1103. infoMsg = "static words: "
  1104. if firstPage and secondPage:
  1105. match = SequenceMatcher(None, firstPage, secondPage).find_longest_match(0, len(firstPage), 0, len(secondPage))
  1106. commonText = firstPage[match[0]:match[0] + match[2]]
  1107. commonWords = getPageWordSet(commonText)
  1108. else:
  1109. commonWords = None
  1110. if commonWords:
  1111. commonWords = list(commonWords)
  1112. commonWords.sort(lambda a, b: cmp(a.lower(), b.lower()))
  1113. for word in commonWords:
  1114. if len(word) > 2:
  1115. infoMsg += "'%s', " % word
  1116. infoMsg = infoMsg.rstrip(", ")
  1117. else:
  1118. infoMsg += "None"
  1119. logger.info(infoMsg)
  1120. def isWindowsPath(filepath):
  1121. """
  1122. Returns True if given filepath is in Windows format
  1123. """
  1124. return re.search("\A[\w]\:\\\\", filepath) is not None
  1125. def isWindowsDriveLetterPath(filepath):
  1126. """
  1127. Returns True if given filepath starts with a Windows drive letter
  1128. """
  1129. return re.search("\A[\w]\:", filepath) is not None
  1130. def posixToNtSlashes(filepath):
  1131. """
  1132. Replaces all occurances of Posix slashes (/) in provided
  1133. filepath with NT ones (/)
  1134. >>> posixToNtSlashes('C:/Windows')
  1135. 'C:\\\\Windows'
  1136. """
  1137. return filepath.replace('/', '\\')
  1138. def ntToPosixSlashes(filepath):
  1139. """
  1140. Replaces all occurances of NT slashes (\) in provided
  1141. filepath with Posix ones (/)
  1142. >>> ntToPosixSlashes('C:\\Windows')
  1143. 'C:/Windows'
  1144. """
  1145. return filepath.replace('\\', '/')
  1146. def isBase64EncodedString(subject):
  1147. """
  1148. Checks if the provided string is Base64 encoded
  1149. >>> isBase64EncodedString('dGVzdA==')
  1150. True
  1151. >>> isBase64EncodedString('123456')
  1152. False
  1153. """
  1154. return re.match(r"\A(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?\Z", subject) is not None
  1155. def isHexEncodedString(subject):
  1156. """
  1157. Checks if the provided string is hex encoded
  1158. >>> isHexEncodedString('DEADBEEF')
  1159. True
  1160. >>> isHexEncodedString('test')
  1161. False
  1162. """
  1163. return re.match(r"\A[0-9a-fA-Fx]+\Z", subject) is not None
  1164. def getConsoleWidth(default=80):
  1165. """
  1166. Returns console width
  1167. """
  1168. width = None
  1169. if os.getenv("COLUMNS", "").isdigit():
  1170. width = int(os.getenv("COLUMNS"))
  1171. else:
  1172. output=execute('stty size', shell=True, stdout=PIPE, stderr=PIPE).stdout.read()
  1173. items = output.split()
  1174. if len(items) == 2 and items[1].isdigit():
  1175. width = int(items[1])
  1176. if width is None:
  1177. try:
  1178. import curses
  1179. stdscr = curses.initscr()
  1180. _, width = stdscr.getmaxyx()
  1181. curses.endwin()
  1182. except:
  1183. pass
  1184. return width or default
  1185. def clearConsoleLine(forceOutput=False):
  1186. """
  1187. Clears current console line
  1188. """
  1189. if getattr(LOGGER_HANDLER, "is_tty", False):
  1190. dataToStdout("\r%s\r" % (" " * (getConsoleWidth() - 1)), forceOutput)
  1191. kb.prependFlag = False
  1192. kb.stickyLevel = None
  1193. def parseXmlFile(xmlFile, handler):
  1194. """
  1195. Parses XML file by a give

Large files files are truncated, but you can click here to view the full file