Skip to content

Commit

Permalink
feat: implement header param injection handling for JWT vulnerabilities
Browse files Browse the repository at this point in the history
  • Loading branch information
leiberbertel committed Aug 19, 2024
1 parent 928f79f commit 0c23ff9
Show file tree
Hide file tree
Showing 9 changed files with 116 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public interface LevelConstants {
String LEVEL_10 = "LEVEL_10";
String LEVEL_11 = "LEVEL_11";
String LEVEL_12 = "LEVEL_12";
String LEVEL_13 = "LEVEL_13";

static int getOrdinal(String level) {
if (level.indexOf("_") > 0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.RequestParam;

import javax.servlet.http.HttpServletRequest;

/**
* JWT client and server side implementation issues and remediations. Server side issues like: 1.
* Weak HMAC key 2. none algorithm attack 3. Weak Hash algorithm 4. tweak Algorithm and Key.
Expand Down Expand Up @@ -662,4 +664,28 @@ private ResponseEntity<GenericVulnerabilityResponseBean<String>> getJWTResponseB
true, token, true, CollectionUtils.toMultiValueMap(headers));
return responseEntity;
}

@AttackVector(
vulnerabilityExposed = VulnerabilityType.HEADER_INJECTION,
description = "HEADER_INJECTION_VULNERABILITY_EXAMPLE"
)
@VulnerableAppRequestMapping(
value = LevelConstants.LEVEL_13,
htmlTemplate = "LEVEL_13/HeaderInjection_Level13"
)
public ResponseEntity<GenericVulnerabilityResponseBean<String>> getHeaderInjectionVulnerability(
HttpServletRequest request) {
String headerValue = request.getHeader("User-Defined-Header");
if (headerValue != null && headerValue.contains("malicious")) {
return new ResponseEntity<>(
new GenericVulnerabilityResponseBean<>("Vulnerability exploited!", false),
HttpStatus.OK
);
}
return new ResponseEntity<>(
new GenericVulnerabilityResponseBean<>("Safe header", true),
HttpStatus.OK
);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public enum VulnerabilityType {
CLIENT_SIDE_VULNERABLE_JWT(null, null),
SERVER_SIDE_VULNERABLE_JWT(null, null),
INSECURE_CONFIGURATION_JWT(null, null),

HEADER_INJECTION(20, 20),
PATH_TRAVERSAL(22, 33),

COMMAND_INJECTION(77, 31),
Expand Down
5 changes: 4 additions & 1 deletion src/main/resources/i18n/messages_en_US.properties
Original file line number Diff line number Diff line change
Expand Up @@ -285,4 +285,7 @@ SSRF_VULNERABILITY_URL_WITHOUT_CHECK=No validation on the provided URL.
SSRF_VULNERABILITY_URL_IF_NOT_FILE_PROTOCOL=file:// protocol is not allowed for the provided URL.
SSRF_VULNERABILITY_URL_IF_NOT_FILE_PROTOCOL_AND_169.254.169.254=file:// protocol as well as access to internal metadata service IP 169.254.169.254 is not allowed.
SSRF_VULNERABILITY_URL_IF_NOT_FILE_PROTOCOL_AND_INTERNAL_METADATA_URL=file:// protocol as well as access to internal metadata service is not allowed.
SSRF_VULNERABILITY_URL_ONLY_IF_IN_THE_WHITELIST=Only Whitelisted URL is allowed.
SSRF_VULNERABILITY_URL_ONLY_IF_IN_THE_WHITELIST=Only Whitelisted URL is allowed.

# JWT Injection Header
HEADER_INJECTION_VULNERABILITY_EXAMPLE=Header Injection Vulnerability Example
2 changes: 2 additions & 0 deletions src/main/resources/i18n/messages_es.properties
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,8 @@ COOKIE_BASED_KEY_CONFUSION_JWT_VULNERABILITY=Validador de token JWT basado en co
COOKIE_BASED_FOR_JWK_HEADER_BASED_JWT_VULNERABILITY=Validador de token JWT basado en cookies, vulnerable por confianza en el campo JWK sin chequear antes si la clave pública provista está presente en TrustStore o no.
COOKIE_BASED_EMPTY_TOKEN_JWT_VULNERABILITY=Token JWT basado en cookies, vulnerable por el ataque de token vacío.

# JWT Injection Header
HEADER_INJECTION_VULNERABILITY_EXAMPLE=Ejemplo de vulnerabilidad de inyección de encabezado


# SQL Injection Vulnerability
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#header_injection_level_13 {
color: black;
text-align: justify;
}

#enterHeader {
font-size: 15px;
display: flex;
margin: 10px;
flex-direction: column;
}

#headerName, #headerValue {
flex: 1;
word-wrap: break-word;
margin-top: 10px;
}

#headerResponse {
font-size: 15px;
word-wrap: break-word;
text-align: center;
margin: 10px;
}

#sendHeader {
background: blueviolet;
display: inline-block;
padding: 4px 4px;
margin: 10px;
border: 1px solid transparent;
border-radius: 2px;
transition: 0.2s opacity;
color: #FFF;
font-size: 12px;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Header Injection</title>
</head>
<body>
<div id="header_injection_level_13">
<div>
<div id="enterHeader">
<div>Header Name:</div>
<input type="text" id="headerName" placeholder="Enter header name" />
<div>Header Value:</div>
<input type="text" id="headerValue" placeholder="Enter header value" />
</div>
<button id="sendHeader">Send Header</button>
<div id="headerResponse"></div>
</div>
</div>

</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
function addEventListenerToSendHeaderButton() {
document.getElementById("sendHeader").addEventListener("click", function() {
const headerName = document.getElementById("headerName").value;
const headerValue = document.getElementById("headerValue").value;

let url = getUrlForVulnerabilityLevel();

doGetAjaxCall(function(data) {
document.getElementById("headerResponse").innerHTML = data.isValid ?
"Header Injection was successful!" :
"Header Injection failed. Please try again.";
}, url, true, {
[headerName]: headerValue
});
});
}

addEventListenerToSendHeaderButton();
7 changes: 6 additions & 1 deletion src/main/resources/static/vulnerableApp.js
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ function genericResponseHandler(xmlHttpRequest, callBack, isJson) {
}
}

function doGetAjaxCall(callBack, url, isJson) {
function doGetAjaxCall(callBack, url, isJson, headers = {}) {
let xmlHttpRequest = new XMLHttpRequest();
xmlHttpRequest.onreadystatechange = function () {
genericResponseHandler(xmlHttpRequest, callBack, isJson);
Expand All @@ -245,6 +245,11 @@ function doGetAjaxCall(callBack, url, isJson) {
"Content-Type",
isJson ? "application/json" : "text/html"
);

for (const header in headers) {
xmlHttpRequest.setRequestHeader(header, headers[header]);
}

xmlHttpRequest.send();
}

Expand Down

0 comments on commit 0c23ff9

Please sign in to comment.