Skip to content

PC is an 'Intermediate' rated box on Offsec Proving Grounds. It is a Linux machine hosting a remote Terminal access via snap on port 8000 HTTP. Since there is no need to establish a foothold, once we access the terminal, we find a vulnerable version of rpc.py that we can exploit to elevate our privileges to root.

Enumeration

We start with an nmap scan.

sudo nmap -A 192.168.167.210

Screenshot

Only two ports that we can see so far, with port 8000 HTTP being the service we're going to investigate.

An interesting result from the nmap scan is that the HTTP Title for the website being hosted is 'Terminal'.

Vulnerability Analysis and Foothold

Browsing to http://192.168.167.210:8000 leads us here:

Screenshot

Very interesting. It appears to be a fully functional terminal. Let's do some test commands.

Screenshot

Looks like it works. We'll do some general enumeration, to include investigating the user's home directory, what permissions we have, and what processes are running on the box. Of interest, we see this python script being run in /opt/.

ps -elf

Screenshot

Taking a look inside to see what's what.

from typing import AsyncGenerator
from typing_extensions import TypedDict

import uvicorn
from rpcpy import RPC

app = RPC(mode="ASGI")


@app.register
async def none() -> None:
    return


@app.register
async def sayhi(name: str) -> str:
    return f"hi {name}"


@app.register
async def yield_data(max_num: int) -> AsyncGenerator[int, None]:
    for i in range(max_num):
        yield i


D = TypedDict("D", {"key": str, "other-key": str})


@app.register
async def query_dict(value: str) -> D:
    return {"key": value, "other-key": value}


if __name__ == "__main__":
    uvicorn.run(app, interface="asgi3", port=65432)

This doesn't seem like a simple script at first glance, a quick Google search can confirm this a is project found on https://pypi.org/project/rpc.py/.

According to the description, rpc.py is a fast and powerful RPC framework based on ASGI/WSGI. Based on WSGI/ASGI, you can deploy the rpc.py server to any server and use http2 to get better performance. And based on httpx's support for multiple http protocols, the client can also use http/1.0, http/1.1 or http2.

Searching the web, we find that rpc.py through 0.6.0 allows Remote Code Execution because an unpickle occurs when the "serializer: pickle" HTTP header is sent. In other words, although JSON (not Pickle) is the default data format, an unauthenticated client can cause the data to be processed with unpickle.

Privilege Escalation

This PoC script on GitHub written by fuzzlove weaponizes this vulnerability. We'll pull his script down, configure it to our purposes, and transfer it to our victim.

Screenshot

We'll change the highlighted portion to our own IP.

Screenshot

Once transferred, we'll spin up a nc listener on TCP port 9091, execute our script on the victim, and catch our shell.

nc -nvlp 9091

Screenshot

Screenshot

Success! Now we can grab proof.txt.

Screenshot