vsftpd 3.0.5 - Alta - Remota - Privilegio residual - FTPS data acepta cualquier ticket reanudado
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · vsftpd-ssl-data-any-ticket
Clase: Resto de privilegio Alcance: Remoto
vsftpd 3.0.5 (Chris Evans) - tarball oficial SHA-256 26b602ae454b0ba6d99ef44a09b6b9e0dfa7f67228106736df1f278c70bc91d3. Las compilaciones FTPS de las distribuciones definen #define VSF_BUILD_SSL (el tarball original lo deja #undef) y los operadores configuran ssl_enable=YES. El modo standalone listen=YES es el valor por defecto compilado y de ejemplo.
ssl_accept (ssl.c:494-501) es el enlace del canal de datos. Solo comprueba SSL_session_reused(). No hay comparación de SSL_SESSION contra el SSL de control. El SSL de datos no tiene USER/PASS de FTP. El ssl_init standalone se ejecuta en el listener antes del fork (main.c:147-150), por lo que los hijos heredan un único SSL_CTX. SSL_CTX_set_timeout(INT_MAX) (ssl.c:182-186). Sin SSL_OP_NO_TICKET. SSL_session_reused()==1 significa que este ClientHello llevaba un ticket que este proceso puede descifrar, no que sea la sesión de control de Alice.
La página de manual de require_ssl_reuse dice que la reutilización demuestra el mismo master secret que el canal de control. El código C no lo hace. Distinto del kill-on-reuse-fail de Tim Kosse en 3.0.3 (ftpdataio.c:184-187), que aún devuelve 522 ante un handshake nuevo y no impide que Mallory reanude un ticket emitido en un control diferente.
Este resto es una única transferencia FTPS. No es un salto de USER/PASS, ni una shell, ni un escape de chroot.
| ID | sin CVE todavía |
| Clase | Resto de privilegio (los datos FTPS aceptan cualquier ticket reanudado) |
| Alcance | Remoto (PASV desde la misma IP; NAT compartido es AC:H) |
| CWE | CWE-345, CWE-287 |
| CVSS | Alto: 7.4 CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N |
| Producto | vsftpd (Chris Evans) |
| Afectados | 3.0.5 con VSF_BUILD_SSL y ssl_enable=YES. require_ssl_reuse=YES (por defecto). require_cert=NO (por defecto) |
| Autenticación | Mallory: solo AUTH TLS (sin USER/PASS). Alice: PBSZ/PROT P anónimo |
| Licencia | GNU Affero GPL v3.0 |
| Laboratorio | 127.0.0.1:18700 control, PASV 18701-18708. Compose vsftpd-ssl-data-any-ticket |
Quién: otro cliente FTPS (o alguien en la ruta) que comparte la IP de origen de Alice. El accept de PASV sigue requiriendo la IP del peer de control (privops.c:212-218) salvo con pasv_promiscuous. El NAT compartido es el caso habitual de FTPS que require_ssl_reuse se añadió para detener. Mallory nunca inicia sesión.
| Método + sink | Privilegio |
|---|---|
Mallory solo AUTH TLS, TLS 1.2 ALPN ftp, conserva el ticket de sesión del SSL_CTX del listener. Alice anónimo PBSZ/PROT P, PASV, RETR secret.txt bloqueado en get_remote_transfer_fd hasta el accept. Mallory PASV desde la misma IP, reanuda su ticket (session_reused=True) | Descifra ese único RETR. Laboratorio: socket de datos 35 bytes VSFTPD-SSL-DATA-ANY-TICKET-WITNESS. Alice 150 y luego 226. El TLS de control y la contraseña siguen siendo de Alice. Sin recorrido de directorios más allá de esa transferencia. |
ssl_accept; el laboratorio fue robo de RETR)| Método + sink | Privilegio |
|---|---|
Misma reanudación de ticket mientras Alice hace STOR / APPE | El archivo nombrado de Alice se escribe desde el texto plano TLS de Mallory, como el uid de Alice / uid ftp anónimo, dentro del chroot existente |
| Método + sink | Privilegio |
|---|---|
Handshake de datos nuevo (reused=False) | 522 session reuse required (kill de 3.0.3). Esa transferencia muere. El control sigue siendo de Alice |
privops.c:212-218)require_cert=YES más un certificado presentado vincula los digests SHA-256PROT C en texto claro para usuarios locales (force_local_data_ssl por defecto YES)ssl_init del listener)ftp (vsftpd da FATAL)Fijé el tarball oficial de vsftpd 3.0.5 en lugar de un mirror de GitHub o un árbol de Debian/Fedora. Diecinueve búsquedas en el código fuente. La búsqueda del SSL se detuvo en ssl_accept: la reutilización es un booleano, no un vínculo a este SSL_SESSION de control. El SSL_CTX del listener más la vida útil del ticket INT_MAX es el resto.
Caminos equivocados: el ALPN debe ser ftp o vsftpd da FATAL (el resto ALPACA de 3.0.4 ya está cerrado). El enlazado en Arm64 necesitó -lpam -lcap explícitos; el vsf_findlibs.sh original solo sondea rutas x86_64. Tratar el kill de Tim Kosse en 3.0.3 como este bug: devuelve 522 ante un handshake nuevo en el fd de datos de Alice y no detiene un ticket emitido en un control diferente.
cd lab
./run.sh
3.0.5 oficial con #define VSF_BUILD_SSL. Conf: ssl_enable=YES, allow_anon_ssl=YES, force_anon_logins_ssl=YES, force_anon_data_ssl=YES, require_ssl_reuse=YES, require_cert=NO. Docker en loopback. Dos clientes desde la misma IP. Tickets TLS 1.2. ALPN ftp. Control 127.0.0.1:18700, PASV 18701-18708. Compose vsftpd-ssl-data-any-ticket. Witness VSFTPD-SSL-DATA-ANY-TICKET-WITNESS. Última línea:
SUCCESS vsftpd-ssl-data-any-ticket reused-ticket=yes fresh-handshake=522 VSFTPD-SSL-DATA-ANY-TICKET-WITNESS
Vincular el SSL_SESSION de datos al SSL_SESSION de control (comparar ids de sesión / master secret). Limitar la vida útil del ticket a la conexión de control. O SSL_OP_NO_TICKET más una caché de sesiones indexada por el control. ProFTPD 1.3.9d compara sesiones.
La recepción del proveedor es [email protected] (security.appspot.com/vsftpd.html). No abras un issue público en GitHub en ningún mirror de vsftpd.
Abraxas Labs - abraxaslabs.tech - github.com/abraxas - @abraxas_null - [email protected]