-
Notifications
You must be signed in to change notification settings - Fork 575
Kerberos and authentication related fixes #895
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Hey i know it initially makes sense to just fix multiple issues in one PR, but this makes it really hard to understand which lines were added in order to resolve which issues. I think next time it would be better to split up the bug fixes into separate PRs |
Yeah I did for other issues, but this PR covers Kerberos/auth all in one. If you want to see each issue fixed, I did a separate commit for each issue, so you can easily check each of those if you want to see them separate. Alternatively, I can close this and separate each commit into a PR, but the commits are pretty clean IMO. |
All good for now and yes I could go through each commit but it just makes it harder to put it together at the end. Just for the future I think we should keep them separate |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should never alter the supplied args. This is the single source of truth where we can get information of the actual supplied information and not something nxc decided to set at some point.
Although the check if the ccache file exists was deeply needed, i don't think the main function is the right place for parsing the ticket information. That should probably be done in the connection itself, probably the login()
function.
Rest looks good
krb_domain, krb_username, krb_tgt, krb_tgs = CCache.parseFile() | ||
nxc_logger.debug(f"Kerberos cache file parsed: {krb_username}, {krb_domain}, {krb_tgt}, {krb_tgs}") | ||
|
||
if len(args.username) > 1: | ||
nxc_logger.error(f"Only one username can be used when using Kerberos cache! The domain\\user for this cache file is '{krb_domain}\\{krb_username}'") | ||
exit(1) | ||
|
||
if args.username and krb_username != args.username[0]: | ||
nxc_logger.error(f"Kerberos cache file username '{krb_username}' does not match provided username '{args.username[0]}', setting username to '{krb_username}'") | ||
else: | ||
nxc_logger.debug(f"No username provided, using the one from the cache file: {krb_username}") | ||
|
||
if args.domain and krb_domain != args.domain: | ||
nxc_logger.error(f"Kerberos cache file domain '{krb_domain}' does not match provided domain '{args.domain}', setting domain to '{krb_domain}'") | ||
else: | ||
nxc_logger.debug(f"No domain provided, using the one from the cache file: {krb_domain}") | ||
|
||
args.username = [krb_username] | ||
args.domain = krb_domain | ||
# at this point the user should be a single user, but in a list, because we still parse credentials the same later, and it expects a list | ||
nxc_logger.debug(f"Domain set to {args.domain} and username set to {args.username} for kerberos cache login") | ||
|
||
if args.password: | ||
nxc_logger.display("Setting password is irrelevant when using Kerberos cache, ignoring") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So should we just completely ignore the parameters if they are passed? Or just stop all execution and tell them not to pass any user/pass/domain? In my first iteration I didnt do any of this setting, but currently if they pass in a user or domain with kkache it just fails without telling them why.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think as it already behaves like we would ignore the users input we should just continue doing that and warn the user.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So add a warning that it's not actually used? Because if we keep it the same as we have it now (accept them but just completely ignore them) it's a bit confusing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, sounds good if that makes it clearer👍
args.username = [krb_username] | ||
args.domain = krb_domain |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i don't think we should override the arguments at any point in time. This can lead to unintended behavior on some edge cases
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Like what? Unfortunately at this place and time the user/domain arent set, so we can do that later I guess, I think in connection?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should just not consider the arg and just pass in the username&domain in the connection.py where we evaluate if we do ticket authentication. But we have to be careful that the user does not overwrite the domain with the arg parameter
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So that's what my other code was doing, making sure it matched and then setting it properly, which I think is useful.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, but imo instead of overwriting the arg and then read the arg at a later point in time we should just read the info from the ticket at the place where we need/parse the info, without clobbering the supplied args.
I think we should always keep args as is, because this is the only "source of truth" where we can check what was actually supplied.
if self.args.use_kcache: # already parsed kcache domain and username in main() | ||
self.domain = self.args.domain | ||
self.username = self.args.username[0] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we don't specify a user via an arg (and don't mess with supplied args somewhere else) this would break when not specifying a username: nxc smb <ip> --use-kcache
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree this is maybe not the best place to parse it, but i don't think the main function of netexec.py is the place to go
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where would be a good place to do it? I considered the alternatives and figured in the main function would be best, so we can stop all execution if something is messed up.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should probably go to place in connectino.py where we check if we use kcache as auth method. Probably best to format/supply all attributes that should go into the actual kerberos login function there:
Lines 545 to 552 in d4c38ea
if self.args.use_kcache: | |
self.logger.debug("Trying to authenticate using Kerberos cache") | |
with sem: | |
username = self.args.username[0] if len(self.args.username) else "" | |
password = self.args.password[0] if len(self.args.password) else "" | |
self.kerberos_login(self.domain, username, password, "", "", self.kdcHost, True) | |
self.logger.info("Successfully authenticated using Kerberos cache") | |
return True |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That way this is also done for all kerberos protocols that implement kerberos auth and doesn't have to be done in smb.py and ldap.py as well
username = self.args.username[0] if len(self.args.username) else "" | ||
password = self.args.password[0] if len(self.args.password) else "" | ||
self.kerberos_login(self.domain, username, password, "", "", self.kdcHost, True) | ||
username = self.args.username[0] # we check this in the main() function when using kcache and set it appropriately already |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will crash if we don't mess with the args somewhere else
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, this is reliant on the username being set in the main function.
elif self.args.use_kcache: # Fixing domain trust, just pull the auth domain out of the ticket | ||
self.domain = CCache.parseFile()[0] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why removing that? How do we ensure that we have the correct domain?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because this is done in the main() function now. But we might change that per your other comments.
…errors occur; fixes #892
…generate-tgt test
Signed-off-by: Marshall Hallenbeck <Marshall.Hallenbeck@gmail.com>
0091e38
to
8d574e2
Compare
@Marshall-Hallenbeck any update on this? |
We still have on-going discussions from your comments. |
Then let's discuss them 😁 |
Description
--local-groups
--local-groups
with-H
Type of change
Insert an "x" inside the brackets for relevant items (do not delete options)
Setup guide for the review
No unusual setup needed
Screenshots (if appropriate):
Can provide
Checklist:
Insert an "x" inside the brackets for completed and relevant items (do not delete options)
poetry run python -m ruff check . --preview
, use--fix
to automatically fix what it can)tests/e2e_commands.txt
file if necessary (new modules or features are required to be added to the e2e tests)