impacket
impacket copied to clipboard
Update ccache.py to enhance the ability of dealing with cross realm ticket
when using the example script atexec.py with a cross realm ticket, I got a wrong realm error:
Impacket v0.10.0 - Copyright 2022 SecureAuth Corporation
[!] This will work ONLY on Windows >= Vista
[-] Kerberos SessionError: KDC_ERR_WRONG_REALM(Reserved for future use)
so I started debugging it and located this issue to lib file impacket/krb5/ccache.py, I modified it, get the right realm from the variable target for variable principal, after that, the issue is solved
and I also made a little change to impacket/krb5/kerberosv5.py so corss realm TGT (referral TGT) ticket can be handled correctly too
if you're using proxy, to use atexec.py or smbclient.py directly with a normal TGT in current domain, you may need to specify domainA/domainB/targetserver.target.domain's IP in host file, like this:

Hi ! Very cool PR, thanks !
I have one suggestion to improve usability. The situation is the following:
We have in our CCache file an ST as principal [email protected], for SPN krbtgt/[email protected] (referral TGT to DOM-B from DOM-A).
We want to use this referral TGT to access a resource in DOM-B. We need to present it to a DOM-B KDC to get an ST for the correct service in DOM-B.
With this PR, we need to add the -dc-ip option with a DOM-B KDC. Otherwise, the TGS-REQ will be sent to a DOM-A KDC, resulting in an error KDC_ERR_WRONG_REALM.
This because the sendReceive function is called on the domain variable, corresponding to the user's domain, DOM-A:
https://github.com/fortra/impacket/blob/ae95a135a788d2f427b46cc65fcb88d46125d177/impacket/krb5/kerberosv5.py#L442
(When setting a -dc-ip option, its value is put in the kdcHost variable with takes precedence over domain, so it works).
My suggestion is to change this line to put targetRealm in place of domain, so that setting -dc-ip is not necessary.
Cheers !
My suggestion is to change this line to put
targetRealmin place ofdomain, so that setting-dc-ipis not necessary.
sorry for the late response, I'll check it in my lab asap
Hi ! Very cool PR, thanks !
I have one suggestion to improve usability. The situation is the following:
We have in our CCache file an ST as principal
[email protected], for SPNkrbtgt/[email protected](referral TGT to DOM-B from DOM-A). We want to use this referral TGT to access a resource in DOM-B. We need to present it to a DOM-B KDC to get an ST for the correct service in DOM-B.With this PR, we need to add the
-dc-ipoption with a DOM-B KDC. Otherwise, the TGS-REQ will be sent to a DOM-A KDC, resulting in an errorKDC_ERR_WRONG_REALM.This because the
sendReceivefunction is called on thedomainvariable, corresponding to the user's domain, DOM-A:https://github.com/fortra/impacket/blob/ae95a135a788d2f427b46cc65fcb88d46125d177/impacket/krb5/kerberosv5.py#L442
(When setting a
-dc-ipoption, its value is put in thekdcHostvariable with takes precedence overdomain, so it works).My suggestion is to change this line to put
targetRealmin place ofdomain, so that setting-dc-ipis not necessary.Cheers !
btw, can I have your contact info(twitter, discord or whatever) so we can talk conveniently? you can find my twitter in my profile
Hi, I think we should keep -dc-ip option, because sometimes you will need to use this tool through a proxy, so the dns resolve may not work, which means the ip address of kdc will not be resolved correctlly and the connection will break
Hi !
1st point:
btw, can I have your contact info(twitter, discord or whatever) so we can talk conveniently? you can find my twitter in my profile
Twitter is the same as my GitHub.
2nd point:
Hi, I think we should keep -dc-ip option, because sometimes you will need to use this tool through a proxy, so the dns resolve may not work, which means the ip address of kdc will not be resolved correctlly and the connection will break
It's true that sometimes we need it, for instance in the situation you mentioned. However, this is only relevant to specific edge cases. Most of the time, the tools themselves could be able to determine which KDC to contact. This is the behaviour of the current mainline Impacket, which is able, most of the time, to automatically determine which KDC to contact, without having to specify a -dc-ip option.
The goal of my suggestion was to push this PR in line feature-wise with mainline Impacket, allowing it to automatically determine which KDC to contact. However, this is your PR so if you don't think it's necessary, feel free to ignore it.
3rd point:
I've encountered another issue: if we have in our CCache a regular TGT (not referral) for [email protected], and we try to access a resource in DOM-B, this PR should use this regular TGT to obtain a referral TGT for DOM-B, to then use it to request an ST for the DOM-B resource.
However, this PR will not be able to find the regular TGT in the CCache, because it is now only looking for referral TGTs in CCache when foreign domains are involved (line principal = 'krbtgt/%s@%s' % (targetRealm.upper(), domain.upper())).
This is a regression from mainline Impacket, which is correctly able to find a regular TGT to ask for a referral TGT, and then for an ST.
Cheers !
Hi!
First point, I can't send message to your twitter
Second point, I think I've understood what do you mean now, with your suggestion, we can resolve the KDC ip when we can, and use -dc-ip when we can not, right?
Third point, working on it
Thanks for @saerxcit's advice, this PR is now working good
Hi,
I am trying to abuse a bidirectional inter-forest trust using the inter-trust account (trust key). SID history and SID filtering is disabled in both directions. After having successfully requested a TGT using the NT hash of the trust key and ticketer.py I need to request a TGS for the CIFS service of the target DC/forest. As I understand it I need to use this PR in order for that to work properly. I can successfully request the TGS but no matter if I use the flag "-dc-ip" or not (it is not clear from this conversation if I need that or not) the following DCSync using secretsdump.py fails with "ERROR_DS_DRA_BAD_DN". This error suggests that the account used for the DCSync does not have the required privileges.
Performing the very same attack against a bidirectional child/parent trust in the same lab works without any issues.
Any ideas what I am doing wrong?
Below you can see the two examples I mentioned above side-by-side. The failing inter-forest attack on the left and the working intra-forest attack on the right. IP 10.0.0.200 resolves to dc1.adlab.local.

Hi !
The issue you're having is that you're adding an extra SID whose RID is < 1000. While this attack works fine within a single forest, RIDs < 1000 are filtered out in all cases when crossing a forest boundary, even when "SID filtering is disabled". This was point 2) of that comment https://github.com/fortra/impacket/pull/1391#issuecomment-1423922768.
Main reference for SID filtering behaviour is https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-pac/55fc19f2-55ba-4251-8a6a-103dd7c66280.
What that means is for cross-forest trusts, trustAttributes needs to have the TREAT_AS_EXTERNAL flag (as well as no QUARANTINED_DOMAIN flag) for SID filtering to be disabled (https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/e9a2d23c-c31e-4a6f-88a0-6646fdb51a3c). In that case, the cross-forest trust will be treated as an external trust, and SIDs >= 1000 will not be filtered.
So to attack this you will first need to identify a custom (non built-in) group in adlab.local (so that the group will have an RID >= 1000) which has interesting high privileges.
Thank you for your reply!
Regarding SID filtering/SID history. According to this site some attacks should work depending on the status of these settings. In my lab they are both disabled which is why I attempted to use RID 519 at first. See below.

In order to test your suggestion I added a custom group (global security group) in the forest adlab.local then gave the group interesting privileges. Note its RID of 1113. I then tested using the higher-than-1000-RID in the same attack as before but that still fails with the same error.


Looking at your screenshots I think it is normal it's not working with your current configuration.
From what I know, the SID history attack that can work when crossing a forest boundary will only work when the trust is considered as an "External" trust. In that case, only RIDs >= 1000 will be usable.
If you have a "Forest" trust (your current setup, because you have the flag FOREST_TRANSITIVE, abbreviated as foresttrans in your nltest /trusted_domains command, in the trustAttributes attribute of the Trusted Domain Object), you can have it be considered "External" by adding the TREAT_AS_EXTERNAL flag (0x40) to the trustAttributes attribute.
Adding this attribute to a "Forest" trust is called "enabling SID history" or "disabling SID filtering". The command to do that is netdom trust localdomain.local /domain:trusteddomain.local /enablesidhistory:yes
You're trying to attack ADLAB.LOCAL after having compromised ADLAB2.LOCAL. As such, ADLAB.LOCAL needs to be configured to not filter SIDs in tickets coming from ADLAB2.LOCAL.
I am seeing two issues with the last command of your first screenshot:
- You're applying the modification on the ADLAB2.LOCAL domain, in order for it to not filter SIDs in tickets coming from ADLAB.LOCAL. This is the opposite of what you want.
- The syntax of the command is incorrect: you're just passing
/enablesidhistory, instead of/enablesidhistory:yes. Passing just/enablesidhistorywill make the command output the current configuration, which explicitely says "SID history is disabled" (meaning "SID filtering is enabled").
If my theory is correct, then your ADLAB.LOCAL domain is configured to filter SIDs in tickets coming from ADLAB2.LOCAL, which would make the attack fail.
You will need to use the following command on a ADLAB.LOCAL DC: netdom trust adlab.local /domain:adlab2.local /enablesidhistory:yes. You will know if the command worked if in nltest /trusted_domains the external flag appears next to foresttrans in the ADLAB2 trust.
I enabled SID history from the forest adlab.local to the forest adlab2.local but DCSyncing still failed with the same error. However, once I made the custom group [email protected] a member of the group [email protected], as oppose to "only" the group domain [email protected] as before, DCSyncing worked. See below.
This seems like a corner case to me so I do not know how likely this is to work in the field. I also cannot understand why being a member of the group domain [email protected] only would not be enough to DCSync. It is in all other cases... Any thoughts on this? I really would like to understand what the minimum requirements for DCSyncing across forests are.

I'm observing the same behaviour in my lab and I have no idea why, this makes no sense as Domain Admins is member of Administrators, so unfortunately I cannot help you further.
Hi, @jsdhasfedssad, how can I get in touch with you? I'd like to discuss this issue with you
my env: server 2022 21H2
I'm not able to test this in my lab, because I keep getting this error: "the sidhistory is disabled for this trust.", I've set the trust to EXTERNAL, and it didn't help, so my test_group(high-priv)'s SID is always filtered, and atexec.py got access denied, but this PR is working correctly
Hi, @jsdhasfedssad, how can I get in touch with you? I'd like to discuss this issue with you
Hi. How about this? https://y99.in/r/935588
Hi, @jsdhasfedssad, how can I get in touch with you? I'd like to discuss this issue with you
Hi. How about this? https://y99.in/r/935588
I'm in that chat room
Hi, @jsdhasfedssad, how can I get in touch with you? I'd like to discuss this issue with you
Hi. How about this? https://y99.in/r/935588
I'm in that chat room
Sorry. I was away. Try again now if you have the time.