Bypassing a login: default credentials and authentication bypass

A method to get past a login form in a pentest: factory credentials, hydra brute force, user enumeration, type juggling, leaky redirects and trusted headers.

· 5 min read

A login form is the wall you hit on almost every web box. The temptation is to fire hydra with rockyou and wait, and that is almost never the way in. There are half a dozen checks that take a minute each and that, on Hack The Box, open far more doors than brute force.

This guide is the order to run them in.

Requirements

  • Burp Suite (Community is enough) with your browser going through it.
  • SecLists in /usr/share/seclists (sudo apt install seclists).
  • Hydra or ffuf for bulk testing.
  • To practise: Jerry (Tomcat), Keeper (Request Tracker) and Previse (a redirect that leaks the page).

Step 1: what application is it

First, find out which product is behind the login. Check the page title, the footer, the favicon, the headers and the source:

whatweb http://10.10.10.95:8080
curl -sI http://10.10.10.95:8080/manager/html
HTTP/1.1 401 Unauthorized
Server: Apache-Coyote/1.1
WWW-Authenticate: Basic realm="Tomcat Manager Application"

With the name and version, google "<product>" default credentials and check SecLists:

ls /usr/share/seclists/Passwords/Default-Credentials/
grep -i tomcat /usr/share/seclists/Passwords/Default-Credentials/default-passwords.csv

Step 2: factory credentials

Try the factory defaults by hand before anything else. These are the ones that come up most on retired boxes:

Product Username and password Box
Tomcat Manager tomcat:s3cret, admin:admin Jerry
Request Tracker root:password Keeper
Dolibarr admin:admin Boardlight
ActiveMQ admin:admin Broker
OpenPLC openplc:openplc WifineticTwo
Raspberry Pi (SSH) pi:raspberry Mirai
October CMS admin:admin October
GoPhish admin:gophish HackBack

If the product is not in the table, also try admin:admin, admin:password, <product>:<product> and the box name as the password. It sounds silly and works more often than you think (Driver, Traceback).

Step 3: targeted brute force

If there is a default-credentials list for that product, run all of it. For Tomcat's basic auth:

hydra -C /usr/share/seclists/Passwords/Default-Credentials/tomcat-betterdefaultpasslist.txt \
  -s 8080 10.10.10.95 http-get /manager/html
[8080][http-get] host: 10.10.10.95   login: tomcat   password: s3cret
1 of 1 target successfully completed, 1 valid password found

For a normal form you need three things from Burp: the path, the parameters and a string that only appears when the login fails:

hydra -l admin -P /usr/share/seclists/Passwords/Common-Credentials/10k-most-common.txt \
  10.10.10.10 http-post-form "/login.php:username=^USER^&password=^PASS^:F=Invalid credentials"

Warning

Do not throw all of rockyou at a web login on HTB: that is 14 million requests. If the factory credentials fail, a short list (10k-most-common.txt) and the users you know is the sensible move. When a box wants brute force, it usually drops a hint (a user list, a password policy).

Step 4: enumerate users from the messages

Compare the response for a user that surely exists (admin) with a made-up one. If the message, status code, size or response time changes, you can enumerate users:

ffuf -u http://10.10.11.160:5000/login -X POST -d 'username=FUZZ&password=x' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -w /usr/share/seclists/Usernames/Names/names.txt -fr 'Invalid credentials'

On Noter the site answers Invalid credentials when the user does not exist and Invalid login when it does. With a valid username you can focus the brute force or forge their cookie.

Step 5: injections in the login itself

The form is just another input. Try these in the username and password:

  • SQL: admin'-- - and ' OR 1=1-- -. The full walkthrough is in the SQL injection guide. Practise on Europa.
  • NoSQL: in JSON, {"username":"admin","password":{"$ne":"x"}}. Details in NoSQL injection and practice on Shoppy.
  • Wildcards: a * as username or password. In a badly built LDAP filter it acts as a wildcard, and on Codify a bash script that compares with an unquoted == accepts * as the password (and lets you guess the real one character by character with a*, ab*...).

Step 6: PHP type juggling

PHP's == comparison is "loose". If the code does if (strcmp($_POST['password'], $real) == 0), send the password as an array:

username=admin&password[]=x

In PHP 7, strcmp with an array returns NULL, and NULL == 0 is true: you are in. PHP 8 throws an error instead, so this only works on older versions.

The other variant is magic hashes: if the app compares md5($pass) == $stored_hash and the stored hash starts with 0e followed only by digits, PHP treats it as a number in scientific notation (zero). Any password whose MD5 is also 0e<digits> gets in, such as 240610708.

Step 7: the redirect that leaks the page

Some apps check the session, send a 302 to the login... and still send the page in the response body. This is called Execution After Redirect. In Burp, enable response interception (Proxy > Options > Intercept Server Responses), request the protected page and change 302 Found to 200 OK.

HTTP/1.1 302 Found
Location: login.php
Content-Length: 2801

A large Content-Length on a 302 is the giveaway. It is the way into Previse and it also shows up on Bank.

Step 8: verbs, headers and paths

  • Change the method: if GET /admin returns 401, try POST, PUT or a made-up method. On Wall basic auth only protects GET.
  • Proxy headers: some apps trust X-Forwarded-For, X-Real-IP or X-Originating-IP to decide whether you come from the internal network. On Control you have to pose as an internal IP with one of them.
  • Password reset: look at what "forgot my password" returns. On Silentium the response includes the user object with the reset token.
  • Product CVEs: with the exact version, look for a known authentication bypass, as on Bizness (Apache OFBiz). The method is in exploiting a public CVE.

Common mistakes

  • Hydra reports dozens of "valid" passwords: the failure string (F=) is not in the response, for instance because the login redirects. Check in Burp exactly what a failed attempt returns and pick another string, or use S= with something that only shows up on success.
  • Nothing works and the form has a hidden csrf_token field: hydra does not refresh it. Use a requests script that reads the token before every attempt.
  • The account gets locked: there is a lockout policy. Stop and find another way; in Active Directory it is worse (see password spraying in Active Directory enumeration).
  • You log in but the session does not stick: the cookie is marked Secure and you are on HTTP, or the cookie domain is a virtual host. Add the name to /etc/hosts and browse through it.

What next

Once in the panel, look for code execution: editable templates, plugins, uploads (file upload) or a WAR on Tomcat. These checks are in the authentication section of the web checklist.

Practise it on real machines

Hack The Box machines where this technique is used. Each ▶ jumps to the minute of the IppSec video where it shows up.

Default credentials 17 machines

See all 17 machines →

Authentication bypass 22 machines

See all 22 machines →

Spotted a mistake or something missing? Tell us