October 4, 2019•946 words
Notes and Format
- What: Convert an object into a stream of bytes by storing the state of the object.
- What gets stored in the byte stream:
- The member variables/fields
- function signature (but NOT the function's code) impacts the bytes created for the object
- How: "The default serialization mechanism for an object writes the class of the
object, the class signature, and the values of all non-transient and
non-static fields. References to other objects (except in transient or
static fields) cause those objects to be written also. Multiple references
to a single object are encoded using a reference sharing mechanism so that
graphs of objects can be restored to the same shape as when the original was
How: "The default deserialization mechanism for objects restores the contents
of each field to the value and type it had when it was written. Fields
declared as transient or static are ignored by the deserialization process.
References to other objects cause those objects to be read from the stream
as necessary. Graphs of objects are restored correctly using a reference
sharing mechanism. New objects are always allocated when deserializing,
which prevents existing objects from being overwritten."
"Reading an object is analogous to running the constructors of a new
object. Memory is allocated for the object and initialized to zero (NULL).
No-arg constructors are invoked for the non-serializable classes and then
the fields of the serializable classes are restored from the stream starting
with the serializable class closest to java.lang.object and finishing with
the object's most specific class. "
- Important: With respect to byte streams, notes on closing the streams:
- For an output stream, calling close() ensures that the data gets written to its destination (file or whathaveyou); not closing the stream will result in the data being in the buffer without being written to its destination.
- For an input stream, a file descriptor is associated with the stream, and is stored in the file descriptor table; consequently, the file descriptor table can run out of space if there is a lot of unclosed file streams, and may stop the program from opening new files -- which can be problematic. Close your input file streams.
- Important: it introduces vulnreability in the code since the serialized byte stream can be easily edited to change bytes such that some invariant of the serialized object is broken.
- source https://docs.oracle.com/javase/7/docs/platform/serialization/spec/protocol.html#10258
- Stream Format For Classes
|Magic Number||Version UID||className||serialVersionUID||handle||classDescFlags byte||field1TypeCode field1Name||fieldNTypeCode fieldNName <classNameForFieldOfObjectType>||fieldBytes||nullReference||prevObjectReference|
- Stream Format For Objects
|Magic Number||Version UID||className||serialVersionUID||handle||classDescFlags byte||field1TypeCode field1Name||fieldNTypeCode fieldNName <classNameForFieldOfObjectType>||fieldBytes||nullReference||prevObjectReference||classData: fieldsInClass, bytesForPrimitives|
magic version contents
content contents content
object: classes, outputStream Objects, Enums
blockdata: primitive dataTypes
- "All of the write methods for primitive types encode their values using a
DataOutputStreamto put them in the standard stream format. The bytes are buffered into block data records so they can be distinguished from the encoding of objects. This buffering allows primitive data to be skipped if necessary for class versioning. It also allows the stream to be parsed without invoking class-specific methods."
Codes used in the serialized data:
B = byte
C = char
D = double
F = float
I = integer
S = short
Z = boolean
[ = array
L = object
final static short STREAMMAGIC = (short)0xaced;final static short STREAMVERSION = 5;final static byte TCNULL = (byte)0x70;final static byte TCREFERENCE = (byte)0x71;final static byte TCCLASSDESC = (byte)0x72;final static byte TCOBJECT = (byte)0x73;final static byte TCSTRING = (byte)0x74;final static byte TCARRAY = (byte)0x75;final static byte TCCLASS = (byte)0x76;final static byte TCBLOCKDATA = (byte)0x77;final static byte TCENDBLOCKDATA = (byte)0x78;final static byte TCRESET = (byte)0x79;final static byte TCBLOCKDATALONG = (byte)0x7A;final static byte TCEXCEPTION = (byte)0x7B;final static byte TCLONGSTRING = (byte) 0x7C;final static byte TCPROXYCLASSDESC = (byte) 0x7D;final static byte TC_ENUM = (byte) 0x7E;final static int baseWireHandle = 0x7E0000;
Serialization Vulnerability Demonstration Code:
<add after lunch>