diff --git a/lib/core/settings.py b/lib/core/settings.py index ef951e649..e8d6d729d 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -20,7 +20,7 @@ from lib.core.enums import OS from thirdparty import six # sqlmap version (...) -VERSION = "1.10.7.138" +VERSION = "1.10.7.139" 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) diff --git a/lib/request/basic.py b/lib/request/basic.py index 5cddbd983..8ea3f750a 100644 --- a/lib/request/basic.py +++ b/lib/request/basic.py @@ -108,7 +108,10 @@ def forgeHeaders(items=None, base=None): if conf.cj: if HTTP_HEADER.COOKIE in headers: for cookie in conf.cj: - if cookie is None or cookie.domain_specified and not (conf.hostname or "").endswith(cookie.domain): + # Note: a domain-scoped cookie (Domain=example.com) is stored by the cookie jar as + # '.example.com', so a plain endswith() wrongly excludes the apex host itself + # ('example.com' does not end with '.example.com'); accept the exact domain too + if cookie is None or cookie.domain_specified and not ((conf.hostname or "").endswith(cookie.domain) or (conf.hostname or "") == cookie.domain.lstrip('.')): continue if ("%s=" % getUnicode(cookie.name)) in getUnicode(headers[HTTP_HEADER.COOKIE]): diff --git a/tests/test_request_basic.py b/tests/test_request_basic.py index 14977489b..29dc53c2a 100644 --- a/tests/test_request_basic.py +++ b/tests/test_request_basic.py @@ -84,5 +84,59 @@ class TestBasicDecodePage(unittest.TestCase): self.assertEqual(getText(decodePage(b"", None, "text/html")), "") +class TestForgeHeadersCookieMerge(unittest.TestCase): + """A domain-scoped jar cookie (Domain=example.com -> '.example.com') must merge into the + request for the apex host, not be dropped by a naive endswith() domain check.""" + + _CONF = ("cj", "hostname", "httpHeaders", "loadCookies", "cookieDel", "parameters", "csrfToken", "safeUrl") + _KB = ("mergeCookies", "testMode", "injection") + + def setUp(self): + self._c = dict((k, conf.get(k)) for k in self._CONF) + self._k = dict((k, kb.get(k)) for k in self._KB) + + def tearDown(self): + for k, v in self._c.items(): + conf[k] = v + for k, v in self._k.items(): + kb[k] = v + + def _jar_with_domain_cookie(self): + try: + from http.cookiejar import CookieJar, Cookie + except ImportError: + from cookielib import CookieJar, Cookie + # a domain-scoped cookie the jar stores as '.example.com' (domain_specified=True), + # exactly as it would after Set-Cookie: sid=NEW; Domain=example.com + cookie = Cookie(version=0, name="sid", value="NEW", port=None, port_specified=False, + domain=".example.com", domain_specified=True, domain_initial_dot=True, + path="/", path_specified=True, secure=False, expires=None, discard=True, + comment=None, comment_url=None, rest={}) + cj = CookieJar() + cj.set_cookie(cookie) + return cj + + def test_domain_cookie_merged_on_apex_host(self): + from lib.request.basic import forgeHeaders + from lib.core.enums import PLACE, HTTP_HEADER + from lib.core.datatype import AttribDict + + conf.cj = self._jar_with_domain_cookie() + conf.hostname = "example.com" # apex host == cookie domain + conf.httpHeaders = [(HTTP_HEADER.COOKIE, "sid=OLD")] + conf.loadCookies = False + conf.cookieDel = None + conf.parameters = {} + conf.csrfToken = conf.safeUrl = None + kb.mergeCookies = True + kb.testMode = False + kb.injection = AttribDict() + kb.injection.place = PLACE.GET + + headers = forgeHeaders() + # before the fix the domain cookie was skipped for the apex host, leaving 'sid=OLD' + self.assertEqual(headers.get(HTTP_HEADER.COOKIE), "sid=NEW") + + if __name__ == "__main__": unittest.main(verbosity=2)