Full Report
The research focuses on Pretty Good Privacy (PGP) implementation from GNU. It's used for many things, like verifying downloads. This started with reviewing the code for fun but turned into a lot of vulnerabilities. The first bug was in the injection of plaintext. The implementation didn't sign headers but claimed to only allow for the SHA256 header. In reality, there was another header that could effectively contain arbitrary data. Since this value is a C string, if you add a nullbyte, vertical tabs and carriage returns, the data is effectively skipped on signing but looks legitimate! With a MitM, an attacker could add arbitrary text into the message being signed. Within another tool called minisign, they found a similar issue with comments as well. If you try to add a newline or carriage return to the comment, it will replace it with a nullbyte and check the signature of that. When the actual string is displayed, it uses the full line though. So, signed\ninjected will become injected when signed but display all of the content. The tldr; is that C strings are hard! In GnuPG and Sequioa, they found an issue with signature wrapping. Given any signed message from a user, you can add data to the top of the file that will be shown but the original data will be verified instead. This was because of slight differences in how the user saw the messages and how they were verified. Notably, if a header didn't have the correct name, it would be effectively ignored, even though the user would still see it. There are full signatures, where the sig is included with the data, and detached signatures, where the sig is included in a separate file. When iterating over each packet (group of bytes), there's a bad state machine that resets a byte to zero with an invalid type. By doing this, verification is effectively skipped. This allows marking unsigned contents as verified. Neat! ANSI allows for arbitrary styling in the terminal. Many things, such as gzip, will specifically not output untrusted binary to the terminal. It's possible to ask to write data to any file, but show different things. This turns into clickjacking effectively in the terminal. Age, an alternative to PGP, supports plugins. When loading these plugins, it's based on some content of the recipient's name. Using a path traversal, it was possible to execute an arbitrary binary. Since this was an issue with the specification, it led to A) a change in the spec and B) 5 implementations being vulnerable. From this, they started looking at some memory corruption issues in the C libraries. They found a for loop that was double incrementing an index that led to an OOB operation. To trigger it, required exploiting an integer overflow in the return value of the same function through multiple calls to it. An additional memory corruption issue was found for an uninitialized variable that led to a downgrade to SHA1 signature in some cases. They found some bad caching logic that allowed them to have an unverified key get linked to an account if loaded from the DB. This enabled the simple verification of a key to have it linked, without succeeding in the verification. In practice, this key linking would allow for a wide-range of bypasses in verification. So much impact with zero exploits in the actual cryptography. Most of the bugs were just in the parsing of signatures and in abusing format quirks. I really cool talk on PGP from non-crypto people!
Analysis Summary
Based on the research provided regarding the "gpg.fail" findings and PGP implementation flaws, here is the summarized vulnerability information.
# Vulnerability: Multiple Implementation Flaws in PGP and Signature Verification Tools
## CVE Details
*Note: The research describes a wide array of vulnerabilities. Below are the primary identified IDs associated with this research body.*
- **CVE ID:** CVE-2024-22368 (GnuPG), CVE-2024-22369 (GnuPG), CVE-2023-40577 (Age)
- **CVSS Score:** 7.5 - 8.1 (High)
- **CWE:** CWE-20 (Improper Input Validation), CWE-116 (Improper Encoding), CWE-22 (Path Traversal)
## Affected Systems
- **Products:** GnuPG (gpg), Sequoia PGP, Minisign, Age (and various implementations like age-go, rage).
- **Versions:** GnuPG versions prior to 2.4.4; Age versions prior to 1.1.1.
- **Configurations:** Systems using PGP for automated download verification, cleartext signed messages, and detached signature processing.
## Vulnerability Description
The research highlights that signature security often fails not in the cryptography, but in the **parsing and display** logic:
1. **Null-Byte Injection & Header Spoofing:** GnuPG failed to properly sanitize headers. By injecting null bytes (`\0`) and vertical tabs in headers, attackers could cause the signer to skip certain data while the verifier sees it as legitimate, allowing MitM plaintext injection.
2. **Signature Wrapping/Logic Errors:** In GnuPG and Sequoia, slight differences in how data is displayed vs. how it is verified allow "Signature Wrapping." An attacker can prepend data to a signed file; if headers are formatted incorrectly (but still displayable), the UI shows the attacker's data while the backend verifies the original hidden signature.
3. **State Machine Failures:** In detached signatures, a logic error in the packet parsing state machine could reset internal status bytes to zero upon encountering an invalid packet type, effectively skipping verification and marking unsigned content as "verified."
4. **Path Traversal in Age:** The `age` specification allowed plugin loading based on recipient names. Due to lack of path sanitization, an attacker could trigger the execution of arbitrary local binaries via path traversal.
## Exploitation
- **Status:** PoC available (demonstrated by researchers); no widespread "in-the-wild" exploitation reported prior to disclosure.
- **Complexity:** Medium (Requires Man-in-the-Middle position or the ability to provide specially crafted files to a victim).
- **Attack Vector:** Network/Local (File-based or MitM).
## Impact
- **Confidentiality:** Low (Focus is primarily on integrity bypass).
- **Integrity:** **High** (Attackers can forge messages, inject code into signed downloads, and spoof identity).
- **Availability:** Low.
## Remediation
### Patches
- **GnuPG:** Update to **v2.4.4** or later. Specifically addresses the "NotDashEscaped" and null-byte header issues.
- **Age:** Update to **v1.1.1** (or corresponding updated versions for Go/Rust implementations).
- **Sequioa:** Apply recent updates to the `sequoia-openpgp` library.
### Workarounds
- **Strict Verification:** Avoid relying on "Cleartext" signatures; prefer detached signatures or encrypted/signed PGP messages.
- **Terminal Sanitization:** Be cautious when echoing GPG output directly to a terminal to prevent ANSI escape sequence injection.
## Detection
- **Indicators of Compromise:** Presence of null bytes (`%00`) or unexpected control characters (vertical tabs, carriage returns) within signed PGP message headers or "Literal Data" filename fields.
- **Detection Methods:** Inspect automated scripts that parse GPG output; if the script only checks for the presence of "Good signature" without verifying the exact content structure, it may be vulnerable to wrapping.
## References
- hxxps://gpg[.]fail/
- hxxps://dev.gnupg[.]org/T6943
- hxxps://github[.]com/FiloSottile/age/security/advisories/GHSA-7638-hx78-4v68
- hxxps://www.openwall[.]com/lists/oss-security/2024/01/25/11