暂无图片
暂无图片
8
暂无图片
暂无图片
暂无图片

[MYSQL] mysql忘记密码怎么办?

原创 大大刺猬 2024-09-19
670

导读

天有不测风云, 今晚(20240919,上海)台风Pulasan就要来了. 难免有忘记mysql密码的时候. 解决办法网上也是一找一大堆的. 这里做个小小的介绍. (不考虑history里面能查询到的情况, 况且那也不属于忘记密码的范畴)
image.png

忘记密码的处理方法

ALTER修改(0星)

如果是忘记普通账号的密码, 可以在业务端配置文件找(能找到的话, 估计也看不到这了.). 更多的情况是都找不到了. 只能重置密码. 命令参考

alter user username@'%' identified with mysql_native_password by '123456'; flush privileges;

注: 最新版mysql不在支持mysql_native_password插件了.

skip_grant_tables(1星)

多数情况, 我们都是忘记root的密码了. 不然都可以使用第一种方法来解决. mysql也预料到了这种情况. 于是整了个参数skip_grant_tables , 该参数为True时,即不做权限/密码认证, 任何账号都能直接登录, 这很危险, 于是又整了个参数skip_networking 来限制TCP/IP连接, 这样我们修改密码的时候,还可以通过socket来连接, 但是其它账号就不能通过网络连接了. 算是安全了.(如果其它人都能登录OS了的话, 也是可以通过socket连接的, 但这属于OS那边的’锅’)

--skip-grant-tables

Command-Line Format --skip-grant-tables[={OFF|ON}]
Type Boolean
Default Value OFF

skip_networking

Command-Line Format --skip-networking[={OFF|ON}]
System Variable skip_networking
Scope Global
Dynamic No
SET_VAR Hint Applies No
Type Boolean
Default Value OFF

这两参数都需要重启数据库. 修改方法可参考如下:

# 停库 systemctl stop mysqld # 编辑配置文件, 增加那两参数 vim my.cnf skip_grant_tables skip_networking # 可选 # 启库 systemctl start mysqld # 登录数据库,并修改密码 mysql -S /tmp/mysql.sock flush privileges; alter user root@'localhost' identified with mysql_native_password by '123456'; flush privileges; # 再把参数修改回去 vim my.cnf # 再重启 systemctl restart mysqld # 使用新密码登录数据库确认 mysql -S /tmp/mysql.sock -p123456

init_file(2星)

第二种方法有丢丢麻烦, 于是官方还有个参数init_file 也能实现修改密码. 该参数表示数据库启动的时候执行的SQL语句, 是不需要验证权限的. 所以我们可以让它直接我们的修改密码的语句就能达到修改密码的要求.

init_file

Command-Line Format --init-file=file_name
System Variable init_file
Scope Global
Dynamic No
SET_VAR Hint Applies No
Type File name

官方重置root密码的教程也是使用的这个参数.

# 编辑sql文件 vim conf/init.sql alter user root@'localhost' identified with mysql_native_password by '123456'; # 编辑配置文件 vim conf/my.cnf init_file='xxx/conf/init.sql' # 重启数据库 systemctl restart mysqld # 验证密码 mysql -S /tmp/mysql.sock -p123456 # 把参数文件修改回去(可选), 不改的话, 每次重启密码都被重置为这个密码了.

这个方法相对于上面的的skip_grant_tables要简单很多, 但也要重启.

爆破

前面几种都是比较常见的方法, 除了第一种都要重启. 生产环境重启不是一件容易的事. 那么有没有不需要重启的方法呢? 当然有了, 那就是爆破(不是团队竞技). 如果每次都建立tcp连接的话, 效率是非常低的, 而且还可能影响业务的正常使用. 我们知道mysql_native_password的加密方法是做2次hash, 也就是我们可以比较hash之后的值是否一致来判断密码是否正确. mysql.user表 保存的也是加密之后的密码, 所以我们可以查看该表来获取加密后的密码, 但现在不是登录不了数据库么, 怎么查看呢?

诶, 我们昨天刚解析了mysql.ibd文件, 里面就有mysql.user表的数据啊. 使用方法如下: (我这里加了个if,只解析mysql表的数据)

python3 get_mysql_ibd.py /data/mysql_dev/data/mysql.ibd

image.png
简单点的方法,我们可以拿该密码去一些hash网站查询.(但可能有的会收费, 但也有免费的)

如果密码很复杂的话, 可能在线查询不到. 而且在线查询还不安全, 这里就可以自己来爆破了. python版爆破方法参考:

import binascii import hashlib NEW_PASSWORD = '1234567' # 这里是二进制的. 需要的话, 可以转为str PASSWORD = b'*'+binascii.hexlify(hashlib.sha1(hashlib.sha1(NEW_PASSWORD.encode()).digest()).digest())

mysql_config_editor.sh (3星)

有种特殊情况是, 忘记了mysql的密码, 但是之前配置了免登(mysql_config_editor),还可以登录数据库, 那么就可以直接修改密码(同时重新配置免登文件). 还有种更优雅的方法, 就是解析~/.mylogin.cnf文件内容. 好巧不巧我们之前就写过这种方法, 这里就不再介绍了, 感兴趣的自己看: https://www.modb.pro/db/1765168815701299200 相关的脚本可以直接在墨天轮下载

这种场景虽然少, 但今天恰好就用到了(文章写得断断续续的原因…). 从库配置了免密, 但主库没有配. 这时候就可以去从库解析,然后在主库上面配置了.

修改mysql.ibd文件 (4星)

前面那些都还算普通操作, 这里开始我们就要来点骚操作了.
getimgdata.gif
既然我们已经能解析ibd文件了, 那么我们就能修改mysql.ibd文件里面root的密码信息, 改为我们要的密码不就行了么.

首先我们得找到密码的位置(PAGENO和OFFSET), 欸, 我们的ibd2sql就有这个功能(–debug).

mysql.user是host,user作为主键的, localhost是字母通常在%后面, 所以基本上都是最后一条, 很快就能找到的.

# 编辑脚本, 打开debug功能 vim get_mysql_ibd.py ddcw.DEBUG = True # 解析解析 python3 get_mysql_ibd.py /data/mysql_dev/data/mysql.ibd

image.png
这里我们就得到了 root@localhost的PAGENO=757, 往后面走, 找到密码位置.
image.png
于是我们得到了OFFSET=2513

然后我们适用如下脚本修改密码并生成一个新的mysql.ibd文件(最近修改ibd文件的脚本基本上都差不多, 注意crc32校验别忘了哟)

#!/usr/bin/env python3 # write by ddcw @https://github.com/ddcw/ibd2sql # 修改Mysql密码的脚本 import binascii import hashlib import struct,os,sys PAGENO = 757 OFFSET = 2513 filename = '/data/mysql_dev/data/mysql.ibd' filename2 = '/tmp/mysql.ibd' NEW_PASSWORD = '123456' PAGE_SIZE = 16384 NEW_PASSWORD = b'*'+binascii.hexlify(hashlib.sha1(hashlib.sha1(NEW_PASSWORD.encode()).digest()).digest()) def create_crc32c_table(): poly = 0x82f63b78 table = [] for i in range(256): crc = i for _ in range(8): if crc & 1: crc = (crc >> 1) ^ poly else: crc >>= 1 table.append(crc) return table crc32_slice_table = create_crc32c_table() def calculate_crc32c(data): crc = 0xFFFFFFFF for byte in bytearray(data): # for PY2 crc = crc32_slice_table[(crc ^ byte) & 0xFF] ^ (crc >> 8) return crc ^ 0xFFFFFFFF def replace_crc32(data): c1 = calculate_crc32c(data[4:26]) c2 = calculate_crc32c(data[38:PAGE_SIZE-8]) cb = struct.pack('>L',(c1^c2)&(2**32-1)) data = cb + data[4:PAGE_SIZE-8] + cb + data[PAGE_SIZE-4:] return data f2 = open(filename2,'wb') with open(filename,'rb') as f: current_pageno = -1 while True: data = f.read(PAGE_SIZE) if data == b'': break current_pageno += 1 if current_pageno == PAGENO: data = data[:OFFSET] + NEW_PASSWORD + data[OFFSET+len(NEW_PASSWORD):] data = replace_crc32(data) f2.write(data) f2.close()

直接执行该脚本, 然后替换掉系统的mysql.ibd文件(建议先备份)

python3 modify_password.py cp -ra /data/mysql_dev/data/mysql.ibd /data/mysql_dev/data/mysql.ibd.bak20240919 chown mysql:mysql /tmp/mysql.ibd mv /tmp/mysql.ibd /data/mysql_dev/data/mysql.ibd

image.png

欸, 这就好了么. 我们先解析这个文件验证下呢(把debug关了, 不然信息太多,看起来乱七八糟的,到处都是 by Neeko)
image.png
mysqld.ibd文件内容确实是我们修改之后的密码了. 那么我们登录数据库试下呢
image.png
居然不行
image.png

flush privileges和flush tables也试了均不行.

那我们重启试下吧.
image.png
重启之后确实可以. 但还是要重启, 而且步骤感觉也不少. 还不如init_file那个

修改内存

以前在某平台学习了一个适用c++修改cs1.6金币的方法, 就是直接修改内存(数字比较多,多修改几次,看看变化的是哪些, 修改那部分的值即可). 那理论上也可以修改mysqld进程的内存数据,把密码修改为我们实际的那个. 看了下内存dump文件, 可能存在多个密码相同的账号, 修改的难度较大. (能力有限, 就不卖弄了)
image.png

gdb跳过认证

使用gdb接管mysqld进程, 待到连接过来的时候, 直接放行即可. 这操作更骚, 且难度不小. 未验证过此方法的可行性.

总结

方法 难度 优点 缺点/限制
ALTER 0星 简单,不需要重启 只能修改普通账号的密码, 需要高权限的账号登录, 业务得同步相关信息
skip_grant_tables 1星 简单? 过程比较啰嗦, 需要多次重启数据库
init_file 2星 简单,官方提供的方法 需要重启
爆破 3星 不需要重启 成本高, 不优雅
mysql_config_editor.sh 3星 简单 适用场景太TM有限了
修改mysql.ibd文件 4星 还是TM要重启
修改内存 5星 不需要重启 危险
gdb跳过认证 离谱 不需要重启 离了个大谱

参考:
https://dev.mysql.com/doc/refman/8.0/en/server-options.html#option_mysqld_skip-grant-tables
https://dev.mysql.com/doc/refman/8.0/en/resetting-permissions.html
https://github.com/ddcw

题外话
甲方要求工时饱和度, 所以后面加班会多点(DBA加班能干啥? dba事情越少越好啊, dba事情多的话就有大问题咯. 但作为外包,只能:好的), 写文章的时间好像还多了???

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
2人已赞赏
F
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论