
MySQL Community Server 26.7.0 - Élevé - SET ROLE ALL EXCEPT FILE résiduel - écriture UID mysqld
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · mysql-set-role-leftover
Classe : Résidu de privilège (FILE en tant qu'UID mysqld ; pas d'élévation de privilèges OS) Portée : Distante
MySQL Community Server mysqld 26.7.0 (06a5c1c) - Oracle
SET ROLE ALL EXCEPT rfile (ou SET ROLE DEFAULT sans rôle par défaut) vide la liste des rôles actifs, puis checkout_access_maps() retourne sans set_master_access(user->access). CURRENT_ROLE() vaut NONE. Les bits globaux statiques que le rôle agrégeait (FILE, PROCESS, SUPER, ...) restent dans m_master_access. check_access lit ce résidu. Labo : le résidu FILE écrit INTO OUTFILE en tant qu'UID mysqld.
SET ROLE NONE est le chemin qui restaure ACL_USER::access. Les privilèges dynamiques (SYSTEM_USER) sont abandonnés. Le résidu au niveau base de données est déjà fermé (Bug#35386565). Les comptes par défaut n'ont pas de rôles.
| ID | pas encore de CVE |
| Classe | Résidu de privilège (FILE en tant qu'UID mysqld ; pas d'élévation de privilèges OS) |
| Portée | Distante (SQL authentifié) |
| CWE | CWE-269 |
| CVSS | Élevé : 8.1 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N |
| Produit | MySQL Community Server mysqld |
| Affecté | 26.7.0 (06a5c1c99c377fc41b2eba1ea244e8b220bdc3c8) |
| Auth | authentifié ; la victime se voit accorder un rôle portant des ACL globales statiques (FILE dans le labo) |
| Licence | GNU Affero GPL v3.0 |
| Labo | 127.0.0.1 uniquement. Fichier témoin. Écriture FILE résiduelle. |
Détenir un compte auquel a été accordé un rôle avec FILE (ou un autre bit global statique). SET ROLE ce rôle, puis SET ROLE ALL EXCEPT celui-ci. CURRENT_ROLE() rapporte NONE. SELECT 'witness' INTO OUTFILE écrit toujours en tant qu'UID mysqld sous secure_file_priv.
Une application qui isole avec SET ROLE ALL EXCEPT dangerous_role ou SET ROLE DEFAULT puis fait confiance à CURRENT_ROLE() possède toujours ces bits statiques. SET ROLE NONE les abandonne réellement.
Le résidu n'accorde pas FILE au compte qui ne l'a jamais détenu via un rôle. Il échoue à abandonner FILE après désactivation.
Même chasse sur 26.7.0 que les trois résidus clients. Le démon par défaut non publié Crit/High était vide. ACL / rôles avaient encore ce retour anticipé de rôle vide.
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 (ALL EXCEPT) et activate_role_default vide appellent ce checkout. activate_role_none fait ensuite set_master_access(user->access).
Mauvaise piste déjà consignée : le premier résidu SELECT note FROM lab.t INTO OUTFILE a retourné 1142 (cache db_acl() 0). Le SELECT 'witness' INTO OUTFILE constant est l'oracle FILE.
cd lab
./run.sh
Image mysql:26.7.0. Publiée sur 127.0.0.1:18630. Le rôle rfile a FILE. La victime a GRANT SELECT ON lab.* et GRANT rfile, file_priv=N, pas de rôle par défaut. Outfile à la connexion 1227. SET ROLE rfile outfile ok. SET ROLE ALL EXCEPT rfile fait que CURRENT_ROLE() vaut NONE ; l'outfile résiduel écrit /var/lib/mysql-files/MYSQL-SET-ROLE-LEFTOVER-WITNESS. SET ROLE NONE redonne 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
Quand m_active_roles est vide, checkout_access_maps() devrait faire set_master_access(user->access) comme le fait déjà SET ROLE NONE. Un ALL EXCEPT / DEFAULT vide ne devrait pas conserver la carte agrégée précédente.
06a5c1c99c377fc41b2eba1ea244e8b220bdc3c8)sql/auth/sql_security_ctx.cc checkout_access_mapssql/auth/roles.cc activate_role_all / activate_role_none