背景 学习目标:
如何利用数据库的功能读写文件,需要什么样的条件才可以读写;
学习数据库系统表的功能,如何利用 sql 语句查询库名、表名、字段名、内容以及当前用户等基本信息;
尝试查询出用户的 hash,并使用 hashcat 来对获取的 hash 进行暴力破解。
MySQL 读写文件 读文件 使用 load_file()
函数 load_file(file_name)
函数读取文件内容,将内容以字符串的形式返回。
前提条件 :
secure_file_priv
不为 NULL,使用 select @@secure_file_priv
查看其值,值不为空字符串时,只能使用该目录进行文件的读写操作, 该值的设置见附录 ;
当前数据库用户具有 FILE
权限,使用 show grants
查看;
系统用户 mysql
对该文件可读(要考虑系统的访问控制策略),在Ubuntu-18.04使用 MySQL 时默认的系统用户是 mysql
;
读取文件的大小小于 max_allowed_packet
,使用 select @@max_allowed_packet
查看;
文件存在服务器上。
如果上述任一条件不满足,函数返回 NULL
值。
用法 :
1 select load_file('filename');
例子: 读取文件 /mysql/test.csv
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 mysql> select @@secure_file_priv,@@max_allowed_packet; +--------------------+----------------------+ | @@secure_file_priv | @@max_allowed_packet | +--------------------+----------------------+ | | 16777216 | +--------------------+----------------------+ mysql> show grants; +----------------------------------------------------------------------------------------------+ | Grants for user101@localhost | +----------------------------------------------------------------------------------------------+ | GRANT SELECT, INSERT, DELETE, CREATE, FILE ON *.* TO 'user101'@'localhost' WITH GRANT OPTION | +----------------------------------------------------------------------------------------------+ mysql> select load_file('/mysql/test.csv'); +------------------------------+ | load_file('/mysql/test.csv') | +------------------------------+ | 3,Hack 4,World 5,Surprise! | +------------------------------+
问题: 在设置 secure_file_privilege=''
且目录权限为 777
后load_file()
无法读取文件
解决方案: Ubuntu 自带的强制访问控制系统 AppArmor 强制限制了每个程序可使用的资源,它并非针对用户,而是针对程序的,所以不论用户是否能访问某一资源,只要程序被 AppArmor 限制访问该资源,则程序就不能访问该资源。因此需要修改 AppArmor 针对于 MySQL 的访问控制策略,修改文件 /etc/apparmor.d/usr.sbin.mysqld
,在其中添加需要访问的目录, 修改完成后,重新加载 AppArmor 配置:sudo /etc/init.d/apparmor reload
。
参考: https://stackoverflow.com/questions/4215231/load-data-infile-error-code-13
使用 LOAD DATA
语句 laod_file()
函数只能从 服务器中读取文件,LOAD DATA
语句既能读取服务器的文件,也能读取 MySQL 客户机的文件,两种方式语法上稍有不同。
前提条件: 和 load_file()
函数使用条件相同,但通过使用 LOCAL
语句从客户主机读取文件内容。
用法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #[] 中的内容为可选内容 LOAD DATA [LOW_PRIORITY | CONCURRENT] [LOCAL] #使用 LOCAL 表示从客户主机读取文件,要设置 mysqld 中的系统变量 local_infile INFILE 'file_name' [REPLACE | IGNORE] INTO TABLE tbl_name [CHARACTER SET charset_name] #处理文件的字符集 [{FIELDS | COLUMNS} #描述每一列的格式 [TERMINATED BY 'string'] [[OPTIONALLY] ENCLOSED BY 'char'] [ESCAPED BY 'char'] ] [LINES #描述行的格式,不满足的行会被略过 [STARTING BY 'string'] [TERMINATED BY 'string'] ] [IGNORE number {LINES | ROWS}] #忽略指定行或列 [(col_name_or_user_var [, col_name_or_user_var] ...)] #写到数据表中的指定列 [SET col_name={expr | DEFAULT}, [, col_name={expr | DEFAULT}] ...]
例子: 读取文件 /mysql/test.csv
到已有的数据表中。CSV文件内容如下:
1 2 3 3,Hack 4,World 5,Surprise!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 mysql> select * from test; +----+------+ | id | name | +----+------+ | 1 | May | | 2 | June | +----+------+ mysql> load data infile '/mysql/test.csv' into table test fields terminated by ','; Query OK, 3 rows affected (0.00 sec) mysql> select * from test; | id | name | +----+-----------+ | 1 | May | | 2 | June | | 3 | Hack | | 4 | World | | 5 | Surprise! | +----+-----------+ 5 rows in set (0.00 sec)
写文件 使用 SELECT INTO OUTFILE 语句 SELECT INTO OUTFILE
和 LOAD DATA
这两条语句是完全互补的,一个写文件,一个读文件,语句的语法也很相似。
前提条件:
secure_file_priv
不为 NULL
,使用 select @@secure_file_priv
查看其值,值不为空字符串时,只能使用该目录进行文件的读写操作, 该值的设置见附录 ;
当前数据库用户具有 FILE
权限,使用 show grants
查看;
系统用户 mysql
对该文件可写(要考虑系统的访问控制策略),在Ubuntu-18.04使用 MySQL 时默认的系统用户是 mysql
;
读取文件的大小小于 max_allowed_packet
,使用 select @@max_allowed_packet
查看;
文件不存在。
用法:
1 2 3 4 5 6 7 8 9 10 11 12 13 #[] 中的内容为可选内容 SELECT select_expr... INTO OUTFILE 'file_name' [CHARACTER SET charset_name] #处理文件的字符集 [{FIELDS | COLUMNS} #描述每一列的格式 [TERMINATED BY 'string'] [[OPTIONALLY] ENCLOSED BY 'char'] [ESCAPED BY 'char'] ] [LINES #描述行的格式 [STARTING BY 'string'] [TERMINATED BY 'string'] ]
例子: 写数据表到 CSV 文件中。
1 2 3 4 5 6 7 8 9 10 11 12 mysql> select * from comments; +----+---------------------------+ | id | comment | +----+---------------------------+ | 1 | test | | 2 | hhhh | | 3 | Need lots of improvements | +----+---------------------------+ 3 rows in set (0.00 sec) mysql> select comment from comments where id>1 into outfile '/mysql/comments.csv' fields terminated by ','; Query OK, 2 rows affected (0.00 sec)
/mysql/comments.csv
内容:
1 2 hhhh Need lots of improvements
注:
使用 SELECT INTO DUMPFILE
可将文件内容写成一行.
1 2 3 >mysql> select comment from comments where id>1 into dumpfile '/mysql/comments'; >Query OK, 2 rows affected (0.00 sec) >
/mysql/comments.csv
内容:
1 2 >hhhhNeed lots of improvements >
如果想把远程数据库的查询结果写到本地主机文件上, 可用:
1 2 >mysql -h hostname -P portnum -u username -p databsename -e "SELECT ..." > file_name >
MySQL 数据库系统表 MySQL-5.7 默认的系统表/视图 放在4个数据库/schema 中,。
在 MySQL 中 schema
和 database
是一样的就不做区分, 但实际上是有区别的,可以参考这篇文章 。
视图也称为虚表,是为了便于查询某些信息,建立在查询结果之上的表,所以视图其实就是被保存起来的一次查询。视图和表的区别简单来说就是视图存储的是SQL查询语句执行的结果,以表的形式存在但在数据库中并没有这个表。
库名
视图数量
基表数量
information_schema
61
0
mysql
0
31
performance_schema
0
87
sys
100
1(sys_config)
MySQL 数据库管理系统中的系统表很多,这里主要介绍和在SQL 注入中常的几个表和视图。
information_schema
存放着 MySQL 服务器维护的所有数据库的详细信息, 包括数据库名、表名、列名、列的数据类型、访问权限等等。
常用视图 在进行 SQL 注入时比较有用的几个视图:SCHEMATA
、 COLUMNS
、TABLES
、user_privileges
。
schemata
视图存放 MySQL 数据管理系统中的所有数据的基本信息,丛中可以获取所有数据库名字,数据库使用的字符集、排序规则(collation,数据库中数据进行排序时的规则,升序、降序,是否忽略大小写等)
1 2 3 4 5 6 7 8 9 10 mysql> select * from schemata; +--------------+--------------------+----------------------------+------------------------+----------+ | CATALOG_NAME | SCHEMA_NAME | DEFAULT_CHARACTER_SET_NAME | DEFAULT_COLLATION_NAME | SQL_PATH | +--------------+--------------------+----------------------------+------------------------+----------+ | def | information_schema | utf8 | utf8_general_ci | NULL | | def | mysql | latin1 | latin1_swedish_ci | NULL | | def | performance_schema | utf8 | utf8_general_ci | NULL | | def | sys | utf8 | utf8_general_ci | NULL | | def | webdb101 | latin1 | latin1_swedish_ci | NULL | +--------------+--------------------+----------------------------+------------------------+----------+
columns
视图存放列相关的信息,常用字段 table_schema
(数据库名), table_name
(表名),column_name
(列名)。
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 mysql> desc columns; +--------------------------+---------------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +--------------------------+---------------------+------+-----+---------+-------+ | TABLE_CATALOG | varchar(512) | NO | | | | | TABLE_SCHEMA | varchar(64) | NO | | | | | TABLE_NAME | varchar(64) | NO | | | | | COLUMN_NAME | varchar(64) | NO | | | | | ORDINAL_POSITION | bigint(21) unsigned | NO | | 0 | | | COLUMN_DEFAULT | longtext | YES | | NULL | | | IS_NULLABLE | varchar(3) | NO | | | | | DATA_TYPE | varchar(64) | NO | | | | | CHARACTER_MAXIMUM_LENGTH | bigint(21) unsigned | YES | | NULL | | | CHARACTER_OCTET_LENGTH | bigint(21) unsigned | YES | | NULL | | | NUMERIC_PRECISION | bigint(21) unsigned | YES | | NULL | | | NUMERIC_SCALE | bigint(21) unsigned | YES | | NULL | | | DATETIME_PRECISION | bigint(21) unsigned | YES | | NULL | | | CHARACTER_SET_NAME | varchar(32) | YES | | NULL | | | COLLATION_NAME | varchar(32) | YES | | NULL | | | COLUMN_TYPE | longtext | NO | | NULL | | | COLUMN_KEY | varchar(3) | NO | | | | | EXTRA | varchar(30) | NO | | | | | PRIVILEGES | varchar(80) | NO | | | | | COLUMN_COMMENT | varchar(1024) | NO | | | | | GENERATION_EXPRESSION | longtext | NO | | NULL | | +--------------------------+---------------------+------+-----+---------+-------+
tables
存放表相关的信息,常用字段 table_schema
(数据库名), table_name
(表名)。
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 mysql> desc tables; +-----------------+---------------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-----------------+---------------------+------+-----+---------+-------+ | TABLE_CATALOG | varchar(512) | NO | | | | | TABLE_SCHEMA | varchar(64) | NO | | | | | TABLE_NAME | varchar(64) | NO | | | | | TABLE_TYPE | varchar(64) | NO | | | | | ENGINE | varchar(64) | YES | | NULL | | | VERSION | bigint(21) unsigned | YES | | NULL | | | ROW_FORMAT | varchar(10) | YES | | NULL | | | TABLE_ROWS | bigint(21) unsigned | YES | | NULL | | | AVG_ROW_LENGTH | bigint(21) unsigned | YES | | NULL | | | DATA_LENGTH | bigint(21) unsigned | YES | | NULL | | | MAX_DATA_LENGTH | bigint(21) unsigned | YES | | NULL | | | INDEX_LENGTH | bigint(21) unsigned | YES | | NULL | | | DATA_FREE | bigint(21) unsigned | YES | | NULL | | | AUTO_INCREMENT | bigint(21) unsigned | YES | | NULL | | | CREATE_TIME | datetime | YES | | NULL | | | UPDATE_TIME | datetime | YES | | NULL | | | CHECK_TIME | datetime | YES | | NULL | | | TABLE_COLLATION | varchar(32) | YES | | NULL | | | CHECKSUM | bigint(21) unsigned | YES | | NULL | | | CREATE_OPTIONS | varchar(255) | YES | | NULL | | | TABLE_COMMENT | varchar(2048) | NO | | | | +-----------------+---------------------+------+-----+---------+-------+ 21 rows in set (0.00 sec)
user_privileges
存放用户的权限信息。
1 2 3 4 5 6 7 8 9 mysql> desc information_schema.user_privileges; +----------------+--------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +----------------+--------------+------+-----+---------+-------+ | GRANTEE | varchar(81) | NO | | | | #被授权的用户名 | TABLE_CATALOG | varchar(512) | NO | | | | | PRIVILEGE_TYPE | varchar(64) | NO | | | | #权限名,如 SELECT、INSERT 等 | IS_GRANTABLE | varchar(3) | NO | | | | #是否授权,YES/NO +----------------+--------------+------+-----+---------+-------+
视图信息利用 用户权限查询
获取当前用户名
1 2 3 4 5 6 selectmysql> select user(); +-------------------+ | user() | +-------------------+ | user101@localhost | +-------------------+
获取用户权限
1 2 3 4 5 6 7 8 9 10 11 mysql> select * from information_schema.user_privileges where grantee like '%user101%'; +-----------------------+---------------+----------------+--------------+ | GRANTEE | TABLE_CATALOG | PRIVILEGE_TYPE | IS_GRANTABLE | +-----------------------+---------------+----------------+--------------+ | 'user101'@'localhost' | def | SELECT | YES | | 'user101'@'localhost' | def | INSERT | YES | | 'user101'@'localhost' | def | UPDATE | YES | | 'user101'@'localhost' | def | DELETE | YES | | 'user101'@'localhost' | def | CREATE | YES | | 'user101'@'localhost' | def | FILE | YES | +-----------------------+---------------+----------------+--------------+
注入时可以利用 information_schema 数据库进行信息查询,一般步骤有:
获取数据库名
1 2 3 4 5 6 7 8 9 10 mysql> select schema_name from information_schema.schemata; +--------------------+ | schema_name | +--------------------+ | information_schema | | mysql | | performance_schema | | sys | | webdb101 | +--------------------+
获取表名
1 2 3 4 5 6 7 mysql> select table_name from information_schema.tables where table_schema='webdb101'; +------------+ | table_name | +------------+ | comments | | test | +------------+
获取列名
1 2 3 4 5 6 7 mysql> select column_name from information_schema.columns where table_name='test'; +-------------+ | column_name | +-------------+ | id | | name | +-------------+
mysql 数据库 mysql 数据中存放的都是表,常用的表有 user
、db
。
user
表中常用字段有 user
、host
、authentication_string
(存储密码的字段,MySQL 版本相关,低一些的版本为 password
)等。
查询所有用户名、连接主机和密码哈希
1 2 3 4 5 6 7 8 9 10 mysql> select user,host,authentication_string from mysql.user; +------------------+-----------+-------------------------------------------+ | user | host | authentication_string | +------------------+-----------+-------------------------------------------+ | root | localhost | | | mysql.session | localhost | *THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE | | mysql.sys | localhost | *THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE | | debian-sys-maint | localhost | *962236403F954BF9C92EBDBA0BC04F7CE7FCFB89 | | user101 | localhost | *6331E4D15433B998EF878BE017AE2A0878316CCC | +------------------+-----------+-------------------------------------------+
注 :
在进行 sql 注入使用常常使用 group_concat(col_name…)
将多个列的信息连成一句话输出,便于回显到浏览器。
如获取用户名及其密码的一条注入语句:
select group_concat(user, authentication_string) from mysql.user
用户密码爆破 MySQL 用户的密码存储方式并非明文直接存储,而是经过 hash 函数加密进行存储的,从 mysql.user
中获取到 MySQL 用户密码的哈希值后,需要使用工具进行破解。
工具: hashcat
hashcat 号称最快的高级密码恢复套机(密码破解工具),支持多系统(Linux,OS,Windows),多平台(GPU,CPU,DSP等),支持多达 200 多种的 Hash 类型,支持使用同一系统的不同设备,支持分布式系统资源等,重要的是开源啊!
下载安装:
推荐在 Windows 上使用,最好不用虚拟机,这样安装最简单,而且能充分利用 hashcat 支持多设备的特点,在 Linux 上安装需要安装很多东西,而且问题特别多,除非特别需要,个人不建议。
使用:
1 ./hashcat64.exe -m 300 -a 3 hashfile -o plaintxt --outfile-format=2 ?a?a?a?a?a?a
参数:
-m 300
:hash 类型,200多种,详见: hashcat --help
,300 选择的是 MySQL4/5 的hash
-a 3
:攻击模式,总共5种,3 表示爆破模式,所有攻击模式如下表:
值
攻击模式
0
Straight:字典模式,从字典内容中依次选择密码候选,进行哈希计算,看是否和待破解的哈希值相同
1
Combination:组合模式,将两个字典的内容组合作为字典内容,可以通过 -k
,-j
选项为两个字典添加额外规则
3
Brute-force:爆破模式/掩码模式,使用掩码固定密码的字符集,减小爆破的候选密码数,掩码格式见下文。
6
Hybrid Wordlist + Mask:混合模式(字典+掩码),通过字典后接掩码的方式构建最终的密码候选。
7
Hybrid Mask + Wordlist:混合模式(掩码+字典),通过掩码后接字典的方式构建最终的密码候选,和上面的组合顺序相反。
-o pliantxt
:破解后输出到文件 plaintxt
--outfile-format=2
:输出文件格式,2表示只输出破解后的内容,所有可用格式如下表
值
输出文件格式
1
hash[:salt]
2
plain
3
hash[:salt]:plain
4
hex_plain
5
hash[:salt]:hex_plain
6
plain:hex_plain
7
hash[:salt]:plain:hex_plain
8
crackpos
9
hash[:salt]:crack_pos
10
plain:crack_pos
11
hash[:salt]:plain:crack_pos
12
hex_plain:crack_pos
13
hash[:salt]:hex_plain:crack_pos
14
plain:hex_plain:crack_pos
15
hash[:salt]:plain:hex_plain:crack_pos
?a?a?a?a?a?a
:这表示密码的掩码,所谓的掩码就是通过 ?[字符集代号]… 的格式表示密码的格式,包括密码的位数和每一位密码使用的字符集。?a 表示所有的键盘上可输入的字符,6个?a表示密码有6位。hashcat 内置字符集如下:
字符集代号
字符集
l
abcdefghijklmnopqrstuvwxyz
u
ABCDEFGHIJKLMNOPQRSTUVWXYZ
d
0123456789
h
0123456789abcdef
H
0123456789ABCDEF
s
!”#$%&’()*+,-./:;<=>?@[]^_`{
a
?l?u?d?s
b
0x00 - 0xff
还通过选项自定义字符集,自定以的字符集对应的字符集代号为 1,2,3,4:
1 2 3 4 --custom-charset1=CS #同 -1 的短选项 --custom-charset2=CS #同 -2 --custom-charset3=CS #同 -3 --custom-charset4=CS #同 -4
如果得知密码第一位为大写字母且不包含字符的8为密码,可自定义掩码,加快解密过程:
1 hashcat -m 300 -a 3 -1 ?l?u?d hashfile ?u?1?1?1?1?1?1?1
参考
SQL注入-文件操作
load-file
LOAD DATA 语法
MySQL常用系统表汇总
附录 MySQLsecure_file_priv
变量
Property
Value
Command-Line Format
--secure-file-priv=dir_name
System Variable
secure_file_priv
Scope
Global
Dynamic
No,表示不能动态使用 set
命令进行设置,只能通过配置文件设置,如在 ~/.my.
Type
String
Default Value (>= 5.7.6)
platform specific
Default Value (<= 5.7.5)
empty string
Valid Values (>= 5.7.6)
empty string
dirname
NULL
Valid Values (<= 5.7.5)
empty string
dirname
该变量限制 MySQL 用户对文件的读写操作,可设置为以下值:
空字符串;
特定路径名;
NULL,表示不允许文件的读写操作;
具体可在 MySQL 启动配置文件 /etc/mysql/my.cnf
中设置如下:
1 2 3 [mysql_safe] #服务器启动脚本 [mysqld] #服务器端配置 secure_file_priv = "" #设置读取文件目录为任意目录
my.cnf
文件中配置格式:
1 2 3 [group] #常用的 group 有 mysqld:MySQL 服务器,client:MySQL 客户端,mysql_safe:服务器启动脚本 opt_name #等同命令行中 --opt_name 选项 opt_name=value #等同命令行中 --opt_name=vale
不同平台的默认值:
INSTALL_LAYOUT
Value
Default secure_file_priv
Value
STANDALONE
empty
DEB
, RPM
, SVR4
/var/lib/mysql-files
Otherwise
mysql-files
under the CMAKE_INSTALL_PREFIX
value