How Secure Are Your Universally Unique IDentifiers (UUIDs)?

Why UUIDs Should Not Be Used as Security Capabilities
How Secure Are Your Universally Unique IDentifiers (UUIDs)?

Universally Unique IDentifiers, also known as UUIDs or GUIDs, are 128-bit numbers used to uniquely identify information in computer systems. UUIDs can be used to refer a wide variety of elements (documents, objects, sessions, tokens, entities, and so on). They can also be used as database keys.

As the name implies, UUIDs should be, for practical purposes, unique and ideally hard to guess, although in certain scenarios – some of them which will be later discussed in this post – an attacker in possession of UUIDs that were previously generated by a system might be able to predict future ones.

What is UUID Used For? Unveiling Universally Unique Identifiers (UUIDs)

Universally Unique Identifiers, also known as UUIDs or GUIDs, are 128-bit numbers used to uniquely identify information in computer systems. UUIDs can be used to refer to a wide variety of elements (documents, objects, sessions, tokens, entities, and so on). They can also be used as database keys.

As the name implies, UUIDs should be for practical purposes unique and ideally hard to guess; although in certain scenarios – some of them which will be later discussed in this post – an attacker in possession of UUIDs that were previously generated by a system might be able to predict future ones.

UUIDs are exploited in a variety of applications and industries for multiple reasons. The primary reason is to dodge conflicts when multiple systems need to generate unique identifiers. UUIDs eradicate the necessity for a centralized authority to manage unique identifiers, simplifying the scaling and distribution of systems.

Moreover, UUIDs are employed in distributed systems where data is spread across multiple servers or databases. Using UUIDs as unique identifiers simplifies the synchronization and merging of data from different sources, ensuring data integrity and consistency.

Format of UUIDs

The 16 octets of a UUID are represented as 32 hexadecimal digits and separated by hyphens into five groups in the form 8-4-4-4-12. This results in a total of 32 alphanumeric characters and 4 hyphens. See the UUID v1 example below:

123e4567-e89b-12d3-a456-426655440000
xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx

In this example:

  • M: Indicates the UUID version. In the example above, it’s UUID v1.
  • N: The 1–3 most significant bits of digit, N, indicate the UUID variant. In the example above, N is a (10102), meaning that the UUID is a variant-1. From the RFC:
Variant Msb0 Msb1 Msb2 Msb3 Description
0 0 X X X Reserved, NCS backward compatibility.
1 1 0 X X The variant specified in this document.
2 1 1 0 X Reserved, Microsoft Corporation backward compatibility.
3 1 1 1 X Reserved for future definition.

Nowadays most implementations adopt variant-1 where the Most Significant Bit (Msb0) is going to be set (1), whereas Msb1 is going to be unset (0). This leaves N with two “free” bits (Msb2 and Msb3), meaning that it can only be one of the following: 8, 9, a or b.

Exploring Different UUID Versions: From Nil UUID to UUID v4

The structure of a UUID consists of five components:

  • Time-based or random: UUIDs can be generated based on the current time or using a random number generator. The time-based UUIDs ensure uniqueness within a system, while random UUIDs provide a higher level of randomness.
  • Version: UUIDs come in different versions, each representing a specific algorithm used for generating the identifier. The most used version is version 4, which is based on random numbers.
  • Variant: The variant specifies the layout of the UUID and its interpretation. The most common variant is variant 2, which is used for all UUIDs generated by modern systems.
  • Timestamp: Time-based UUIDs include a timestamp component that represents the time of their generation. This allows for sorting and ordering based on creation time.
  • Node: The node component of a UUID is typically the MAC address of the generating node. It ensures uniqueness even in distributed systems.

In the UUID 00000000-0000-0000-0000-000000000000, all bits are set to zero.

UUIDs v1, also known as host or time based UUIDs, are generated taking into consideration different components. Take for example, the following UUID v1:

e034b5847d8911e996691aecf481a97b

  • Timestamp: A 60-bit value, representing the number of 100 nanosecond intervals since 15 October 1582 00:00:00.00. In this example, timestamp has the hexadecimal value of 1e97d89e034b584. In order to extract the time from said representation, the following calculations should be performed:
    1. Convert the hex value 1e97d89e034b584 to a decimal representation:
      • 0x1e97d89e034b584 = 137779294737053060.
    2. Subtract 122192928000000000 (the interval between Julian and Gregorian calendar in 100 nanoseconds) to the previous number and divide by 10000
      • (137779294737053060122192928000000000) / 10000 = 1558636673705.
    3. We now have the time in regular epoch/Unix timestamp. Convert to date and we obtain:
      • Thu May 23 13:37:53 CDT 2019.
  • Version: The UUIDs version in this example can be found in the grey text area “1”, which makes the example’s version UUID v1.
  • Clock Sequence / Clock ID: A 14-bit value, originally initialized to a random value to minimize the correlation across systems. (i.e., only performed once in the lifetime of a system). In this example, it’s 1669. In the UUID itself, the first digit isn’t a 1 but a 9 because the most significant bit is also set, as mandated by the variant.
  • Node ID: 48-bit MAC address of the “node” (that is, the computer generating the UUID). In this example, its 1a:ec:f4:81:a9:7b.
‍‍Version 1 UUIDs are often used in distributed systems where the uniqueness and time-based ordering of the identifiers are important, such as in database keys or log files.‍

UUID v2

Version-2 UUIDs are similar to version 1, except the least significant 8 bits of the clock sequence are replaced by a “local domain” number, and the least significant 32 bits of the timestamp are replaced by an integer identifier meaningful within the specified local domain, however, many UUID implementations omit version 2.

UUID v3 and UUID v5

Both UUID v3 and UUID v5 are generated using the hash of namespace and name. The key difference between versions three and five is that UUID v3 uses MD5 as the hashing algorithm, whereas UUID v5 uses SHA-1.

UUID = hash(NAMESPACE_IDENTIFIER + NAME)

UUID v4

UUIDs v4 are generated almost entirely random. Only four (4) bits are used to indicate the version and two (2) bits are used to indicate the variant (when variant-1 is adopted). The rest of the bits (122) are randomly generated. See the UUID v4 example below:

00e8da9b-9ae8-4bdd-af76-af89bed2262f

  • Version: UUID v4.
  • Variant: Instead of the a, also an 8, 9 or b could be present in that position.

One of the disadvantages of using UUID v4 is that there is a small chance of generating duplicated UUIDs. Although, with the high number of possible combinations (2^122), this situation is highly unlikely to happen.

Sandwich Attack: A New Way Of Brute Forcing UUIDs

Consider the following scenario: A web application allows users to reset their password by means of a “Forgot Password” functionality. After following the password reset process, a new UUID v1 is generated and an email with a unique reset link is sent to the email associated with said user. The reset link may look something like this:

https://www.acme.com/reset/836d28b2-7592-11e9-8201-bb2f15014a14

Once an attacker knows the web application uses UUID v1 for generating the password reset link, they could take the approach listed below to guess the right token for an arbitrary account:

    1. Send a password reset request for an account the attacker controls, for example, [email protected].
    2. Immediately after, send a password reset request for the targeted account ([email protected]) followed by a request for another account owned by the attacker ([email protected]). If multiple password reset requests are allowed in a short period, the first account can be used again ([email protected]). In order to carry out the attack as quickly as possible, tools like Turbo Intruder (Burp Suite extension) or racepwn can be used.
    3. Compare the URLs obtained for each password reset request:

https://www.acme.com/reset/99874128-7592-11e9-8201-bb2f15014a14

https://www.acme.com/reset/998796b4-7592-11e9-8201-bb2f15014a14

  1. Brute force the hexadecimal range between 998796b4 and 99874128 until the victim’s reset link is found. In this particular example, the space is considerably short (~22,000 combinations). If no rate-limiting protections are in place, the link can be found in less than an hour using standard computing resources.
  2. The targeted account’s password reset link will be something in the form:

https://www.acme.com/reset/99876914-7592-11e9-8201-bb2f15014a14

Applications and Practical Uses of UUIDs

Universally Unique Identifiers (UUIDs) play a critical role in various applications and software systems. Let’s delve into their applications in distributed databases, their integration in software systems, and the benefits and drawbacks of using UUIDs.

In distributed databases, UUIDs are critical for ensuring uniqueness across multiple nodes. As the name suggests, UUIDs are universally unique, meaning they are highly unlikely to collide with other identifiers. This uniqueness is especially crucial in distributed environments where multiple databases are needed to synchronize data.

Software systems also benefit from the integration of UUIDs. By using UUIDs as identifiers for entities such as users, products, or transactions, developers can ensure that these entities can be uniquely identified across different systems and databases. This allows for seamless integration and data synchronization, making it easier to build scalable and robust software applications.

Despite their advantages, using UUIDs also comes with some drawbacks. One of the main concerns is their length. UUIDs are typically represented as 128-bit values, resulting in longer strings compared to other identifier formats. This can have an impact on storage requirements, especially in situations where space optimization is crucial.

Additionally, the use of UUIDs may require additional computational resources to generate and handle these identifiers.

In summary, Universally Unique Identifiers have proven to be invaluable in ensuring uniqueness and integration in various applications and software systems. While they may have some drawbacks, the benefits they bring to distributed databases and software integration make them a valuable tool for developers.

Security Considerations When Building an Application with UUIDs

There are several security considerations for each version of UUIDs to consider when building an application. The best solution is to go with the most secure version of UUIDs for the kind and nature of the application you’re building.

For automated passive testing, use the UUID issues for the Burp Suite extension (also available in the PortSwigger repository).

Web Application Security

VerSprite focuses on emulating cybercrime and simulating test scenarios that not only reflect current attack patterns, but also threat motives. The foundation of VerSprite’s penetration testing methodology is based on emulating realistic attacks by a malicious actor through the use of PASTA (Process for Attack Simulation and Threat Analysis). Read More →

Professional Cyber Security Services for UUIDs

At VerSprite, we offer comprehensive solutions that leverage the power of UUIDs to ensure secure and unique identification of entities in various applications.

Contact the team at VerSprite now to discover how our expertise can assist you in implementing robust UUID-based solutions.