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.
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 witha*,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 /adminreturns401, tryPOST,PUTor a made-up method. On Wall basic auth only protectsGET. - Proxy headers: some apps trust
X-Forwarded-For,X-Real-IPorX-Originating-IPto 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 useS=with something that only shows up on success. - Nothing works and the form has a hidden
csrf_tokenfield: hydra does not refresh it. Use arequestsscript 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
Secureand you are on HTTP, or the cookie domain is a virtual host. Add the name to/etc/hostsand 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.