Implement kpasswd
Implement the Kerberos Change Password and Set Password protocols. It fixes the second request of #1156.
As it is a completely different protocol than what smbpasswd.py is using, with different properties and constraints, I have created a new example script. It may be possible to merge the two, let me know if you would prefer it that way.
It differs from #1177 because it is not using SamrUnicodeChangePasswordUser2 to change the password, but the Kerberos Change Password protocol.
Seems to be not working correctly when using the KRB5CCNAME
root@ubuntu:~/impacket/examples# python3 kpasswd.py -ts -newpass 'ASDqwe123' SITTINGDUCK.INFO/uberuser
Impacket v0.9.25.dev1+20211027.123255.1dad8f7f - Copyright 2021 SecureAuth Corporation
[2021-11-03 02:57:56] [*] Current password not given: will use KRB5CCNAME
[2021-11-03 02:57:56] [*] Changing the password of \
Traceback (most recent call last):
File "kpasswd.py", line 141, in <module>
kpasswd.changePassword(newPassword)
File "kpasswd.py", line 59, in changePassword
changePassword(self.username, self.domain, newPassword, self.oldPassword, self.oldPwdHashLM, self.oldPwdHashNT, self.aesKey, kdcHost=self.kdcHost)
File "/usr/local/lib/python3.8/dist-packages/impacket-0.9.25.dev1+20211027.123255.1dad8f7f-py3.8.egg/impacket/krb5/kpasswd.py", line 278, in changePassword
setPassword(clientName, domain, None, None, *args, **kwargs)
File "/usr/local/lib/python3.8/dist-packages/impacket-0.9.25.dev1+20211027.123255.1dad8f7f-py3.8.egg/impacket/krb5/kpasswd.py", line 289, in setPassword
userName = Principal(clientName, type=PrincipalNameType.NT_PRINCIPAL.value)
File "/usr/local/lib/python3.8/dist-packages/impacket-0.9.25.dev1+20211027.123255.1dad8f7f-py3.8.egg/impacket/krb5/types.py", line 90, in __init__
raise KerberosException("invalid principal syntax")
impacket.krb5.types.KerberosException: invalid principal syntax
Klist:
root@ubuntu:~/impacket/examples# klist
Ticket cache: FILE:/tmp/krb5cc_0
Default principal: [email protected]
Valid starting Expires Service principal
11/03/21 02:24:45 11/03/21 12:24:45 krbtgt/[email protected]
renew until 11/04/21 02:24:43
Figured out the issue, target in the help needs to be updated:
positional arguments:
target [[domain/]username[:password]]
Where as the examples give an actual host for a target:
# kpasswd.py contoso.local/j.doe:'Passw0rd!'@DC1 -newpass 'N3wPassw0rd!'
Thanks for noticing that. The DC could be an optional parameter (it was originally but I changed to parse_target instead of parse_credentials, causing the bug). However, I think it is better to be coherent with smbpasswd parameters.
Rebasing to latest master as this PR received some attention for CVE-2022-32744
We should wait for https://github.com/fortra/impacket/pull/1177 to be merged before reviewing this pull request.
#1177 does not implement the same protocol. It uses SamrChangePasswordUser, with Kerberos autentication, whereas my PR implements the kpasswd protocol.
Some additional info here on the different protocols. Mine is 3. and 4., #1177 is 1.
fingers crossed to see this one added
Is there anything more I can do to help with the review of this PR, since it has been assigned?
Hello, sorry for the delayed response. Despite https://github.com/fortra/impacket/pull/1177 (which has to be merged), we are thinking to integrate all the PRs related to password change/reset (https://github.com/fortra/impacket/pull/1304, https://github.com/fortra/impacket/pull/1207, and this one) into one example like changepaswd.py or similar. Let us know your opinions on that. thanks!
Hello, Thanks for the answer!
If I understand correctly all these PR, we have:
- current smbpasswd.py functionality of using SAMR over SMB transport, using NTLM authentication
- #1177: adding Kerberos authentication, before continuing with SAMR over SMB transport
- #1304: using SAMR over MS-RPC transport, with NTLM authentication. I guess it could be compatible with Kerberos auth too.
- #1207: Adding "reset password" capability via SAMR over SMB transport. I think this one is a duplicate of what was implemented in #1171
- #1189 (this one): implementing a different password change protocol, kpassword. This one does not use SAMR at all and requires Kerberos authentication.
It would make sense from an exploitation perspective to regroup all of these similar features in the same script. However, from an example code perspective, the script would be harder to understand if not planned correctly, especially because we would mix 3 different transport protocols. Up to you to decide if you prefer focusing on "ease of use for attackers" or "clarity of example scripts for developers".
If you want to go ahead on a single "changepasswd.py" script that merge all these PR, I'd be happy to give it a try in a new PR if no one is already working on it. I'd suggest an interface like this one:
usage: changepasswd.py [-h] [-ts] [-debug] (-newpass NEWPASS | -newhashes LMHASH:NTHASH) [-hashes LMHASH:NTHASH] [-no-pass] [-k] [-aesKey hex key] [-altuser ALTUSER] [-altpass ALTPASS] [-althash ALTHASH]
[-protocol {smb-samr,rpc-samr,kpasswd}] [-reset] [-dc-ip ip address]
target
Change or reset password over different protocols.
positional arguments:
target [[domain/]username[:password]@]<targetName or address>
options:
-h, --help show this help message and exit
-ts adds timestamp to every logging output
-debug turn DEBUG output ON
-newpass NEWPASS new password
-newhashes LMHASH:NTHASH
new NTLM hashes, format is LMHASH:NTHASH
Authentication (target user changing their password):
-hashes LMHASH:NTHASH
NTLM hashes, format is LMHASH:NTHASH
-no-pass Don't ask for password (useful for -k)
-k Use Kerberos authentication. Grabs credentials from ccache file (KRB5CCNAME) based on target parameters. If valid credentials cannot be found, it will use the ones specified in the command line
-aesKey hex key AES key to use for Kerberos Authentication (128 or 256 bits)
Authentication (optional, privileged user performing the change):
-altuser ALTUSER Alternative username
-altpass ALTPASS Alternative password
-althash ALTHASH Alternative NT hash
Method of operations:
-protocol {smb-samr,rpc-samr,kpasswd}
Protocol to use for password change/reset
-reset, -admin Try to reset the password with privileges (may bypass some password policies)
Connection:
-dc-ip ip address IP Address of the domain controller. If omitted it will use the domain part (FQDN) specified in the target parameter
Examples:
SAMR protocol over SMB transport to change passwords (like smbpasswd.py, -protocol smb-samr is implied)
changepasswd.py [email protected]
changepasswd.py contoso.local/j.doe@DC1 -hashes :fc525c9683e8fe067095ba2ddc971889
changepasswd.py -protocol smb-samr contoso.local/j.doe:'Passw0rd!'@DC1 -newpass 'N3wPassw0rd!'
changepasswd.py contoso.local/j.doe:'Passw0rd!'@DC1 -newhashes :126502da14a98b58f2c319b81b3a49cb
changepasswd.py contoso.local/j.doe@DC1 -newhashes :126502da14a98b58f2c319b81b3a49cb -k -no-pass
SAMR protocol over SMB transport to reset passwords (like smbpasswd.py, -protocol smb-samr is implied)
changepasswd.py contoso.local/j.doe:'Passw0rd!'@DC1 -newpass 'N3wPassw0rd!' -altuser administrator -altpass 'Adm1nPassw0rd!'
changepasswd.py -protocol smb-samr contoso.local/j.doe:'Passw0rd!'@DC1 -newhashes :126502da14a98b58f2c319b81b3a49cb -altuser CONTOSO/administrator -altpass 'Adm1nPassw0rd!' -reset
changepasswd.py SRV01/administrator:'Passw0rd!'@10.10.13.37 -newhashes :126502da14a98b58f2c319b81b3a49cb -altuser CONTOSO/SrvAdm -althash 6fe945ead39a7a6a2091001d98a913ab -reset
changepasswd.py SRV01/administrator:'Passw0rd!'@10.10.13.37 -newhashes :126502da14a98b58f2c319b81b3a49cb -altuser CONTOSO/DomAdm -k -no-pass -reset
SAMR protocol over MS-RPC transport to change passwords
changepasswd.py -protocol rpc-samr contoso.local/j.doe:'Passw0rd!'@DC1 -newpass 'N3wPassw0rd!'
changepasswd.py -protocol rpc-samr contoso.local/j.doe@DC1 -newhashes :126502da14a98b58f2c319b81b3a49cb -k
SAMR protocol over MS-RPC transport to reset passwords
changepasswd.py -protocol rpc-samr contoso.local/j.doe@DC1 -newpass 'N3wPassw0rd!' -altuser CONTOSO/SrvAdm -althash 6fe945ead39a7a6a2091001d98a913ab -reset
changepasswd.py -protocol rpc-samr contoso.local/j.doe@DC1 -newhashes :126502da14a98b58f2c319b81b3a49cb -altuser CONTOSO/SrvAdm -k -reset
Kerberos Change Password protocol (like kpasswd) (-newhashes is not supported)
changepasswd.py -protocol kpasswd contoso.local/j.doe:'Passw0rd!'@DC1 -newpass 'N3wPassw0rd!' -k
Kerberos Reset Password protocol (like kpasswd) (-newhashes is not supported)
changepasswd.py -protocol kpasswd contoso.local/j.doe@DC1 -newpass 'N3wPassw0rd!' -altuser CONTOSO/SrvAdm -k -reset
Wow that's really great and helpful feedback! We haven't started merging those PRs yet Thank you!
As #1559 was merged and is a superset of this PR, I am closing this one.