This article is the 2nd part of the “Fintech Bug Bounty” series.
Summary
- How I became a millionaire in 3h | Fintech Bug Bounty — Part 1
- GraphQL Exploitation Techniques | Fintech Bug Bounty — Part 2
- Running a MITM on a Google Play App | Fintech Bug Bounty — Part 3
- (REDACTED) | Fintech Bug Bounty — Part 4 | Available on Mar 2023
- (REDACTED) | Fintech Bug Bounty — Part 5 | Available on Apr 2023
After sending the report for the bugs found in Part 1, I had the chance to speak with the technical team and get some insider information: There was a service I hadn’t discovered yet, that was being used only on the mobile application.
I first did install Lucky Patcher on my phone, an application that allows you to back up APK files from applications installed on your phone.
Probably there are better options to do this, but I’ve been using it for over a decade now. Old habits die hard.
I sent the APK file to my computer and decompiled it with Apktool.
This is as easy as running:
sudo apt install apktool
apktool d <apk file>
Having the application decompiled, I opened the folder with Visual Studio and searched for the bank domain.
I was expecting to find, at least, a new subdomain. But that’s when I discovered they had a secondary domain. That’s why I missed the backend service for the mobile application!
Investigating the new domain
They were not using the base domain. The URL that I found in the application code had a production
subdomain (f.e: production.medium.com
)
This made me think that there could also exist subdomains for other environments. Instead of searching for them manually, I used Security Trails. It’s a great tool I like to use when I don’t want to use fuzzers.
Long story short, I found a development
and a testing
environment.
And on both of them, there was a GraphQL Playground instance.
Using the GraphQL Playground
Finding a GraphQL Playground can’t be considered a vulnerability (because it is not). We must prove there’s an impact on having it enabled.
However, if there’s a GraphQL Playground, there’s a high chance that Introspection Queries are enabled. These queries are used to fulfil the Documentation section.
An Introspection Query is a GraphQL query that returns information about the developed service. If enabled, it can return every available query, mutation and data type defined in the application.
In a conventional JSON:API, this would be like having an endpoint
calledGET /schema
that tells you what the available endpoints are, what parameters they need, and what should you be expecting in the response.
But without an official or public documentation site 😉
If you’re running a pentest against a company having an active bug bounty program, this may not be relevant: they may be offering this information on purpose. Instead, it is a big deal for companies that expect to keep this secret.
In this case, I didn’t need to run the Introspection Query because the Documentation section of the GraphQL Playground had plenty of info.
But in a different situation, I would have tried running:
# Introspection Query
query IntrospectionQuery {
__schema {
queryType { name }
mutationType { name }
subscriptionType { name }
types { ...FullType }
directives {
name
description
locations
args { ...InputValue }
}
}
}
fragment FullType on __Type {
kind
name
description
fields(includeDeprecated: true) {
name
description
args { ...InputValue }
type { ...TypeRef }
isDeprecated
deprecationReason
}
inputFields { ...InputValue }
interfaces { ...TypeRef }
enumValues(includeDeprecated: true) {
name
description
isDeprecated
deprecationReason
}
possibleTypes { ...TypeRef }
}
fragment InputValue on __InputValue {
name
description
type { ...TypeRef }
defaultValue
}
fragment TypeRef on __Type {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
}
}
}
}
}
}
}
}
You’ll identify if the response is successful or not easily. If it is, you can go to a public Playground website, intercept the Introspection Query request (using Burp, for example) and replace the original response with your result. This will give you a visual interface to investigate the “available endpoints”.
Analysis result
After spending some time looking at the endpoints, I discovered two different issues:
- In the
development
andtesting
environments, there was a query that allowed me to retrieve all the users on the platform. It was not critical, but I could gather the personal information of multiple developers and business clients. - In
production
, there was a query that could be abused to check for existing emails and phones within the platform (PII disclosure, but only if you know what you’re searching for).
And none of this required authentication!
Conclusion
They awarded a bounty for the three vulnerabilities: 2 scored as High, and one scored as Low (The GraphQL Introspection Queries + Playground sites).
However, this is not the end. Some other queries and mutations seemed suspicious, but I couldn’t exploit them because they require authentication. And replicating the login process wasn’t that simple…
But we’ll talk about that in the next chapter!