GHSA-6m5f-j7w2-w953 AVideo has a PGP 2FA Bypass via Cryptographically Broken 512-bit RSA Key Generation in LoginControl Plugin
SummaryThe `createKeys()` function in the LoginControl plugin's PGP 2FA system generates 512-bit RSA keys, which have been publicly factorable since 1999. An attacker who obtains a target user's public key can factor the 512-bit RSA modulus on commodity hardware in hours, derive the complete private key, and decrypt any PGP 2FA challenge issued by the system — completely bypassing the second authentication factor. Additionally, the `generateKeys.json.php` and `encryptMessage.json.php` endpoints lack any authentication checks, exposing CPU-intensive key generation to anonymous users.DetailsThe vulnerability originates in `plugin/LoginControl/pgp/functions.php` at line 26:This code was copied from the `singpolyma/openpgp-php` library's example/demo code, which was never intended for production use. The entire PGP 2FA flow relies on these weak keys:**Key generation**: When a user enables PGP 2FA, the UI calls `createKeys()` which generates a 512-bit RSA keypair. The public key is saved to the database via `savePublicKey.json.php`.**Challenge creation** (`LoginControl.php:520-531`): During login, a `uniqid()` token is generated, stored in the session, and encrypted with the user's stored public key:**Challenge verification** (`LoginControl.php:533-539`): The user must decrypt the challenge and submit the plaintext. Verification is a simple equality check:Since 512-bit RSA was publicly factored in 1999 (RSA-155 challenge), an attacker who obtains the public key can factor the modulus using freely available tools (CADO-NFS, msieve, yafu) in a matter of hours on modern hardware, reconstruct the complete private key from the prime factors, and decrypt any challenge encrypted with that key.**Unauthenticated endpoints** (compounding issue):`generateKeys.json.php` does not include `configuration.php` and has no authentication check:Similarly, `encryptMessage.json.php` has no authentication. Both are accessible to anonymous users, enabling abuse of CPU-intensive RSA key generation for denial-of-service.PoC**Step 1: Obtain the target user's 512-bit public key**The public key must be obtained through a side channel (e.g., the user sharing it per PGP conventions, another vulnerability leaking database contents, or admin access). The key is stored in the `users_externalOptions` table under the key `PGPKey`.**Step 2: Extract the RSA modulus from the public key****Step 3: Factor the 512-bit modulus****Step 4: Reconstruct the private key and decrypt the 2FA challenge****Step 5: Submit decrypted challenge to bypass 2FA****Unauthenticated endpoint abuse:**Impact**2FA Bypass**: Any user who enabled PGP 2FA using the built-in key generator has their second factor effectively nullified. An attacker with knowledge of the password (phishing, credential stuffing, breach reuse) can bypass the 2FA protection entirely.**Account Takeover**: Combined with any credential compromise, this enables full account takeover of 2FA-protected accounts.**Denial of Service**: The unauthenticated `generateKeys.json.php` endpoint allows anonymous users to trigger CPU-intensive RSA key generation operations with no rate limiting.**Scope**: All users who enabled PGP 2FA using the application's built-in key generator are affected. Users who imported their own externally-generated keys with adequate key sizes (2048+ bits) are not affected by the key weakness, but the unauthenticated endpoints affect all deployments with the LoginControl plugin.Recommended Fix**1. Increase RSA key size to 2048 bits minimum** (`plugin/LoginControl/pgp/functions.php:26`):**2. Add authentication to `generateKeys.json.php`** (match the pattern used in `decryptMessage.json.php`):**3. Add authentication to `encryptMessage.json.php`** (same pattern):**4. Add minimum key size validation in `savePublicKey.json.php`** to reject weak keys regardless of how they were generated:
CVSS v3.1 score: 7.4