diff options
author | Eli Collins <elic@assurancetechnologies.com> | 2012-03-10 17:35:11 -0500 |
---|---|---|
committer | Eli Collins <elic@assurancetechnologies.com> | 2012-03-10 17:35:11 -0500 |
commit | 50965db6ee2b6ff2c9227ea6c740e9513963c4f6 (patch) | |
tree | 6b40f902cd587ac7a431af2bc79778fea808053a /passlib | |
parent | e84f3f69e55f407a935e9f80c7e41d81b3ea63b7 (diff) | |
download | passlib-50965db6ee2b6ff2c9227ea6c740e9513963c4f6.tar.gz |
added Window's DCC hashes (aka mscache / mscash) version 1 & 2
Diffstat (limited to 'passlib')
-rw-r--r-- | passlib/handlers/windows.py (renamed from passlib/handlers/nthash.py) | 97 | ||||
-rw-r--r-- | passlib/registry.py | 8 | ||||
-rw-r--r-- | passlib/tests/test_handlers.py | 93 |
3 files changed, 194 insertions, 4 deletions
diff --git a/passlib/handlers/nthash.py b/passlib/handlers/windows.py index e1ad34f..e4a5199 100644 --- a/passlib/handlers/nthash.py +++ b/passlib/handlers/windows.py @@ -1,4 +1,4 @@ -"""passlib.handlers.nthash - unix-crypt compatible nthash passwords""" +"""passlib.handlers.nthash - Microsoft Windows -related hashes""" #========================================================= #imports #========================================================= @@ -19,6 +19,8 @@ __all__ = [ "lmhash", "nthash", "bsd_nthash", + "msdcc", + "msdcc2", ] #========================================================= @@ -220,5 +222,98 @@ bsd_nthash = uh.PrefixWrapper("bsd_nthash", nthash, prefix="$3$$", ident="$3$$", ## return lmhash.verify(secret, lm) or nthash.verify(secret, nt) #========================================================= +# msdcc v1 +#========================================================= +class msdcc(uh.HasUserContext, uh.StaticHandler): + """This class implements Microsoft's Domain Cached Credentials password hash, + and follows the :ref:`password-hash-api`. + + It has a fixed number of rounds, and uses the associated + username as the salt. + + The :meth:`encrypt()`, :meth:`genhash()`, and :meth:`verify()` methods + have the following optional keywords: + + :param user: + String containing name of user account this password is associated with. + This is required to properly calculate the hash. + + This keyword is case-insensitive, and should contain just the username + (e.g. ``Administrator``, not ``SOMEDOMAIN\\Administrator``). + + Note that while this class outputs lower-case hexidecimal digests, + it will accept upper-case digests as well. + """ + name = "msdcc" + checksum_chars = uh.HEX_CHARS + checksum_size = 32 + + @classmethod + def _norm_hash(cls, hash): + return hash.lower() + + def _calc_checksum(self, secret): + return hexlify(self.raw(secret, self.user)).decode("ascii") + + @classmethod + def raw(cls, secret, user): + """encode password using mscash v1 algorithm + + :arg secret: secret as unicode or utf-8 encoded bytes + :arg user: username to use as salt + + :returns: returns string of raw bytes + """ + secret = to_unicode(secret, "utf-8", errname="secret").encode("utf-16-le") + user = to_unicode(user, "utf-8", errname="user").lower().encode("utf-16-le") + return md4(md4(secret).digest() + user).digest() + +#========================================================= +# msdcc2 aka mscash2 +#========================================================= +class msdcc2(uh.HasUserContext, uh.StaticHandler): + """This class implements version 2 of Microsoft's Domain Cached Credentials + password hash, and follows the :ref:`password-hash-api`. + + It has a fixed number of rounds, and uses the associated + username as the salt. + + The :meth:`encrypt()`, :meth:`genhash()`, and :meth:`verify()` methods + have the following extra keyword: + + :param user: + String containing name of user account this password is associated with. + This is required to properly calculate the hash. + + This keyword is case-insensitive, and should contain just the username + (e.g. ``Administrator``, not ``SOMEDOMAIN\\Administrator``). + """ + name = "msdcc2" + checksum_chars = uh.HEX_CHARS + checksum_size = 32 + + @classmethod + def _norm_hash(cls, hash): + return hash.lower() + + def _calc_checksum(self, secret): + return hexlify(self.raw(secret, self.user)).decode("ascii") + + @classmethod + def raw(cls, secret, user): + """encode password using msdcc v2 algorithm + + :arg secret: secret as unicode or utf-8 encoded bytes + :arg user: username to use as salt + + :returns: returns string of raw bytes + """ + from passlib.utils.pbkdf2 import pbkdf2 + secret = to_unicode(secret, "utf-8", errname="secret").encode("utf-16-le") + user = to_unicode(user, "utf-8", errname="user").lower().encode("utf-16-le") + tmp = md4(md4(secret).digest() + user).digest() + return pbkdf2(tmp, user, 10240, 16, 'hmac-sha1') + +#========================================================= #eof #========================================================= diff --git a/passlib/registry.py b/passlib/registry.py index e39a45d..bf252fd 100644 --- a/passlib/registry.py +++ b/passlib/registry.py @@ -84,7 +84,7 @@ _handler_locations = { ("passlib.handlers.pbkdf2", "atlassian_pbkdf2_sha1"), "bcrypt": ("passlib.handlers.bcrypt", "bcrypt"), "bigcrypt": ("passlib.handlers.des_crypt", "bigcrypt"), - "bsd_nthash": ("passlib.handlers.nthash", "bsd_nthash"), + "bsd_nthash": ("passlib.handlers.windows", "bsd_nthash"), "bsdi_crypt": ("passlib.handlers.des_crypt", "bsdi_crypt"), "cisco_pix": ("passlib.handlers.cisco", "cisco_pix"), "cisco_type7": ("passlib.handlers.cisco", "cisco_type7"), @@ -124,13 +124,15 @@ _handler_locations = { ("passlib.handlers.pbkdf2", "ldap_pbkdf2_sha256"), "ldap_pbkdf2_sha512": ("passlib.handlers.pbkdf2", "ldap_pbkdf2_sha512"), - "lmhash": ("passlib.handlers.nthash", "lmhash"), + "lmhash": ("passlib.handlers.windows", "lmhash"), "md5_crypt": ("passlib.handlers.md5_crypt", "md5_crypt"), + "msdcc": ("passlib.handlers.windows", "msdcc"), + "msdcc2": ("passlib.handlers.windows", "msdcc2"), "mssql2000": ("passlib.handlers.mssql", "mssql2000"), "mssql2005": ("passlib.handlers.mssql", "mssql2005"), "mysql323": ("passlib.handlers.mysql", "mysql323"), "mysql41": ("passlib.handlers.mysql", "mysql41"), - "nthash": ("passlib.handlers.nthash", "nthash"), + "nthash": ("passlib.handlers.windows", "nthash"), "oracle10": ("passlib.handlers.oracle", "oracle10"), "oracle11": ("passlib.handlers.oracle", "oracle11"), "pbkdf2_sha1": ("passlib.handlers.pbkdf2", "pbkdf2_sha1"), diff --git a/passlib/tests/test_handlers.py b/passlib/tests/test_handlers.py index d0555f3..260d011 100644 --- a/passlib/tests/test_handlers.py +++ b/passlib/tests/test_handlers.py @@ -951,6 +951,99 @@ os_crypt_md5_crypt_test = create_backend_case(_md5_crypt_test, "os_crypt") builtin_md5_crypt_test = create_backend_case(_md5_crypt_test, "builtin") #========================================================= +# msdcc 1 & 2 +#========================================================= +class msdcc_test(UserHandlerMixin, HandlerCase): + handler = hash.msdcc + user_case_insensitive = True + + known_correct_hashes = [ + + # + # http://www.jedge.com/wordpress/windows-password-cache/ + # + (("Asdf999", "sevans"), "b1176c2587478785ec1037e5abc916d0"), + + # + # http://infosecisland.com/blogview/12156-Cachedump-for-Meterpreter-in-Action.html + # + (("ASDqwe123", "jdoe"), "592cdfbc3f1ef77ae95c75f851e37166"), + + # + # http://comments.gmane.org/gmane.comp.security.openwall.john.user/1917 + # + (("test1", "test1"), "64cd29e36a8431a2b111378564a10631"), + (("test2", "test2"), "ab60bdb4493822b175486810ac2abe63"), + (("test3", "test3"), "14dd041848e12fc48c0aa7a416a4a00c"), + (("test4", "test4"), "b945d24866af4b01a6d89b9d932a153c"), + + # + # http://ciscoit.wordpress.com/2011/04/13/metasploit-hashdump-vs-cachedump/ + # + (("1234qwer!@#$", "Administrator"), "7b69d06ef494621e3f47b9802fe7776d"), + + # + # http://www.securiteam.com/tools/5JP0I2KFPA.html + # + (("password", "user"), "2d9f0b052932ad18b87f315641921cda"), + + # + # from JTR 1.7.9 + # + (("", "root"), "176a4c2bd45ac73687676c2f09045353"), + (("test1", "TEST1"), "64cd29e36a8431a2b111378564a10631"), + (("okolada", "nineteen_characters"), "290efa10307e36a79b3eebf2a6b29455"), + ((u("\u00FC"), u("\u00FC")), "48f84e6f73d6d5305f6558a33fa2c9bb"), + ((u("\u00FC\u00FC"), u("\u00FC\u00FC")), "593246a8335cf0261799bda2a2a9c623"), + ((u("\u20AC\u20AC"), "user"), "9121790702dda0fa5d353014c334c2ce"), + + # + # custom + # + + # ensures utf-8 used for unicode + ((UPASS_TABLE, 'bob'), 'fcb82eb4212865c7ac3503156ca3f349'), + ] + + known_alternate_hashes = [ + # check uppercase accepted. + ("B1176C2587478785EC1037E5ABC916D0", ("Asdf999", "sevans"), + "b1176c2587478785ec1037e5abc916d0"), + ] + +class msdcc2_test(UserHandlerMixin, HandlerCase): + handler = hash.msdcc2 + user_case_insensitive = True + + known_correct_hashes = [ + # + # from JTR 1.7.9 + # + (("test1", "test1"), "607bbe89611e37446e736f7856515bf8"), + (("qerwt", "Joe"), "e09b38f84ab0be586b730baf61781e30"), + (("12345", "Joe"), "6432f517a900b3fc34ffe57f0f346e16"), + (("", "bin"), "c0cbe0313a861062e29f92ede58f9b36"), + (("w00t", "nineteen_characters"), "87136ae0a18b2dafe4a41d555425b2ed"), + (("w00t", "eighteencharacters"), "fc5df74eca97afd7cd5abb0032496223"), + (("longpassword", "twentyXXX_characters"), "cfc6a1e33eb36c3d4f84e4c2606623d2"), + (("longpassword", "twentyoneX_characters"), "99ff74cea552799da8769d30b2684bee"), + (("longpassword", "twentytwoXX_characters"), "0a721bdc92f27d7fb23b87a445ec562f"), + (("test2", "TEST2"), "c6758e5be7fc943d00b97972a8a97620"), + (("test3", "test3"), "360e51304a2d383ea33467ab0b639cc4"), + (("test4", "test4"), "6f79ee93518306f071c47185998566ae"), + ((u("\u00FC"), "joe"), "bdb80f2c4656a8b8591bd27d39064a54"), + ((u("\u20AC\u20AC"), "joe"), "1e1e20f482ff748038e47d801d0d1bda"), + ((u("\u00FC\u00FC"), "admin"), "0839e4a07c00f18a8c65cf5b985b9e73"), + + # + # custom + # + + # custom unicode test + ((UPASS_TABLE, 'bob'), 'cad511dc9edefcf69201da72efb6bb55'), + ] + +#========================================================= # mssql 2000 & 2005 #========================================================= class mssql2000_test(HandlerCase): |