Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sqlmapproject
GitHub Repository: sqlmapproject/sqlmap
Path: blob/master/lib/request/redirecthandler.py
3556 views
1
#!/usr/bin/env python
2
3
"""
4
Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org)
5
See the file 'LICENSE' for copying permission
6
"""
7
8
import io
9
import re
10
import time
11
import types
12
13
from lib.core.common import getHostHeader
14
from lib.core.common import getSafeExString
15
from lib.core.common import logHTTPTraffic
16
from lib.core.common import readInput
17
from lib.core.convert import getBytes
18
from lib.core.convert import getUnicode
19
from lib.core.data import conf
20
from lib.core.data import kb
21
from lib.core.data import logger
22
from lib.core.enums import CUSTOM_LOGGING
23
from lib.core.enums import HTTP_HEADER
24
from lib.core.enums import HTTPMETHOD
25
from lib.core.enums import REDIRECTION
26
from lib.core.exception import SqlmapConnectionException
27
from lib.core.settings import DEFAULT_COOKIE_DELIMITER
28
from lib.core.settings import MAX_CONNECTION_READ_SIZE
29
from lib.core.settings import MAX_CONNECTION_TOTAL_SIZE
30
from lib.core.settings import MAX_SINGLE_URL_REDIRECTIONS
31
from lib.core.settings import MAX_TOTAL_REDIRECTIONS
32
from lib.core.threads import getCurrentThreadData
33
from lib.request.basic import decodePage
34
from lib.request.basic import parseResponse
35
from thirdparty import six
36
from thirdparty.six.moves import http_client as _http_client
37
from thirdparty.six.moves import urllib as _urllib
38
39
class SmartRedirectHandler(_urllib.request.HTTPRedirectHandler):
40
def _get_header_redirect(self, headers):
41
retVal = None
42
43
if headers:
44
if HTTP_HEADER.LOCATION in headers:
45
retVal = headers[HTTP_HEADER.LOCATION]
46
elif HTTP_HEADER.URI in headers:
47
retVal = headers[HTTP_HEADER.URI]
48
49
return retVal
50
51
def _ask_redirect_choice(self, redcode, redurl, method):
52
with kb.locks.redirect:
53
if kb.choices.redirect is None:
54
msg = "got a %d redirect to " % redcode
55
msg += "'%s'. Do you want to follow? [Y/n] " % redurl
56
57
kb.choices.redirect = REDIRECTION.YES if readInput(msg, default='Y', boolean=True) else REDIRECTION.NO
58
59
if kb.choices.redirect == REDIRECTION.YES and method == HTTPMETHOD.POST and kb.resendPostOnRedirect is None:
60
msg = "redirect is a result of a "
61
msg += "POST request. Do you want to "
62
msg += "resend original POST data to a new "
63
msg += "location? [%s] " % ("Y/n" if not kb.originalPage else "y/N")
64
65
kb.resendPostOnRedirect = readInput(msg, default=('Y' if not kb.originalPage else 'N'), boolean=True)
66
67
if kb.resendPostOnRedirect:
68
self.redirect_request = self._redirect_request
69
70
def _redirect_request(self, req, fp, code, msg, headers, newurl):
71
retVal = _urllib.request.Request(newurl.replace(' ', '%20'), data=req.data, headers=req.headers, origin_req_host=req.get_origin_req_host() if hasattr(req, "get_origin_req_host") else req.origin_req_host)
72
73
if hasattr(req, "redirect_dict"):
74
retVal.redirect_dict = req.redirect_dict
75
76
return retVal
77
78
def http_error_302(self, req, fp, code, msg, headers):
79
start = time.time()
80
content = None
81
forceRedirect = False
82
redurl = self._get_header_redirect(headers) if not conf.ignoreRedirects else None
83
84
try:
85
content = fp.fp.read(MAX_CONNECTION_TOTAL_SIZE)
86
fp.fp = io.BytesIO(content)
87
except _http_client.IncompleteRead as ex:
88
content = ex.partial
89
fp.fp = io.BytesIO(content)
90
except:
91
content = b""
92
93
content = decodePage(content, headers.get(HTTP_HEADER.CONTENT_ENCODING), headers.get(HTTP_HEADER.CONTENT_TYPE))
94
95
threadData = getCurrentThreadData()
96
threadData.lastRedirectMsg = (threadData.lastRequestUID, content)
97
98
redirectMsg = "HTTP redirect "
99
redirectMsg += "[#%d] (%d %s):\r\n" % (threadData.lastRequestUID, code, getUnicode(msg))
100
101
if headers:
102
logHeaders = "\r\n".join("%s: %s" % (getUnicode(key.capitalize() if hasattr(key, "capitalize") else key), getUnicode(value)) for (key, value) in headers.items())
103
else:
104
logHeaders = ""
105
106
redirectMsg += logHeaders
107
if content:
108
redirectMsg += "\r\n\r\n%s" % getUnicode(content[:MAX_CONNECTION_READ_SIZE])
109
110
logHTTPTraffic(threadData.lastRequestMsg, redirectMsg, start, time.time())
111
logger.log(CUSTOM_LOGGING.TRAFFIC_IN, redirectMsg)
112
113
if redurl:
114
try:
115
if not _urllib.parse.urlsplit(redurl).netloc:
116
redurl = _urllib.parse.urljoin(req.get_full_url(), redurl)
117
118
self._infinite_loop_check(req)
119
if conf.scope:
120
if not re.search(conf.scope, redurl, re.I):
121
redurl = None
122
else:
123
forceRedirect = True
124
else:
125
self._ask_redirect_choice(code, redurl, req.get_method())
126
except ValueError:
127
redurl = None
128
result = fp
129
130
if redurl and (kb.choices.redirect == REDIRECTION.YES or forceRedirect):
131
parseResponse(content, headers)
132
133
req.headers[HTTP_HEADER.HOST] = getHostHeader(redurl)
134
if headers and HTTP_HEADER.SET_COOKIE in headers:
135
cookies = dict()
136
delimiter = conf.cookieDel or DEFAULT_COOKIE_DELIMITER
137
last = None
138
139
for part in getUnicode(req.headers.get(HTTP_HEADER.COOKIE, "")).split(delimiter) + ([headers[HTTP_HEADER.SET_COOKIE]] if HTTP_HEADER.SET_COOKIE in headers else []):
140
if '=' in part:
141
part = part.strip()
142
key, value = part.split('=', 1)
143
cookies[key] = value
144
last = key
145
elif last:
146
cookies[last] += "%s%s" % (delimiter, part)
147
148
req.headers[HTTP_HEADER.COOKIE] = delimiter.join("%s=%s" % (key, cookies[key]) for key in cookies)
149
150
try:
151
result = _urllib.request.HTTPRedirectHandler.http_error_302(self, req, fp, code, msg, headers)
152
except _urllib.error.HTTPError as ex:
153
result = ex
154
155
# Dirty hack for https://github.com/sqlmapproject/sqlmap/issues/4046
156
try:
157
hasattr(result, "read")
158
except KeyError:
159
class _(object):
160
pass
161
result = _()
162
163
# Dirty hack for http://bugs.python.org/issue15701
164
try:
165
result.info()
166
except AttributeError:
167
def _(self):
168
return getattr(self, "hdrs", {})
169
170
result.info = types.MethodType(_, result)
171
172
if not hasattr(result, "read"):
173
def _(self, length=None):
174
try:
175
retVal = getSafeExString(ex) # Note: pyflakes mistakenly marks 'ex' as undefined (NOTE: tested in both Python2 and Python3)
176
except:
177
retVal = ""
178
return getBytes(retVal)
179
180
result.read = types.MethodType(_, result)
181
182
if not getattr(result, "url", None):
183
result.url = redurl
184
185
if not getattr(result, "code", None):
186
result.code = 999
187
except:
188
redurl = None
189
result = fp
190
fp.read = io.BytesIO(b"").read
191
else:
192
result = fp
193
194
threadData.lastRedirectURL = (threadData.lastRequestUID, redurl)
195
196
result.redcode = code
197
result.redurl = getUnicode(redurl) if six.PY3 else redurl
198
return result
199
200
http_error_301 = http_error_303 = http_error_307 = http_error_308 = http_error_302
201
202
def _infinite_loop_check(self, req):
203
if hasattr(req, 'redirect_dict') and (req.redirect_dict.get(req.get_full_url(), 0) >= MAX_SINGLE_URL_REDIRECTIONS or len(req.redirect_dict) >= MAX_TOTAL_REDIRECTIONS):
204
errMsg = "infinite redirect loop detected (%s). " % ", ".join(item for item in req.redirect_dict.keys())
205
errMsg += "Please check all provided parameters and/or provide missing ones"
206
raise SqlmapConnectionException(errMsg)
207
208