Mysql(二)
Mysql(二)
0.前言
前篇对mysql的编译安装进行了相关的内容阐述,接下来就是对于两种运维中常用并且是不同类型的数据库进行讲述,mysql与redis这两种典型的关系型数据库和非关系类型数据,关系型数据库是指采用了关系模型来组织数据的数据库。简单来说,关系模式就是二维表格模型,而大都是针对一些特性的应用需求出现的。根据结构化方法和应用场景的不同,也有不同的类型(key-value数据库、面向文档数据库、分布式数据库等)
1.用户权限管理
MySQL用户权限管理是非常重要的,可以保护数据库的安全性和完整性。以下是一些基本的MySQL用户权限管理方法:
1 |
|
1 |
|
这是一个MySQL授权语句,它将授予名为“test2”的用户在所有数据库和表上拥有所有权限的访问权限,并且该用户可以使用“test2”作为密码进行身份验证。此外,该语句还包含了“with grant option”选项,允许该用户将其所拥有的权限授予其他用户
1 |
|
这依旧是一个授权指令,将授予名为“custom”的用户在“bank”数据库中的所有表上执行SELECT、INSERT、UPDATE、DELETE、CREATE和DROP操作的权限,并且该用户可以使用“123456”作为密码进行身份验证。这里的GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP本质上与grant all privileges on *.*的作用是一至的,都是赋予了相应的全部权限功能
1 |
|
这里与前文相比就是将连接限制设置为了只能从ywjt.org的连接,这里出现了一个报错,我们使用SHOW WARNINGS; 进行错误查看,根据提供的信息,这里显示我们使用GRANT语句创建新用户已经被弃用,并且在未来的版本中将被删除。相反,应该使用CREATE USER语句来创建新用户
显示用户权限
1 |
|
撤销用户权限
1 |
|
这是一个REVOKE语句,用于从用户“custom”在主机“localhost”上撤销对“test”数据库中所有表格的删除、插入和更新权限。
撤销用户的grant权限
1 |
|
与前面的测小用户权限用法相似,这里就不过多阐述了
改变用户密码:
1 |
|
删除用户账号
1 |
|
drop user‘test‘@’localhost’; 与该语句delete from mysql.user where user=’test’ and host=’localhost’; 的区别在哪?
与之前提到的DROP USER语句相比,这个语句使用了DELETE FROM语法来删除用户帐号。它还需要指定要删除的表(mysql.user)和WHERE子句来指定要删除的行。
虽然这两个语句都可以用于删除用户帐号,但它们的实现方式略有不同。DROP USER语句是专门用于删除用户帐号的语句,而DELETE FROM语句则可以用于删除任何表中的行。此外,DROP USER语句通常比DELETE FROM语句更快,因为它不需要执行额外的检查和约束
2.基础命令
首先了解下简单的连接,当我们需要连接数据库时,使用-u指定用户,-p表示输入密码
1 |
|
这里需要注意的是-u与root用户名之间的空格可以省略,而密码与-p选项之间是不能存在空格的
在连接mysql的时候,除了进入数据库使用use语句选择数据库,我们也能在登录时,使用-D指定数据库的名称,比如连接test数据库
1 |
|
在本地连接mysql时,我们还可以指定通过哪个套接字文件连接到数据库,通过-S指定套接字位置
1 |
|
在连接mysql时,我们也可以指定连接到远程的某一台主机的mysql上,也可以指定端口,-h指定的是mysql主机,-P指定了mysql服务器对应的端口:
1 |
|
可以看到我们mysql127的地址是通过的,当使用mysql -h本机ip地址命令连接MySQL服务器时出现了访问被拒绝的错误。
这是因为MySQL服务器配置了访问控制列表(ACL),并且没有允许来自该IP地址的用户访问MySQL服务器。可以尝试使用GRANT语句授权该IP地址访问MySQL服务:
1 |
|
授权当前客户端的IP地址访问MySQL服务器:在MySQL命令行界面中输入以下命令:GRANT ALL PRIVILEGES ON database_name.* TO ‘username‘@’ip_address’ IDENTIFIED BY ‘password’;
其中,database_name是要授权访问的数据库名称,username是要授权的MySQL用户名,ip_address是当前客户端的IP地址,password是MySQL用户的密码。而FLUSH PRIVILEGES;s 将刷新MySQL服务器的权限表,使新的授权生效。可以看到最后是指定ip地址服务成功了,用连接其他主机的ip地址也是一个道理,不过需要注意的是防火墙放行问题
在mysql中,连接数据库的同时,并返回对应的结果是允许的,比如:
1 |
|
1 |
|
3.基础语法
在我们连接进入mysql数据库后,我们可以使用help命令或者是\?进行帮助信息的获取,首先是可以直接使用hlep
1 |
|
也可以指定相关的关键字查看具体命令:
1 |
|
当获取到相关信息后,我们可以细化关键词的信息,达到进一步查询的目的:
1 |
|
除此之外,我们还能够通过分类查看帮助,使用contents命令进行查看,使用help的方法大致重要是这几种,其他的这里就不作跟多的阐述和表达了
首先是创建数据库的基本语法为:
首先是database/schema,在mysql 5.0.2之后,创建数据库就可以不用区分这两个的区别了,但需要注意的是在其他关系型数据库中,这两者是有区别的,Database是指在计算机系统中,按照一定的数据结构组织、存储和管理数据的集合。而Schema则是指数据库中的一个逻辑结构,用于描述数据库中的表、字段、索引等对象之间的关系
if not exists表示在对应的数据库不存在的时候才会创建,if not exists被中括号括起来,表示此项为可选,create_specification表示我们可以在创建数据库时指定对应的数据库规范,接下来进行创建库的演示:
1 |
|
列出已经存在的数据库:
1 |
|
列出创建对应数据库:
1 |
|
查询库的排序方式:
1 |
|
查看当前数据库与当前连接相关信息:
1 |
|
如图所示,信息表明了正在使用MySQL 5.7.24版本,并且当前连接到名为zabbix的数据库。还可以看到一些有关服务器和连接的详细信息,例如服务器的字符集、连接ID、运行时间等。
Threads表示当前服务器中正在运行的线程数,Questions表示自服务器启动以来处理的查询数,Slow queries表示慢查询数,Opens表示打开的表数,Flush tables表示刷新表的次数,Open tables表示当前打开的表数,Queries per second avg表示平均每秒处理的查询数。
很多时候,公司待不下去了,就会有跑路的想法,这就需要我们的删库跑路语句,其和创建数据库的语法基本差不多,只是判断没存在改为了判断存在(删库别慌,牢底做到穿):
1 |
|
列出所有表:
1 |
|
1 |
|
这里需要注意的是table后面不加s了,使用上述命令查看的表信息包括每张表的名称,所使用的存储引擎,版本,字符集,描述信息,创建时间等信息,当我们指向查看库中的某个表的状态的时候就可以使用到like命令:
注意,这里的like是完全匹配,接下来就是查看表结构的对应语句:
1 |
|
查看表给创建时对应的sql语句:
1 |
|
创建表的内容有比较多中情况,可以是直接创建一个新的空,或者是从数据库中查询出来的数据填充到创建的新表,亦或者是复制一个原有的表并剪贴出一个新表,但是整体结构肯定是基本不变的,首先我们查看help的帮助,获取相关命令的信息
可以看到,表的创建语法介绍是比较多的,接下来就是逐步进行相关的解析,对于创建表尔雅你,我们可以将语法分为两个部分,上半部分就是创建表的表明和相关信息,内容和创建库的信息是基本你一直的,后半部分这是表的内容,其中的create_definition是需要被括号括起来,其定义有三类别,分别是字段定义、表级别约束定义以及索引定义
举个例子:
1 |
|
这里需要注意的是在最后一个列类型的创建时,末尾是不需要加入逗号的,所以培训文档中的语句有点小错误,school_addr varchar(50)后不加逗号,否则是报错的,好咧,接下来另外两种刚刚提到的创建表的操作了,首先是从其他数据查询后创建出一个新的数据表:
1 |
|
而复制一个表其实就是其他数据查询后创建出一个新的数据表的最终版,只需要将数据修改为全部即可
1 |
|
这里就不就行相关展示了,反馈和第二种情况是一样的,接下来就是对于库的删除和修改问题,首先是删除表,表的删除可以是指定的单张表,也可以是用逗号隔开的多张表
1 |
|
对于表的修改,主要是使用alter进行相关的修改,这里就不进行相关演示,给出案例代码即可:
修改表名
1 |
|
为表添加字段
1 |
|
为表添加字段,同时为添加的字段设定相应的约束:
1 |
|
为表删除字段
1 |
|
重命名字段,修改字段名称
1 |
|
将test1表中的name字段重命名为name1,name字段的数据类型为char(5),需要注意的是即使只是重命名,也需要在新名称后指定原字段的数据类型,否则mysql就会报错
1)insert
mysql数据库中的增语句一般都是使用insert,insert的雨具语法如下:
1 |
|
比如,接下来向表test中插入id为1,name为Tom的数据
1 |
|
有或者是插入多条数据,以逗号作为分割即可
1 |
|
如果是对应每一个字段进行插入,也可以不指定字段
当然,除了这种插入办法,还有便是使用insert与set结合的办法,其对应的语法是:
1 |
|
举个例子,依旧是test的测试表,我们插入对应的值
1 |
|
可以看到,与前面的values相比,区别在于字段名称与字段值是否分开,set的方式是将字段和字段值放在一起,除此之外,可以看到我使用set的时候,字段的顺序是可以不同的,而在values中,字段是必须按表中的顺序的
添加的雨具介绍到这,需要提及的一点是mysql默认的sqlmode为宽松模式,这意味着即使插入的数据并不是完全符合数据类型的要求,也有可能也能插入数据,如果我们想要就需要修改对应的模式:
1 |
|
而我们可以通过使用set语句来设置sql_mode变量:
1 |
|
2)delete
接下来就是删除语句,mysql中的删除语句比较简单,基本主要通过where进行定位删除的相关内容,而where的使用在后续的select中会广泛提到,接下来主要展示是几种删除的情况,第一种极速直接删除表的所有数据,也就是清空数据的操作
1 |
|
然后是删除使用where给定条件下的相关数据
1 |
|
这里需要提及一个就是
1 |
|
rlike是一个正则表达式匹配运算符,它可以在WHERE子句中使用。’^h.*’表示以字母“h”开头的任何字符串
3)update
修改数据的语句本质上也比较简单,和删除delete相似,通过where进行给定修改范围,需要注意的是在执行更新语句之前要确定给定的条件是正确的,因为不加任何条件的更新语句表示更新表中的所有字段,这是比较危险的。
将test表中的所有id字段的值都修改为了1
1 |
|
第二种是将表中id为3的值将名字修改为who
1 |
|
对于多个字段的修改,使用逗号隔开即可,例如
1 |
|
4)select
由于时间有限,这里仅仅展示select的基本用法,后续的分组,聚合多表查询后期补上,首先就是查询表汇总的所有数据
1 |
|
查询数据后仅显示前三行
1 |
|
使用where进行条件筛选
1 |
|
使用模糊查询
1 |
|
4.数据库中的数据备份及恢复
首先明确,备份数据的最终目的是为了在出现一些意外情况的时,能够通过备份将数据还原,所以在备份数据库时,除了备份数据本身以外,也要注意到备份相关的数据库性感环境,如配置文件,定时任务,sudo权限等相关信息,这里需要明确几个备份概念
1 |
|
在mysql数据库中,常见的数据备份工具有来个,一个是mysql自带的备份攻击mysqldump,一个是由Percona提供的xtrabackup,接下来主要了解mysqldump工具
首先是mysqldump,作为mysql自带的工具,是一种逻辑备份工具,它的使用是将数据从数据库中读初,并转化为对应的sql语句,能够首先完全备份或者部分备份,使用innodb表类型的表能够使用mysqldump进行热备。使用myisam表类型的表只能够使用mysqldump进行温备。因此数据量较小时,使用mysqldump是一种不错的选择
mysqldump作为一个客户端命令,所以在使用的时候,我们需要指定连接的用户名,需要连接的数据库服务ip,以及使用-p选项提示我们输入Miami,接下来演示备份test数据库
1 |
|
正确后,就会显示如下的输出:
这里的输出会包含一些注释,内容是包括mysqldump的版本你,mysql的版本,主机ip以及数据库对应的相关信息,值得一提的是,他会提供一些注释符号内容:
以第一条注释为例,40101表示MySQL版本号,如果当前版本大于等于40101,则执行SET语句。在这个例子中,SET character_set_client = @saved_cs_client表示将客户端字符集设置为之前保存的@saved_cs_client变量的值。这个变量通常用于在执行某些操作之前保存原始的客户端字符集,以便在操作完成后恢复它,当然这些注释语句不必在意,我们需要看的是转化为sql语句的部分
test库的test表中,将其内容的所有数据转化为 insert语句,重要我们执行就能够还原test表的所有内容,当然,既然产出了西瓜你的语句,那么存放的位置在哪就需要我们使用>符号进行一个指定:
1 |
|
前面演示了如何进行一个完全的备份,通过分析语句我们也能够知道,其备份的本质是备份其中的表的内容,并不会生成创建test数据库的相关语句,那么接下来,就是演示如何只备份一个表:
1 |
|
备份多个数据库的指令也仅仅是用-databases后用逗号分割即可,这里就不进行演示了,而这里需要注意的是,如果我们使用的是
1 |
|
这个命令是备份出创建test数据库的对应语句的,在某些时候,我们只是想要将数据库的表结构备份出来,不想备份数据,以便创建一个完全相同的干净数据库,那么我们可以使用如下语句备份数据库的所有表结构,如下命令表示备份zsythink数据库中的所有表的表结构,不包含表数据,不包含创建库的语句,只有创建表的语句
1 |
|
前面大致讲解了如何进行表的备份操作,接下来就是表的备份数据进行恢复的操作,首先drop 掉原有的test数据库
接下来执行报存的sql语句即可
1 |
|
报错了,这是由于前面提到的,如果不加上-database的话,备份的文件是不会创建相关的数据库的,所以执行是找不到数据库的,接下来就需要指定到对应的数据库即可:
最终还原备份成功
5.数据库中的配置优化
数据库的配置优化主要目的是提高数据库的性能和可靠性,我们可以从多个方面对数据库进行相应的思考和操作:
修改my.cnf文件:
1 |
|
找到innodb_buffer_pool_size参数并修改为所需大小,例如:
1 |
|
重启MySQL服务:
1 |
|
分析查询计划:
1 |
|
添加索引
1 |
|
删除索引
1 |
|
配置二进制日志:在my.cnf文件中添加以下参数:
1 |
|
配置错误日志:在my.cnf文件中添加以下参数:
1 |
|
配置慢查询日志:在my.cnf文件中添加以下参数:
1 |
|
6.漏洞复现举例
前面复刻了几个redis的漏洞问题,现在开始着手mysql的漏洞搭建,mysql的现成搭建漏洞环境比较少,使用的工具有比较多,这里就暂且挑选两个漏洞进行复刻的尝试,首先了解一下mysql的漏洞问题,对于这列中间件,最重要的摸过与提权问题,而MySQL中, UDF 提权、MOF 提权也算是耳熟能详,这些提权的前提条件都是拿到高权限的mysql用户,也就是说mysql的提权来讲,我们首先说起到高权限的mysql用户,之后再进行系统的一个提权操作,这是一般的思路。获取用户账户密码的也无非就是这几种方式:
1 |
|
前面提到了UDF 提权、MOF 提权这里进行解释,辅导一些提权过程的截图(查找来的资料)
在MySQL中,UDF提权是指通过利用用户定义函数的漏洞来获取更高权限的过程。当存在UDF的安全漏洞时,攻击者可以通过构造恶意的UDF来执行任意代码,并以数据库系统的特权身份运行该代码,从而获得比其正常权限更高的访问权限
MOF提权是指通过利用Windows管理对象格式文件的漏洞来获取更高权限的过程。MOF文件是一种用于描述和定义Windows管理对象的文件格式。当存在MOF文件的安全漏洞时,攻击者可以通过构造恶意的MOF文件来执行任意代码,并以系统级别权限运行该代码,从而获得比其正常权限更高的访问权限
启动项提权是指通过修改系统启动项的方式来获取更高权限的过程。启动项是在计算机启动时自动运行的程序或脚本。攻击者可以通过修改启动项,将恶意程序或脚本添加到系统启动流程中,并以系统级别权限运行该恶意代码,从而获得比其正常权限更高的访问权限
1 |
|
安装完成后,启动Docker服务并将其设置为开机自启动。使用以下命令:
1 |
|
安装docker
1 |
|
-d 参数表示以后台模式运行容器。-p 83:80 表示将主机的83端口映射到容器的80端口,这样你可以通过访问主机的83端口来访问容器中运行的Web服务器。-p 3366:3306 表示将主机的3366端口映射到容器的3306端口,这样你可以通过访问主机的3366端口来访问容器中运行的MySQL数据库。-p 9999:9999 表示将主机的9999端口映射到容器的9999端口,这可能是用于反弹连接或其他特定用途。最后,–name MySQLprivileges 指定了容器的名称为MySQLprivileges,而tutum/lamp:latest 是使用的Docker镜像
1 |
|
注意这里的6d62681aa477需要使用docker ps指令进行相关查看,6d62681aa477是一个示例容器ID,需要将其替换为要进入的实际容器的ID。一旦进入了容器的bash shell,你可以在其中运行各种命令,就像在本地计算机上一样。可以使用这个shell来查看和修改容器内部的文件、安装软件包、运行脚本等等。当完成操作后,可以使用exit命令退出容器的bash shell,并返回到主机的命令行界面
apt update && apt install -y wget gcc libmysqlclient-dev这个命令是在容器的bash shell中使用apt包管理器来更新软件包列表,并安装了wget、gcc和libmysqlclient-dev软件包,这是为后面的mysql环境做准备
接下来是webshell的写入:
1 |
|
1 |
|
目标主机配置必须是是基于文件的日志(默认配置),也就是不能是syslog方式,tutum/lamp日志方式为syslog,需要修改
1 |
|
别问,问就是这个环境没有vim,vim用习惯了
重启mysql:
1 |
|
使用grep指令鉴别对应的mysql,没有返回任何结果即满足所谓的”基于问价日志”要求,接下来就是上传mysql-chowned.sh,代码网上也有,这里就不过多展示了(代码太长了),这里需要注意的是必须以mysql权限执行才能成功提为root,可以利用CVE-2016-6663提升为mysql权限的shell执行如下指令
1 |
|
最后就是,获得root的相关权限了,由于这里没有才菜刀,所以都说跳过了6663的漏洞模拟,没想到在这里等着我,可恶啊,最终达到的效果大致是如下:
同样道理,使用docker查看对应的容器, 这里使用了Vulhub 中的 mysql/CVE-2012-2122 模块,在 vulhub/mysql/CVE-2012-2122 目录下使用 docker-compose up -d 命令启动容器:
1 |
|
执行容器:
这里提示了我们,有其他进程正在使用端口3306,这是由于我之前就按照了5.7版本的mysql没有关闭,因此,需要stop掉,用netstat -tuln | grep 3306或者ps aux | grep mysql进行检验:
1 |
|
检验是否启动常用,测试数据库即可
1 |
|
连接正常,说明没有问题,接下来进行5.5版本的漏洞利用
1 |
|
尽管我们的密码是错误的,也在多次连接失败后成功进入到数据库中
CVE-2012-2122是一个影响MySQL数据库的身份认证绕过漏洞,也被称为”MySQL Authentication Bypass”漏洞。该漏洞的利用原理如下:在MySQL中,用户可以选择使用密码进行身份验证,也可以选择使用无密码身份验证。当用户选择无密码身份验证时,MySQL会尝试通过Unix套接字(socket)连接进行身份验证。由于一个错误的实现,MySQL在处理Unix套接字连接时存在漏洞。攻击者可以通过发送特制的请求来利用这个漏洞。攻击者可以通过向MySQL服务器发送恶意请求,使其在进行身份验证时跳过密码验证步骤,从而绕过密码验证并获得对数据库的访问权限。
具体来说,攻击者可以通过在Unix套接字连接上发送一个空的或包含空字符的用户名,然后在密码字段中输入任意值,从而欺骗MySQL服务器绕过密码验证。