|
33 | 33 | OPCODE_PING, |
34 | 34 | OPCODE_CLOSE, |
35 | 35 | ) |
| 36 | +from lib.request.connect import Connect |
| 37 | + |
| 38 | +_GET_PAGE = Connect.__dict__["getPage"] |
36 | 39 |
|
37 | 40 |
|
38 | 41 | class _FakeSock(object): |
@@ -162,6 +165,88 @@ def sendall(self, data): |
162 | 165 | finally: |
163 | 166 | W.socket.create_connection = original |
164 | 167 |
|
| 168 | + def test_getpage_preserves_host_header(self): |
| 169 | + import socket |
| 170 | + import tempfile |
| 171 | + import lib.request.websocket as W |
| 172 | + from lib.core.data import conf, kb |
| 173 | + from lib.core.option import _setKnowledgeBaseAttributes |
| 174 | + from lib.core.threads import getCurrentThreadData |
| 175 | + |
| 176 | + class _HandshakeSock(_FakeSock): |
| 177 | + def __init__(self): |
| 178 | + _FakeSock.__init__(self) |
| 179 | + self.handshake = None |
| 180 | + self.response = b"" |
| 181 | + |
| 182 | + def settimeout(self, value): |
| 183 | + pass |
| 184 | + |
| 185 | + def sendall(self, data): |
| 186 | + if self.handshake is None: |
| 187 | + self.handshake = data |
| 188 | + key = next(line.split(b":", 1)[1].strip() for line in data.split(b"\r\n") if line.lower().startswith(b"sec-websocket-key:")) |
| 189 | + accept = base64.b64encode(hashlib.sha1(key + _GUID.encode("ascii")).digest()) |
| 190 | + self.response = b"HTTP/1.1 101 Switching Protocols\r\nSec-WebSocket-Accept: " + accept + b"\r\n\r\n" + _serverFrame("ok") |
| 191 | + |
| 192 | + def recv(self, size): |
| 193 | + result, self.response = self.response[:size], self.response[size:] |
| 194 | + return result |
| 195 | + |
| 196 | + sockets = [] |
| 197 | + def create_socket(*args, **kwargs): |
| 198 | + sock = _HandshakeSock() |
| 199 | + sockets.append(sock) |
| 200 | + return sock |
| 201 | + |
| 202 | + oldConf, oldKb = dict(conf), dict(kb) |
| 203 | + threadData = getCurrentThreadData() |
| 204 | + oldThreadData = dict(threadData.__dict__) |
| 205 | + oldTimeout = socket.getdefaulttimeout() |
| 206 | + original = W.socket.create_connection |
| 207 | + oldGetPage = Connect.__dict__["getPage"] |
| 208 | + fd, headersFile = tempfile.mkstemp(prefix="sqlmap-ws-headers-") |
| 209 | + try: |
| 210 | + with os.fdopen(fd, "w") as f: |
| 211 | + f.write("hOsT: file.example\n") |
| 212 | + threadData.__dict__.clear() |
| 213 | + threadData.reset() |
| 214 | + _setKnowledgeBaseAttributes(False) |
| 215 | + kb.wizardMode, kb.webSocketRecvCount = True, 1 |
| 216 | + conf.url = "ws://example.test:8080/test" |
| 217 | + conf.hostname, conf.scheme, conf.port, conf.path = "example.test", "ws", 8080, "/test" |
| 218 | + conf.parameters, conf.data = {}, None |
| 219 | + conf.abortCode, conf.ignoreCode = [], [] |
| 220 | + conf.timeout, conf.batch, conf.keepAlive = 3, True, False |
| 221 | + conf.retryOn, conf.ignoreRedirects, conf.scope = None, False, None |
| 222 | + W.socket.create_connection = create_socket |
| 223 | + Connect.getPage = _GET_PAGE |
| 224 | + cases = ( |
| 225 | + ("ws://example.test:8080/test", [], None, None, None, False, "example.test:8080"), |
| 226 | + ("ws://user:pass@example.test:8080/test", [], None, None, None, False, "example.test:8080"), |
| 227 | + ("ws://example.test:8080/test", [('hOsT', 'configured.example')], None, None, None, False, "configured.example"), |
| 228 | + ("ws://example.test:8080/test", [('Host', 'configured.example')], "override.example:8443", None, None, False, "override.example:8443"), |
| 229 | + ("ws://example.test:8080/test", [], None, {'Host': 'aux.example'}, None, False, "aux.example"), |
| 230 | + ("ws://example.test:8080/test", [], None, None, headersFile, False, "file.example"), |
| 231 | + ("ws://example.test:8080/test", [], None, None, None, True, "localhost"), |
| 232 | + ) |
| 233 | + for url, headers, host, aux, path, localhost, expected in cases: |
| 234 | + conf.url = url |
| 235 | + conf.httpHeaders = headers |
| 236 | + conf.localhost, kb.headersFile = localhost, path |
| 237 | + self.assertEqual(Connect.getPage(url=url, host=host, auxHeaders=aux)[0], "ok") |
| 238 | + hostLines = [line for line in sockets[-1].handshake.split(b"\r\n") if line.lower().startswith(b"host:")] |
| 239 | + self.assertEqual(len(hostLines), 1) |
| 240 | + self.assertEqual(hostLines[0].split(b":", 1)[1].strip(), expected.encode("ascii")) |
| 241 | + finally: |
| 242 | + Connect.getPage = oldGetPage |
| 243 | + W.socket.create_connection = original |
| 244 | + socket.setdefaulttimeout(oldTimeout) |
| 245 | + conf.clear(); conf.update(oldConf) |
| 246 | + kb.clear(); kb.update(oldKb) |
| 247 | + threadData.__dict__.clear(); threadData.__dict__.update(oldThreadData) |
| 248 | + os.unlink(headersFile) |
| 249 | + |
165 | 250 |
|
166 | 251 | if __name__ == "__main__": |
167 | 252 | unittest.main() |
0 commit comments