Skip to content

Replace linear key mixing and fixed-IV CBC in Broken Crypto Home Made Key - #262

Open
JBHook wants to merge 3 commits into
OWASP-CTF:dc34-ctffrom
JBHook:fix/crypto-homemade-aes-gcm
Open

JBHook wants to merge 3 commits into
OWASP-CTF:dc34-ctffrom
JBHook:fix/crypto-homemade-aes-gcm

Conversation

@JBHook

@JBHook JBHook commented Aug 9, 2026

Copy link
Copy Markdown

Summary

createUserSpecificEncryptionKey() mixed the fully attacker-controlled "name" parameter with the secret serverEncryptionKey via plain byte-wise addition mod 256 - a linear, invertible operation. Since doGet() echoes the plaintext baseKey literal alongside its ciphertext for any attacker-chosen name, this is a chosen-key setup that lets an attacker recover serverEncryptionKey byte-by-byte, then decrypt the hidden challenge's own answer. Compounding this, encryption used AES/CBC with a fixed all-zero IV.

Fix

Added dedicated key-derivation/encryption/decryption methods for the user-specific-key path: key derivation now uses SHA-256(serverEncryptionKey || userNameKey) (one-way), and encryption uses AES-256-GCM with a random IV per call, matching the pattern already merged for BrokenCrypto3.java. Also fixed the submission-comparison logic to decrypt-and-compare plaintext instead of comparing ciphertext strings (required since GCM's random IV means re-encrypting never reproduces the same ciphertext).

Test plan

  • mvn compile, mvn spotless:check clean, full test suite passes
  • Live-validated: doGet with a chosen name produces valid varying-length AES-GCM ciphertexts; a garbage/wrong submission is handled gracefully as "incorrect" rather than erroring; a standalone round-trip test (encrypt via generateUserSolutionKeyOnly, decrypt via decryptUserSpecificSolution) confirms the full pipeline is internally consistent.

🤖 Generated with Claude Code

JBHook and others added 2 commits August 9, 2026 10:12
… Key

createUserSpecificEncryptionKey() mixed the fully attacker-controlled
"name" parameter with the secret serverEncryptionKey via plain
byte-wise addition mod 256 - a linear, invertible operation. Since the
doGet() endpoint echoes the plaintext baseKey literal alongside its
ciphertext for any attacker-chosen name (except the hidden "This
Challenge" entry), this is a chosen-key setup that lets an attacker
recover serverEncryptionKey byte-by-byte, then decrypt the hidden
challenge's own answer.

Compounding this, encrypt()/decrypt() used AES/CBC with a fixed
all-zero IV, making ciphertexts for the same plaintext+key always
identical.

Added dedicated createUserSpecificEncryptionKey/encryptUserSpecific/
decryptUserSpecific methods for the user-specific-key path: key
derivation now uses SHA-256(serverEncryptionKey || userNameKey)
(one-way, so chosen-input outputs reveal nothing about the secret),
and encryption uses AES-256-GCM with a random IV per call
(IV prepended to ciphertext), matching the pattern already merged for
BrokenCrypto3.java. The unrelated, unused generic encrypt()/decrypt()/
decryptUserName() methods (not part of the reported key-derivation
bug, and not called anywhere in the codebase) are left untouched.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
AES-GCM uses a random IV per encryption, so re-encrypting the same
plaintext never reproduces the same ciphertext string. The doPost
handler was still comparing the submitted ciphertext against a freshly
re-encrypted "expected" ciphertext for string equality - this would
have rejected every submission, including correct ones, after the
prior commit's switch away from deterministic fixed-IV CBC.

Now decrypts the submitted ciphertext with the user's derived key and
compares the resulting plaintext against the expected baseKey+salt
value instead.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown

🏆 Security Shepherd — CTF Patch Score

░░░░░░░░░░░░░░░░░░░░  0 / 79 pts  (0%)

0 / 40 challenges patched

Per-challenge detail is withheld — it would reveal the rubric.

Commit: 2c68cc7 · scoring run

No points yet — this commit didn't solve any challenges, so there's nothing on the leaderboard for it. Patch a vulnerability and push again! 💪

…lied name

The previous commit switched key derivation to SHA-256 to stop an attacker
recovering the server's secret key via the old linear byte-addition mixing,
but left the "name" value itself coming straight from the request
parameter. That's an IDOR via the key-derivation input rather than the
usual object-id parameter: submitting another user's username as "name"
returns that user's personalised encrypted answers in the response, with
no relation to who is actually authenticated.

Derive it from the session's own userName instead, so a caller can only
ever request their own encrypted answers.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant