sqlmap/lib/request/httpshandler.py

134 lines
5.4 KiB
Python
Raw Normal View History

2019-05-08 13:47:52 +03:00
#!/usr/bin/env python
2012-06-04 23:46:28 +04:00
"""
2023-01-03 01:24:59 +03:00
Copyright (c) 2006-2023 sqlmap developers (https://sqlmap.org/)
2017-10-11 15:50:46 +03:00
See the file 'LICENSE' for copying permission
2012-06-04 23:46:28 +04:00
"""
2016-11-04 17:04:38 +03:00
import re
2012-06-04 23:46:28 +04:00
import socket
2019-03-29 04:28:16 +03:00
from lib.core.common import filterNone
from lib.core.common import getSafeExString
2021-10-07 01:29:31 +03:00
from lib.core.compat import LooseVersion
2020-08-23 23:11:24 +03:00
from lib.core.compat import xrange
from lib.core.data import conf
2015-06-01 11:45:16 +03:00
from lib.core.data import kb
2012-06-04 23:46:28 +04:00
from lib.core.data import logger
from lib.core.exception import SqlmapConnectionException
from lib.core.settings import PYVERSION
from thirdparty.six.moves import http_client as _http_client
from thirdparty.six.moves import urllib as _urllib
2012-06-04 23:46:28 +04:00
ssl = None
try:
import ssl as _ssl
ssl = _ssl
except ImportError:
pass
2019-03-29 04:28:16 +03:00
_protocols = filterNone(getattr(ssl, _, None) for _ in ("PROTOCOL_TLSv1_2", "PROTOCOL_TLSv1_1", "PROTOCOL_TLSv1", "PROTOCOL_SSLv3", "PROTOCOL_SSLv23", "PROTOCOL_SSLv2"))
2019-11-09 01:45:30 +03:00
_lut = dict((getattr(ssl, _), _) for _ in dir(ssl) if _.startswith("PROTOCOL_"))
2020-04-07 03:07:54 +03:00
_contexts = {}
2012-06-04 23:46:28 +04:00
class HTTPSConnection(_http_client.HTTPSConnection):
2012-06-04 23:46:28 +04:00
"""
Connection class that enables usage of newer SSL protocols.
Reference: http://bugs.python.org/msg128686
2022-08-22 17:25:55 +03:00
NOTE: use https://check-tls.akamaized.net/ to check if (e.g.) TLS/SNI is working properly
2012-06-04 23:46:28 +04:00
"""
def __init__(self, *args, **kwargs):
2020-04-07 03:07:54 +03:00
# NOTE: Dirty patch for https://bugs.python.org/issue38251 / https://github.com/sqlmapproject/sqlmap/issues/4158
if hasattr(ssl, "_create_default_https_context"):
if None not in _contexts:
_contexts[None] = ssl._create_default_https_context()
kwargs["context"] = _contexts[None]
2020-08-23 23:11:24 +03:00
self.retrying = False
_http_client.HTTPSConnection.__init__(self, *args, **kwargs)
2012-06-04 23:46:28 +04:00
def connect(self):
def create_sock():
sock = socket.create_connection((self.host, self.port), self.timeout)
if getattr(self, "_tunnel_host", None):
self.sock = sock
self._tunnel()
return sock
success = False
2012-06-04 23:52:51 +04:00
2015-11-25 15:04:34 +03:00
# Reference(s): https://docs.python.org/2/library/ssl.html#ssl.SSLContext
# https://www.mnot.net/blog/2014/12/27/python_2_and_tls_sni
2022-11-02 01:26:15 +03:00
if hasattr(ssl, "SSLContext"):
2020-08-13 17:22:09 +03:00
for protocol in (_ for _ in _protocols if _ >= ssl.PROTOCOL_TLSv1):
2015-06-01 11:45:16 +03:00
try:
sock = create_sock()
2020-04-07 03:07:54 +03:00
if protocol not in _contexts:
_contexts[protocol] = ssl.SSLContext(protocol)
2022-11-29 17:05:34 +03:00
if getattr(self, "cert_file", None) and getattr(self, "key_file", None):
2022-11-02 01:26:15 +03:00
_contexts[protocol].load_cert_chain(certfile=self.cert_file, keyfile=self.key_file)
2020-12-04 13:40:09 +03:00
try:
# Reference(s): https://askubuntu.com/a/1263098
# https://askubuntu.com/a/1250807
_contexts[protocol].set_ciphers("DEFAULT@SECLEVEL=1")
except ssl.SSLError:
pass
2022-11-02 01:26:15 +03:00
result = _contexts[protocol].wrap_socket(sock, do_handshake_on_connect=True, server_hostname=self.host if re.search(r"\A[\d.]+\Z", self.host or "") is None else None)
2020-04-07 03:07:54 +03:00
if result:
2015-06-01 11:45:16 +03:00
success = True
2020-04-07 03:07:54 +03:00
self.sock = result
2015-06-01 11:45:16 +03:00
_protocols.remove(protocol)
_protocols.insert(0, protocol)
break
else:
sock.close()
except (ssl.SSLError, socket.error, _http_client.BadStatusLine) as ex:
2015-06-01 11:45:16 +03:00
self._tunnel_host = None
2019-11-09 01:45:30 +03:00
logger.debug("SSL connection error occurred for '%s' ('%s')" % (_lut[protocol], getSafeExString(ex)))
2015-06-01 11:45:16 +03:00
2022-11-02 01:26:15 +03:00
elif hasattr(ssl, "wrap_socket"):
2015-11-25 15:04:34 +03:00
for protocol in _protocols:
2015-06-01 11:45:16 +03:00
try:
sock = create_sock()
2022-11-22 02:28:20 +03:00
_ = ssl.wrap_socket(sock, keyfile=getattr(self, "key_file"), certfile=getattr(self, "cert_file"), ssl_version=protocol)
2015-06-01 11:45:16 +03:00
if _:
2015-11-25 15:04:34 +03:00
success = True
2015-06-01 11:45:16 +03:00
self.sock = _
_protocols.remove(protocol)
_protocols.insert(0, protocol)
break
else:
sock.close()
except (ssl.SSLError, socket.error, _http_client.BadStatusLine) as ex:
2015-06-01 11:45:16 +03:00
self._tunnel_host = None
2019-11-09 01:45:30 +03:00
logger.debug("SSL connection error occurred for '%s' ('%s')" % (_lut[protocol], getSafeExString(ex)))
2012-06-04 23:46:28 +04:00
if not success:
errMsg = "can't establish SSL connection"
2016-08-02 13:38:57 +03:00
# Reference: https://docs.python.org/2/library/ssl.html
2021-10-07 01:29:31 +03:00
if LooseVersion(PYVERSION) < LooseVersion("2.7.9"):
2016-08-02 13:38:57 +03:00
errMsg += " (please retry with Python >= 2.7.9)"
2020-08-23 23:11:24 +03:00
if kb.sslSuccess and not self.retrying:
self.retrying = True
for _ in xrange(conf.retries):
try:
self.connect()
except SqlmapConnectionException:
pass
else:
return
raise SqlmapConnectionException(errMsg)
2020-08-23 23:11:24 +03:00
else:
kb.sslSuccess = True
2012-06-04 23:46:28 +04:00
class HTTPSHandler(_urllib.request.HTTPSHandler):
2012-06-04 23:46:28 +04:00
def https_open(self, req):
return self.do_open(HTTPSConnection if ssl else _http_client.HTTPSConnection, req)