Msldap in Emergencies
Published at Feb 18, 2023 - 01:00 PM
Contents
Introduction
I had a situation recently where every tool that talked to LDAP or LDAPS failed. That means no SharpHound, no bloodhound.py, no certipy and no ldapdomaindump. The one tool I could get working however, was msldap. This blog post aims to give some examples of how to use this tool for real-world engagements.
Thanks to p0dalirius1 for their very useful blog post that includes a bunch of LDAP queries.
What is LDAP?
LDAP (Lightweight Directory Access Protocol)
It's the protocol used to query and modify the structure of Active Directory. Think SQL… but for a database of users, groups, network resources etc.
When performing a penetration test, LDAP contains useful information about how Active Directory is configured, about who users are and what access they get to the network, about what groups users are placed into and so much more.
Typically, any account can query Active Directory. This includes computer accounts, service accounts and user accounts.
Using msldap
msldap
is a project designed to provide a simple framework for developers to
use when querying LDAP. It also includes a built-in LDAP client that we will be
using.
Connecting to LDAP server
The first step, of course, is to connect and authenticate against the LDAP
server. msldap
uses connection urls to define connections. These contain the protocol, authentication
method, credentials, hostname or IP address and optional parameters that can
change how msldap
behaves.
msldap 'ldap+ntlm-password://DOMAIN\Username:Password01@127.0.0.1'
Or alternatively, to use LDAPS (the encrypted variant of LDAP):
msldap 'ldaps+ntlm-password://DOMAIN\Username:Password01@127.0.0.1'
We can also authenticate using a bunch of other cool supported modes such as:
msldap 'ldaps+ntlm-nt://DOMAIN\Username:8846f7eaee8fb117ad06bdd830b7586c@10.2.18.10'
You can find more good examples in the README.
WARNING: The anonymous auth example is outdated/wrong and won't work, if you want anonymous auth do:
msldap 'ldaps+simple://127.0.0.1'
Important Note
The first IMPORTANT command we must run after connecting to a server is
login
:
$ login
BIND OK!
If we don't do this, every command will fail (because we aren't connected and authenticated against the LDAP server yet).
Dump LDAP
msldap
includes a handy feature to dump the information stored about
users and computers from LDAP:
$ dump
This creates two Tab-Separated Values (TSV) files.
Find Domain Admins
Referring to the aforementioned1 p0dalirius article, there is a specific query that is useful for finding Domain Admins:
$ query '(&(objectCategory=user)(adminCount=1))'
This will return a list of users that are either Domain Administrators, or transitively Domain Administrators (i.e. they are not part of the Domain Administrator group, but have the same level of privileges).
Enumerate Certificate Templates
Certificate templates can be misconfigured quite easily, and tools such as certipy and certify are usually the go-to for finding and exploiting vulnerable configurations. When LDAP fails though these tools can no longer use LDAP queries to enumerate and identify vulnerable certificate templates.
msldap
has some in-built commands that can help find these vulnerable
certificate templates.
The certify
(confusing I know) msldap
command will spit out certificates that have vulnerabilities if you
run it as shown. However, I'm not quite sure if this supports checks for all of ESC1-10… you can see a full list
of all the checks it goes through here.
$ certify vuln
There is also the more boring option which outputs all the details of the certificate templates:
$ certtemplates
Enumerate Group Policies
Group Policies can be a goldmine34 for information
$ gpos
MSADUser
cn: {31B2F340-016D-11D2-945F-00C04FB984F9}
distinguishedName:
CN={31B2F340-016D-11D2-945F-00C04FB984F9},CN=Policies,CN=System,DC=corp,DC=enterprise,DC=local
path:
\\corp.enterprise.local\sysvol\corp.enterprise.local\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}
displayName: Default Domain Policy
MSADUser
cn: {6AC1786C-016F-11D2-945F-00C04fB984F9}
distinguishedName:
CN={6AC1786C-016F-11D2-945F-00C04fB984F9},CN=Policies,CN=System,DC=corp,DC=enterprise,DC=local
path:
\\corp.enterprise.local\sysvol\corp.enterprise.local\Policies\{6AC1786C-016F-11D2-945F-00C04fB984F9}
displayName: Default Domain Controllers Policy
Get User Descriptions
I recommend having a quick look at these by-hand after searching for 'pwd'
and 'password'. I've seen networks where the user description just straight up
contained a password, i.e. the description of the Administrator
account would
be something like S3cur3itY!!--!!Test
.
$ query '(&(objectCategory=user))' 'samAccountName','description'
{'objectName': 'CN=Administrator,CN=Users,DC=corp,DC=enterprise,DC=local',
'attributes': {'description': 'Built-in account for administering the
computer/domain', 'sAMAccountName': 'Administrator'}}
{'objectName': 'CN=Guest,CN=Users,DC=corp,DC=enterprise,DC=local',
'attributes': {'description': 'Built-in account for guest access to the
computer/domain', 'sAMAccountName': 'Guest'}}
{'objectName': 'CN=vagrant,CN=Users,DC=corp,DC=enterprise,DC=local',
'attributes': {'description': 'Vagrant', 'sAMAccountName': 'vagrant'}}
{'objectName': 'CN=krbtgt,CN=Users,DC=corp,DC=enterprise,DC=local',
'attributes': {'description': 'Key Distribution Center Service Account',
'sAMAccountName': 'krbtgt'}}
{'objectName': 'CN=testuser,CN=Users,DC=corp,DC=enterprise,DC=local',
'attributes': {'sAMAccountName': 'testuser'}}
{'objectName': 'CN=alice,CN=Users,DC=corp,DC=enterprise,DC=local',
'attributes': {'sAMAccountName': 'alice'}}
{'objectName': 'CN=bob,CN=Users,DC=corp,DC=enterprise,DC=local', 'attributes':
{'sAMAccountName': 'bob'}}
{'objectName': 'CN=svc-mssql,CN=Users,DC=corp,DC=enterprise,DC=local',
'attributes': {'sAMAccountName': 'svc-mssql'}}
Now this can be a little hard to parse as a human, and writing a way to decode this data is a bit of a pain… so here is the hard work done for you! (as a bash script):
while read -r var;
do
echo $var | python -c 'print(__import__("json").dumps(eval(input())))';
done < <(\
msldap 'ldap+ntlm-password://CORP\alice:password123!@192.168.56.2' \
"login" \
"query '(&(objectCategory=user))' 'samAccountName','description'" \
| tail -n +2 #remove the BIND OK! from the output
)
Obviously there is some stuff here that needs to be customised, specifically the connection string and the specific query you want, but this will out JSON objects for each line returned, which is much easier to use with any of your chosen tools. For example, you could one-line this and pipe it into jq2:
while read -r var; do echo $var | python -c 'print(__import__("json").dumps(eval(input())))'; done < <(msldap 'ldap+ntlm-password://CORP\alice:password123!@192.168.56.2' "login" "query '(&(objectCategory=user))' 'samAccountName','description'" | tail -n +2) | jq '.attributes'
Which will spit out:
...excerpt...
{
"description": "Built-in account for administering the computer/domain",
"sAMAccountName": "Administrator"
}
{
"description": "Built-in account for guest access to the computer/domain",
"sAMAccountName": "Guest"
}
{
"description": "Key Distribution Center Service Account",
"sAMAccountName": "krbtgt"
}
...excerpt...
You could also alternatively write a python script to use msldap
as a
library… but that's an exercise for the reader :).
ObjectGUID
One of the fields you need to provide to ADFSSpoof when performing a GoldenSAML
attack is the ObjectGUID
. Unfortunately most tools don't output this… but don't
worry, msldap has your back:
$ user 'alice'
This will return a big list of information about the user, and this includes
the objectGUID
:
MSADUser
sn: None
cn: alice
... excerpt ...
objectGUID: 0c9a578b-eb3f-42bb-8e9a-5e2293c1d6fe
objectSid: S-1-5-21-4065317252-3566386198-2278894098-1105
... excerpt ...
TL;DR
msldap is an effective tool that can connect to LDAP over various methods that allows it to be resilient against jank network set-ups that cause other tools to fail.
- Super handy list of LDAP queries, see https://podalirius.net/en/articles/useful-ldap-queries-for-windows-active-directory-pentesting/↩
- Auto-login passwords are sin, see https://adsecurity.org/?p=2288↩
- If you can control GPOs you can do some funky stuff, see https://github.com/Hackndo/pyGPOAbuse or https://pentestmag.com/gpo-abuse-you-cant-see-me/↩
jq
is a json processor for the command line, see https://stedolan.github.io/jq/↩