In 2011, researchers published a proof of concept for an attack dubbed BEAST (Browser Exploit Against SSL/TLS) that allowed a man-in-the-middle attacker to uncover information from an encrypted SSL/TLS 1.0 session. While it was deemed hard to perform in the wild, the threat eventually prompted browser vendors and web server administrators to move to TLS v1.1 or higher and implement additional safeguards to eliminate the vulnerability. Even though no modern web browser remains vulnerable, the BEAST attack provides a fascinating tale of how a minor and seemingly only theoretical vulnerability can be combined with other weaknesses to eventually craft a practical attack. In this article, we will look at how the BEAST attack worked, why it was possible, and how it was eventually mitigated.
The Vulnerability: Unsafe Initialization Vectors in TLS 1.0
The vulnerability in the TLS (Transport Layer Security) protocol that was exploited in the BEAST attack had been discovered by Phillip Rogaway as far back as 2002, and actually mitigated in 2006 in the TLS 1.1 specification. The weakness was considered to be impractical to exploit, as it required a huge number of attempts to discover any useful information. So when the first proof of concept was published in 2011, most websites still used TLS 1.0 or an earlier version of SSL – and were vulnerable.
In a nutshell, the BEAST attack exploited a vulnerability in the way the TLS 1.0 protocol generated initialization vectors for block ciphers in CBC mode (CVE-2011-3389). Combined with clever manipulation of block boundaries, the flaw allowed a man-in-the-middle attacker sniffing encrypted traffic to discover small amounts of information without performing any decryption, and could be exploited regardless of the type and strength of the block cipher. To understand exactly how this was possible, let’s start with a little background information about symmetric cryptography using block ciphers.
Block Ciphers and Initialization Vectors
When you connect to a website over HTTPS, the web browser and server negotiate an encryption scheme and key to be used for the session. The negotiation process is protected using asymmetric (public-key) cryptography but actual communication is encrypted using much faster symmetric algorithms, usually block ciphers such as DES, 3DES, or AES. Block ciphers encrypt data in fixed-length blocks, and if the last block of a message is not completely filled, it is padded with random data.
Without additional processing, a block cipher would always give the same ciphertext for the same data and key, and be vulnerable to chosen plaintext attacks. That’s why block ciphers are only used in specific modes of operation that perform additional processing to increase security. The most common mode is Cipher Block Chaining (CBC), where each block of plaintext is combined (XORed) with the previous block of ciphertext, so the value of each block depends on all the preceding blocks. But what about the first block?
In CBC mode, the first block is combined with an initialization vector (IV) – a random block of data that makes each message unique. The security of any block cipher in CBC mode depends entirely on the randomness of initialization vectors. And here’s the problem: in TLS 1.0, initialization vectors were not randomly generated. Instead of generating a new IV for each message, the protocol uses the last block of ciphertext from the previous message as the new IV. This opens up a serious vulnerability because anyone who intercepts the encrypted data also gets the initialization vectors. Blocks are combined using XOR, which is a reversible operation, so knowing the initialization vectors could allow an attacker to discover information from encrypted messages.
Figure 1. How it should work: encryption using a block cipher in CBC mode
Recovering Information Without Decrypting It
Let’s say we have a man-in-the-middle attacker who is sniffing TLS 1.0 traffic and can inject data into it. If the attacker knows what kind of data is being sent and where it is in the message, they can inject a specially crafted data block and check if the resulting encrypted block is the same as the corresponding block in the actual message stream. If so, the injected guess was correct and the attacker has discovered the plaintext block. If not, they can try again and again with different likely values. This is called a record splitting attack.
And what is that specially crafted data block? To encrypt a data block in CBC mode, TLS 1.0 uses XOR to combine the plaintext block, the previous ciphertext block (which the attacker knows), and the initialization vector (which the attacker also knows from sniffing the previous message). XOR is reversible, so the attacker can mount a chosen plaintext attack by guessing a likely block of data and XOR-ing it with the IV and the preceding block of ciphertext, and injecting the result into the session.
Crucially, the attacker can only check if the entire block was guessed correctly. Block size varies depending on the cipher but brute-forcing a whole block would, in any case, require an impractically large number of attempts. For example, if we have 8-byte (64-bit) blocks with 256 possible values for each byte, the total number of combinations to check is 2568 – less if you limit the values to only alphanumeric characters or another known subset, but still far too much. This is why the vulnerability was not considered a real threat until the first proof of concept surfaced.
Figure 2. The vulnerability: a record splitting attack against TLS 1.0
The Exploit: Record Splitting with a Chosen Boundary Attack
In 2011, security researchers Thai Duong and Juliano Rizzo published the first proof of concept exploiting this vulnerability. They managed to drastically cut the number of attempts required to guess a value by shifting cipher block boundaries to isolate just one byte of a block. This greatly reduced the complexity of the attack – instead of guessing the whole block, the attacker is brute-forcing one byte at a time, so guessing a 10-digit number would require just 10 guesses for each digit and no more than 100 attempts for the whole number (50 on average).
The approach described by Duong and Rizzo relies on the rigid structure and predictable content of HTTP packets, especially containing equally predictable HTML code. By carefully crafting HTTP requests, it is possible to control the location of cipher block boundaries (hence the name Blockwise Chosen Boundary Attack) and create a message where all bytes are known except the targeted data – typically the session cookie. The block boundaries are then moved to obtain a block where exactly one byte is unknown. Now the actual TLS vulnerability can be exploited to check likely values. After each successful check, the block boundaries are shifted by one byte and the process repeats until all unknown bytes have been discovered.
Figure 3. The exploit: a chosen boundary attack combined with record splitting
The attack was limited to recovering short strings and required a relatively large number of requests but even so, in specific situations, it could be used to read session cookies or login credentials. In a perfectly feasible attack scenario, the user browses to a site that executes the malicious script. Without closing this site, the user then logs into a high-value website, such as an online banking application, and keeps both sites open for 10 minutes or so. The attack script runs in the background, attempting to brute-force the active session cookie. If the attack succeeds, the attacker can hijack the banking session and impersonate the user until the legitimate user logs out.
News of the exploit prompted software vendors scrambled to mitigate the threat, both on the server side and in browsers. The safest way to ensure security was to allow only TLS 1.1 or TLS 1.2, as they fixed the underlying TLS 1.0 vulnerability. Unfortunately, nearly all websites and major browsers still supported TLS 1.0 as the highest version of the SSL protocol. Specifically, Google Chrome, Mozilla Firefox, and Safari for Mac OS X 10.7 (or earlier) were vulnerable, as was Internet Explorer on Microsoft Windows XP. In Windows Server 2008 R2, TLS 1.1 was disabled by default but could be enabled by changing Windows Secure Channel (SChannel) settings.
Before TLS 1.1 was widely adopted, several ways to mitigate the vulnerability without upgrading the protocol were explored:
- Switch to a stream cipher: Apart from block ciphers, the TLS specification also mandated support for at least one stream cipher: RC4. The vulnerability only affected block ciphers in CBC mode, so initially, the recommended workaround was to switch to the RC4 cipher. Unfortunately, in 2013 researchers demonstrated that RC4 was theoretically insecure, and as more flaws in the cipher were discovered, in 2015 the IETF published RFC 7465, officially forbidding the use of RC4 in TLS implementations.
- Change the block cipher mode: The attack targeted CBC mode, so theoretically switching to another block cipher mode would do the trick. However, TLS 1.0 (unlike later TLS versions) only supported CBC mode, so this workaround was not possible.
- Insert empty packets to consume unsafe initialization vectors: A quick fix was developed that used additional empty packets (with zero-length payloads). Incomplete blocks are padded with random data to the block size, so sending a zero-length data block would generate a full block of random padding. When inserted between messages, this random block was then used as the initialization vector for the next message, making encryption secure again. However, this behavior was not documented in the TLS 1.0 specification, and the fix caused compatibility issues with some SSL stacks, notably Internet Explorer 6.0. In OpenSSL, the fix was implemented but disabled by default.
- Use 1/n-1 packet splitting: Some browsers, including Firefox and Safari, patched their TLS 1.0 implementations to split HTTPS packets. The idea is similar to the empty packets fix but without zero-length payloads. At the start of each message, you send the first byte of an n-byte data block in a separate packet and put the remaining n-1 bytes of this block in a second packet (hence 1/n-1 split). The first packet will be padded with random data before being combined with the insecure initialization vector, thus restoring randomness to the encryption process.
The Aftermath of the BEAST
As of October 2019, the vast majority of websites support TLS v1.2, which combined with mitigation measures integrated into modern browsers means that BEAST and similar attacks are no longer a threat. The upcoming deprecation of TLS 1.0 and 1.1 in major browsers will only serve to reinforce this. Of course, this only applies to modern web browsers and operating systems – there’s a good chance that vulnerable legacy applications still linger on in company intranets, maybe still running on Windows XP and requiring Internet Explorer 6.0 with some long-obsolete DirectX control or ancient Java applet.
The story of the BEAST attack provides valuable lessons for security professionals. The key takeaway is that implementations often lag far behind the latest security protocol specifications – when the first exploit was published, the vulnerability had already been fixed for five years in the TLS 1.1 specification. What’s more, cryptographic vulnerabilities considered impractical or purely theoretical will be exploited in practice if you wait long enough, so it’s good practice to keep up with recommended specifications. And finally, theoretically secure cryptographic schemes can be compromised by even slightly inaccurate implementations, so it’s always a good idea to use state-of-the-art vulnerability scanners that can test your application for deprecated protocol support to maintain security.