sqlmap/lib/request/httpshandler.py
Miroslav Stampar 9a87f47777 Trivial updates
2024-06-26 13:21:01 +02:00

139 lines
5.7 KiB
Python

#!/usr/bin/env python
"""
Copyright (c) 2006-2024 sqlmap developers (https://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
import re
import socket
from lib.core.common import filterNone
from lib.core.common import getSafeExString
from lib.core.compat import LooseVersion
from lib.core.compat import xrange
from lib.core.data import conf
from lib.core.data import kb
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
ssl = None
try:
import ssl as _ssl
ssl = _ssl
except ImportError:
pass
_protocols = filterNone(getattr(ssl, _, None) for _ in ("PROTOCOL_TLS_CLIENT", "PROTOCOL_TLSv1_2", "PROTOCOL_TLSv1_1", "PROTOCOL_TLSv1", "PROTOCOL_SSLv3", "PROTOCOL_SSLv23", "PROTOCOL_SSLv2"))
_lut = dict((getattr(ssl, _), _) for _ in dir(ssl) if _.startswith("PROTOCOL_"))
_contexts = {}
class HTTPSConnection(_http_client.HTTPSConnection):
"""
Connection class that enables usage of newer SSL protocols.
Reference: http://bugs.python.org/msg128686
NOTE: use https://check-tls.akamaized.net/ to check if (e.g.) TLS/SNI is working properly
"""
def __init__(self, *args, **kwargs):
# 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]
self.retrying = False
_http_client.HTTPSConnection.__init__(self, *args, **kwargs)
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
# 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
if hasattr(ssl, "SSLContext"):
for protocol in (_ for _ in _protocols if _ >= ssl.PROTOCOL_TLSv1):
try:
sock = create_sock()
if protocol not in _contexts:
_contexts[protocol] = ssl.SSLContext(protocol)
# Disable certificate and hostname validation enabled by default with PROTOCOL_TLS_CLIENT
_contexts[protocol].check_hostname = False
_contexts[protocol].verify_mode = ssl.CERT_NONE
if getattr(self, "cert_file", None) and getattr(self, "key_file", None):
_contexts[protocol].load_cert_chain(certfile=self.cert_file, keyfile=self.key_file)
try:
# Reference(s): https://askubuntu.com/a/1263098
# https://askubuntu.com/a/1250807
_contexts[protocol].set_ciphers("DEFAULT@SECLEVEL=1")
except (ssl.SSLError, AttributeError):
pass
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)
if result:
success = True
self.sock = result
_protocols.remove(protocol)
_protocols.insert(0, protocol)
break
else:
sock.close()
except (ssl.SSLError, socket.error, _http_client.BadStatusLine) as ex:
self._tunnel_host = None
logger.debug("SSL connection error occurred for '%s' ('%s')" % (_lut[protocol], getSafeExString(ex)))
elif hasattr(ssl, "wrap_socket"):
for protocol in _protocols:
try:
sock = create_sock()
_ = ssl.wrap_socket(sock, keyfile=getattr(self, "key_file"), certfile=getattr(self, "cert_file"), ssl_version=protocol)
if _:
success = True
self.sock = _
_protocols.remove(protocol)
_protocols.insert(0, protocol)
break
else:
sock.close()
except (ssl.SSLError, socket.error, _http_client.BadStatusLine) as ex:
self._tunnel_host = None
logger.debug("SSL connection error occurred for '%s' ('%s')" % (_lut[protocol], getSafeExString(ex)))
if not success:
errMsg = "can't establish SSL connection"
# Reference: https://docs.python.org/2/library/ssl.html
if LooseVersion(PYVERSION) < LooseVersion("2.7.9"):
errMsg += " (please retry with Python >= 2.7.9)"
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)
else:
kb.sslSuccess = True
class HTTPSHandler(_urllib.request.HTTPSHandler):
def https_open(self, req):
return self.do_open(HTTPSConnection if ssl else _http_client.HTTPSConnection, req)