Add Kerberos protocol for user enumeration
Description
Currently, username enumeration "like kerbrute" in NetExec requires LDAP access, which needs valid credentials. However, Kerberos AS-REQ requests can enumerate valid usernames without any credentials and without incrementing badPwdCount (resolve issue #195 ), making it interesting for initial reconnaissance, an allow us to get rid of kerbrute lookalikes.
Type of change
Insert an "x" inside the brackets for relevant items (do not delete options)
- [ ] Bug fix (non-breaking change which fixes an issue)
- [x] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] Deprecation of feature or functionality
- [x] This change requires a documentation update
- [ ] This requires a third party update (such as Impacket, Dploot, lsassy, etc)
Setup guide for the review
- Target: Any Active Directory domain controller (tested on Windows Server 2019/2022, on
hercules.htb). - NetExec: Latest main branch + this PR.
- Dependencies: None (uses existing Impacket/Kerberos utilities).
Use the names.withletters trick to create name.a, name.b variants:
awk '/^[[:space:]]*$/ {next} { gsub(/^[ \t]+|[ \t]+$/,""); for(i=97;i<=122;i++) printf "%s.%c\n", $0, i }' /usr/share/seclists/Usernames/Names/names.txt | tee /tmp/names.txt > /dev/null
Screenshots (if appropriate):
Single user check:
Threaded user enumeration (kerbrute):
Checklist:
Insert an "x" inside the brackets for completed and relevant items (do not delete options)
- [x] I have ran Ruff against my changes (via poetry:
poetry run python -m ruff check . --preview, use--fixto automatically fix what it can) - [x] I have added or updated the
tests/e2e_commands.txtfile if necessary (new modules or features are required to be added to the e2e tests) - [x] New and existing e2e tests pass locally with my changes
- [ ] If reliant on changes of third party dependencies, such as Impacket, dploot, lsassy, etc, I have linked the relevant PRs in those projects
- [x] I have performed a self-review of my own code
- [x] I have commented my code, particularly in hard-to-understand areas
- [x] I have made corresponding changes to the documentation (PR here: https://github.com/Pennyw0rth/NetExec-Wiki/pull/77)
Thanks for the PR!
However, i don't really see the advantage over the existing Kerberos authentication schemes. Also, Kerberos is an authentication protocol so there is not much you can do besides authenticating.
The new kerberos protocol provides functionality that is fundamentally different from using SMB/LDAP with the -k flag:
netexec smb 10.10.11.91 -d hercules.htb -k -u /tmp/names.txt -p '' --continue-on-success
- Attempts full Kerberos authentication via
getKerberosTGT()for each username. - Sends AS-REQ with password/credential (with empty password).
- Tries to establish an SMB session after getting TGT.
- Does increment
badPwdCountbecause it's attempting authentication with credentials.
Result is KDC_ERR_C_PRINCIPAL_UNKNOWN errors for non-existent users, but also triggers account lockout mechanisms! And, output is not work-ready:
netexec kerberos 10.10.11.91 -u /tmp/names.txt -d hercules.htb
- Sends AS-REQ without any preauthentication data (no password).
- Only checks if the KDC recognizes the principal.
- Does NOT increment
badPwdCount, since no credentials are validated.
The goal of this addition is to leverage the pre-authentication phase for enumeration, similar to what tools like kerbrute do. However, instead of relying on an external tool, this functionality is integrated directly into NetExec, because, everyone love using this tool. 🫣
However, if you think the protocol clearly has no chance of succeeding, I could put this in nxc/protocols/ldap.py with --enum-users-kerb, but that would be really confusing and not Single Responsibility Pattern (SRP) friendly, don't you think?
Why not simply improve the smb/ldap kerberos auth when no password is provided by sending AS-REQ without any preauthentication data (no password) ?
I understand the suggestion and can definitely implement it that way if needed. You all have the final say on merging, that is your call!
For me, this goes against nxc's design principles because you'd end up typing nxc ldap/smb to run a pure Kerberos operation. That's unintuitive and a bad design decision. It creates confusing UX (Least Surprise Principle) where users won't know where to find Kerberos features, and forces us to add messy if-else conditions in the LDAP codebase just to handle Kerberos enumeration. Having a kerberos section keeps the codebase clean.
I will move the code and make it work if that's the decision, but I still believe a dedicated kerberos protocol is the cleaner approach. Let me know how you want to proceed.
So in NetExec protocols should be network protocols that has functionality besides authentication. While it is fine to have tools that solely does authentication or information dumping/gathering while using authentication protocols (e.g. DumpNTLMInfo.py from impacket), i don't think it would be the right choice to go that route in NetExec. That would lead to much confusion, because now you have Kerberos authentication in various network protocols, while also having it as an standalone authentication protocol. I would also chose not to implement NTLM as its own protocol just for checking stuff like NTLMv1/host header etc.
Also, adding a whole separate protocol for NetExec for manipulating authentication steps that are already done in other protocols would mean a ton of duplicate code which in return means a ton of maintenance work that would otherwise not be necessary.
Besides, this decision has been made implicitly in the past already, at the point where similar authentication manipulation was implemented, such as kerberoasting, asreproasting, delegation via S4U etc.
This decision has indeed the disadvantage that we will do this authentication manipulation on top of a whole other protocol like SMB or LDAP, but when implemented properly and independently there is not much duplicate code or work that has to be done to utilize it in other protocols (in other words if implemented protocol independent).
Understood. What are your thoughts, @NeffIsBack?
Do you think this kind of enumeration should be included in Netexec, or should I put it directly in the Impacket examples?
If you think it should be in netexec, where should it go?
I think it is still a cool addition!
That could definitely be something that would be a good addition to impacket, getting something merged into impacket is a challenge on its own (no hate to the maintainers, just a fact that is the result of the amount of PRs opened to impacket).
To get this into NetExec it should live in its own file, so it is independent of the protocol, but could live in the protocol folder. I would suggest using SMB due to the existing enumeration functions, but ldap would probably work just as well.
We could either add a separate flag, or just combine it with the --continue-on-success function which is used for user enumeration. Perhaps something like:
def kerberos_login():
if continue_on_success:
get_tgt()
else:
impacket_kerb_login()
Thanks for the feedback. I have refactored the code to integrate Kerberos user enumeration directly into the SMB protocol as requested, rather than as a separate protocol.
Batch enumeration
Single user verification
However, in my opinion, it remains misleading as it shows 'SMB' and port 445 while actually using pure Kerberos (port 88), but that is our current tradeoff. At least it exists now.
The enumeration is slower than desired due to NetExec's architecture - the framework uses a global semaphore (BoundedSemaphore(1)) in connection.py that serializes all authentication attempts to prevent race conditions. This design means even with --threads 20, enumeration happens sequentially.
While threading at the orchestration level (in netexec.py) could improve speed, I've kept changes minimal and focused on the integration.
Even though it has a low chance of hatching, I have added it directly to the examples folder: https://github.com/fortra/impacket/pull/2079