Skip to content
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

Can't bind using NTLM and specific AD settings #1049

Closed
nowak-ninja opened this issue Aug 22, 2022 · 11 comments
Closed

Can't bind using NTLM and specific AD settings #1049

nowak-ninja opened this issue Aug 22, 2022 · 11 comments

Comments

@nowak-ninja
Copy link

nowak-ninja commented Aug 22, 2022

Hey, I have working solution which uses this great ldap3 library. My security team is going to enable some options in AD at some point, so I had to test the solution and it seems these changes break current solution.

Changes in AD:

Domain controller: LDAP server channel binding token requirements: Always
Domain controller: LDAP server signing requirements: Require signing

The second option one does not affect my script, but the first one causes problems like:

LDAPInvalidCredentialsResult - 49 - invalidCredentials - None - 80090346: LdapErr: DSID-0C0906C1, comment: AcceptSecurityContext error, data 80090346, v3839 - bindResponse - None

After some reading, this is how I setup the connection now:

server = Server("ldaps://10.x.x.x.x", use_ssl=True, get_info=ALL)
conn = Connection(
    server,
    user="domain.local\username",
    password="veryStrongPassword",
    authentication=NTLM,
    #auto_bind=True,
    raise_exceptions=True
)
conn.bind()

I have added conn.bind() which wasn't there before and auto_bind=True wasn't commented. I am AD/LDAP newbie, hence I would like to ask if I am missing something here or such option changes in AD are not compatible with this library and I have to look for other ways to solve this?

I have searched through issues and found this: #923 hoping for solution, but it looks like dead end.

@ThePirateWhoSmellsOfSunflowers
Copy link
Contributor

Hi!
Unfortunately, ldap3 is not compatible with LDAP Channel Binding (the first option) and only supports LDAP Signing (the second option) if it used from a Windows box (according to the documentation, I never tried it).

If a PKI is deployed within your AD environment (through ADCS for example), maybe you can try to use TLS authentication in your script. TLS authentication is, by design, not subject to Channel Binding. See #1032

Hope it helps 👍

🌻

@nowak-ninja
Copy link
Author

Thanks @ThePirateWhoSmellsOfSunflowers for quick answer.

As I understand, I can't have Channel Binding enabled at all, no matter if I use TLS You've mentioned or the solution won't work?

@ThePirateWhoSmellsOfSunflowers
Copy link
Contributor

If you want to keep this (which is a good security hardening recommended by Microsoft btw) :

Domain controller: LDAP server channel binding token requirements: Always
Domain controller: LDAP server signing requirements: Require signing

you can no longer use password based authentication with ldap3 (more information about Channel Binding here).

However, as a workaround, you can still use certificate based authentication, because ldap3 supports it and Channel Binding has nothing to do with certificate authentication, so it's good for your script.

On the one hand, you keep your AD environment secure (the two options are enabled), but on the other hand, your Domain Controller needs to trust your certificates, so Active Directory Certificate Services (ADCS) needs to be deployed within your AD env.

You can also disable Channel Binding, and your script will work again with password, but as a security professional I can't recommend that to you 😆

🌻

@nowak-ninja
Copy link
Author

@ThePirateWhoSmellsOfSunflowers thank You again, that's what my eyes wanted to see :) Kudos!

@zorn96
Copy link
Collaborator

zorn96 commented Aug 22, 2022

@nowak-ninja if you use kerberos (gssapi) authentication, that will also work! The ldap3 library supports channel binding with kerberos, using the gssapi library on unix and winkerberos on windows.

Depending on your setup, this might be easier than certificate based auth. You can turn username/password -> kerberos credential; on unix gssapi supports it, but on windows the winkerberos library won’t do it natively (though you can shell out and run kinit.exe to do it).

@nowak-ninja
Copy link
Author

nowak-ninja commented Aug 23, 2022

Thank You @zorn96, as it sounds great I am aware I am not fully armed with knowledge on how to do this :) Is there any howto related?

PS. I have followed library manual: https://ldap3.readthedocs.io/en/latest/bind.html#kerberos

        conn = Connection(
            server,
            user=creds["username"],
            authentication=SASL,
            sasl_mechanism=KERBEROS,
            raise_exceptions=True
        )
        conn.bind()

raise_exceptions commented:
Major (851968): Unspecified GSS failure. Minor code may provide more information, Minor (2529638919): Server not found in Kerberos database

raise_exceptions uncommented:
LDAPAuthMethodNotSupportedResult - 7 - authMethodNotSupported - None - 00002027: LdapErr: DSID-0C0905FB, comment: Invalid Authentication method, data 0, v3839 - bindResponse - None

Honestly, I am doing blind tries. Got kerberos token with kinit and can view it with klist, but dunno what to do further with that:

Ticket cache: FILE:/tmp/krb5cc_1000
Default principal: XXXX@XXX.GROUP

Valid starting     Expires            Service principal
08/23/22 12:13:51  08/23/22 22:13:51  krbtgt/XXX.GROUP@XXX.GROUP
        renew until 08/24/22 12:13:48

@ThePirateWhoSmellsOfSunflowers
Copy link
Contributor

Can you try this ?

        conn = Connection(
            server,
            user="XXXX@XXX.GROUP",
            cred_store = dict(),
            authentication=SASL,
            sasl_mechanism=KERBEROS,
            raise_exceptions=True
        )
        conn.bind()

@nowak-ninja
Copy link
Author

Hey @ThePirateWhoSmellsOfSunflowers, I tried but without any change on the output. It reads Kerberos ticket/token because if it expires I will get that:

Major (458752): No credentials were supplied, or the credentials were unavailable or inaccessible, Minor (2529639053): Can't find client principal XXXX@XXX.GROUP in cache collection

After I do kinit and get a ticket, the above error changes to the one of mentioned before. I believe, the current issue may be related to misconfiguration of AD or the client host as I run AD on EC2 without proper DNS setup. I will switch to on-prem test AD to have a more prod-like environment.

Anyway, thx for Your time and support <3

@ThePirateWhoSmellsOfSunflowers
Copy link
Contributor

Hey
I'm part of a project that use Kerberos authentication with ldap3, maybe this part of the source code can help you.

Anyway, good luck, Kerberos can be such a headache haha

🌻

@zorn96
Copy link
Collaborator

zorn96 commented Aug 25, 2022

You can also check out the ms_active_directory library (full disclosure: I maintain it). It builds on the ldap3 library and has support for automatically configuring your laptop for kerberos with a domain based on automatically discovering domain resources in DNS (though you can also set them yourself)

one note in general for kerberos is that you need dns to use it properly. Kerberos won’t really work with IP addresses

@nowak-ninja
Copy link
Author

nowak-ninja commented Sep 23, 2022

Dear @ThePirateWhoSmellsOfSunflowers @zorn96

I have played a bit with configuration and this is what I have found so far:

  1. Request signing and channel bidding are enabled on TEST env
  2. Kerberos worked "partially" with my own AD run on EC2 instance but failed to but communicate properly with PROD-like environment so I have ditched this path as it would be over complicated solution for my case where I want to use AWS Lambda function to talk with PROD AD
  3. I have tried to put together upper comments and snippets from documentation to make SASL BIND, but the problem probably lies in my understanding of the topic so I decided to prepare a small use-case loop over different configurations. I wrote simple code to iterate over specified function prefixes and try to create AD connection:

code: https://pastebin.com/72TWT8Ux
result: https://i.postimg.cc/6BLMBypM/Zrzut-ekranu-2022-09-23-165100.png

PS. Where I can find an example how to setup 509x cert for authentication (ADCS)?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants