概述:MySQL8 密码生成逻辑,注入测试。
0x01 相关函数
- mysqld!generate_native_password
- mysqld!generate_sha256_password
如下所示:为创建密码为 admin123 生成的 mysql_native_password 的密码加密结果,*01A6717B58FF5C7EAFFF6CB7C96F7428EA65FE4C
create USER mnpweak1 IDENTIFIED WITH mysql_native_password BY 'admin123';
看一下数据库入库结果,与上述函数计算结果一致。
调用堆栈如下所示:
[0x0] mysqld!generate_native_password 0xc9ce8f8128 0x7ff6fb80ef43
[0x1] mysqld!set_and_validate_user_attributes+0xc03 0xc9ce8f8130 0x7ff6fb80ae8f
[0x2] mysqld!mysql_create_user+0x7df 0xc9ce8f8940 0x7ff6fb607556
[0x3] mysqld!mysql_execute_command+0x1df6 0xc9ce8fcb00 0x7ff6fb60348f
[0x4] mysqld!dispatch_sql_command+0x36f 0xc9ce8fe000 0x7ff6fb6029e1
[0x5] mysqld!dispatch_command+0x19c1 0xc9ce8fe0b0 0x7ff6fb603860
[0x6] mysqld!do_command+0x230 0xc9ce8ff4a0 0x7ff6fb43c9f8
[0x7] mysqld!handle_connection+0x138 0xc9ce8ff940 0x7ff6fca6d7e9
[0x8] mysqld!pfs_spawn_thread+0x129 0xc9ce8ff980 0x7ff6fc4d3bdc
[0x9] mysqld!win_thread_start+0x1c 0xc9ce8ff9b0 0x7ffdba6c9363
[0xa] ucrtbase!thread_start<unsigned int (__cdecl*)(void *),1>+0x93 0xc9ce8ff9e0 0x7ffdbbd9257d
[0xb] KERNEL32!BaseThreadInitThunk+0x1d 0xc9ce8ffa10 0x7ffdbcc2aa78
[0xc] ntdll!RtlUserThreadStart+0x28 0xc9ce8ffa40 0x0 相关函数以插件形式保存在全局变量 mysqld!g_cached_authentication_plugins
MySQl 认证插件详解
MySQL 在启动时会初始化相关插件并加载插件的相关调用。每个身份认证插件都保存了一种认证方式,mysql在实现这些特性上有着和Windows类似的设计,结构体。
MySQL 插件相关结构体
插件结构体,该结构体保存了插件的详细信息,包括句柄这么的,在mysql中,有几个重要的 st_mysql_plugin 结构体数组,builtin_mysql_password_plugin 和 builtin_caching_sha2_password_plugin ,可以调试看看这两个结构体数组保存的相关内容。
struct st_mysql_plugin {
int type;
void *info; // 插件加密函数
const char *name;
const char *author;
const char *descr;
int license;
int (*init)(MYSQL_PLUGIN);
int (*check_uninstall)(MYSQL_PLUGIN);
int (*deinit)(MYSQL_PLUGIN);
unsigned int version;
SHOW_VAR *status_vars;
SYS_VAR **system_vars;
void *__reserved1;
unsigned long flags;
};字段说明:
| 字段 | 类型 | 描述 |
|---|---|---|
| type | int | 用于描述plugin的类型,随着版本更新,越来越多,在5.5中包含8种类型:MYSQL_UDF_PLUGIN,MYSQL_STORAGE_ENGINE_PLUGIN,MYSQL_FTPARSER_PLUGIN,MYSQL_DAEMON_PLUGIN,MYSQL_INFORMATION_SCHEMA_PLUGINMYSQL_AUDIT_PLUGINMYSQL_REPLICATION_PLUGINMYSQL_AUTHENTICATION_PLUGIN |
| info | void* | 用于指向特定的plugin描述符结构体,在daemon plugin中结构体为st_mysql_daemon,一般第一个字段都是插件接口的版本号 |
| name | const char* | plugin的名字,需要和安装时的名字一致 |
| author | const char* | plugin的作者信息,会在i_s.plugins表中显示 |
| descr | const char* | 描述插件 |
| license | ubt | 插件许可证:PLUGIN_LICENSE_PROPRIETARYPLUGIN_LICENSE_GPLPLUGIN_LICENSE_BSD |
| init | int (*init)(void *) | 当插件被加载时或者mysqld重启时会执行该函数,一般我们会在这里创建好后台线程 |
| deinit | int (*deinit)(void *); | 当插件被卸载时做的工作,例如取消线程,清理内存等 |
| version | unsigned int | plugin的版本信息 |
| status_vars | st_mysql_show_var* | 描述在执行show status时显示的信息 |
| system_vars | st_mysql_sys_var ** | 描述在执行show variables显示的信息 |
| __reserved1 | void* | 注释说为检查依赖而保留,不太明白,直接设为NULL即可 |
| flags | unsigned long | 5.5之后增加的字段,plugin的flag:0、PLUGIN_OPT_NO_INSTALL(不可动态加载)、PLUGIN_OPT_NO_UNINSTALL(不可动态加载) |
其中,info 成员比较重要,指向另外一个结构体 st_mysql_auth,先看一下 info 变量的结构体,保存了 mysql 身份认证插件相关的函数,st_mysql_plugin.info 指向的的结构体 st_mysql_auth:
// file: plugin_auth.h
/**
Server authentication plugin descriptor
*/
struct st_mysql_auth {
int interface_version; /** version plugin uses */
/**
A plugin that a client must use for authentication with this server
plugin. Can be NULL to mean "any plugin".
*/
const char *client_auth_plugin;
authenticate_user_t authenticate_user;
generate_authentication_string_t generate_authentication_string;
validate_authentication_string_t validate_authentication_string;
set_salt_t set_salt;
/**
Authentication plugin capabilities
*/
const unsigned long authentication_flags;
compare_password_with_hash_t compare_password_with_hash;
};结构体相关变量
了解了相关结构之后,需要在mysql中查看相应的变量。查找相关结构体变量可以看到一个全局定义的宏
// file: sql_authentication.cc
mysql_declare_plugin(mysql_password){
MYSQL_AUTHENTICATION_PLUGIN, /* type constant */
&native_password_handler, /* type descriptor */
Cached_authentication_plugins::get_plugin_name(
PLUGIN_MYSQL_NATIVE_PASSWORD), /* Name */
PLUGIN_AUTHOR_ORACLE, /* Author */
"Native MySQL authentication", /* Description */
PLUGIN_LICENSE_GPL, /* License */
nullptr, /* Init function */
nullptr, /* Check uninstall */
nullptr, /* Deinit function */
0x0101, /* Version (1.0) */
nullptr, /* status variables */
nullptr, /* system variables */
nullptr, /* config options */
0, /* flags */
},
{
MYSQL_AUTHENTICATION_PLUGIN, /* type constant */
&sha256_password_handler, /* type descriptor */
Cached_authentication_plugins::get_plugin_name(
PLUGIN_SHA256_PASSWORD), /* Name */
PLUGIN_AUTHOR_ORACLE, /* Author */
"SHA256 password authentication", /* Description */
PLUGIN_LICENSE_GPL, /* License */
&init_sha256_password_handler, /* Init function */
nullptr, /* Check uninstall */
nullptr, /* Deinit function */
0x0101, /* Version (1.0) */
nullptr, /* status variables */
sha256_password_sysvars, /* system variables */
nullptr, /* config options */
0 /* flags */
} mysql_declare_plugin_end;展开后如下所示, 也就能看到对应的结构体 st_mysql_plugin 以及其数组定义了
int builtin_mysql_password_plugin_interface_version = 0x010B;
int builtin_mysql_password_sizeof_struct_st_plugin = sizeof(struct st_mysql_plugin);
struct st_mysql_plugin builtin_mysql_password_plugin[] = {
{
MYSQL_AUTHENTICATION_PLUGIN, /* type constant */
&native_password_handler, /* type descriptor */
Cached_authentication_plugins::get_plugin_name(
PLUGIN_MYSQL_NATIVE_PASSWORD), /* Name */
PLUGIN_AUTHOR_ORACLE, /* Author */
"Native MySQL authentication", /* Description */
PLUGIN_LICENSE_GPL, /* License */
nullptr, /* Init function */
nullptr, /* Check uninstall */
nullptr, /* Deinit function */
0x0101, /* Version (1.0) */
nullptr, /* status variables */
nullptr, /* system variables */
nullptr, /* config options */
0, /* flags */
},
{
MYSQL_AUTHENTICATION_PLUGIN, /* type constant */
&sha256_password_handler, /* type descriptor */
Cached_authentication_plugins::get_plugin_name(
PLUGIN_SHA256_PASSWORD), /* Name */
PLUGIN_AUTHOR_ORACLE, /* Author */
"SHA256 password authentication", /* Description */
PLUGIN_LICENSE_GPL, /* License */
&init_sha256_password_handler, /* Init function */
nullptr, /* Check uninstall */
nullptr, /* Deinit function */
0x0101, /* Version (1.0) */
nullptr, /* status variables */
sha256_password_sysvars, /* system variables */
nullptr, /* config options */
0 /* flags */
},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
}还有 caching_sha2_password 身份认证插件对应的宏定义,展开后与 mysql_password 类似,这里就省略了。
// file: sha2_password.cc
/*
caching_sha2_password plugin declaration
*/
mysql_declare_plugin(caching_sha2_password){
MYSQL_AUTHENTICATION_PLUGIN, /* plugin type */
&caching_sha2_auth_handler, /* type specific descriptor */
Cached_authentication_plugins::get_plugin_name(
PLUGIN_CACHING_SHA2_PASSWORD), /* plugin name */
PLUGIN_AUTHOR_ORACLE, /* author */
"Caching sha2 authentication", /* description */
PLUGIN_LICENSE_GPL, /* license */
caching_sha2_authentication_init, /* plugin initializer */
nullptr, /* Uninstall notifier */
caching_sha2_authentication_deinit, /* plugin deinitializer */
0x0100, /* version (1.0) */
caching_sha2_password_status_variables, /* status variables */
caching_sha2_password_sysvars, /* system variables */
nullptr, /* reserved */
0, /* flags */
},
{
MYSQL_AUDIT_PLUGIN, /* plugin type */
&sha2_cache_cleaner, /* type specific descriptor */
"sha2_cache_cleaner", /* plugin name */
PLUGIN_AUTHOR_ORACLE, /* author */
"Cache cleaner for Caching sha2 authentication", /* description */
PLUGIN_LICENSE_GPL, /* license */
caching_sha2_cache_cleaner_init, /* plugin initializer */
nullptr, /* Uninstall notifier */
caching_sha2_cache_cleaner_deinit, /* plugin deinitializer */
0x0100, /* version (1.0) */
nullptr, /* status variables */
nullptr, /* system variables */
nullptr, /* reserved */
0 /* flags */
} mysql_declare_plugin_end;以及相应的全局成员变量(file:sql_builtin.cc.in)如下所示:
//sql_builtin.cc.in
#include "mysql/plugin.h"
typedef struct st_mysql_plugin builtin_plugin[];
#ifdef _MSC_VER
extern "C"
#else
extern
#endif
builtin_plugin
@mysql_mandatory_plugins@ @mysql_optional_plugins@ builtin_binlog_plugin, builtin_mysql_password_plugin, builtin_caching_sha2_password_plugin, builtin_daemon_keyring_proxy_plugin;
struct st_mysql_plugin *mysql_optional_plugins[]=
{
@mysql_optional_plugins@ 0
};
struct st_mysql_plugin *mysql_mandatory_plugins[]=
{
builtin_binlog_plugin, builtin_mysql_password_plugin, builtin_caching_sha2_password_plugin, builtin_daemon_keyring_proxy_plugin, @mysql_mandatory_plugins@ 0
};用 IDA 查看可以发现,mysqld 导出了一个 st_mysql_plugin 的变量 builtin_mysql_password_plugin
上述两个结构体只是 mysql_native_password 和 sha356_password 两个的相关句柄,caching_sha2_auth_handler 的相关处理句柄在另外一个变量中,如下所示:
/** st_mysql_auth for caching_sha2_password plugin */
static struct st_mysql_auth caching_sha2_auth_handler {
MYSQL_AUTHENTICATION_INTERFACE_VERSION,
Cached_authentication_plugins::get_plugin_name(
PLUGIN_CACHING_SHA2_PASSWORD),
caching_sha2_password_authenticate, caching_sha2_password_generate,
caching_sha2_password_validate, caching_sha2_password_salt,
AUTH_FLAG_USES_INTERNAL_STORAGE, compare_caching_sha2_password_with_hash
};生成密码函数
生成密码的函数原型,也就是 st_mysql_auth 中的 generate_authentication_string_t 成员。
对应 generate_native_password 和 sha256_password_authenticate 以及 caching_sha2_password_generate
/**
New plugin API to generate password digest out of authentication string.
This function will first invoke a service to check for validity of the
password based on the policies defined and then generate encrypted hash
@param[out] outbuf A buffer provided by server which will hold the
authentication string generated by plugin.
@param[in,out] outbuflen Length of server provided buffer as IN param and
length of plugin generated string as OUT param.
@param[in] inbuf auth string provided by user.
@param[in] inbuflen auth string length.
@retval 0 OK
@retval 1 ERROR
*/
typedef int (*generate_authentication_string_t)(char *outbuf,
unsigned int *outbuflen,
const char *inbuf,
unsigned int inbuflen);以 caching_sha2_password 为例,在相关函数 caching_sha2_password_generate 打断点调试, 可以看到初始密码为 admin123 经过加密之后加密字符串为
$A$005$"4eh#.@.^B3Tu.[ngw'.81iezRRMhYZg1f.29kTTLOKMTbmQWXSZfUJ6NF/4a.8
查一下数据库入库密码
