From 6997438f8773c188dee1de49251b57ca2af1bc27 Mon Sep 17 00:00:00 2001 From: ShellSmasher Date: Tue, 4 Feb 2025 21:42:24 +0100 Subject: [PATCH 1/5] Update XSSInImgTagAttribute.java Adding 4 Secure ways of handling XSS Reflected --- .../xss/reflected/XSSInImgTagAttribute.java | 105 ++++++++++++++++++ 1 file changed, 105 insertions(+) diff --git a/src/main/java/org/sasanlabs/service/vulnerability/xss/reflected/XSSInImgTagAttribute.java b/src/main/java/org/sasanlabs/service/vulnerability/xss/reflected/XSSInImgTagAttribute.java index dc2819c4..35c47860 100644 --- a/src/main/java/org/sasanlabs/service/vulnerability/xss/reflected/XSSInImgTagAttribute.java +++ b/src/main/java/org/sasanlabs/service/vulnerability/xss/reflected/XSSInImgTagAttribute.java @@ -201,4 +201,109 @@ public ResponseEntity getVulnerablePayloadLevelSecure( return new ResponseEntity<>(HttpStatus.BAD_REQUEST); } } + @AttackVector( + vulnerabilityExposed = VulnerabilityType.NONE, + description = "SECURE_XSS_WITH_STRICT_WHITELIST") + @VulnerableAppRequestMapping( + value = LevelConstants.LEVEL_10, + variant = Variant.SECURE, + htmlTemplate = "LEVEL_1/XSS") + public ResponseEntity getSecurePayloadWithWhitelist( + @RequestParam(PARAMETER_NAME) String imageLocation) { + + HttpHeaders headers = new HttpHeaders(); + headers.add("Content-Security-Policy", "default-src 'self'; img-src 'self'"); + + if (allowedValues.contains(imageLocation)) { + String payload = String.format("", + HtmlUtils.htmlEscape(imageLocation)); + + return new ResponseEntity<>(payload, headers, HttpStatus.OK); + } + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + } + + @AttackVector( + vulnerabilityExposed = VulnerabilityType.NONE, + description = "SECURE_XSS_WITH_MIME_TYPE_VALIDATION") + @VulnerableAppRequestMapping( + value = LevelConstants.LEVEL_9, + variant = Variant.SECURE, + htmlTemplate = "LEVEL_1/XSS") + public ResponseEntity getSecurePayloadWithMimeType( + @RequestParam(PARAMETER_NAME) String imageLocation) { + + Path imagePath = Paths.get(imageLocation); + + try { + String mimeType = Files.probeContentType(imagePath); + if (!"image/png".equals(mimeType) && !"image/jpeg".equals(mimeType)) { + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + } + } catch (IOException e) { + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + } + + String payload = String.format("", + HtmlUtils.htmlEscape(imageLocation)); + return new ResponseEntity<>(payload, HttpStatus.OK); + } + @AttackVector( + vulnerabilityExposed = VulnerabilityType.NONE, + description = "SECURE_XSS_WITH_IMAGE_HASH_VALIDATION") + @VulnerableAppRequestMapping( + value = LevelConstants.LEVEL_10, + variant = Variant.SECURE, + htmlTemplate = "LEVEL_1/XSS") + public ResponseEntity getSecurePayloadWithHashValidation( + @RequestParam(PARAMETER_NAME) String imageLocation) { + + Map allowedHashes = Map.of( + "/VulnerableApp/images/OWASP.png", "6374f10c07ebcebe4dcff4df7ea882ab4e5feeb9ba132c94cd38ac880eb1407b", + "/VulnerableApp/images/ZAP.png", "bd473875115034776f0fed141a0b6f8cbd46989e0ff1d52864f88a4e48882c75" + ); + + try (InputStream is = Files.newInputStream(Paths.get(imageLocation))) { + String sha256 = DigestUtils.sha256Hex(is); + + if (!allowedHashes.containsKey(imageLocation) || + !allowedHashes.get(imageLocation).equals(sha256)) { + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + } + } catch (IOException e) { + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + } + + String payload = String.format("", + HtmlUtils.htmlEscape(imageLocation)); + return new ResponseEntity<>(payload, HttpStatus.OK); + } + + @AttackVector( + vulnerabilityExposed = VulnerabilityType.NONE, + description = "SECURE_XSS_WITH_REGEX_VALIDATION") + @VulnerableAppRequestMapping( + value = LevelConstants.LEVEL_11, + variant = Variant.SECURE, + htmlTemplate = "LEVEL_1/XSS") + public ResponseEntity getSecurePayloadWithRegex( + @RequestParam(PARAMETER_NAME) String imageLocation) { + + HttpHeaders headers = new HttpHeaders(); + headers.add("Content-Security-Policy", "default-src 'self'; img-src 'self'"); + + // Validation stricte via regex : uniquement les chemins autorisés + Pattern pattern = Pattern.compile("^/VulnerableApp/images/[a-zA-Z0-9_-]+\\.(png|jpg|jpeg)$"); + Matcher matcher = pattern.matcher(imageLocation); + + if (matcher.matches()) { + String payload = String.format("", + HtmlUtils.htmlEscape(imageLocation)); + + return new ResponseEntity<>(payload, headers, HttpStatus.OK); + } + + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + } + } From e25d6bcb3d9152df491cdafdccbfecf73a097d3e Mon Sep 17 00:00:00 2001 From: ShellSmasher Date: Tue, 4 Feb 2025 22:24:49 +0100 Subject: [PATCH 2/5] Update XSSInImgTagAttribute.java --- .../xss/reflected/XSSInImgTagAttribute.java | 105 ------------------ 1 file changed, 105 deletions(-) diff --git a/src/main/java/org/sasanlabs/service/vulnerability/xss/reflected/XSSInImgTagAttribute.java b/src/main/java/org/sasanlabs/service/vulnerability/xss/reflected/XSSInImgTagAttribute.java index 35c47860..dc2819c4 100644 --- a/src/main/java/org/sasanlabs/service/vulnerability/xss/reflected/XSSInImgTagAttribute.java +++ b/src/main/java/org/sasanlabs/service/vulnerability/xss/reflected/XSSInImgTagAttribute.java @@ -201,109 +201,4 @@ public ResponseEntity getVulnerablePayloadLevelSecure( return new ResponseEntity<>(HttpStatus.BAD_REQUEST); } } - @AttackVector( - vulnerabilityExposed = VulnerabilityType.NONE, - description = "SECURE_XSS_WITH_STRICT_WHITELIST") - @VulnerableAppRequestMapping( - value = LevelConstants.LEVEL_10, - variant = Variant.SECURE, - htmlTemplate = "LEVEL_1/XSS") - public ResponseEntity getSecurePayloadWithWhitelist( - @RequestParam(PARAMETER_NAME) String imageLocation) { - - HttpHeaders headers = new HttpHeaders(); - headers.add("Content-Security-Policy", "default-src 'self'; img-src 'self'"); - - if (allowedValues.contains(imageLocation)) { - String payload = String.format("", - HtmlUtils.htmlEscape(imageLocation)); - - return new ResponseEntity<>(payload, headers, HttpStatus.OK); - } - return new ResponseEntity<>(HttpStatus.BAD_REQUEST); - } - - @AttackVector( - vulnerabilityExposed = VulnerabilityType.NONE, - description = "SECURE_XSS_WITH_MIME_TYPE_VALIDATION") - @VulnerableAppRequestMapping( - value = LevelConstants.LEVEL_9, - variant = Variant.SECURE, - htmlTemplate = "LEVEL_1/XSS") - public ResponseEntity getSecurePayloadWithMimeType( - @RequestParam(PARAMETER_NAME) String imageLocation) { - - Path imagePath = Paths.get(imageLocation); - - try { - String mimeType = Files.probeContentType(imagePath); - if (!"image/png".equals(mimeType) && !"image/jpeg".equals(mimeType)) { - return new ResponseEntity<>(HttpStatus.BAD_REQUEST); - } - } catch (IOException e) { - return new ResponseEntity<>(HttpStatus.BAD_REQUEST); - } - - String payload = String.format("", - HtmlUtils.htmlEscape(imageLocation)); - return new ResponseEntity<>(payload, HttpStatus.OK); - } - @AttackVector( - vulnerabilityExposed = VulnerabilityType.NONE, - description = "SECURE_XSS_WITH_IMAGE_HASH_VALIDATION") - @VulnerableAppRequestMapping( - value = LevelConstants.LEVEL_10, - variant = Variant.SECURE, - htmlTemplate = "LEVEL_1/XSS") - public ResponseEntity getSecurePayloadWithHashValidation( - @RequestParam(PARAMETER_NAME) String imageLocation) { - - Map allowedHashes = Map.of( - "/VulnerableApp/images/OWASP.png", "6374f10c07ebcebe4dcff4df7ea882ab4e5feeb9ba132c94cd38ac880eb1407b", - "/VulnerableApp/images/ZAP.png", "bd473875115034776f0fed141a0b6f8cbd46989e0ff1d52864f88a4e48882c75" - ); - - try (InputStream is = Files.newInputStream(Paths.get(imageLocation))) { - String sha256 = DigestUtils.sha256Hex(is); - - if (!allowedHashes.containsKey(imageLocation) || - !allowedHashes.get(imageLocation).equals(sha256)) { - return new ResponseEntity<>(HttpStatus.BAD_REQUEST); - } - } catch (IOException e) { - return new ResponseEntity<>(HttpStatus.BAD_REQUEST); - } - - String payload = String.format("", - HtmlUtils.htmlEscape(imageLocation)); - return new ResponseEntity<>(payload, HttpStatus.OK); - } - - @AttackVector( - vulnerabilityExposed = VulnerabilityType.NONE, - description = "SECURE_XSS_WITH_REGEX_VALIDATION") - @VulnerableAppRequestMapping( - value = LevelConstants.LEVEL_11, - variant = Variant.SECURE, - htmlTemplate = "LEVEL_1/XSS") - public ResponseEntity getSecurePayloadWithRegex( - @RequestParam(PARAMETER_NAME) String imageLocation) { - - HttpHeaders headers = new HttpHeaders(); - headers.add("Content-Security-Policy", "default-src 'self'; img-src 'self'"); - - // Validation stricte via regex : uniquement les chemins autorisés - Pattern pattern = Pattern.compile("^/VulnerableApp/images/[a-zA-Z0-9_-]+\\.(png|jpg|jpeg)$"); - Matcher matcher = pattern.matcher(imageLocation); - - if (matcher.matches()) { - String payload = String.format("", - HtmlUtils.htmlEscape(imageLocation)); - - return new ResponseEntity<>(payload, headers, HttpStatus.OK); - } - - return new ResponseEntity<>(HttpStatus.BAD_REQUEST); - } - } From 3d5cf8fdafd3344c3b15ed9ef962dcf0027f3c22 Mon Sep 17 00:00:00 2001 From: Lyes Date: Tue, 4 Feb 2025 23:38:09 +0100 Subject: [PATCH 3/5] New XSS Secure Level Added --- .classpath | 7 ++ .settings/org.eclipse.buildship.core.prefs | 11 +++ .../xss/reflected/XSSInImgTagAttribute.java | 93 +++++++++++++++++++ .../resources/i18n/messages_en_US.properties | 3 + 4 files changed, 114 insertions(+) diff --git a/.classpath b/.classpath index 467ef2f2..f00842bf 100644 --- a/.classpath +++ b/.classpath @@ -12,6 +12,13 @@ + + + + + + + diff --git a/.settings/org.eclipse.buildship.core.prefs b/.settings/org.eclipse.buildship.core.prefs index e8895216..87b1185f 100644 --- a/.settings/org.eclipse.buildship.core.prefs +++ b/.settings/org.eclipse.buildship.core.prefs @@ -1,2 +1,13 @@ +arguments=--init-script /home/lyes/.config/Code/User/globalStorage/redhat.java/1.39.0/config_linux/org.eclipse.osgi/58/0/.cp/gradle/init/init.gradle --init-script /home/lyes/.config/Code/User/globalStorage/redhat.java/1.39.0/config_linux/org.eclipse.osgi/58/0/.cp/gradle/protobuf/init.gradle +auto.sync=false +build.scans.enabled=false +connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER) connection.project.dir= eclipse.preferences.version=1 +gradle.user.home= +java.home=/usr/lib/jvm/jdk-23.0.1-oracle-x64 +jvm.arguments= +offline.mode=false +override.workspace.settings=true +show.console.view=true +show.executions.view=true diff --git a/src/main/java/org/sasanlabs/service/vulnerability/xss/reflected/XSSInImgTagAttribute.java b/src/main/java/org/sasanlabs/service/vulnerability/xss/reflected/XSSInImgTagAttribute.java index dc2819c4..66088a4f 100644 --- a/src/main/java/org/sasanlabs/service/vulnerability/xss/reflected/XSSInImgTagAttribute.java +++ b/src/main/java/org/sasanlabs/service/vulnerability/xss/reflected/XSSInImgTagAttribute.java @@ -14,6 +14,15 @@ import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.util.HtmlUtils; +import org.springframework.http.HttpHeaders; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.io.File; +import java.nio.file.Files; +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.net.URLConnection; /** * This class contains XSS vulnerabilities which are present in Image Tag attribute. @@ -201,4 +210,88 @@ public ResponseEntity getVulnerablePayloadLevelSecure( return new ResponseEntity<>(HttpStatus.BAD_REQUEST); } } + + // Level 8: Protection avec Content Security Policy (CSP) + @AttackVector( + vulnerabilityExposed = VulnerabilityType.REFLECTED_XSS, + description = "XSS_CSP_PROTECTION") + @VulnerableAppRequestMapping( + value = LevelConstants.LEVEL_8, + variant = Variant.SECURE, + htmlTemplate = "LEVEL_1/XSS") + public ResponseEntity getVulnerablePayloadLevelSecure2(@RequestParam(PARAMETER_NAME) String imageLocation) { + HttpHeaders headers = new HttpHeaders(); + headers.add("Content-Security-Policy", "default-src 'self'; img-src 'self'"); + String vulnerablePayloadWithPlaceHolder = ""; + String payload = String.format(vulnerablePayloadWithPlaceHolder, HtmlUtils.htmlEscape(imageLocation)); + return new ResponseEntity<>(payload, headers, HttpStatus.OK); + } + + // Level 9: Protection avec validation du type MIME + @AttackVector( + vulnerabilityExposed = VulnerabilityType.REFLECTED_XSS, + description = "XSS_MIME_TYPE_VALIDATION") + @VulnerableAppRequestMapping( + value = LevelConstants.LEVEL_9, + variant = Variant.SECURE, + htmlTemplate = "LEVEL_1/XSS") + public ResponseEntity validateMimeType(@RequestParam(PARAMETER_NAME) String imageLocation) { + Path filePath = Paths.get(imageLocation); + try { + File file = filePath.toFile(); + String mimeType = Files.probeContentType(filePath); + if (mimeType == null) { + mimeType = URLConnection.guessContentTypeFromName(file.getName()); + } + if (mimeType != null && mimeType.startsWith("image/")) { + String vulnerablePayloadWithPlaceHolder = ""; + String payload = String.format(vulnerablePayloadWithPlaceHolder, imageLocation); + return new ResponseEntity<>(payload, HttpStatus.OK); + } + } catch (IOException e) { + return new ResponseEntity<>("Error detecting MIME Type", HttpStatus.INTERNAL_SERVER_ERROR); + } + return new ResponseEntity<>("Invalid MIME Type", HttpStatus.BAD_REQUEST); + } + + // Level 10: Protection avec hachage du chemin de l'image + @AttackVector( + vulnerabilityExposed = VulnerabilityType.REFLECTED_XSS, + description = "XSS_HASH_VALIDATION") + @VulnerableAppRequestMapping( + value = LevelConstants.LEVEL_10, + variant = Variant.SECURE, + htmlTemplate = "LEVEL_1/XSS") + public ResponseEntity getVulnerablePayloadLevelSecure4(@RequestParam(PARAMETER_NAME) String imageLocation) { + String hashedValue = hashSHA256(imageLocation); + if (hashedValue.equals("bd473875115034776f0fed141a0b6f8cbd46989e0ff1d52864f88a4e48882c75") || + hashedValue.equals("6374f10c07ebcebe4dcff4df7ea882ab4e5feeb9ba132c94cd38ac880eb1407b")) { + String vulnerablePayloadWithPlaceHolder = ""; + String payload = String.format(vulnerablePayloadWithPlaceHolder, imageLocation); + return new ResponseEntity<>(payload, HttpStatus.OK); + } + return new ResponseEntity<>("Invalid Image Hash", HttpStatus.BAD_REQUEST); + } + + private String hashSHA256(String input) { + try { + MessageDigest digest = MessageDigest.getInstance("SHA-256"); + byte[] hash = digest.digest(input.getBytes()); + return bytesToHex(hash); + } catch (NoSuchAlgorithmException e) { + return ""; + } + } + + private String bytesToHex(byte[] bytes) { + StringBuilder hexString = new StringBuilder(); + for (byte b : bytes) { + String hex = Integer.toHexString(0xff & b); + if (hex.length() == 1) { + hexString.append('0'); + } + hexString.append(hex); + } + return hexString.toString(); + } } diff --git a/src/main/resources/i18n/messages_en_US.properties b/src/main/resources/i18n/messages_en_US.properties index d73d7e89..305930cb 100755 --- a/src/main/resources/i18n/messages_en_US.properties +++ b/src/main/resources/i18n/messages_en_US.properties @@ -40,6 +40,9 @@ XSS_HTML_ESCAPE_ON_DIRECT_INPUT_AND_REMOVAL_OF_VALUES_WITH_PARENTHESIS_SRC_ATTRI XSS_QUOTES_AND_WITH_HTML_ESCAPE_ON_INPUT_SRC_ATTRIBUTE_IMG_TAG=HTML escaping is done on the Url Parameters and then inserted inside Quotes into the src attribute of Image Tag. XSS_HTML_ESCAPE_PLUS_FILTERING_ON_INPUT_SRC_ATTRIBUTE_IMG_TAG_BUT_NULL_BYTE_VULNERABLE=Url Parameters are HTML escaped, validated against whitelist of filenames and inserted into the src attribute of Image Tag, However validator for validating filenames is vulnerable with Null Byte Injection. XSS_QUOTES_AND_WITH_HTML_ESCAPE_PLUS_FILTERING_ON_INPUT_SRC_ATTRIBUTE_IMG_TAG=Url Parameters are HTML escaped, validated against whitelist of filenames and inserted inside Quotes into the src attribute of Image Tag. +XSS_CSP_PROTECTION="CSP is Used to prevent XSS" +XSS_MIME_TYPE_VALIDATION="MIME Type is tested to ensure that the file is PNG" +XSS_HASH_VALIDATION="Hash of the path is used to ensure that only the requested images are displayed" ## Html Tag Injection XSS_HTML_TAG_INJECTION=Html Tag based XSS attack. From 21904c547f563abe2e0da0107cc4dc80c6a751e9 Mon Sep 17 00:00:00 2001 From: Lyes Date: Tue, 4 Feb 2025 23:41:26 +0100 Subject: [PATCH 4/5] New XSS Secure Level Added --- .settings/org.eclipse.jdt.core.prefs | 4 + .vscode/settings.json | 3 + .../SampleVulnerability.java | 108 ++++++++++++++++++ .../LEVEL_1/SampleVulnerability.css | 16 +++ .../LEVEL_1/SampleVulnerability.html | 9 ++ .../LEVEL_1/SampleVulnerability.js | 23 ++++ 6 files changed, 163 insertions(+) create mode 100644 .settings/org.eclipse.jdt.core.prefs create mode 100644 .vscode/settings.json create mode 100644 src/main/java/org/sasanlabs/service/vulnerability/sampleVulnerability/SampleVulnerability.java create mode 100644 src/main/resources/static/templates/SampleVulnerability/LEVEL_1/SampleVulnerability.css create mode 100644 src/main/resources/static/templates/SampleVulnerability/LEVEL_1/SampleVulnerability.html create mode 100644 src/main/resources/static/templates/SampleVulnerability/LEVEL_1/SampleVulnerability.js diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000..35068d95 --- /dev/null +++ b/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,4 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..c5f3f6b9 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "java.configuration.updateBuildConfiguration": "interactive" +} \ No newline at end of file diff --git a/src/main/java/org/sasanlabs/service/vulnerability/sampleVulnerability/SampleVulnerability.java b/src/main/java/org/sasanlabs/service/vulnerability/sampleVulnerability/SampleVulnerability.java new file mode 100644 index 00000000..3f15c150 --- /dev/null +++ b/src/main/java/org/sasanlabs/service/vulnerability/sampleVulnerability/SampleVulnerability.java @@ -0,0 +1,108 @@ +package org.sasanlabs.service.vulnerability.sampleVulnerability; + +import org.sasanlabs.internal.utility.LevelConstants; +import org.sasanlabs.internal.utility.Variant; +import org.sasanlabs.internal.utility.annotations.AttackVector; +import org.sasanlabs.internal.utility.annotations.VulnerableAppRequestMapping; +import org.sasanlabs.internal.utility.annotations.VulnerableAppRestController; +import org.sasanlabs.service.vulnerability.bean.GenericVulnerabilityResponseBean; +import org.sasanlabs.vulnerability.types.VulnerabilityType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RequestParam; + +/** + * This is a sample vulnerability for helping developers in adding a new Vulnerability for + * VulnerableApp + * + * @author KSASAN preetkaran20@gmail.com + */ +/** + * {@code VulnerableAppRestController} annotation is similar to {@link + * org.springframework.stereotype.Controller} Annotation + */ +@VulnerableAppRestController( + /** + * "descriptionLabel" parameter of annotation is i18n label stored in {@link + * /VulnerableApp/src/main/resources/i18n/}. This descriptionLabel + * will be shown in the UI as the description of the Vulnerability. It helps students to + * learn about the vulnerability and can also include some of the useful references etc. + */ + descriptionLabel = "SAMPLE_VULNERABILITY", + /** + * "value" parameter of annotation is used to create the request mapping. e.g. for the below + * parameter value, /VulnerableApp/SampleVulnerability will be created as URI Path. + */ + value = "SampleVulnerability") +public class SampleVulnerability { + + /** + * {@code AttackVector} annotation is used to create the Hints section in the User Interface. + * This annotation can be mentioned multiple times in case the same vulnerability level + */ + @AttackVector( + /** + * "vulnerabilityExposed" parameter is used to depict the Vulnerability exposed by the + * level. For example say a level is exposing SQL_INJECTION. + */ + vulnerabilityExposed = VulnerabilityType.SAMPLE_VULNERABILITY, + /** + * "description" parameter of annotation is i18n label stored in {@link + * /VulnerableApp/src/main/resources/i18n/}. This description + * will be shown in the UI as hint to give some indication on how the level is handling + * input to help user to crack the level. + */ + description = "SAMPLE_VULNERABILITY_USER_INPUT_HANDLING_INJECTION", + + /** + * "payload" parameter of annotation is i18n label stored in {@link + * /VulnerableApp/src/main/resources/attackvectors/*.properties}. This payload will be + * shown in UI to help users find/exploit the vulnerability + */ + payload = "NOT_APPLICABLE") + /** + * This annotation is similar to {@link RequestMapping} SpringBoot annotation. It will map the + * endpoint to /VulnerableApp/SampleVulnerability/LEVEL_1 where LEVEL_1 is coming from the value + * parameter. + */ + @VulnerableAppRequestMapping( + /** + * "value" parameter is used to map the level to URI path + * /VulnerableApp/SampleVulnerability/${value}. + */ + value = LevelConstants.LEVEL_1, + + /** + * "htmlTemplate" is used to load the UI for the level for taking input from the user. + * It points to files in directory + * src/main/resource/static/templates/${VulnerabilityName} e.g. + * src/main/resource/static/templates/SampleVulnerability as ${htmlTemplate}.js, + * ${htmlTemplate}.css, ${htmlTemplate}.html. e.g. in this case it will be: + * src/main/resource/static/templates/SampleVulnerability/LEVEL_1/SampleVulnerability_Level1.js + * etc + * + *

CSS, JS and HTML are all loaded to render the UI. + */ + htmlTemplate = "LEVEL_1/SampleVulnerability") + public GenericVulnerabilityResponseBean sampleUnsecuredLevel(@RequestParam("name") String key) { + /** Add Business logic here */ + return new GenericVulnerabilityResponseBean<>("Not Implemented", true); + } + + /** For secured level there is no need for {@link AttackVector} annotation. */ + @VulnerableAppRequestMapping( + value = LevelConstants.LEVEL_2, + + // Can reuse the same UI template in case it doesn't change between levels + htmlTemplate = "LEVEL_1/SampleVulnerability", + /** + * "variant" parameter defines whether the level is secure or not and same is depicted + * in the UI as a closed lock and open lock icon. Default value of the variant is + * UNSECURE so in case a secure level is added, please add the variant as {@link + * Variant#SECURE} + */ + variant = Variant.SECURE) + public GenericVulnerabilityResponseBean sampleSecuredLevel(@RequestParam("name") String key) { + /** Add Business logic here */ + return new GenericVulnerabilityResponseBean<>("Not Implemented", true); + } +} \ No newline at end of file diff --git a/src/main/resources/static/templates/SampleVulnerability/LEVEL_1/SampleVulnerability.css b/src/main/resources/static/templates/SampleVulnerability/LEVEL_1/SampleVulnerability.css new file mode 100644 index 00000000..e5d57b25 --- /dev/null +++ b/src/main/resources/static/templates/SampleVulnerability/LEVEL_1/SampleVulnerability.css @@ -0,0 +1,16 @@ +#SampleVulnerability { + color: black; + text-align: center; +} + +#fetchDetails { + background: blueviolet; + display: inline-block; + padding: 8px 8px; + margin: 10px; + border: 2px solid transparent; + border-radius: 3px; + transition: 0.2s opacity; + color: #FFF; + font-size: 12px; +} \ No newline at end of file diff --git a/src/main/resources/static/templates/SampleVulnerability/LEVEL_1/SampleVulnerability.html b/src/main/resources/static/templates/SampleVulnerability/LEVEL_1/SampleVulnerability.html new file mode 100644 index 00000000..dddeea7d --- /dev/null +++ b/src/main/resources/static/templates/SampleVulnerability/LEVEL_1/SampleVulnerability.html @@ -0,0 +1,9 @@ +

+
+
+ This is a Sample Vulnerability. please add the UI components here. +
+ +
+
+
\ No newline at end of file diff --git a/src/main/resources/static/templates/SampleVulnerability/LEVEL_1/SampleVulnerability.js b/src/main/resources/static/templates/SampleVulnerability/LEVEL_1/SampleVulnerability.js new file mode 100644 index 00000000..78641721 --- /dev/null +++ b/src/main/resources/static/templates/SampleVulnerability/LEVEL_1/SampleVulnerability.js @@ -0,0 +1,23 @@ +function addingEventListenerToFetchData() { + document + .getElementById("fetchDetails") + .addEventListener("click", function () { + /** + * getUrlForVulnerabilityLevel() method provides url to call the Vulnerability Level + * of Sample Vulnerability. + * e.g. /VulnerableApp/SampleVulnerability/LEVEL_1 for LEVEL_1 + */ + let url = getUrlForVulnerabilityLevel(); + /** + * doGetAjaxCall() method is used to do the ajax get call to the Vulnerability Level + */ + doGetAjaxCall(fetchDataCallback, url + "?name=dummyInput", true); + }); +} +// Used to register event on the button or any other component +addingEventListenerToFetchData(); + +//Callback function to handle the response and render in the UI +function fetchDataCallback(data) { + document.getElementById("response").innerHTML = data.content; +} From ad707f560687fa18c35553948592eb07a005d6bc Mon Sep 17 00:00:00 2001 From: Lyes Date: Fri, 7 Feb 2025 11:50:44 +0100 Subject: [PATCH 5/5] 3 New XSS Stored Secure Level Added --- .classpath | 14 +++--- .project | 11 ++++ .settings/org.eclipse.jdt.core.prefs | 1 + .../PersistentXSSInHTMLTagVulnerability.java | 50 +++++++++++++++++++ 4 files changed, 69 insertions(+), 7 deletions(-) diff --git a/.classpath b/.classpath index f00842bf..53ba604a 100644 --- a/.classpath +++ b/.classpath @@ -1,9 +1,10 @@ - + - - + + + @@ -12,11 +13,10 @@ - + - - - + + diff --git a/.project b/.project index cc8af00e..f6e3bd91 100644 --- a/.project +++ b/.project @@ -20,4 +20,15 @@ org.eclipse.jdt.core.javanature org.eclipse.buildship.core.gradleprojectnature + + + 1738769978762 + + 30 + + org.eclipse.core.resources.regexFilterMatcher + node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ + + + diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs index 35068d95..559aa4bd 100644 --- a/.settings/org.eclipse.jdt.core.prefs +++ b/.settings/org.eclipse.jdt.core.prefs @@ -1,4 +1,5 @@ eclipse.preferences.version=1 +org.eclipse.jdt.core.classpath.outputOverlappingAnotherSource=ignore org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 org.eclipse.jdt.core.compiler.compliance=1.8 org.eclipse.jdt.core.compiler.source=1.8 diff --git a/src/main/java/org/sasanlabs/service/vulnerability/xss/persistent/PersistentXSSInHTMLTagVulnerability.java b/src/main/java/org/sasanlabs/service/vulnerability/xss/persistent/PersistentXSSInHTMLTagVulnerability.java index 124dfb4f..6b5e134d 100644 --- a/src/main/java/org/sasanlabs/service/vulnerability/xss/persistent/PersistentXSSInHTMLTagVulnerability.java +++ b/src/main/java/org/sasanlabs/service/vulnerability/xss/persistent/PersistentXSSInHTMLTagVulnerability.java @@ -218,4 +218,54 @@ public ResponseEntity getVulnerablePayloadLevel7( post -> StringEscapeUtils.escapeHtml4(post)), HttpStatus.OK); } + //escape html and delete all the script and img tags + @VulnerableAppRequestMapping( + value = LevelConstants.LEVEL_8, + htmlTemplate = "LEVEL_1/PersistentXSS", + variant = Variant.SECURE) + public ResponseEntity getSecurePayloadLevel8( + @RequestParam Map queryParams) { + return new ResponseEntity<>( + this.getCommentsPayload( + queryParams, + LevelConstants.LEVEL_8, + post -> StringEscapeUtils.escapeHtml4( + post.replaceAll("(?i).*?", "") + .replaceAll("(?i)", ""))), + HttpStatus.OK); + } + //delete all the html tags + @VulnerableAppRequestMapping( + value = LevelConstants.LEVEL_9, + htmlTemplate = "LEVEL_1/PersistentXSS", + variant = Variant.SECURE) + public ResponseEntity getSecurePayloadLevel9( + @RequestParam Map queryParams) { + Function function = + (post) -> { + String sanitizedPost = post.replaceAll("<.*?>", ""); // Delete all the html balises + return StringEscapeUtils.escapeHtml4(sanitizedPost); + }; + return new ResponseEntity<>( + this.getCommentsPayload(queryParams, LevelConstants.LEVEL_9, function), + HttpStatus.OK); + } + //delete all the js calls + @VulnerableAppRequestMapping( + value = LevelConstants.LEVEL_10, + htmlTemplate = "LEVEL_1/PersistentXSS", + variant = Variant.SECURE) + public ResponseEntity getSecurePayloadLevel10( + @RequestParam Map queryParams) { + Function function = + (post) -> { + String sanitizedPost = StringEscapeUtils.escapeHtml4(post); + sanitizedPost = sanitizedPost.replaceAll("(?i)javascript:", ""); // Delete all the js calls + return StringEscapeUtils.escapeHtml4(sanitizedPost); + }; + return new ResponseEntity<>( + this.getCommentsPayload(queryParams, LevelConstants.LEVEL_10, function), + HttpStatus.OK); + } + }