
MySQL Community Server 26.7.0 - Alta - SET ROLE ALL EXCEPT residuo FILE - scrittura UID mysqld
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · mysql-set-role-leftover
Write-up: https://abraxaslabs.tech/research/mysql-set-role-leftover
Classe: Privilegio residuo (FILE come UID di mysqld; non LPE a livello OS) Raggiungibilità: Remota
MySQL Community Server mysqld 26.7.0 (06a5c1c) - Oracle
SET ROLE ALL EXCEPT rfile (o SET ROLE DEFAULT senza default) svuota la lista dei ruoli attivi, poi checkout_access_maps() ritorna senza set_master_access(user->access). CURRENT_ROLE() è NONE. I bit globali statici aggregati dal ruolo (FILE, PROCESS, SUPER, ...) restano in m_master_access. check_access legge quel residuo. In laboratorio: il FILE residuo scrive INTO OUTFILE con l'UID di mysqld.
SET ROLE NONE è il percorso che ripristina ACL_USER::access. I privilegi dinamici (SYSTEM_USER) decadono. Il residuo a livello di database è già chiuso (Bug#35386565). Gli account di default non hanno ruoli.
| ID | nessuna CVE al momento |
| Classe | Privilegio residuo (FILE come UID di mysqld; non LPE a livello OS) |
| Raggiungibilità | Remota (SQL autenticato) |
| CWE | CWE-269 |
| CVSS | Alto: 8.1 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N |
| Prodotto | MySQL Community Server mysqld |
| Affetto | 26.7.0 (06a5c1c99c377fc41b2eba1ea244e8b220bdc3c8) |
| Auth | autenticato; alla vittima è stato concesso un ruolo che porta ACL globali statiche (FILE in laboratorio) |
| Licenza | GNU Affero GPL v3.0 |
| Lab | solo 127.0.0.1. File testimone. Scrittura FILE residua. |
Disporre di un account a cui è stato concesso un ruolo con FILE (o un altro bit globale statico). Eseguire SET ROLE su quel ruolo, poi SET ROLE ALL EXCEPT su di esso. CURRENT_ROLE() riporta NONE. SELECT 'witness' INTO OUTFILE scrive comunque con l'UID di mysqld sotto secure_file_priv.
Un'applicazione che applica il sandboxing con SET ROLE ALL EXCEPT dangerous_role o SET ROLE DEFAULT e poi si fida di CURRENT_ROLE() conserva ancora quei bit statici. SET ROLE NONE li rimuove davvero.
Il residuo non concede FILE a un account che non l'ha mai ottenuto tramite un ruolo. Non riesce a rimuovere FILE dopo la disattivazione.
Stessa ricerca sulla 26.7.0 dei tre residui lato client. Il daemon di default non pubblicava nulla di Crit/High. La parte ACL / ruoli presentava ancora questo ritorno anticipato a ruolo vuoto.
void Security_context::checkout_access_maps(void) {
if (m_acl_map != nullptr) {
get_global_acl_cache()->return_acl_map(m_acl_map);
m_acl_map = nullptr;
}
if (m_active_roles.size() == 0) return;
// ...
}
activate_role_all (TUTTI TRANNE) e la chiamata vuota a activate_role_default eseguono quel checkout. activate_role_none esegue poi set_master_access(user->access).
Errore già registrato: il primo residuo SELECT note FROM lab.t INTO OUTFILE ha restituito 1142 (cache db_acl() 0). La costante SELECT 'witness' INTO OUTFILE è l'oracolo FILE.
cd lab
./run.sh
Immagine mysql:26.7.0. Pubblicata su 127.0.0.1:18630. Il ruolo rfile ha FILE. La vittima ha GRANT SELECT ON lab.* e GRANT rfile, file_priv=N, nessun ruolo predefinito. Login outfile 1227. SET ROLE rfile outfile ok. SET ROLE ALL EXCEPT rfile rende CURRENT_ROLE() NONE; le scritture outfile residue scrivono in /var/lib/mysql-files/MYSQL-SET-ROLE-LEFTOVER-WITNESS. SET ROLE NONE restituisce di nuovo 1227.
SUCCESS mysql-set-role-leftover before-file=denied with-role=yes leftover-role=NONE leftover-file=yes after-none=denied dump=26.7.0 image=mysql:26.7.0 MYSQL-SET-ROLE-LEFTOVER-WITNESS
Quando m_active_roles è vuoto, checkout_access_maps() dovrebbe eseguire set_master_access(user->access) allo stesso modo in cui lo fa già SET ROLE NONE. Un ALL EXCEPT / DEFAULT vuoto non dovrebbe mantenere la mappa aggregata precedente.
06a5c1c99c377fc41b2eba1ea244e8b220bdc3c8)sql/auth/sql_security_ctx.cc checkout_access_mapssql/auth/roles.cc activate_role_all / activate_role_none