unserialize()
readObject()
pickle.loads()
Marshall.load()
User
object to store data about a user's session in a cookie. If an attacker spotted this serialized object in an HTTP request, they might decode it to find the following byte stream:isAdmin
attribute is an obvious point of interest. An attacker could simply change the boolean value of the attribute to 1
(true), re-encode the object, and overwrite their current cookie with this modified value. In isolation, this has no effect. However, let's say the website uses this cookie to check whether the current user has access to certain administrative functionality:User
object based on the data from the cookie, including the attacker-modified isAdmin
attribute. At no point is the authenticity of the serialized object checked. This data is then passed into the conditional statement and, in this case, would allow for an easy privilege escalation.==
) when comparing different data types. For example, if you perform a loose comparison between an integer and a string, PHP will attempt to convert the string to an integer, meaning that 5 == "5"
evaluates to true
.5 == "5 of something"
is in practice treated as 5 == 5
.0
:0
.0
instead of the expected string. As long as the stored password does not start with a number, the condition would always return true
, enabling an authentication bypass. Note that this is only possible because deserialization preserves the data type. If the code fetched the password from the request directly, the 0
would be converted to a string and the condition would evaluate to false
.__construct()
, which is invoked whenever an object of the class is instantiated, similar to Python's __init__
. Typically, constructor magic methods like this contain code to initialize the attributes of the instance. However, magic methods can be customized by developers to execute any code they want.unserialize()
method looks for and invokes an object's __wakeup()
magic method.ObjectInputStream.readObject()
method, which is used to read data from the initial byte stream and essentially acts like a constructor for "re-initializing" a serialized object. However, Serializable
classes can also declare their own readObject()
method as follows:readObject()
method declared in exactly this way acts as a magic method that is invoked during deserialization. This allows the class to control the deserialization of its own fields more closely.