Skip to content

Commit

Permalink
Implement experimental --http2 (#4402)
Browse files Browse the repository at this point in the history
  • Loading branch information
stamparm authored and tanaydin committed Feb 20, 2025
1 parent 27dc8a9 commit 1a5e316
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 8 deletions.
1 change: 1 addition & 0 deletions lib/core/optiondict.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"liveCookies": "string",
"loadCookies": "string",
"dropSetCookie": "boolean",
"http2": "boolean",
"agent": "string",
"mobile": "boolean",
"randomAgent": "boolean",
Expand Down
2 changes: 1 addition & 1 deletion lib/core/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
from thirdparty import six

# sqlmap version (<major>.<minor>.<month>.<monthly commit>)
VERSION = "1.9.2.9"
VERSION = "1.9.2.10"
TYPE = "dev" if VERSION.count('.') > 2 and VERSION.split('.')[-1] != '0' else "stable"
TYPE_COLORS = {"dev": 33, "stable": 90, "pip": 34}
VERSION_STRING = "sqlmap/%s#%s" % ('.'.join(VERSION.split('.')[:-1]) if VERSION.count('.') > 2 and VERSION.split('.')[-1] == '0' else VERSION, TYPE)
Expand Down
3 changes: 3 additions & 0 deletions lib/parse/cmdline.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,9 @@ def cmdLineParser(argv=None):
request.add_argument("--drop-set-cookie", dest="dropSetCookie", action="store_true",
help="Ignore Set-Cookie header from response")

request.add_argument("--http2", dest="http2", action="store_true",
help="Use HTTP version 2 (experimental)")

request.add_argument("--mobile", dest="mobile", action="store_true",
help="Imitate smartphone through HTTP User-Agent header")

Expand Down
49 changes: 42 additions & 7 deletions lib/request/connect.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ class WebSocketException(Exception):
from lib.core.exception import SqlmapCompressionException
from lib.core.exception import SqlmapConnectionException
from lib.core.exception import SqlmapGenericException
from lib.core.exception import SqlmapMissingDependence
from lib.core.exception import SqlmapSkipTargetException
from lib.core.exception import SqlmapSyntaxException
from lib.core.exception import SqlmapTokenException
Expand Down Expand Up @@ -603,11 +604,6 @@ class _(dict):
if not chunked:
requestMsg += "\r\n"

if not multipart:
threadData.lastRequestMsg = requestMsg

logger.log(CUSTOM_LOGGING.TRAFFIC_OUT, requestMsg)

if conf.cj:
for cookie in conf.cj:
if cookie.value is None:
Expand All @@ -616,7 +612,46 @@ class _(dict):
for char in (r"\r", r"\n"):
cookie.value = re.sub(r"(%s)([^ \t])" % char, r"\g<1>\t\g<2>", cookie.value)

conn = _urllib.request.urlopen(req)
if conf.http2:
try:
import httpx
with httpx.Client(verify=False, http2=True, timeout=timeout, follow_redirects=True, cookies=conf.cj) as client:
conn = client.request(method or (HTTPMETHOD.POST if post is not None else HTTPMETHOD.GET), url, headers=headers, data=post)
except ImportError:
raise SqlmapMissingDependence("httpx[http2] not available (e.g. 'pip%s install httpx[http2]')" % ('3' if six.PY3 else ""))
else:
conn.code = conn.status_code
conn.msg = conn.reason_phrase
conn.info = lambda c=conn: c.headers

conn._read_buffer = conn.read()
conn._read_offset = 0

requestMsg = re.sub(" HTTP/[0-9.]+\r\n", " %s\r\n" % conn.http_version, requestMsg, count=1)

if not multipart:
threadData.lastRequestMsg = requestMsg

logger.log(CUSTOM_LOGGING.TRAFFIC_OUT, requestMsg)

def _read(count=None):
offset = conn._read_offset
if count is None:
result = conn._read_buffer[offset:]
conn._read_offset = len(conn._read_buffer)
else:
result = conn._read_buffer[offset: offset + count]
conn._read_offset += len(result)
return result

conn.read = _read
else:
if not multipart:
threadData.lastRequestMsg = requestMsg

logger.log(CUSTOM_LOGGING.TRAFFIC_OUT, requestMsg)

conn = _urllib.request.urlopen(req)

if not kb.authHeader and getRequestHeader(req, HTTP_HEADER.AUTHORIZATION) and (conf.authType or "").lower() == AUTH_TYPE.BASIC.lower():
kb.authHeader = getUnicode(getRequestHeader(req, HTTP_HEADER.AUTHORIZATION))
Expand Down Expand Up @@ -699,7 +734,7 @@ class _(dict):
# Explicit closing of connection object
if conn and not conf.keepAlive:
try:
if hasattr(conn.fp, '_sock'):
if hasattr(conn, "fp") and hasattr(conn.fp, '_sock'):
conn.fp._sock.close()
conn.close()
except Exception as ex:
Expand Down
10 changes: 10 additions & 0 deletions lib/utils/deps.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,16 @@ def checkDependencies():
logger.warning(warnMsg)
missing_libraries.add('python-ntlm')

try:
__import__("httpx")
debugMsg = "'httpx[http2]' third-party library is found"
logger.debug(debugMsg)
except ImportError:
warnMsg = "sqlmap requires 'httpx[http2]' third-party library "
warnMsg += "if you plan to use HTTP version 2"
logger.warning(warnMsg)
missing_libraries.add('httpx[http2]')

try:
__import__("websocket._abnf")
debugMsg = "'websocket-client' library is found"
Expand Down
4 changes: 4 additions & 0 deletions sqlmap.conf
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ loadCookies =
# Valid: True or False
dropSetCookie = False

# Use HTTP version 2 (experimental).
# Valid: True or False
http2 = False

# HTTP User-Agent header value. Useful to fake the HTTP User-Agent header value
# at each HTTP request.
# sqlmap will also test for SQL injection on the HTTP User-Agent value.
Expand Down

0 comments on commit 1a5e316

Please sign in to comment.