
SQLite 3.53.4 - Alta - Local - Fuga de información - Desajuste del tamaño de página WAL/DB en la cola de página no inicializada
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · sqlite-wal-pagesize
Análisis: https://abraxaslabs.tech/research/sqlite-wal-pagesize
Clase: Fuga de información Alcance: Local
SQLite 3.53.4 (b09c88c) todavía lee de forma incompleta un frame WAL hacia una página completa del pager sin poner a cero el resto. walIndexRecover acepta cualquier tamaño de página WAL potencia de dos en [512, SQLITE_MAX_PAGE_SIZE] y nunca lo compara con el tamaño de página de la base de datos. Los slots de pcache reciclados devuelven entonces bytes previos del heap/página a través de SQL ordinario.
Laboratorio: .db en modo WAL con páginas de 4096, cabecera -wal hermana con tamaño de página 512, SELECT b FROM t devolvió 2000 bytes. La cola más allá del frame de 512 bytes era SQLITE-WAL-PAGESIZE-WITNESS. No es RCE.
| ID | aún sin CVE |
| Clase | Fuga de información (cola del pager sin inicializar a través de SQL) |
| Alcance | Local (.db no confiable más -wal hermana) |
| CWE | CWE-908, CWE-200 |
| CVSS | Alto: 7.5 CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N |
| Producto | SQLite (Hwaci) |
| Afectado | 3.53.4 (b09c88c14082339b66c7b7158d609a771e64ca69); SOURCE_ID 2026-07-24 19:02:57 bf7c7f30031888f4e796e429ab3978879485813aaca6f641c7b33e4e09459bcc |
| Autenticación | ninguna (la víctima abre los archivos del atacante) |
| Licencia | GNU Affero GPL v3.0 |
| Laboratorio | solo 127.0.0.1:18830 |
Entregar un .db en modo WAL junto con una -wal hermana cuyo tamaño de página en la cabecera sea una potencia de dos válida menor que la de la base de datos. La recuperación lo acepta. sqlite3WalReadFrame copia solo el tamaño del frame WAL en un búfer del pager dimensionado según el .db. Una celda de hoja de tabla que declara un payload mayor que ese frame se satisface desde la cola reciclada del pcache. SELECT / substr() / hex() sobre ese blob devuelve bytes sobrantes del pager/heap de páginas previas en el mismo proceso.
La discrepancia inversa (WAL mayor que el pager) produce SQLITE_CORRUPT en el checkpoint. Este sobrante corresponde únicamente a la ruta de lectura con WAL menor. No es RCE.
Veinte búsquedas en el código fuente de 3.53.4 tras la matriz de sobrantes del trunk posterior. Winter lo reportó en el foro como 2026-08-17T15:54:41Z. El trunk f9b4ee3695 / branch-3.53 4fde87b2a0 (2026-08-16) es posterior a este GA (2026-07-24). sqlite3WalReadFrame en este pin sigue siendo (nOut>sz ? sz : nOut) sin memset de la cola.
Falso camino: una celda de hoja temprana estaba malformada y SELECT devolvió SQLITE_CORRUPT rc=11. La celda que funciona declara 2000 bytes de payload local a través de un frame de 512 bytes en una página de pager de 4096 bytes.
cd lab
./run.sh
Compila SQLite 3.53.4 desde el zip de código fuente canónico. Compone sqlite-wal-pagesize. Publica 127.0.0.1:18830. Prepara la pcache con 48 filas testigo de 4000 bytes, luego SELECT b FROM t sobre la hoja de lectura corta.
SUCCESS sqlite-wal-pagesize how=wal-shortread-pcache-tail len=2000 rootpage=2 SQLITE-WAL-PAGESIZE-WITNESS
Comparar el tamaño de página del encabezado del WAL con el tamaño de página de la base de datos durante la recuperación. Cuando no coincidan, rechazar el WAL o inicializar completamente la página del paginador:
if( nOut>sz ){
memset(pOut+sz, 0, nOut-sz);
nOut = sz;
}
Ese fragmento está en el tronco después de esta GA. No está en 3.53.4.
b09c88c14082339b66c7b7158d609a771e64ca69)src/wal.c sqlite3WalReadFrame, walIndexRecoversrc/pager.c readDbPage