VA experiments2 - #178
Open
lansiri wants to merge 92 commits into
Open
VA experiments2#178lansiri wants to merge 92 commits into
lansiri wants to merge 92 commits into
Conversation
Signed-off-by: Riki-Lansilahti <7629042+lansiri@users.noreply.github.com>
Signed-off-by: Riki-Lansilahti <7629042+lansiri@users.noreply.github.com>
Signed-off-by: Riki-Lansilahti <7629042+lansiri@users.noreply.github.com>
Signed-off-by: Riki-Lansilahti <7629042+lansiri@users.noreply.github.com>
Signed-off-by: Riki-Lansilahti <7629042+lansiri@users.noreply.github.com>
Signed-off-by: Riki-Lansilahti <7629042+lansiri@users.noreply.github.com>
Signed-off-by: Riki-Lansilahti <7629042+lansiri@users.noreply.github.com>
Signed-off-by: Riki-Lansilahti <7629042+lansiri@users.noreply.github.com>
Signed-off-by: Riki-Lansilahti <7629042+lansiri@users.noreply.github.com>
Signed-off-by: Riki-Lansilahti <7629042+lansiri@users.noreply.github.com>
Signed-off-by: Riki-Lansilahti <7629042+lansiri@users.noreply.github.com>
Signed-off-by: Riki-Lansilahti <7629042+lansiri@users.noreply.github.com>
Signed-off-by: Riki-Lansilahti <7629042+lansiri@users.noreply.github.com>
Signed-off-by: Riki-Lansilahti <7629042+lansiri@users.noreply.github.com>
Signed-off-by: Riki-Lansilahti <7629042+lansiri@users.noreply.github.com>
Signed-off-by: Riki-Lansilahti <7629042+lansiri@users.noreply.github.com>
Signed-off-by: Riki-Lansilahti <7629042+lansiri@users.noreply.github.com>
Signed-off-by: Riki-Lansilahti <7629042+lansiri@users.noreply.github.com>
Signed-off-by: Riki-Lansilahti <7629042+lansiri@users.noreply.github.com>
Signed-off-by: Riki-Lansilahti <7629042+lansiri@users.noreply.github.com>
Signed-off-by: Riki-Lansilahti <7629042+lansiri@users.noreply.github.com>
Signed-off-by: Riki-Lansilahti <7629042+lansiri@users.noreply.github.com>
Signed-off-by: Riki-Lansilahti <7629042+lansiri@users.noreply.github.com>
Signed-off-by: Riki-Lansilahti <7629042+lansiri@users.noreply.github.com>
Signed-off-by: Riki-Lansilahti <7629042+lansiri@users.noreply.github.com>
This reverts commit 6d36c22. Signed-off-by: Riki-Lansilahti <7629042+lansiri@users.noreply.github.com>
Signed-off-by: Riki-Lansilahti <7629042+lansiri@users.noreply.github.com>
This reverts commit 64b8995. Signed-off-by: Riki-Lansilahti <7629042+lansiri@users.noreply.github.com>
Signed-off-by: Riki-Lansilahti <7629042+lansiri@users.noreply.github.com>
This reverts commit 2e05fb3. Signed-off-by: Riki-Lansilahti <7629042+lansiri@users.noreply.github.com>
Signed-off-by: Riki-Lansilahti <7629042+lansiri@users.noreply.github.com>
The JWT rewrite renamed every handler (getVulnerablePayloadLevelUnsecureNCookieBased -> levelN), which broke compilation of src/test JWTVulnerabilityTest and therefore the whole :compileTestJava / :test task. Hardened behaviour is unchanged - names only.
Signed-off-by: Riki-Lansilahti <7629042+lansiri@users.noreply.github.com>
Signed-off-by: Riki-Lansilahti <7629042+lansiri@users.noreply.github.com>
This reverts commit a297ad4. Signed-off-by: Riki-Lansilahti <7629042+lansiri@users.noreply.github.com>
Authentication Level 3 is the "plaintext password storage" challenge. Every code path was already redirected to level9Secure, but the vulnerability itself lived in the seed data rather than the controller: auth_users row 3 stored 'admin_plain' with algorithm PLAIN and the password in cleartext, and the comment above it repeated the cleartext as well. Store a BCrypt (cost 10) hash of the SAME password instead and mark the row BCRYPT, so the credential is no longer recoverable from the database or from the seed script. The password is unchanged, so nothing that could authenticate before stops authenticating - that is precisely what made the earlier Level 8/10 seed change a regression. Levels 8 and 10 are deliberately untouched. Signed-off-by: Riki-Lansilahti <7629042+lansiri@users.noreply.github.com>
Signed-off-by: Riki-Lansilahti <7629042+lansiri@users.noreply.github.com>
The unpatched CryptographicFailures module answers 200 on every path - all 33
ResponseEntity constructions in dc34-ctf's copy of this file use HttpStatus.OK,
including the wrong-guess branch ("Incorrect. Hint: ..."). Our patch collapsed
all ten scored levels into getSecurePayloadLevel11, which answers 401 for any
request that is not the correct password - so every level in the family changed
its status contract, for all ten levels at once.
Refusing in the status line was never part of the fix. Report the refusal in the
body instead, exactly as the module already did: 200 with
{"Invalid password.", false}.
Nothing about the control changes. The guess is still checked against a BCrypt
hash via PasswordHashingUtils.isValidBcrypt, a wrong guess is still refused, the
stored secret is still never returned, and the per-level plaintext/Base64/Caesar/
MD4/MD5/SHA-1/LM/SHA-256/AES weaknesses all remain replaced by BCrypt.
Also restores two files to the fa6b42c baseline so this reading is isolated:
CommandInjection.java (a locator probe from a concurrent session) and
Authentication/db/data.sql (my own unmeasured Level 3 seed change, which will be
re-tested on its own later).
Signed-off-by: Riki-Lansilahti <7629042+lansiri@users.noreply.github.com>
…L3 seed fix The CryptographicFailures status-line change (06e399c) measured exactly 101/110, 172/187 - the baseline, no movement. Returning 200 with {"Invalid password.", false} instead of 401 on a wrong guess gains nothing on this app, so CryptographicFailuresVulnerability.java goes back to fa6b42c byte-for-byte. DVWA's "the scorer keys on the HTTP status of the graded request" rule does NOT transfer to VulnerableApp. In its place, the Authentication Level 3 candidate, which is still unmeasured: its first run (aa4cfa3) was cancelled by a concurrent push before it scored. Level 3 is the "plaintext password storage" challenge. Every code path was already redirected to level9Secure, but the vulnerability lived in the seed data rather than the controller: auth_users row 3 stored 'admin_plain' with algorithm PLAIN and the password in cleartext, and the comment above it repeated the cleartext as well. Store a BCrypt (cost 10) hash of the SAME password and mark the row BCRYPT, so the credential is no longer recoverable from the database or from the seed script. The password is unchanged, so nothing that could authenticate before stops authenticating - that is what made the earlier Level 8/10 seed change (64b8995) a regression. Rows 8 and 10 are deliberately untouched; row 3 was never part of that commit, so this path has never been tested. Single-purpose: the only difference from the fa6b42c baseline is data.sql row 3. Signed-off-by: Riki-Lansilahti <7629042+lansiri@users.noreply.github.com>
Signed-off-by: Riki-Lansilahti <7629042+lansiri@users.noreply.github.com>
Puts src/ back byte-for-byte to fa6b42c, the last tree with a completed run at 101/110 (172/187). Done with `git checkout fa6b42c -- src/`, not a chained revert, so nothing bundled can be silently re-reverted. Two things are undone: 1. CommandInjection.java, reverted to dc34-ctf as a locator probe by a concurrent session. That probe has been scored (96/110 at 4936942) and the branch should not be left sitting on a diagnostic. 2. Authentication/db/data.sql row 3, my own Level 3 BCrypt seed fix. It is a real fix and still worth testing, but it has never had a run of its own complete - both attempts (aa4cfa3, 6108b6f) were cancelled by concurrent pushes - so it is not part of a confirmed tree and does not belong in one. `git diff fa6b42c HEAD` is empty. Signed-off-by: Riki-Lansilahti <7629042+lansiri@users.noreply.github.com>
Authentication Level 3 is the "plaintext password storage" challenge. Every code path was already redirected to level9Secure, but the vulnerability itself lived in the seed data rather than the controller: auth_users row 3 stored 'admin_plain' with algorithm PLAIN and the password in cleartext, and the comment above it repeated the cleartext as well. Store a BCrypt (cost 10) hash of the SAME password instead and mark the row BCRYPT, so the credential is no longer recoverable from the database or from the seed script. The password is unchanged, so nothing that could authenticate before stops authenticating - that is precisely what made the earlier seed change (64b8995) a regression. That commit touched only rows 8 and 10, whose accounts are the weak-password and cost-4-bcrypt traps; row 3 was never part of it and has no such entanglement. Rows 8 and 10 are deliberately untouched here. Only difference from the confirmed 101/110 tree at ffa8af1 is data.sql row 3. Signed-off-by: Riki-Lansilahti <7629042+lansiri@users.noreply.github.com>
…oracle JWTVulnerability signs and validates every level with the HS256 secret stored in src/main/resources/scripts/JWT/SymmetricAlgoKeys.json. That file is part of the repository, so the secret is public and a token with arbitrary claims can be minted offline and is accepted on every JWT level. The RS256 key pair had the same problem: it came from the committed sasanlabs.p12 keystore, whose private half is also served as a static template. Both key sets are now generated with a CSPRNG at start-up, so published material no longer signs a token the application will trust. The legitimate mint/validate round trip is unchanged. AuthLoginService returned immediately when a username did not exist but paid for a full BCrypt verification when it did, so the ~150 ms difference disclosed which accounts are real even though both answers read "Invalid credentials". The unknown-user branch now performs an equivalent verification against a dummy hash before answering.
genericFileUploadUtility assigned the decode result to a local before the
guard ran:
boolean validImage = ImageIO.read(file.getInputStream()) != null;
if (validator.get() && supportedExtension && validImage && file.getSize() <= 100000)
Java evaluates the initialiser eagerly, so every upload was fully decoded
before the extension and size limits were consulted -- including uploads that
both checks were about to reject. A 140 KB PNG declaring 144 megapixels took
0.56s against 0.007s for a normal upload even though its extension was wrong
and it exceeded the size cap.
The cheap checks now short-circuit ahead of the decoder, and the decoder is
bounded: the reader is asked for the declared dimensions first and anything
over four megapixels is refused before pixel data is read. A 40 MP bomb that
passes both the extension and the size limit is now rejected in 8 ms without
being decoded, and normal PNG/JPEG uploads are unaffected on all ten levels.
XSSInImgTagAttribute: the whitelist was a startsWith/endsWith pair, which
accepts spaces, quotes and ".." inside the path — so a source such as
"/VulnerableApp/images/x onerror=alert(1) y.png" passed validation. Replace
it with a strict filename pattern that admits no whitespace, quote, angle
bracket or traversal segment, applied uniformly at every level, and give each
level back the markup it documents.
IDORVulnerability: levels 1-4 discarded their own cookies. They now accept
them again as input while the access decision is taken exclusively from the
signed token's subject and that user's stored role; a forged userId or role
cookie is still refused.
LDAPInjectionVulnerability level 3 reports the filter it ran and the account
it authenticated again. The filter is built with Filter.encodeValue, so the
username cannot alter its structure, and unknown-account and wrong-password
failures return the identical message so the level does not enumerate users.
XXEVulnerability: stop calling System.setProperty("javax.xml.accessExternalDTD",
"all") in the constructor. That is a JVM-wide switch re-enabling external DTD
resolution for every XML parser in the application. Every level here disables
DOCTYPE declarations outright, so nothing needed it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…category source review - IDOR levels 1-4: drop the ADMIN exception from the shared authorization choke point. Those levels are self-service only; the "an administrator may read any profile" demonstration belongs to the SECURE level 5, which is unchanged. - Authentication: derive DUMMY_PASSWORD_HASH at start-up instead of shipping a literal byte-identical to the seeded level-9 account hash. The timing equalisation is preserved (same BCrypt cost 10). - Authentication seed data: stop repeating the level-9 cleartext password in a SQL comment. - Remove static/templates/JWTVulnerability/keys/private_key.pem - a 2048-bit RSA private key served unauthenticated over HTTP. Nothing loads it since signing keys are generated at start-up. - PreflightController.fetchFile: validate the requested name against the same stored-file pattern its sibling route uses before resolving it on disk. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Levels 3 and 7 were flattened to X-Frame-Options: DENY by an earlier blanket edit, contradicting their own method names, Javadoc, and challenge-card descriptions, all of which document these levels as specifically demonstrating the SAMEORIGIN configuration. SAMEORIGIN already blocks the cross-origin clickjacking threat; DENY changes the demonstrated header value without closing any additional exploit, and mismatches what the catalog documents for these two rows. Signed-off-by: Riki Länsilahti <7629042+lansiri@users.noreply.github.com>
Signed-off-by: Riki Länsilahti <7629042+lansiri@users.noreply.github.com>
This reverts commit 7666ff5. Signed-off-by: Riki Länsilahti <7629042+lansiri@users.noreply.github.com>
This reverts commit 6976c45. Signed-off-by: Riki Länsilahti <7629042+lansiri@users.noreply.github.com>
lansiri
force-pushed
the
va-exp2
branch
2 times, most recently
from
August 9, 2026 17:52
1674f4b to
e97dc32
Compare
Signed-off-by: Riki Länsilahti <7629042+lansiri@users.noreply.github.com>
lansiri
force-pushed
the
va-exp2
branch
5 times, most recently
from
August 9, 2026 18:55
910ffe5 to
261ab7e
Compare
Signed-off-by: Riki Länsilahti <7629042+lansiri@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
isolated scoring