Cryptography is a critical component of virtually all modern technology solutions, ranging from basic web applications to the most complex cyber systems imaginable. Take a moment and reflect on what comes to mind when you think of “cryptography”; you may think about its use in encrypting sensitive data or in cookie-based authentication, or even in cryptocurrency. While it’s true that cryptography is used in each of these ways billions of times each day, these common use cases only scratch the surface of all the ways cryptography is used in modern technology.
For hackers, cryptography presents many valuable opportunities. It often underpins the most sensitive elements of a target. As developers and manufacturers strive to produce innovative solutions for their customers, we are increasingly seeing cryptography being used in novel (and unexpected) ways. In other words, cryptography presents hackers with the opportunity to find high-impact bugs and relatively unexplored functionalities within existing targets.
Get ready. This is an in-depth piece into the nuances of cryptography and how to attack it. Not only that, this is the first in a substantial series on everything you need to know about hacking cryptography. We’ll explore many of the opportunities that cryptography presents hackers. Some of the topics we’ll tackle include:
- Web, mobile, and desktop applications
- Advanced authentication solutions
- Cryptocurrency and blockchains
- Hardware hacking
As you can probably imagine, cryptography is a huge field, and entire books have been written on each of its subtopics. The purpose of this series is to provide hackers with actionable insights into how cryptography is being used. Additionally, it will offer practical knowledge about tools, tactics, and techniques that you can start using right away. To kick things off, we’ll start with a cryptography primer developed with hackers in mind.
Design flaws vs. implementation flaws
Naturally, before one can attack cryptography in a target, it’s critical to have a solid understanding of how cryptographic algorithms work “under the hood.” But before we delve into the nitty gritty details about various cryptographic algorithms, it’s important to note the difference between two tracks:
- Attacking the design of a cryptographic algorithm (i.e., cryptanalysis)
- Attacking the implementation of a cryptographic algorithm.
Having had success on both fronts, I can attest that both are viable attack vectors for hackers. However, as a general rule, cryptanalysis of a given algorithm is way harder and much more time-consuming than attacking the implementation of the algorithm in a specific application, product, or platform. With this in mind, it’s helpful to think of cryptography in terms of three distinct layers, each of which is typically susceptible to different classes of vulnerabilities:
1) The underlying mathematics
This is the most complicated layer and generally requires either formal education in mathematics or a lot of self-study of very dense material. In this layer, an attacker aims to identify fundamental flaws in the mathematics underpinning the algorithms themselves. On the one hand, hackers should never take anything for granted; on the other hand, the most commonly used algorithms have been vetted by a worldwide community of very smart people. That said, any time a developer “rolls their own” cryptography, the chances of a flaw in the underlying mathematics increase significantly.
For example, I once evaluated a homegrown cryptographic algorithm and found that it used multiplication (Px) instead of exponentiation (Px) for key generation, which dramatically weakened the strength of its keys.
2) Commonly used libraries
Virtually all commonly used cryptographic algorithms are described in detail via public documentation, such as Internet Engineering Task Force (IETF), Request For Comments (RFC), and/or Federal Information Processing Standards (FIPS) publications (see FIPS-PUB-197 and RFC 3602). Public knowledge of cryptographic algorithms is a cornerstone of their reliability, as it allows anyone to evaluate the algorithms for weaknesses. Such standards also help to ensure algorithms are implemented in a consistent manner across vendors.
Due to the complexity of cryptographic algorithms, an application security best practice is to integrate trusted open-source libraries that handle all low-level cryptographic operations. For example, the OpenSSL library is widely used to handle encryption/decryption, hashing, random number generation, and key generation. Being open source in nature, most such libraries have been reviewed by many security researchers and have generally been found to be secure. However, that’s not to say vulnerabilities aren’t sometimes found in such libraries (see CVE-2022-3602 and CVE-2022-3786). Remember, never take anything for granted. As hackers, it can be worthwhile to both evaluate the security of such open-source libraries and to look for outdated versions of such libraries integrated into third-party applications and products.
3) Application-specific implementation
This layer involves the implementation of cryptographic functionalities into target applications. As hackers, this layer presents the most opportunities for high-impact vulnerabilities. This is because it’s where application developers have the most direct impact. Typically, this layer has been subjected to the least security review. In many cases, seemingly innocuous decisions by developers during the design phase have led to serious vulnerabilities in their applications. Some common examples include:
- Insecure key generation
- Hardcoded keys
- Key reuse
- Insufficient entropy during random number generation
- Use of insecure/deprecated algorithms
- Insecure initialization vectors (IVs) or padding.
Symmetric encryption vs. asymmetric encryption
Symmetric encryption
Symmetric encryption relies on a single key for both encryption and decryption, which presents a number of key management challenges. The strength of symmetric encryption lies in its speed and simplicity, making it ideal for the encryption of large datasets. From the hacker’s perspective, common high-impact vulnerabilities include:
- Hardcoded keys
- Insecure key generation, exchange, or storage
- Use of insecure/deprecated cryptographic algorithms.
Over the years, many of the algorithms used in symmetric encryption implementations have been found to be insecure. Examples include AES-ECB, 3DES, DES, and RC4. This is a great example of how design-time decisions can lead to serious vulnerabilities, as the algorithms permitted by an application are often defined via configuration files and/or source code parameters. As hackers, we should always check for the use of insecure/deprecated ciphers. We’ll revisit this attack vector throughout this series, with examples of how it manifests across various types of targets.
Advanced Encryption Standard (AES)
The AES is the gold standard for symmetric encryption. Due to its robustness and efficiency, it has been widely adopted across industries. It supports key lengths of 128, 192, and 256 bits, with 256 bits providing the highest level of security. The AES operates in several modes:
- Electronic codebook (ECB): This mode encrypts data in independent blocks. While straightforward, it leaks patterns in data, making it unsuitable for most applications.
- Cipher block chaining (CBC): This mode adds randomness with an IV. However, improper implementation can lead to padding oracle attacks.
- Galois/counter mode (GCM): This mode combines encryption with data integrity verification, making it ideal for secure communications like HTTPS.
Asymmetric encryption
Asymmetric encryption (i.e., public-key cryptography) employs a pair of keys: a public key for encryption and a private key for decryption. This approach eliminates the need for secure key exchange but is computationally intensive. In many cases, the computational intensity of asymmetric encryption is overcome by combining it with symmetric encryption, where the asymmetric keys are used to derive temporary (or limited-time-use) symmetric keys. Asymmetric keys are also used to secure the communication channel over which symmetric keys are exchanged. Naturally, the specifics of how an application combines these encryption schemes are prime targets of bug bounty hunters. There are several asymmetric encryption algorithms that are commonly used today, each of which provides unique benefits and challenges.
RSA
RSA is based on the mathematical difficulty of factoring large integers. It is commonly used for secure key exchange and digital signatures. Perhaps the most common use case for RSA is the transport layer security (TLS) protocol to protect web traffic (HTTPS). Vulnerabilities include insufficient key lengths (keys shorter than 2048 bits are no longer secure) and susceptibility to padding oracle attacks if implemented with insecure padding schemes like PKCS#1 v1.5.
Elliptic curve cryptography (ECC)
ECC offers similar security to RSA but with much smaller key sizes, making it efficient for mobile and IoT devices. Its security relies on the hardness of the elliptic curve discrete logarithm problem (ECDLP). However, improperly chosen curve parameters or side-channel attacks can compromise ECC.
Diffie–Hellman (DH) key exchange
DH enables secure key exchange over insecure channels. A common use case for DH is the IPSec protocol, which secures network traffic and provides virtual private network (VPN) services. While DH itself is a secure algorithm, its implementation is susceptible to the use of insecure/deprecated ciphers via weak configuration parameters, which were exploited in the Logjam attack to downgrade connections to insecure levels.
Cryptographic hashes
Cryptographic hashing algorithms
Hashing algorithms produce fixed-length outputs (hashes) from input data of any size. They ensure data integrity and are crucial for password storage and digital signatures.
SHA-2
The SHA-2 family, including SHA-256 and SHA-512, provides robust security against collision and preimage attacks. It’s widely used in modern applications, including blockchain technologies and secure communications.
SHA-3
Developed as a successor to SHA-2, SHA-3 employs a sponge construction based on the Keccak algorithm. It offers resilience against differential and linear cryptanalysis, ensuring its robustness for future applications. While SHA-2 is still widely used and deemed to be secure, SHA-3 highlights the constant tension between the computational complexity of cryptographic algorithms and the computational power available.
MD5 and SHA-1
These algorithms were once ubiquitous but are now deprecated due to their vulnerability to collision attacks. Such vulnerabilities enable attackers to forge digital signatures or tamper with data. Any time a target makes use of MD5 or SHA-1 (or even allows for the use of these algorithms), there’s a high likelihood that it can be leveraged to achieve severe impact.
BLAKE2
BLAKE2 is a high-performance alternative to SHA-3. It was designed for applications requiring fast and secure hashing. It is favored for its speed and simplicity in implementation.
Cryptographic key management
Virtually all cryptographic implementations are only as secure as the keys that they use. For this reason, it is critical that developers take a secure and trustworthy approach to cryptographic key generation, exchange, storage, rotation, revocation, and expiration. Taken together, these activities fall under the umbrella of cryptographic key life cycle management. From the hacker’s perspective, each phase of the cryptographic key life cycle presents unique opportunities to compromise a target. In the coming weeks, we’ll explore practical examples of exploitable key management vulnerabilities, but for now, let’s have a high-level look at some of the “key” life cycle management considerations:
Key generation
When generating cryptographic keys, it is vitally important that an implementation’s outputs are not predictable. Thus, a critical aspect of trustworthy key generation is the use of a secure entropy source. If an implementation fails to do so, an attacker may be able to predict cryptographic secrets, session tokens, API keys, etc. Because cryptographic key generation is complex and riddled with pitfalls, many solutions implement algorithms that simplify the key generation process.
One such example is the password-based key derivation function (PBKDF-2), which uses an iterative process to convert an alphanumeric password into a cryptographic key. Another common weakness in the implementation of cryptographic keys is the use of an insufficient number of iterations in the PBKDF-2 parameter definition.
Key exchange
For two (or more) parties to securely exchange information without exposing it to tampering and/or prying eyes, the keys used for cryptographic operations must first be securely exchanged. While this may seem simple enough, it’s quite challenging to achieve in practice, especially when it must be performed transparently and at scale. Many commonly used solutions to this problem leverage asymmetric cryptography. This allows for the public dissemination of one of the keys (i.e., the “public” key) and requires that the secrecy of the other key (i.e., the “private” key) be maintained.
As hackers, whenever we observe cryptography in use, we should ask ourselves: “What constraints did the developer have to work through when designing the key exchange strategy, and what opportunities might these constraints present?” For example, I once identified an impactful vulnerability in the way a popular desktop application integrated with its mobile app counterpart. At the root of that vulnerability was a weakness in the application’s key exchange strategy, which became obvious to me once I realized that the desktop application had to have some way of authenticating mobile peers without any prior setup.
Key storage
Insecure key storage is one of the most common cryptographic vulnerabilities that we see in the bug bounty context. It often presents as a hardcoded key in an application binary or configuration file. It’s also one of my favorites because while this bug pattern is seemingly simple, it rears its head in novel ways every day, and it almost always leads to have critical impact. Whether testing a mobile app, a desktop app, a hardware device, or anything in between, we should always be on the lookout for insecure key storage. From the defender’s perspective, best practices involve using hardware security modules (HSMs) for secure storage, implementing robust key distribution protocols, and securely destroying keys when they are no longer needed.
Key rotation, revocation, and expiry
The last phase of a cryptographic key’s life cycle is easy to overlook in the development process. However, it can lead to some of the most critical findings. As hackers, we should be mindful that no cryptographic key is designed to be used forever, and the longer it’s used, the weaker it becomes. For this reason, we should be on the lookout for poor practices in the ways developers handle key rotation, revocation, and expiry. Some common examples of such vulnerabilities are (a) long-lived keys using outdated algorithms or cryptographic parameters (e.g., key size), (b) failure of an application to properly validate cryptographic keys, and (c) defaulting to “allow” in the event that key revocation services, such as certificate revocation lists (CRLs) and the Online Certificate Status Protocol (OCSP), are unreachable.
Common cryptographic attacks
Brute force attacks
Brute force attacks are perhaps the most straightforward cryptanalysis technique, wherein an attacker systematically attempts all possible keys, passwords, tokens, etc. until they identify the correct value. While simple enough in theory, brute force attacks are generally not feasible due to the computational complexity of modern cryptographic algorithms. Consider the following example: An 8-bit keyspace provides only 65,536 possible values (2^16), which is trivial to brute force. However, a 64-bit keyspace provides 18,446,744,073,709,551,616 possible values (2^64). Thus, there is always a tension between the computational complexity of modern cryptographic algorithms and the computational power afforded by current hardware. This is one reason why quantum computing potentially poses major challenges for current cryptographic algorithms, as quantum computers exponentially increase the computing power available by using quantum bits (i.e., qubits), which can represent multiple possible values simultaneously. Fortunately, quantum computers are still in their infancy. According to leaders in the quantum computing space, it will be years before such systems are capable of effective brute force attacks against current cryptographic algorithms.
While brute force attacks against large keyspaces might be unfeasible, it is common to encounter environments or applications in which legacy algorithms and protocols are used. These may be susceptible to a variety of brute force attacks. Below is a list of common brute force attack vectors:
- Password cracking: Attackers systematically guess passwords hashed using algorithms like MD5 or SHA-1. Tools like hashcat leverage GPUs to speed up this process.
- Keyspace exhaustion: Attackers attempt every possible encryption key in algorithms with small key sizes, such as DES (56-bit key).
- Dictionary attacks: This specialized form of brute force tests likely combinations, such as common passwords or phrases, instead of every possible input.
- Rainbow table attacks: These involve precomputed hash values for common inputs, significantly reducing the time required to brute force hash algorithms.
- Credential Stuffing: This uses previously breached username–password pairs to attempt unauthorized access.
Brute force attacks can be a viable means of identifying high-impact vulnerabilities in many different ways. In the simplest case, a web application that fails to implement rate-limiting and/or account lockout protections is susceptible to brute force password attacks. As another example, an application that implements SMS-based one-time passwords (OTPs) but fails to implement rate-limiting and/or account lockout protections is also susceptible to brute force attacks. Such attacks likely will be effective means of identifying the correct OTP due to the relatively small keyspace of SMS-based OTP tokens (e.g., 6 digits). In a more complex case, suppose we have managed to exfiltrate a copy of a web application’s password database but the passwords are salted and hashed. In this example, if the target application fails to implement a strong password length and complexity policy, we can use tools like hashcat or John the Ripper to brute force some of the passwords. Once a password has been compromised, the account can potentially be used to escalate privileges or pivot to attack other, more privileged users (assuming this is permitted in a bug bounty program’s scope).
Side-channel attacks
In contrast to brute force attacks, which are generally the simplest to execute, side-channel attacks tend to be some of the most complex cryptographic attacks to carry out. At their core, side-channel attacks focus on external characteristics, such as timing, power consumption, electromagnetic emissions, or even acoustic signals. By analyzing these side effects, attackers can infer cryptographic keys or sensitive data. While such attacks may seem outlandish, there is actually a well-documented history of side-channel attacks being used to compromise high-value targets. This has led to the development of several standards pertaining to the evaluation of a target’s ability to withstand side-channel attacks, such as the TEMPEST and Common Criteria standards. Some common examples of side-channel attacks include the following:
- Timing attacks: These exploit variations in processing times for cryptographic operations. For example, the time taken to validate padding in RSA decryption can reveal information about the private key. Timing attacks are particularly effective against algorithms that do not employ constant-time operations.
- Electromagnetic (EM) attacks: By measuring electromagnetic emissions during cryptographic operations, attackers can reconstruct data being processed. EM attacks are highly invasive but effective against poorly shielded devices.
- Cache attacks: These exploit the behaviors of CPU caches. For example, attackers can infer cryptographic operations by analyzing cache access patterns, particularly in shared environments like virtual machines.
- Acoustic cryptanalysis: In rare cases, attackers analyze sound emissions from devices during cryptographic processing. For example, variations in fan noise or vibrations can reveal sensitive data.
- Fault injection attacks: These induce deliberate errors in cryptographic computations through techniques like voltage manipulation, laser injection, or electromagnetic pulses. The resulting errors can help attackers recover secret keys.
- Power analysis attacks: These involve measuring the power consumption of a device during cryptographic operations. Variants include:
- Simple power analysis (SPA), which observes power usage patterns to deduce key operations.
- Differential power analysis (DPA), which analyzes multiple power traces to identify statistical correlations with secret keys.
Side-channel vulnerabilities may present unique opportunities because they arise from flaws in the implementation(s) of cryptographic algorithms rather than flaws in the algorithms themselves. Unsurprisingly, side-channel attacks often require an attacker to have access to the hardware on which cryptographic operations are being performed (both to gather baseline data and to evaluate the active target), which makes such vectors particularly useful against targets of hardware hacking. For example, consider a hardware device that makes use of a shared private key for cryptographic operations but the key is properly stored in an onboard Trusted Platform Module (TPM) chip. Tools like ChipWhisperer can be used to perform side-channel attacks against the device to glean the private key. In this example, there are actually two vulnerabilities at play: (a) use of a shared private key across multiple hardware devices and (b) side-channel weaknesses. When they are on their own, it may be difficult to demonstrate meaningful impact in the bug bounty context. But taken together, these vulnerabilities can be used to achieve critical impact, such as the ability to take over an entire fleet of devices.
Padding oracle attacks
Padding oracle attacks are another type of attack that exploits vulnerabilities in the implementation of a cryptographic algorithm, as opposed to flaws in the algorithm itself. In the case of padding oracles, such attacks specifically target block cipher modes, such as CBC, which require padding of plaintext to match the block size of the encryption algorithm. Insecure implementations often leak information about whether the padding of decrypted ciphertext is valid or invalid. We can use this information (i.e., the oracle) to iteratively decrypt data or forge valid ciphertexts without knowing the encryption key. To take advantage of a padding oracle attack, it is necessary to have some form of observable feedback that can be used to infer the validity of padding in decrypted data. A common example is a web application that takes as its input some encrypted data and generates a stack trace if decryption fails. In this example, by systematically modifying the ciphertext submitted to the web application, we can recover decrypted plaintext or possibly even manipulate encrypted data (depending on the use case of the encrypted input). Some common examples of padding oracle attacks include the following:
- CBC padding oracle attack: This classic attack exploits systems that improperly validate padding in the CBC mode. For example, an attacker might submit modified ciphertexts to a decryption endpoint and observe whether the response indicates valid or invalid padding. This would allow the attacker to deduce plaintext values byte by byte.
- Browser Exploit Against SSL/TLS (BEAST): While primarily a side-channel attack, BEAST leverages padding oracle techniques to target SSL/TLS connections using CBC mode encryption. By analyzing predictable patterns in block ciphers, the attack reveals plaintext data in encrypted communications.
- PKCS#7 padding exploits: Many implementations use the PKCS#7 padding scheme, where plaintext is padded with bytes indicating the padding length. Improper handling of PKCS#7 padding can lead to padding oracle vulnerabilities, enabling attackers to decrypt or forge data.
Padding oracle attacks can reveal high-impact vulnerabilities because such weaknesses often lead to the unauthorized disclosure of critical and/or sensitive user information, session tokens, etc. We’ll explore specific examples of such vulnerabilities later in this series, but to operate at a high level, we want to keep an eye out for any variations in server responses based on attacker-controlled ciphertext. Such variations can range from the obvious, like stack traces, to subtle differences like web server response times.
Timing attacks
Cryptographic timing attacks exploit variations in the time taken to perform certain cryptographic operations, such as conditional statements, loops, or mathematically intense operations within cryptographic algorithms. By measuring the time it takes to execute certain cryptographic functions, we can infer information about encryption/decryption keys, passwords, or other sensitive data. In this way, cryptographic timing attacks are similar to side-channel attacks. We could even make the argument that timing attacks are really just a subcategory of side-channel attacks. In practice, however, there have been so many real-world instances of cryptographic timing attacks against well-known algorithms/protocols that such attacks warrant their own classification. From a methodology perspective, this helps to ensure that we are thoroughly testing all potential attack vectors and, in the process, leveraging our understanding of historical weaknesses to identify novel instances of recurring bug patterns.
One way to visualize cryptographic timing attacks is to consider that cryptographic algorithms often make use of operational “blocks,” which are chained together and computed iteratively to achieve the desired result (e.g., encryption or decryption). If a given operational block tends to complete faster or slower depending on the plaintext, ciphertext, or keys used, these differences can be used as a type of oracle to glean information about secret information. While this may seem like a farfetched attack vector, there have actually been many instances of such vulnerabilities in the wild:
- RSA timing attacks: RSA implementations that use modular exponentiation can reveal private key bits based on variations in the computation time. An attacker can analyze the time taken for decryption or signing operations to reconstruct the private key.
- SSL/TLS timing attacks: Insecure implementations of SSL/TLS protocols have been vulnerable to timing attacks, such as analyses of the time taken to respond to handshake messages or validate session tickets. These attacks can compromise session keys or plaintext data.
- Password validation timing attacks: Web applications that validate passwords character by character, or byte by byte, often exhibit timing discrepancies. An attacker can use these discrepancies to brute force passwords one character at a time, significantly reducing the attack complexity.
- Hash-based message authentication code (HMAC) timing attacks: HMACs are used to verify the integrity of data. If the comparison of expected and actual HMAC values is not in constant-time, an attacker can deduce the correct value byte by byte by analyzing response times.
- Cache-timing attacks: These leverage timing differences in accessing CPU cache memory during cryptographic operations. Cache-timing attacks have been used to extract AES keys by analyzing memory access patterns during encryption.
Cryptographic functionalities in the targets we test are often somewhat of a black box, so it may take some creative brainstorming to hypothesize potential timing-based attack vectors. While this is often more time-consuming than testing for run-of-the-mill web application vulnerabilities, it also presents unique opportunities. This is because as a general rule, the higher the barrier to entry for testing a particular functionality, the less other researchers tend to test them. This, in turn, translates into less competition and a lower likelihood of duplicate findings. Additionally, as with many cryptography-related bugs, the impact of cryptographic timing vulnerabilities can be quite severe, as they often lead to the complete compromise of highly sensitive information and/or systems.
Insufficient entropy in random number generation
Random number generation is critical for many cryptographic operations. In this context, entropy refers to the measure of unpredictability or randomness in generated numbers. When a random number generator (RNG) lacks sufficient entropy, it produces predictable outputs, which can lead to severe vulnerabilities in cryptographic implementation. Insufficient entropy often arises from using deterministic algorithms, inadequate sources of randomness, or poor seeding mechanisms. For example, if an RNG is seeded with a predictable value, such as a system clock, its outputs become predictable, which we can leverage to make educated guesses about keys, tokens, or other sensitive data. Here are some common examples of how insufficient entropy in RNG can undermine cryptographic implementations:
- Predictable key generation: Cryptographic keys generated using low-entropy sources, such as user inputs or timestamps, are vulnerable. Attackers can brute force the key space by focusing on likely values, significantly reducing the computational effort required.
- TLS nonce prediction: TLS relies on nonces (numbers used once) to ensure secure communications. If nonces are predictable, attackers can replay or manipulate encrypted messages.
- Session token prediction: Web applications often generate session tokens to maintain user sessions. Tokens created using low-entropy RNGs can be guessed, allowing attackers to hijack sessions and impersonate users.
- Bitcoin wallet exploits: Insufficient entropy in the generation of private keys for Bitcoin wallets has led to theft. Attackers were able to predict private keys and gain unauthorized access to cryptocurrency.
- Captcha and OTP vulnerabilities: Captchas or OTPs generated with low entropy can be guessed, defeating their security purpose.
Many platforms (e.g., Python) provide both secure and insecure RNGs, so developers must take care to use the appropriate RNG for cryptographic operations. As hackers, we encounter RNGs on a daily basis, in use cases ranging from cryptographic key generation to session token generation. We should evaluate all possible instances in which a target may use an RNG as a source of randomness and attempt to predict its output(s) using blank, default, or weak RNG seed values. Such opportunities highlight the importance of thoroughly researching bug bounty targets, including accurate fingerprinting of the underlying platforms, tools, and/or programming languages used. Throughout this series, we will continue to explore several practical examples of how insufficient entropy in RNGs can be exploited to achieve critical impact.
Conclusion
We’re just getting started! The nuances of cryptography can be difficult to understand. However, such knowledge is crucial to bug bounty researchers aiming to identify and exploit high-impact vulnerabilities. Cryptographic operations in bug bounty targets also present researchers with potentially untested functionalities due to the perceived complexity of the topic. In other words, in-depth testing of cryptographic functionalities is glossed over by many internal application security teams and hackers alike, which makes for extensive and fertile hacking grounds! Stay tuned for more target-specific articles on valuable cryptographic hacking techniques that you can put to work right away.