Skip to content

Add targeted Kerberoasting by injecting/removing temporary SPNs#840

Merged
NeffIsBack merged 19 commits intoPennyw0rth:mainfrom
azoxlpf:feat/add-targeted-kerberoast
Apr 26, 2026
Merged

Add targeted Kerberoasting by injecting/removing temporary SPNs#840
NeffIsBack merged 19 commits intoPennyw0rth:mainfrom
azoxlpf:feat/add-targeted-kerberoast

Conversation

@azoxlpf
Copy link
Copy Markdown
Contributor

@azoxlpf azoxlpf commented Aug 3, 2025

Description

The attack is possible when the authenticated user has GenericAll, GenericWrite, WriteProperty, or Validated-SPN rights over a target account.

By adding a temporary SPN (ServicePrincipalName) to such a user, the account becomes Kerberoastable. The function requests a ST for the injected SPN, extracts the hash, and immediately removes the SPN afterward to reduce detection.

Note: Once this PR is merged Allow for specifying specific users to kerberoast a follow-up update will introduce support for targeting a specific user, e.g.:

--targetedkerberoast --user tmoulin4 hashe.txt

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)
  • 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
  • This change requires a documentation update
  • This requires a third party update (such as Impacket, Dploot, lsassy, etc)

Setup guide for the review

Notes:

The current implementation uses a direct ldap3 bind for modifying SPNs. This only works when using NTLM authentication with username and password.

Kerberos authentication with ldap3 is problematic, as it relies on GSSAPI, which in turn depends on native system libraries like libkrb5 and gssapi bindings. This limits cross-platform compatibility, particularly in containerized or constrained environments.

To test the feature, use an account with permissions over user objects (e.g., Account Operators group). No additional GPO or registry changes are required.

Limitation:

To fully support all authentication methods (NT hash, AES key, kerberos ccache), the current workaround is to use NTLM (username + password). Integrating broader support would require implementing full LDAP authentication logic using Impacket, as ldap3 does not natively support these methods without relying on GSSAPI.

Screenshots (if appropriate):

The screenshot below demonstrates a successful targeted Kerberoasting attack. It shows:

  • SPN injection on user accounts without existing SPNs.
  • Successful TGS hash retrieval for offline cracking.
  • Immediate SPN cleanup (removal) after extraction.
1

Checklist:

Insert an "x" inside the brackets for completed and relevant items (do not delete options)

  • I have ran Ruff against my changes (via poetry: poetry run python -m ruff check . --preview, use --fix to automatically fix what it can)
  • I have added or updated the tests/e2e_commands.txt file if necessary (new modules or features are required to be added to the e2e tests)
  • 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
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation (PR here: https://github.com/Pennyw0rth/NetExec-Wiki)

@azoxlpf
Copy link
Copy Markdown
Contributor Author

azoxlpf commented Aug 5, 2025

In the description I said that “Kerberos authentication with ldap3 is problematic because it relies on native GSSAPI libraries (libkrb5, etc.).”
That statement was wrong.

The new helper introduced in add ldap3 Kerberos authentication function performs a pure-Python SASL/GSS-SPNEGO bind through ldap3; it does not depend on any system libraries or extra packages. Once that PR is merged, this PR:

adds / removes the temporary SPN via the same ldap3 connection,

works with every credential type (password, NT hash, AES-128/256 key, ticket cache).

Therefore this PR depends on add ldap3 Kerberos authentication function

Below are two quick screenshots that prove the point:

AES 128 :

kerberoast_aes128

KCACHE :

kerberoast_kcache

@azoxlpf azoxlpf force-pushed the feat/add-targeted-kerberoast branch from db68443 to 7df50ab Compare February 5, 2026 16:07
@azoxlpf
Copy link
Copy Markdown
Contributor Author

azoxlpf commented Feb 5, 2026

I refactored the code and replaced ldap3 with impacket’s LDAP CRUD now that @NeffIsBack PR has been merged into impacket :

image

Comment thread nxc/protocols/ldap.py Outdated
Comment thread nxc/protocols/ldap.py Outdated
Comment thread nxc/protocols/ldap.py Outdated
Comment thread nxc/protocols/ldap.py Outdated
Comment thread nxc/protocols/ldap.py Outdated
Comment thread nxc/protocols/ldap.py Outdated
@NeffIsBack
Copy link
Copy Markdown
Member

Do we really want to modify&request STs for every person on the domain by default? That would result in hundreds or thousands of modification and TGT/ST requests in large domain. Should we perhaps limit this to some requested users that were specified? Thoughts everyone?

@azoxlpf
Copy link
Copy Markdown
Contributor Author

azoxlpf commented Feb 17, 2026

Do we really want to modify&request STs for every person on the domain by default? That would result in hundreds or thousands of modification and TGT/ST requests in large domain. Should we perhaps limit this to some requested users that were specified? Thoughts everyone?

Fair point, doing this for every user by default would be too noisy in large domains.

One thing to consider : verifying the right to add SPNs before trying would introduce another problem. Sometimes we can't read the ntsecuritydescriptor (e.g. ACLs) but we can still modify the attribute. In those cases, a pre-check would incorrectly skip accounts we could actually modify, so we'd miss some valid targets.

We could also make this option only work when one or more users are explicitly specified, idk what do you think ?

@Marshall-Hallenbeck
Copy link
Copy Markdown
Collaborator

We could also make this option only work when one or more users are explicitly specified, idk what do you think ?

Yeah I think for this the operator should have to explicitly list which user(s) to edit since this is actually making the environment less secure.

@NeffIsBack
Copy link
Copy Markdown
Member

One thing to consider : verifying the right to add SPNs before trying would introduce another problem. Sometimes we can't read the ntsecuritydescriptor (e.g. ACLs) but we can still modify the attribute. In those cases, a pre-check would incorrectly skip accounts we could actually modify, so we'd miss some valid targets.

We don't do a pre-check at the moment, or do we? I think we should just try to add it because of exactly these issues and as far as I can tell that's also the way it is implemented.

We could also make this option only work when one or more users are explicitly specified, idk what do you think?

Yeah that sounds good. The question would be how to properly specify them. Maybe something similar to the asreproast/kerberoast combination?

Yeah I think for this the operator should have to explicitly list which user(s) to edit since this is actually making the environment less secure.

Agreed, but one small detail: The SPN is removed afterwards, so there is nothing that gets more insecure.

@Marshall-Hallenbeck
Copy link
Copy Markdown
Collaborator

Agreed, but one small detail: The SPN is removed afterwards, so there is nothing that gets more insecure.

Well, assuming it gets removed correctly :P

@azoxlpf
Copy link
Copy Markdown
Contributor Author

azoxlpf commented Feb 19, 2026

We don't do a pre-check at the moment, or do we? I think we should just try to add it because of exactly these issues and as far as I can tell that's also the way it is implemented.

No, we don’t do a pre-check right now, we look for users without SPNs and try to add one to them without checking if we actually have the rights to do so, which is what targetedKerberoast does and what I based this on. On a large domain this can indeed be an issue, but adding a rights-check before adding SPNs also multiplies the LDAP queries and can lead to false negatives. The middle ground would be to avoid trying on every user in the domain and only target the users provided, and still skip the rights check and just try to add the SPN directly

@azoxlpf
Copy link
Copy Markdown
Contributor Author

azoxlpf commented Feb 19, 2026

Yeah that sounds good. The question would be how to properly specify them. Maybe something similar to the asreproast/kerberoast combination?

Exactly, I think we could just do something like --targetedkerberoast user1 out.txt, or if we want to specify multiple users put them in a file and use --targetedkerberoast users.txt out.txt.

@NeffIsBack
Copy link
Copy Markdown
Member

Yeah that sounds good. The question would be how to properly specify them. Maybe something similar to the asreproast/kerberoast combination?

Exactly, I think we could just do something like --targetedkerberoast user1 out.txt, or if we want to specify multiple users put them in a file and use --targetedkerberoast users.txt out.txt.

Mixing the purpose of args is not a good idea. This will likely lead to a problem in the logic and is unintuitive. We should probably do it like the --no-preauth-targets arg and add an arg like --targeted-kergeroast user1 user2 and require --kerberoasting as an arg so we have an output file.

@azoxlpf
Copy link
Copy Markdown
Contributor Author

azoxlpf commented Feb 19, 2026

Yeah that sounds good. The question would be how to properly specify them. Maybe something similar to the asreproast/kerberoast combination?

Exactly, I think we could just do something like --targetedkerberoast user1 out.txt, or if we want to specify multiple users put them in a file and use --targetedkerberoast users.txt out.txt.

Mixing the purpose of args is not a good idea. This will likely lead to a problem in the logic and is unintuitive. We should probably do it like the --no-preauth-targets arg and add an arg like --targeted-kergeroast user1 user2 and require --kerberoasting as an arg so we have an output file.

You’re right, I hadn’t thought of that, but it actually sounds like the best approach

@azoxlpf
Copy link
Copy Markdown
Contributor Author

azoxlpf commented Mar 4, 2026

I've made the suggested changes @NeffIsBack, let me know if it looks good to you.

image

@NeffIsBack NeffIsBack added this to the v1.6.0 milestone Mar 22, 2026
Copy link
Copy Markdown
Member

@NeffIsBack NeffIsBack left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fyi, I extracted the logic for the no-preauth roasting as this does not have anything to do with the rest of the kerberoasting logic.

Please integrate targeted kerberoasting into the existing kerberoasting logic, so that we don't have so much duplicate code. Meaning, similar to the kerberoast_account logic we should build a different filter, only retrieving the specified users. Then, before we actually get the ST we have to check if we need to modify the SPNs (is the arg set) and then add/remove the SPNs accordingly.
Pretty much, we shouldn't have all of the kerberoast logic 2x in the code.

@azoxlpf
Copy link
Copy Markdown
Contributor Author

azoxlpf commented Apr 12, 2026

LGTM, targeted kerberoast now shares the same flow as normal kerberoasting, only the LDAP filter + temporary SPN handling differ :
image

Heads-up: Found N enabled users without SPN means N accounts matched the query (enabled, no SPN), not that we can write SPNs on all of them permission failures still show up later. Fine to keep as-is, or we can reword if you want that distinction in the log

Copy link
Copy Markdown
Member

@NeffIsBack NeffIsBack left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few small things left to do.

Comment thread nxc/protocols/ldap.py Outdated
Comment thread nxc/protocols/ldap.py Outdated
Comment thread nxc/protocols/ldap.py Outdated
Comment thread nxc/protocols/ldap.py Outdated
Comment thread nxc/protocols/ldap.py Outdated
Comment thread nxc/protocols/ldap.py Outdated
Comment thread nxc/protocols/ldap.py Outdated
Copy link
Copy Markdown
Member

@NeffIsBack NeffIsBack left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM:
Image

@NeffIsBack NeffIsBack merged commit f7e1187 into Pennyw0rth:main Apr 26, 2026
5 checks passed
@azoxlpf azoxlpf deleted the feat/add-targeted-kerberoast branch April 26, 2026 19:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants