pyLDAPGui - How It was Born

pyLDAPGui - How It was Born

pyLDAPGui is an app I've been playing about with for a few months but it wasn't until recently that I decided, probably a good idea to release it in a proof of concept form for people to play about. The concept came about while working on development of my course Malwareless Adversarial Emulation(MAE) and looking at tools for effective living off the land cross-OS which as these things do, sent me down a rabbit hole looking at available options that were portable.

GitHub - ZephrFish/pyLDAPGui: Python based GUI for browsing LDAP
Python based GUI for browsing LDAP. Contribute to ZephrFish/pyLDAPGui development by creating an account on GitHub.

If you have ever done any form of pentesting, red teaming or auditing focused on active directory environments, chances are you have used Active Directory Explorer(AD Explorer). It is a great utility for use on Windows hosts to connect to a LDAP server often a DC and give you a nice view of the AD Environment.

If you haven't used it before, this is the view you get when you connect to an AD, as a systems administration tool it is great but there are lots of limitations. It can be slow, the snapshots it kicks out are in .dat format and can be converted to BloodHound data with ADExplorerSnapshot.py but it's also limited to just Windows host machines which can make it a bit of a pain to deal with sometimes.

AD Explorer connected to my home lab yxz.red

The biggest limitation of ADExplorer to me is that it's only available on Windows which is great for most environments but if you want to operate from a *nix VM or a Mac you're out of luck for using it (I know things like mono and wine exist so you could technically get it working but not natively).

Alternatives

So in my travels looking for alternative LDAP Browsers with UIs I found a few useful sysadmin tools that did similar, GoDAP exists as a terminal UI so rather than a graphical user interface it still operates from terminal which is fine and great but I wanted a GUI. In the same vein ldap_shell has a great terminal UI with various features.

There's also the Softerra LDAP Browser which takes me back to the C# applications of old for Xbox modding and game modding with the similar familiar UI but once again dependant on being on Windows. LDAP Wiki also has a good index of available browsers but still limited selection so that led me down the rabbit hole of looking at GUI based creations.

Python and GUIs

When it comes to creating GUI applications, I have written a few apps but nothing super exciting, some flask web applications, the usual VBS/C# GUIs and a few limited hello world apps in Python and Go. So approaching this from the perspective of what language is pretty multi functional with available languages and I settled on Python, yes I could have used Go, Rust, C, <insert your language here> but Python was the easiest option for me at least.

The next challenge/choice was to work out what library to use for a GUI within python, there are a few options and after reading documentation for each I settled on PyQt for the ease of access/expandability and cross-OS support (technically a few of them had this):

pyLDAPGui

So after much deliberation on GUIs, options available and things todo the next step was to work out what I actually wanted the tool todo. Originally when looking at languages and GUIs I started out with Go and Rust but later realised that the learning curve and hacking stuff together to be properly easy to build and support wasn't going to be it.

Go GUI

While rust offered a lot more in terms of GUI look it felt similar to Proxmox's UI but unfortunately the featureset I wanted wasn't enough or more wasn't easy enough to configure which is what led me down the route of python.

Design

Next up once the library was decided and language I set about to plan out what I wanted the tool to do, as these things often go I started out with a simple skeleton outline of what I wanted to achieve and as I started writing functions other ideas came to me.

The design needed to be simple to use but with enough features to make it easily usable and accessible. At its core I wanted to have similar functions to ADExplorer:

  • Connect to LDAP with Tree view
  • Support both LDAP and LDAPS
  • Be able to export to a reasonable format, mainly CSV and JSON (for BloodHound compatibility)
  • Have an easy search that was quick plus the ability to run specific LDAP queries

Starting with this simple baseline I had a working PoC pretty quickly leaning on Stack Overflow I read this post as a baseline to learn about what I needed to google and learn more about.

The Logo and GPT Woes

All the cool kids have ASCII art for their tools and I wanted to be different so I went with a logo based on the original BloodHound logo with a bit of a python twist, to save time I chucked the logo at ChatGPT and asked it for a permutated version using the following prompt and it took a bit of work but we got there:

Generate me an image that uses a python wrapped around this image and, make the python go the other way and come out the dog's head

Attempt 1:

It looked OK but I wanted it to look better, make the python green and the bloodhound rainbow :

This looked ok but I wanted it to be better still so asked it to make the python the dog's tail:

Now lets add a bit of colour and tada the final image was born:

Challenges

There were a few challenges when writing this tool, mainly designing GUIs in python isn't as straight forward as I thought it'd be plus working out the structure for certain files for export. Additionally getting SOCKs working wasn't as easy as I initially thought it'd be, I got it working eventually through lots of googling and trial and error, bare in mind lots of the functions of this tool were tested in a small lab generated with Ludus and thus the performance hasn't been tested against a broader environment.

Opsec Considerations

I also had the thought of throttling/opsec mid development so there is a half cobbled together operational security focus with some of the queries as shown, I flipped and randomised some of the queries that the tooling makes.

  
        self.attribute_variations = {
            'samaccountname': ['sAMAccountName', 'samAccountName', 'SAMACCOUNTNAME', 'sAmAcCoUnTnAmE'],
            'objectclass': ['objectClass', 'OBJECTCLASS', 'ObjectClass', 'oBjEcTcLaSs'],
            'memberof': ['memberOf', 'MEMBEROF', 'MemberOf', 'mEmBeRoF'],
            'serviceprincipalname': ['servicePrincipalName', 'SERVICEPRINCIPALNAME', 'ServicePrincipalName'],
            'useraccountcontrol': ['userAccountControl', 'USERACCOUNTCONTROL', 'UserAccountControl'],
            'objectcategory': ['objectCategory', 'OBJECTCATEGORY', 'ObjectCategory'],
            'cn': ['CN', 'cn', 'Cn', 'cN'],
            'ou': ['OU', 'ou', 'Ou', 'oU'],
            'dc': ['DC', 'dc', 'Dc', 'dC'],
            'distinguishedname': ['distinguishedName', 'DISTINGUISHEDNAME', 'DistinguishedName'],
            'name': ['name', 'NAME', 'Name', 'nAmE'],
            'description': ['description', 'DESCRIPTION', 'Description', 'dEsCrIpTiOn'],
            'mail': ['mail', 'MAIL', 'Mail', 'mAiL'],
            'givenname': ['givenName', 'GIVENNAME', 'GivenName', 'gIvEnNaMe'],
            'sn': ['sn', 'SN', 'Sn', 'sN'],
            'displayname': ['displayName', 'DISPLAYNAME', 'DisplayName', 'dIsPlAyNaMe'],
            'pwdlastset': ['pwdLastSet', 'PWDLASTSET', 'PwdLastSet', 'pWdLaStSeT'],
            'lastlogon': ['lastLogon', 'LASTLOGON', 'LastLogon', 'lAsTlOgOn'],
            'admincount': ['adminCount', 'ADMINCOUNT', 'AdminCount', 'aDmInCoUnT'],
            'primarygroupid': ['primaryGroupID', 'PRIMARYGROUPID', 'PrimaryGroupID'],
        }
        

I also wanted the output to be as minimal as I could with as few queries as possible to still maintain the output required for BloodHound. The tool makes the following types of LDAP queries:

  1. Tree Navigation (get_children): Triggered when expanding tree nodes
  2. Entry Details (get_entry): Triggered when selecting items
  3. Bulk Exports (get_bloodhound_data): 6 large queries for BloodHound
    export
  4. General Search (search): Used for CSV exports and browsing

In addition to reducing the queries I also added throttling between queries to try to not flood the server with requests but also to try to maintain some degree of stealthy-ness so there's basically random delays (0.5-2s) between queries and every time it runs the queries they are shuffled to try to evade standard signatures.

There are additional changes that can be made to the code to try to remain more under the radar, I haven't implemented them yet but it is a case of changing a few settings within main.py around line 699 where the connection is established:

ldap_conn.set_opsec_mode(True, 10.0, 30.0)  # 10-30s random delays
ldap_conn.set_throttle_settings(True, 2, 1)  # Only 2 queries/minute
ldap_conn.set_cache_settings(500, 86400)     # 24-hour cache

GitHub Actions

One of the other challenges I had was with GitHub actions, I love CI/CD and use it as much as possible with all of my tool creations, mainly because it removes the pain from having a standard dev environment per system and allows ephemeral builds for ease of deployment. All of that said, GitHub actions' code takes a bit of trial and error to get right!

Note: if you want to build releases from GH Actions you need to have these two perms set otherwise you will spend a lot of time (like me) clawing your eyes out wondering why stuff builds but doesn't push anywhere!

permissions:
  contents: write
  packages: write

One of the things I did learn though is the ability to write GitHub actions to cleanup commit history and workflow commits which makes for more fun.

It took me 26+ attempts to get it working nicely but as you'll see in the commit history it is clean thanks to git's ability to detach branches and rebuild easily!

Result

Once everything was put together, the GUI actually turned out not bad with some buttons (some don't do anything useful yet but there's a plan there at least). The core feature set that works so far:

  • Connect to LDAP/LDAPS Server and list out in a tree view
  • Export to CSV/Export to BH
  • Ingest straight into Neo4j (provided you can reach it from the host you're running this on, you can do it over the network and it takes user/pass/neo4j DB details and it'll go away and ingest happily to BH DB).
pyLDAPGui/assets/MacExample.png at main ยท ZephrFish/pyLDAPGui
Python based GUI for browsing LDAP. Contribute to ZephrFish/pyLDAPGui development by creating an account on GitHub.

I do have some additional plans to improve the code some more and add more features like the aforementioned ingest using OpenGraph for BloodHound CE and the ability to export specific details and parse for more information from the data which is what I hope the ADCS Analysis button will eventually do!

For the moment, thanks for reading my fun times I've had over the last few months and hope you get some use out of my PoC. If you're interested in more living off the land fun sign up to my course pre-order to be notified when it publishes:

 https://mae.zsec.red

Get Notified - Malwareless Adversarial Emulation