Authentication Bypass by Primary Weakness in firefly-iii/firefly-iii
Reported on
Oct 23rd 2021
Description
Firefly 3 allows users to register OAuth clients. However, Firefly allows duplicate client names to be registered into the application. Hence, attackers from a different account (assuming registration is enabled) can register a client with duplicate client name and trick the user into accepting the authorization request, gaining access to their account.
Proof of Concept
1: Two accounts. Register OAuth client "Legit Application" onto account 1.
2: Register OAuth client "Legit Application" onto account 2 with redirect_uri as http://[MALICIOUS-SERVER].
3: On session with account 1, access the following link:
http://10.0.2.15/oauth/authorize?response_type=code&redirect_uri=http://[MALICIOUS-SERVER]&client_id=2
4: Notice that the OAuth prompt still uses "Legit Application" name, which user Account 1 would implicitly trust.
5: If the attacker manages to retrieve the auth code through the GET request to the malicious server via the victim clicking the button then they can send it together with their client secret to retrieve the access token.
6: And with the access_token, by using it in the Authorization: Bearer header I can now access API as my victim account
The following are the available APIs (from your Swagger document) which Auth bearer header can be used with: https://api-docs.firefly-iii.org/#/about/getCurrentUser
Impact
An attacker can send the OAuth link to a user in an email and allow the attacker to interact with the API using the victim account via tricking them into accepting the OAuth authorization with a duplicate client name which they trust.
Recommended Fix:
Either display OAuth redirect_uri in the authorization page or prevent duplicate client names.
Occurrences
If the attacker manages to retrieve the auth code by the victim clicking the button then he can send it together with their client secret to retrieve the access token.
(Image)[https://drive.google.com/file/d/1EZN6hMkZCok6x_ySSmZFx7LPxUvU2_z5/view?usp=sharing]
And with the access_token, by using it in the Authorization: Bearer header I can now access the API as the user
https://drive.google.com/file/d/1MyQC4Sq6qQ7kJAK3WtSW-IDtXqVtkxOV/view?usp=sharing
The following are the available APIs (from your Swagger document) which Auth bearer header can be used with: https://api-docs.firefly-iii.org/#/about/getCurrentUser
OK. How did you get the original users client secret? So user 1, not user 2.
Hi there, as a registered user I register a client with duplicate name and it comes along with the client secret. Lets say this is client_id 2. All i need is for the user to click on my URL:
http://10.0.2.15/oauth/authorize?response_type=code&redirect_uri=http://[MALICIOUS-SERVER]&client_id=2
And then I receive the authorization code.
I now can complete the OAuth request.
Ok so you just happen to know the apps name from user one?
I mean theoretically it could work, and I’ll check it out but this is very far fetched not gonna lie.
So what I mean is User 2 the attacker sets up a malicious client with duplicate name and so should know the client_secret. Then User 2 sends the link to User 1. When User 1 clicks authorize, User 2 receives User 1 authorization code and thus can complete the OAuth process to takeover User 1's account
The PoC is a representation of the attack scenario.
The attack scenario would be for example a public website which is integrated with a Firefly 3 instance and which User 1 and User 2 can both access. As such User 2 can start an OAuth process on the public website and find out the name of the client the public website is registered as.
I'm going to ask @admin if I should validate this. I see the issue, although I think the sun will swallow the earth before somebody will execute this. However, it more depends on people being stupid because there's no explanation on how the attacker gets hold of the victim's original token name.
I mean I can edit the popup so the redirect URL is shown, which is a fair precaution and a good idea. But the attack scenario is entirely unrealistic imo.
Alright then, and so, I will summarise the conditions and expected impact for this attack:
Conditions:
- Attacker must know the client_name of the OAuth the victim will implicitly trust, this can be identified through various means such as the scenario I described above or through information gathering means
- Attacker must be able to register an account on the platform.
Impact:
- By making the user visit the link and click "authorize" on the OAuth prompt, then the attacker will obtain authorization code and access token which can be used to takeover the victim's account (If you think about it, this has the same impact as the commonly exploited redirect_uri in OAuth mechanisms, as that too relies on tricking the user to implicitly trust the OAuth prompt and click authorize), and in your application, there is no differentiation between the OAuth prompt of a fake client and the OAuth prompt of a real client.
@jc5 - if you believe that the exploit scenario is extremely difficult and unlikely, and borders on not being a security issue, i.e. more of an opinionated stance, feel free to mark as invalid.
If you believe that it does have concerning security implications, we would recommend leaning on the side of valid, but we typically always try to leave it up to the maintainer, and not take a position on the validity of security issues.
Let me know if you have any further questions! 🤗
No matter how I feel, it would be kind of hypocritical to not acknowledge the issue but then submit code to fix it. ^^