PageRenderTime 55ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/request/basic.py

https://bitbucket.org/moon2l/sqlmap
Python | 233 lines | 227 code | 1 blank | 5 comment | 2 complexity | 0ac510bd6c88f503b71a4c76065fae01 MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause
  1. #!/usr/bin/env python
  2. """
  3. $Id: basic.py 4718 2012-02-06 09:48:44Z stamparm $
  4. Copyright (c) 2006-2012 sqlmap developers (http://www.sqlmap.org/)
  5. See the file 'doc/COPYING' for copying permission
  6. """
  7. import codecs
  8. import gzip
  9. import logging
  10. import os
  11. import re
  12. import StringIO
  13. import zlib
  14. from extra.chardet import detect
  15. from lib.core.common import extractErrorMessage
  16. from lib.core.common import extractRegexResult
  17. from lib.core.common import getUnicode
  18. from lib.core.common import isWindowsDriveLetterPath
  19. from lib.core.common import posixToNtSlashes
  20. from lib.core.common import readInput
  21. from lib.core.common import sanitizeAsciiString
  22. from lib.core.common import singleTimeLogMessage
  23. from lib.core.data import conf
  24. from lib.core.data import kb
  25. from lib.core.data import logger
  26. from lib.core.enums import HTTPHEADER
  27. from lib.core.enums import PLACE
  28. from lib.core.exception import sqlmapDataException
  29. from lib.core.settings import DEFAULT_COOKIE_DELIMITER
  30. from lib.core.settings import ML
  31. from lib.core.settings import META_CHARSET_REGEX
  32. from lib.core.settings import PARSE_HEADERS_LIMIT
  33. from lib.core.settings import UNICODE_ENCODING
  34. from lib.parse.headers import headersParser
  35. from lib.parse.html import htmlParser
  36. def forgeHeaders(items=None):
  37. """
  38. Prepare HTTP Cookie, HTTP User-Agent and HTTP Referer headers to use when performing
  39. the HTTP requests
  40. """
  41. items = items or {}
  42. for _ in items.keys():
  43. if items[_] is None:
  44. del items[_]
  45. headers = dict(conf.httpHeaders)
  46. headers.update(items or {})
  47. if conf.cj:
  48. if HTTPHEADER.COOKIE in headers:
  49. for cookie in conf.cj:
  50. if ("%s=" % cookie.name) in headers[HTTPHEADER.COOKIE]:
  51. if kb.mergeCookies is None:
  52. message = "you provided a HTTP %s header value. " % HTTPHEADER.COOKIE
  53. message += "The target url provided it's own cookies within "
  54. message += "the HTTP %s header which intersect with yours. " % HTTPHEADER.SET_COOKIE
  55. message += "Do you want to merge them in futher requests? [Y/n] "
  56. test = readInput(message, default="Y")
  57. kb.mergeCookies = not test or test[0] in ("y", "Y")
  58. if kb.mergeCookies:
  59. _ = lambda x: re.sub("%s=[^%s]+" % (cookie.name, DEFAULT_COOKIE_DELIMITER), "%s=%s" % (cookie.name, cookie.value), x, re.I)
  60. headers[HTTPHEADER.COOKIE] = _(headers[HTTPHEADER.COOKIE])
  61. if PLACE.COOKIE in conf.parameters:
  62. conf.parameters[PLACE.COOKIE] = _(conf.parameters[PLACE.COOKIE])
  63. conf.httpHeaders = [(item[0], item[1] if item[0] != HTTPHEADER.COOKIE else _(item[1])) for item in conf.httpHeaders]
  64. elif not kb.testMode:
  65. headers[HTTPHEADER.COOKIE] += "%s %s=%s" % (DEFAULT_COOKIE_DELIMITER, cookie.name, cookie.value)
  66. if kb.testMode:
  67. conf.cj.clear()
  68. if kb.redirectSetCookie and not conf.dropSetCookie:
  69. if HTTPHEADER.COOKIE in headers:
  70. headers[HTTPHEADER.COOKIE] += "%s %s" % (DEFAULT_COOKIE_DELIMITER, kb.redirectSetCookie)
  71. else:
  72. headers[HTTPHEADER.COOKIE] = kb.redirectSetCookie
  73. return headers
  74. def parseResponse(page, headers):
  75. """
  76. @param page: the page to parse to feed the knowledge base htmlFp
  77. (back-end DBMS fingerprint based upon DBMS error messages return
  78. through the web application) list and absFilePaths (absolute file
  79. paths) set.
  80. """
  81. if headers:
  82. headersParser(headers)
  83. if page:
  84. htmlParser(page)
  85. def checkCharEncoding(encoding):
  86. if encoding:
  87. encoding = encoding.lower()
  88. else:
  89. return encoding
  90. # http://www.destructor.de/charsets/index.htm
  91. translate = { "windows-874": "iso-8859-11", "en_us": "utf8", "macintosh": "iso-8859-1", "euc_tw": "big5_tw", "th": "tis-620", "unicode": "utf8" }
  92. for delimiter in (';', ',', '('):
  93. if delimiter in encoding:
  94. encoding = encoding[:encoding.find(delimiter)].strip()
  95. # popular typos/errors
  96. if "8858" in encoding:
  97. encoding = encoding.replace("8858", "8859") # iso-8858 -> iso-8859
  98. elif "8559" in encoding:
  99. encoding = encoding.replace("8559", "8859") # iso-8559 -> iso-8859
  100. elif "5889" in encoding:
  101. encoding = encoding.replace("5889", "8859") # iso-5889 -> iso-8859
  102. elif "2313" in encoding:
  103. encoding = encoding.replace("2313", "2312") # gb2313 -> gb2312
  104. elif "x-euc" in encoding:
  105. encoding = encoding.replace("x-euc", "euc") # x-euc-kr -> euc-kr
  106. # name adjustment for compatibility
  107. if encoding.startswith("8859"):
  108. encoding = "iso-%s" % encoding
  109. elif encoding.startswith("cp-"):
  110. encoding = "cp%s" % encoding[3:]
  111. elif encoding.startswith("euc-"):
  112. encoding = "euc_%s" % encoding[4:]
  113. elif encoding.startswith("windows") and not encoding.startswith("windows-"):
  114. encoding = "windows-%s" % encoding[7:]
  115. elif encoding.find("iso-88") > 0:
  116. encoding = encoding[encoding.find("iso-88"):]
  117. elif encoding.startswith("is0-"):
  118. encoding = "iso%s" % encoding[4:]
  119. elif encoding.find("ascii") > 0:
  120. encoding = "ascii"
  121. elif encoding.find("utf8") > 0:
  122. encoding = "utf8"
  123. # http://philip.html5.org/data/charsets-2.html
  124. if encoding in translate:
  125. encoding = translate[encoding]
  126. elif encoding in ("null", "{charset}", "*"):
  127. return None
  128. # http://www.iana.org/assignments/character-sets
  129. # http://docs.python.org/library/codecs.html
  130. try:
  131. codecs.lookup(encoding)
  132. except LookupError:
  133. warnMsg = "unknown web page charset '%s'. " % encoding
  134. warnMsg += "Please report by e-mail to %s." % ML
  135. singleTimeLogMessage(warnMsg, logging.WARN, encoding)
  136. encoding = None
  137. return encoding
  138. def getHeuristicCharEncoding(page):
  139. """
  140. Returns page encoding charset detected by usage of heuristics
  141. Reference: http://chardet.feedparser.org/docs/
  142. """
  143. retVal = detect(page)["encoding"]
  144. infoMsg = "heuristics detected web page charset '%s'" % retVal
  145. singleTimeLogMessage(infoMsg, logging.INFO, retVal)
  146. return retVal
  147. def decodePage(page, contentEncoding, contentType):
  148. """
  149. Decode compressed/charset HTTP response
  150. """
  151. if not page or (conf.nullConnection and len(page) < 2):
  152. return getUnicode(page)
  153. if isinstance(contentEncoding, basestring) and contentEncoding.lower() in ("gzip", "x-gzip", "deflate"):
  154. if contentEncoding == "deflate":
  155. # http://stackoverflow.com/questions/1089662/python-inflate-and-deflate-implementations
  156. data = StringIO.StringIO(zlib.decompress(page, -15))
  157. else:
  158. data = gzip.GzipFile('', 'rb', 9, StringIO.StringIO(page))
  159. try:
  160. page = data.read()
  161. except Exception, msg:
  162. errMsg = "detected invalid data for declared content "
  163. errMsg += "encoding '%s' ('%s')" % (contentEncoding, msg)
  164. singleTimeLogMessage(errMsg, logging.ERROR)
  165. if not conf.charset:
  166. httpCharset, metaCharset = None, None
  167. # http://stackoverflow.com/questions/1020892/python-urllib2-read-to-unicode
  168. if contentType and (contentType.find('charset=') != -1):
  169. httpCharset = checkCharEncoding(contentType.split('charset=')[-1])
  170. metaCharset = checkCharEncoding(extractRegexResult(META_CHARSET_REGEX, page, re.DOTALL | re.IGNORECASE))
  171. if ((httpCharset or metaCharset) and not all([httpCharset, metaCharset]))\
  172. or (httpCharset == metaCharset and all([httpCharset, metaCharset])):
  173. kb.pageEncoding = httpCharset or metaCharset
  174. else:
  175. kb.pageEncoding = None
  176. else:
  177. kb.pageEncoding = conf.charset
  178. if contentType and any(map(lambda x: x in contentType.lower(), ('text/txt', 'text/raw', 'text/html', 'text/xml'))):
  179. # can't do for all responses because we need to support binary files too
  180. kb.pageEncoding = kb.pageEncoding or checkCharEncoding(getHeuristicCharEncoding(page))
  181. page = getUnicode(page, kb.pageEncoding)
  182. return page
  183. def processResponse(page, responseHeaders):
  184. kb.processResponseCounter += 1
  185. if not kb.dumpMode:
  186. parseResponse(page, responseHeaders if kb.processResponseCounter < PARSE_HEADERS_LIMIT else None)
  187. if conf.parseErrors:
  188. msg = extractErrorMessage(page)
  189. if msg:
  190. logger.info("parsed error message: '%s'" % msg)