The milkshake bandits are back attacking your app. They’ve changed their attack again! You’ll need to update the rule to block these requests, whilst allow genuine customers.
All WAF Rules are defined as JSON objects. For complex rules, it can be more efficient to work directly with the JSON format than via the Console rules editor. You can retrieve existing rules in JSON format using the API, CLI or Console using the get-rule-group command. Modify them using your favourite JSON text editor, then reupload them using update-rule-group in the API, CLI or Console.
Defining rules in JSON allows you to use version control as a source of truth to see how, when and why iterations of complex rulesets have changed.
For this challenge, you start with a rule:
This Rule will block any requests that either::
x-milkshake: chocolate
milkshake=banana
{
"Name": "complex-rule-challenge",
"Priority": 0,
"Action": {
"Block": {}
},
"VisibilityConfig": {
"SampledRequestsEnabled": true,
"CloudWatchMetricsEnabled": true,
"MetricName": "complex-rule-challenge"
},
"Statement": {
"OrStatement": {
"Statements": [
{
"ByteMatchStatement": {
"FieldToMatch": {
"SingleHeader": {
"Name": "x-milkshake"
}
},
"PositionalConstraint": "EXACTLY",
"SearchString": "chocolate",
"TextTransformations": [
{
"Type": "NONE",
"Priority": 0
}
]
}
},
{
"ByteMatchStatement": {
"FieldToMatch": {
"SingleQueryArgument": {
"Name": "milkshake"
}
},
"PositionalConstraint": "EXACTLY",
"SearchString": "banana",
"TextTransformations": [
{
"Type": "NONE",
"Priority": 0
}
]
}
}
]
}
}
}
3. Drag the screen down, Click Add rule.
4. Click Save.
This rule was working, but the attackers have adapted. Now malicious requests contain either:
x-milkshake: chocolate
and the header x-favourite-topping: nuts
parameter milkshake=banana
and the query parameter favourite-topping=sauce
{
"Name": "complex-rule-challenge",
"Priority": 0,
"Action": {
"Block": {}
},
"VisibilityConfig": {
"SampledRequestsEnabled": true,
"CloudWatchMetricsEnabled": true,
"MetricName": "complex-rule-challenge"
},
"Statement": {
"OrStatement": {
"Statements": [
{
"AndStatement": {
"Statements": [
{
"ByteMatchStatement": {
"FieldToMatch": {
"SingleHeader": {
"Name": "x-milkshake"
}
},
"PositionalConstraint": "EXACTLY",
"SearchString": "chocolate",
"TextTransformations": [
{
"Type": "NONE",
"Priority": 0
}
]
}
},
{
"ByteMatchStatement": {
"FieldToMatch": {
"SingleHeader": {
"Name": "x-favourite-topping"
}
},
"PositionalConstraint": "EXACTLY",
"SearchString": "nuts",
"TextTransformations": [
{
"Type": "NONE",
"Priority": 0
}
]
}
}
]
}
},
{
"AndStatement": {
"Statements": [
{
"ByteMatchStatement": {
"FieldToMatch": {
"SingleQueryArgument": {
"Name": "milkshake"
}
},
"PositionalConstraint": "EXACTLY",
"SearchString": "banana",
"TextTransformations": [
{
"Type": "NONE",
"Priority": 0
}
]
}
},
{
"ByteMatchStatement": {
"FieldToMatch": {
"SingleQueryArgument": {
"Name": "favourite-topping"
}
},
"PositionalConstraint": "EXACTLY",
"SearchString": "sauce",
"TextTransformations": [
{
"Type": "NONE",
"Priority": 0
}
]
}
}
]
}
}
]
}
}
}
4. Click Save rule.
5. Click Save
6. Run command
# This will be allowed
curl -H "x-milkshake: chocolate" "<Your Juice Shop URL>"
curl "<Your Juice Shop URL>?milkshake=banana"
7. Run command
# This will be blocked
curl -H "x-milkshake: chocolate" -H "x-favourite-topping: nuts" "<Your Juice Shop URL>"
curl "<Your Juice Shop URL>?milkshake=banana&favourite-topping=sauce"
Blocked requests will give a response like below:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>ERROR: The request could not be satisfied</title>
</head>
<body>
<h1>403 ERROR</h1>
<!-- Omitted -->
</body>
</html>
In this section, you learnt about the JSON format for WAF Rules. Complex logic can be defined in rules using the And, Or and Not operators.