diff --git a/Chapter20/20-1.md b/Chapter20/20-1.md new file mode 100644 index 0000000..a4e46fa --- /dev/null +++ b/Chapter20/20-1.md @@ -0,0 +1,46 @@ +### === 和 == 的区别 + +**`==` (相等运算符)** + +`==` 运算符只比较**值**是否相等。如果两个变量的值相同,即使它们的数据类型不同,`==` 也会返回 `true`。在比较之前,PHP 会尝试将一个变量的类型转换成另一个变量的类型,以便进行比较。这种行为被称为**“类型转换”**或**“弱类型比较”** + +**示例:** + +```php +// 字符串 '10' 和整数 10 +var_dump('10' == 10); // true,因为 '10' 会被转换为整数 10 + +// 字符串 'Hello' 和整数 0 +var_dump('Hello' == 0); // true,因为 'Hello' 在数字比较时被转换为 0 + +// 字符串 '10abc' 和整数 10 +var_dump('10abc' == 10); // true,因为 '10abc' 的起始数字部分被转换为 10 + +// null 和 false +var_dump(null == false); // true,因为 null 在布尔比较时被视为 false +``` + +**`===` (全等运算符)** + +`===` 运算符不仅比较**值**是否相等,还比较**数据类型**是否相同。只有当两个变量的值和数据类型都完全相同时,`===` 才会返回 `true`。这种行为被称为**“不进行类型转换的比较”**或**“强类型比较”** + +**示例:** + +```php +// 字符串 '10' 和整数 10 +var_dump('10' === 10); // false,因为一个变量是字符串,另一个是整数 + +// 字符串 'Hello' 和整数 0 +var_dump('Hello' === 0); // false,因为数据类型不匹配 + +// 字符串 '10abc' 和整数 10 +var_dump('10abc' === 10); // false,因为数据类型不匹配 + +// null 和 false +var_dump(null === false); // false,因为 null 和 false 的数据类型不同 +``` + +| 运算符 | 比较内容 | 行为 | 什么时候用? | +| ------ | -------- | ------------------------ | ------------------------------------------------------------ | +| == | 值 | 弱类型比较(有类型转换) | 当你确定不需要关心变量类型,只关心值是否相同时。 | +| === | 值和类型 | 强类型比较(无类型转换) | 大多数情况下,推荐使用 ===,因为它能防止因隐式类型转换导致的意外行为,使代码更健壮和可预测。 | \ No newline at end of file diff --git a/Chapter20/20-10.md b/Chapter20/20-10.md new file mode 100644 index 0000000..b343ed6 --- /dev/null +++ b/Chapter20/20-10.md @@ -0,0 +1,9 @@ +### 本地文件包含能不能通过 PHP 配置限制文件包含的路径 + +当然能,这个关键的配置项就是 `open_basedir` + +**`open_basedir` 的作用** + +`open_basedir` 是一个强大的安全配置,它定义了 PHP 脚本可以访问的**根目录**。当一个 PHP 脚本试图使用文件系统函数(如 `include`、`require`、`fopen`、`file_get_contents` 等)来访问文件时,`open_basedir` 会检查目标文件路径是否位于它指定的目录或其子目录中 + +如果目标文件不在指定的目录范围内,PHP 会拒绝该操作并抛出错误 \ No newline at end of file diff --git a/Chapter20/20-11.md b/Chapter20/20-11.md new file mode 100644 index 0000000..e89ece9 --- /dev/null +++ b/Chapter20/20-11.md @@ -0,0 +1,93 @@ +### PHP 在做 SQL 注入防御时有哪些方法 + +**1. 使用预处理语句** + +这是防御 SQL 注入的**首选方法**,也是最安全、最推荐的方式。预处理语句将 SQL 代码与数据**完全分离**,数据库会先编译SQL 模板,然后再将用户数据作为参数绑定进去。这样,无论用户输入什么,数据都只会被当作值来处理,而不会被当作SQL 代码的一部分 + +- **PDO (PHP Data Objects)** + + ```php + // 创建PDO连接 + $pdo = new PDO("mysql:host=localhost;dbname=testdb", "username", "password"); + + // 1. 准备SQL语句模板,使用 ? 占位符 + $stmt = $pdo->prepare("SELECT * FROM users WHERE username = ?"); + + // 2. 绑定参数,将用户输入作为值传递 + $stmt->execute([$_POST['username']]); + + // 3. 获取结果 + $user = $stmt->fetch(); + ``` + + PDO 是现代 PHP 开发中处理数据库连接和查询的标准库,它支持多种数据库,并且提供了强大的预处理功能 + +- **MySQLi** + + ```php + // 创建MySQLi连接 + $mysqli = new mysqli("localhost", "username", "password", "testdb"); + + // 1. 准备SQL语句模板,使用 ? 占位符 + $stmt = $mysqli->prepare("SELECT * FROM users WHERE username = ?"); + + // 2. 绑定参数,指定数据类型 + $stmt->bind_param("s", $_POST['username']); // "s" 表示 string + + // 3. 执行查询 + $stmt->execute(); + + // 4. 获取结果 + $result = $stmt->get_result(); + $user = $result->fetch_assoc(); + ``` + + MySQLi 是专为 MySQL 设计的扩展,也支持预处理语句 + +**2. 使用 ORM 框架** + +如果你在使用像 **Laravel**、**Symfony** 或 **Yii** 这样的现代 PHP 框架,那么ORM(对象关系映射)库(如Eloquent或Doctrine)已经为你处理了预处理语句的复杂性 + +- **Laravel Eloquent 示例** + + ```php + use App\Models\User; + + // Eloquent会自动使用预处理语句 + $user = User::where('username', $_POST['username'])->first(); + ``` + + 使用 ORM,你不再需要直接编写 SQL 语句,而是通过操作对象来完成数据库交互,这从根本上避免了 SQL 注入的可能性 + +**3. 数据转义** + +在某些老旧的系统或特殊情况下,如果无法使用预处理语句,你必须对所有用户输入进行**转义**。转义的目的是将用户输入中的特殊字符(如单引号 `'`、双引号 `"`、反斜杠 `\` 等)进行处理,使它们失去原有的特殊含义,被数据库当作普通字符串来处理 + +- **使用 `mysqli_real_escape_string()`** + + ```php + // 在使用前确保已经建立了MySQLi连接 + $username = mysqli_real_escape_string($conn, $_POST['username']); + + // 将转义后的变量拼接到SQL语句中 + $sql = "SELECT * FROM users WHERE username = '$username'"; + $result = mysqli_query($conn, $sql); + ``` + + 这种方法**只在最后一道防线**使用,并且**不推荐**作为主要防御手段,因为它容易被遗漏,并且不同的数据库需要不同的转义函数,增加了开发者的负担 + +- **注意**:**绝对不要再使用 `addslashes()`**,因为它无法处理所有字符集,容易被绕过。`mysql_escape_string()` 也已经被废弃 + +**4. 最小权限原则** + +这是一个重要的安全原则,可以降低 SQL 注入成功后的危害 + +- **不要使用 `root` 用户**或拥有所有权限的用户来连接数据库 +- 为应用程序**创建专用的数据库用户**,并只赋予它完成任务所需的最小权限。例如,一个只读操作的脚本,其数据库用户就应该只有 `SELECT` 权限 + +| 防御方法 | 优点 | 缺点 | 推荐度 | +| ---------- | ------------------------------------------------- | -------------------------------------------------------- | ---------------------- | +| 预处理语句 | 最安全、最彻底的防御;将数据与代码分离;性能好。 | 语法相对复杂一些;无法用于某些动态 SQL(如表名、列名)。 | 最高 | +| ORM 框架 | 从根本上杜绝 SQL 注入;开发效率高;代码可读性好。 | 需要学习框架;不适用于简单或无框架项目。 | 非常高 | +| 数据转义 | 适用于老旧系统或无框架的项目。 | 容易遗漏;依赖开发者记忆;不彻底。 | 低,仅作补充 | +| 最小权限 | 降低攻击后的危害。 | 无法从根本上防御注入。 | 非常高(作为安全原则) | \ No newline at end of file diff --git a/Chapter20/20-12.md b/Chapter20/20-12.md new file mode 100644 index 0000000..46aba7b --- /dev/null +++ b/Chapter20/20-12.md @@ -0,0 +1,87 @@ +### 如果审计到了一个文件下载漏洞如何深入的去利用 + +**1. 确认与初步利用** + +首先,要确认这是一个真正的文件下载漏洞,而不是一个伪装的假象。通常,漏洞代码看起来是这样的: + +```php + +``` + +这里的关键在于 `$file = $_GET['file'];` 这行代码没有对用户输入进行任何过滤 + +**初步利用方式:** + +- **路径遍历(Path Traversal):** 尝试使用 `../` 来向上跳目录,下载服务器上的敏感文件 + - **Payload:** `?file=../../../../etc/passwd` + - **目的:** 验证漏洞是否存在,并尝试下载系统敏感文件,如 `/etc/passwd`(Linux 用户列表)或 `C:\Windows\System32\drivers\etc\hosts`(Windows 主机文件) +- **下载源码:** 尝试下载网站的 PHP 源代码文件。 + - **Payload:** `?file=../../../../var/www/html/index.php` 或 `?file=../../../../var/www/html/config.php` + - **目的:** 获取网站的数据库连接信息、API密钥或其他硬编码的凭据,为下一步攻击做准备 + +**2. 深入利用:组合攻击** + +如果仅仅是下载文件,漏洞的危害有限。但如果将它与其他漏洞或服务器配置问题结合起来,它的威力会成倍增加。 + +**场景一:与日志文件结合** + +如果服务器的 Web 日志文件可以被下载,而你又可以向日志中写入数据,那么这个文件下载漏洞就可能变成一个**远程代码执行**漏洞 + +**利用步骤:** + +1. **向日志中写入恶意 PHP 代码:** + - 通常,Web 服务器(如 Apache)会记录用户的 User-Agent、Referer 等 HTTP 头信息 + - 将你的 User-Agent 设置为包含恶意 PHP 代码,例如:`` + - **Payload:** `User-Agent: ` + - 通过访问一个不存在的页面来触发日志记录 +2. **利用文件下载漏洞下载并执行日志文件:** + - 找到日志文件的路径。通常位于 `/var/log/apache2/access.log` 或 `/var/log/httpd/access_log` + - **Payload:** `?file=../../../../var/log/apache2/access.log` + - 当服务器执行 `readfile()` 函数时,它会将日志文件作为 PHP 代码来解析并执行 + - **执行命令:** 你的浏览器现在会显示 `ls -al` 命令的输出 +3. **最终利用:** + - 现在你可以通过在URL中添加 `&cmd=...` 来执行任意命令 + - **Payload:** `?file=../../../../var/log/apache2/access.log&cmd=id` + - 你可以通过这个方式上传一个WebShell,从而完全控制服务器 + +**场景二:与本地文件包含(LFI)漏洞结合** + +如果目标服务器存在本地文件包含漏洞,但你不知道路径或无法直接利用,文件下载漏洞可以帮助你获取更多信息 + +**利用步骤:** + +1. **使用文件下载漏洞下载 PHPinfo 文件** + - 找到服务器上的一个 `phpinfo()` 文件(如果有的话) + - **Payload:** `?file=../../../../var/www/html/info.php` + - **目的:** `phpinfo()` 页面会暴露大量敏感信息,包括服务器的配置、环境变量、安装的模块等,这些信息可以帮助你找到新的攻击面 +2. **利用 LFI 漏洞包含敏感文件:** + - 如果你发现了一个可以包含文件的漏洞,但是无法直接包含日志文件 + - 你可以先利用文件下载漏洞,下载服务器上的`/proc/self/environ`文件。这个文件通常包含进程的环境变量,包括你之前设置的 User-Agent + - 然后,利用LFI漏洞去包含 `/proc/self/environ`,从而执行你注入到 User-Agent 中的代码 + +**3. 利用思路的扩展** + +除了上述两种常见的组合攻击,你还可以尝试以下利用方式: + +- **下载 SSH 密钥:** 如果服务器启用了SSH,你可以尝试下载用户的 SSH 密钥 + - **Payload:** `?file=../../../../home/user/.ssh/id_rsa` + - **目的:** 使用密钥直接登录服务器,获取 Shell 权限 +- **下载数据库文件:** + - 对于 SQLite 等数据库,其数据存储在文件中 + - **Payload:** `?file=../../../../var/www/html/database/db.sqlite` + - **目的:** 获取整个数据库的内容,包括用户密码(如果未加密)、个人信息等 +- **绕过防御:** + - 如果开发者对 `../` 进行了过滤,可以尝试双重编码 `..%252f` 或其他编码方式来绕过 + - 如果路径是硬编码的,例如 `downloads/`,尝试使用空字节 `%00` 来截断路径 + - **Payload:** `?file=../../../../etc/passwd%00` \ No newline at end of file diff --git a/Chapter20/20-13.md b/Chapter20/20-13.md new file mode 100644 index 0000000..0fded19 --- /dev/null +++ b/Chapter20/20-13.md @@ -0,0 +1,23 @@ +### 讲讲 Fortity 等代码审计工具原理 + +**Fortify 等代码审计工具的原理** + +Fortify、Checkmarx、SonarQube 等自动化代码审计工具,其核心原理是**静态应用安全测试(Static Application Security Testing, SAST)**。它们不对程序进行实际运行,而是通过分析程序的**源代码、字节码或二进制文件**,来识别其中的安全漏洞 + +这就像一个医生在给病人看病时,不是通过观察病人的症状,而是直接通过分析病人的基因图谱来预测潜在的疾病风险。 + +这些工具的工作流程通常分为以下几个阶段: + +1. **解析(Parsing)** 这是工具的第一步,也是最重要的一步。它会像编译器一样,对输入的源代码进行词法分析、语法分析和语义分析,将代码转换为一个更容易分析的中间表示,通常是**抽象语法树(Abstract Syntax Tree, AST)** + - **目的**:将代码的文本形式转换为结构化的数据,方便后续的分析 +2. **数据流分析(Data Flow Analysis)** 这个阶段是 SAST 工具的核心。它会追踪程序中**数据的流动路径**,特别是从**外部输入源(Source)**到**敏感操作(Sink)**的路径 + - **外部输入源(Source)**:指那些可能被用户控制的输入,例如 HTTP 请求的参数(`$_GET`、`$_POST`)、文件上传、数据库查询结果等 + - **敏感操作(Sink)**:指那些可能引发安全漏洞的操作,例如执行系统命令(`system()`)、执行 SQL 查询(`mysqli_query()`)、写入文件等 + - **分析过程**:工具会模拟数据从 Source 流向 Sink 的过程。如果发现一个未经验证或过滤的外部输入直接进入了敏感操作,它就会标记为一个潜在的漏洞 + - **例如**:当一个用户输入的 `$username` 直接被拼接到 SQL 查询语句中,工具就会识别出这是一个潜在的 SQL 注入漏洞 +3. **控制流分析(Control Flow Analysis)** 这个阶段分析程序执行的**所有可能的路径**。它会构建一个**控制流图(Control Flow Graph, CFG)**,来模拟程序在不同条件分支(`if/else`、`for`、`while`)下的执行路径 + - **目的**:结合数据流分析,判断漏洞是否在**可达的执行路径**上。如果一个漏洞位于一个永远不会被执行到的代码块中,那么它就是一个假阳性 + - **例如**:一个敏感操作被放在一个永远为 `false` 的 `if` 语句中,那么工具会识别出这个漏洞无法被触发 +4. **规则匹配(Rule Matching)** Fortify 等工具内置了一个庞大的**漏洞规则库**,这些规则定义了各种已知的漏洞模式。在分析了数据流和控制流之后,工具会将分析结果与规则库进行匹配 + - **规则库**:包含了各种语言(Java、PHP、Python 等)的常见漏洞,例如命令注入、跨站脚本(XSS)、文件上传漏洞等 + - **匹配过程**:如果一个数据流路径符合某个漏洞规则,工具就会生成一个漏洞报告 \ No newline at end of file diff --git a/Chapter20/20-2.md b/Chapter20/20-2.md new file mode 100644 index 0000000..32dd28d --- /dev/null +++ b/Chapter20/20-2.md @@ -0,0 +1,54 @@ +### 常见入口函数怎么找 + +**1. 查找 Web 框架的路由文件** + +如果你面对的是一个流行的 Web 框架(如 Laravel, Symfony, ThinkPHP, Yii),那么入口通常由框架定义 + +- **Laravel**: 入口文件通常是 `public/index.php`。所有请求都会被这个文件处理,然后根据 `routes` 目录下的路由配置文件(如 `routes/web.php` 或 `routes/api.php`)分发给不同的控制器方法 +- **ThinkPHP**: 入口文件同样是项目根目录下的 `public/index.php`,路由文件在 `route` 目录下 +- **WordPress**: 入口文件是根目录下的 `index.php`。它会加载 `wp-load.php`,进而加载整个 WordPress 核心 + +**2. 查找包含或加载其他文件的文件** + +如果不是一个标准的框架,那么入口文件通常是一个包含或加载了许多其他文件的文件 + +- **关键词搜索**: 在代码库中搜索 `require`, `include`, `require_once`, `include_once` 等关键词。通常,代码量最少且包含最多其他文件的那个文件,就是入口文件 +- **文件名猜测**: 很多开发者会使用通用的文件名作为入口,例如 `index.php`, `main.php`, `bootstrap.php` 或 `init.php` + +**示例:** + +```php +// index.php +require_once 'config/db.php'; +require_once 'lib/auth.php'; +include 'views/header.php'; + +// ... +``` + +在这个例子中,`index.php` 就是一个很明显的入口 + +**3. 查看 Web 服务器的配置** + +对于一些特殊的配置,Web 服务器(如 Apache 或 Nginx)的配置文件会指定入口文件 + +- **Apache**: 在 `.htaccess` 文件或 Apache 的主配置文件(如 `httpd.conf`)中查找 `DirectoryIndex` 或 `RewriteRule` 规则 +- **Nginx**: 在 Nginx 的配置文件(通常在 `/etc/nginx/sites-available/` 或 `/etc/nginx/conf.d/`)中查找 `index` 指令或 `location` 块中的 `rewrite` 规则 + +**示例(Nginx 配置):** + +```nginx +location / { + # 如果请求的文件不存在,则将请求重写到 index.php + try_files $uri $uri/ /index.php?$args; +} +``` + +这条规则明确指定了所有请求都会被转发到 `index.php` + +**4. 追踪用户输入** + +更高级的分析方法是追踪用户输入 + +- **搜索超全局变量**: 在代码库中搜索 `$_GET`, `$_POST`, `$_REQUEST`, `$_COOKIE`, `$_FILES` 等超全局变量。这些变量是用户输入的最直接来源 +- **回溯分析**: 找到这些变量的使用点后,向上追溯调用链。例如,如果你看到一个函数 `process_input($_POST['data'])`,你需要找到 `process_input` 函数是在哪里被调用的,直到找到程序的起点 \ No newline at end of file diff --git a/Chapter20/20-3.md b/Chapter20/20-3.md new file mode 100644 index 0000000..cf9c7ae --- /dev/null +++ b/Chapter20/20-3.md @@ -0,0 +1,36 @@ +### PHP 代码审计流程 + +**1. 宏观分析与项目理解** + +- **项目概况了解**: 首先,你需要快速浏览整个代码库,了解项目的规模、所使用的框架(例如 Laravel, ThinkPHP, WordPress 等)、版本以及主要功能模块。这有助于你构建一个大致的威胁模型 +- **寻找入口点**: 确定程序的入口文件(如 `index.php`)和主要路由配置。这是所有用户输入和请求的起点,也是你后续深入分析的起点 +- **识别关键功能**: 重点关注那些与用户交互、文件操作、数据库查询、命令执行以及身份认证相关的模块,这些地方最容易出现漏洞 + +**2. 自动化工具扫描** + +- **静态分析(SAST)**: 使用专门的静态代码分析工具对整个代码库进行扫描。这些工具可以快速地发现一些明显的、模式化的漏洞,例如 SQL 注入、XSS、命令注入等 + - **常用工具**: + - **`PHPStan`**: 检查代码中的潜在错误和不规范之处 + - **`SonarQube`**: 功能强大的代码质量管理平台,可以集成多种规则集 + - **`RIPS`** (付费) 或 **`php-security-scanner`** (开源): 专注于 PHP 安全漏洞扫描 +- **动态分析(DAST)**: 如果条件允许,在测试环境中部署代码,使用动态扫描工具(如 Burp Suite Pro, OWASP ZAP)模拟黑客行为进行测试。这可以发现那些只有在运行时才能触发的漏洞 + +**3. 人工审计与深度分析** + +人工审计是发现复杂和逻辑漏洞的关键步骤,它需要你结合自动化工具的报告进行深入分析 + +- **查找敏感函数**: 重点关注那些可能导致危险操作的函数,回溯它们的调用链,看参数是否可控、是否进行了过滤。 + - **命令执行**: `exec()`, `shell_exec()`, `passthru()`, `system()` + - **文件操作**: `file_get_contents()`, `file_put_contents()`, `include()`, `require()` + - **SQL 注入**: `mysqli_query()`, `PDO::query()` + - **代码执行**: `eval()`, `assert()`, `unserialize()` + - **重定向**: `header('Location: ...')` + +**4. 漏洞确认与报告** + +- **漏洞复现**: 找到潜在漏洞后,你需要在本地或测试环境中复现它,确认其真实存在且可利用 +- **编写报告**: 撰写详细的漏洞报告,包括: + - **漏洞描述**: 漏洞的类型、影响范围和风险等级 + - **漏洞位置**: 精确的代码文件和行号 + - **复现步骤**: 详细的攻击步骤,帮助开发者理解和验证 + - **修复建议**: 给出具体的代码修复方案 \ No newline at end of file diff --git a/Chapter20/20-4.md b/Chapter20/20-4.md new file mode 100644 index 0000000..f61b5c8 --- /dev/null +++ b/Chapter20/20-4.md @@ -0,0 +1,43 @@ +### ThinkPHP 框架审计起来有什么不同 + +**1. 核心差异:文件结构与路由机制** + +- **传统 PHP 代码**: + - **文件结构**: 通常比较随意,一个页面一个文件,或者通过 `include`/`require` 组织 + - **入口点**: 可能会有多个入口文件,例如 `index.php`、`login.php`、`upload.php` 等 + - **审计思路**: 从每个入口文件开始,逐个跟踪用户输入,找到所有可能被利用的敏感函数,例如 `eval`、`system`、`include` +- **ThinkPHP 框架**: + - **文件结构**: 严格遵循 MVC(模型-视图-控制器)架构,有固定的目录结构,如 `app`、`config`、`public`、`route` 等 + - **入口点**: 通常只有一个统一的入口文件,`public/index.php`。所有请求都通过这个文件,然后由框架的路由系统进行分发 + - **审计思路**: 重点分析**路由文件**(`route` 目录),理解请求如何被分发到哪个**控制器**的哪个**方法**。审计不再是线性的文件流,而是基于路由-控制器-模型-视图的调用链 + +**2. 安全机制与新漏洞点** + +- **传统 PHP 代码**: + - **安全机制**: 几乎没有内置的安全机制,所有安全检查(如输入过滤、SQL 预处理)都需要开发者手动实现,非常依赖开发者的安全意识 + - **常见漏洞**: 由于缺乏统一的过滤,SQL 注入、XSS、命令执行等漏洞非常普遍且容易发现 +- **ThinkPHP 框架**: + - **安全机制**: + - **自动路由解析**: 框架会根据 URL 自动将参数传入控制器方法,但若使用不当会产生漏洞 + - **SQL 预处理**: 提供了 ORM(对象关系映射)和查询构造器,鼓励开发者使用参数化查询,从而有效防御 SQL 注入 + - **自动过滤**: 在早期版本中(如 ThinkPHP 5.x),`Request` 对象会进行自动过滤,但若开发者使用 `get()`、`post()` 等函数而不做安全处理,仍可能存在风险 + - **跨站请求伪造(CSRF)防护**: 内置了 CSRF Token 机制 + - **新漏洞点**: + - **路由解析漏洞**: 早期版本曾出现因 URL 解析不当导致的代码执行漏洞 + - **SQL 注入**: 尽管有 ORM,但若开发者仍使用原始的 `query()` 方法或拼接字符串,SQL 注入依然会存在 + - **文件包含**: 尽管框架本身减少了 `include` 的使用,但若开发者在控制器中动态加载了用户可控的文件,仍可能导致文件包含漏洞 + - **远程命令执行(RCE)**: 框架本身可能存在一些高危的 RCE 漏洞,如历史上的 **ThinkPHP RCE 漏洞**,这些是框架自身的问题,而非开发者代码问题。 + +**3. 审计流程的差异** + +- **审计传统 PHP 代码**: + - **方法**: 重点是“找”,即找到所有用户输入点和敏感函数 + - **关键**: 逐个文件、逐个功能地进行黑盒或白盒测试 +- **审计 ThinkPHP 框架代码**: + - **方法**: 重点是“理解和跟踪” + - **关键**: + 1. **理解路由**: 从 `route` 文件开始,理解 URL 如何映射到控制器和方法 + 2. **跟踪参数**: 找到控制器方法中使用了 `Request::get()`、`Request::post()` 或直接从参数列表接收用户输入的地方 + 3. **检查数据流**: 跟踪这些用户输入是如何被使用,是否直接进入了数据库查询、文件操作或命令执行函数 + 4. **关注框架漏洞**: 检查框架版本,看是否存在已知的框架级别漏洞 + 5. **ORM 审计**: 检查 ORM 查询,看是否存在使用原始 SQL 语句的情况,或者在使用 `where`、`find` 等方法时,参数是否被正确处理 \ No newline at end of file diff --git a/Chapter20/20-5.md b/Chapter20/20-5.md new file mode 100644 index 0000000..1e10555 --- /dev/null +++ b/Chapter20/20-5.md @@ -0,0 +1,54 @@ +### PHP 原生的敏感函数有哪些 + +**1. 代码执行 / 命令执行** + +这些函数可以直接执行系统命令或 PHP 代码,是最高危的一类函数 + +- **`eval()`**: 将字符串作为 PHP 代码执行 +- **`assert()`**: 检查一个字符串是否为合法的 PHP 代码,如果是则执行 +- **`shell_exec()`**: 通过 shell 执行命令并返回所有输出 +- **`exec()`**: 执行一个外部程序 +- **`system()`**: 执行外部程序并显示输出 +- **`passthru()`**: 执行外部程序并直接将原始输出传递给浏览器 +- **`proc_open()`**: 执行一个命令,并打开指向其标准输入/输出/错误的文件指针 +- **`popen()`**: 打开一个指向进程的管道。 + +**2. 文件包含 / 读取 / 写入** + +这些函数如果参数可控,可能导致任意文件读取、写入,甚至是远程代码执行(RCE) + +- **`include()` / `include_once()`**: 包含并执行指定文件 +- **`require()` / `require_once()`**: 包含并执行指定文件,若失败则抛出致命错误 +- **`file_get_contents()`**: 将整个文件读入一个字符串 +- **`file_put_contents()`**: 将一个字符串写入文件 +- **`fopen()` / `fread()` / `fwrite()`**: 用于打开、读取和写入文件 +- **`unlink()`**: 删除文件 +- **`move_uploaded_file()`**: 将上传的文件移动到新位置 +- **`readfile()`**: 读取文件并写入到输出缓冲 + +**3. 数据处理与反序列化** + +这些函数在处理用户输入时如果不加限制,可能导致反序列化漏洞 + +- **`unserialize()`**: 将字符串反序列化为 PHP 值 +- **`json_decode()`**: 将 JSON 字符串解码为 PHP 变量 +- **`gzuncompress()` / `gzinflate()`**: 解压压缩字符串,可能引发内存溢出或拒绝服务。 + +**4. 变量操作与反射** + +- **`extract()`**: 从数组中导入变量到当前符号表。如果数组内容可控,可能覆盖现有变量 +- **`parse_str()`**: 将字符串解析成变量,同样可能导致变量覆盖 +- **`create_function()`**: 创建一个匿名函数。在 PHP 7.2.0 之后已被废弃,但旧版本中可能存在代码执行风险 + +**5. 数据库操作** + +尽管大多数现代框架都有自己的 ORM 和查询构造器,但仍需注意原生数据库函数的使用,尤其是拼接 SQL 语句时 + +- **`mysql_query()`**: 执行 SQL 查询(已废弃) +- **`mysqli_query()`**: 执行 SQL 查询 +- **`PDO::query()`**: 执行 SQL 查询 + +**6. 其他** + +- **`header()`**: 用于设置 HTTP 头信息。如果参数可控,可能导致 CRLF 注入或重定向漏洞 +- **`die()` / `exit()`**: 终止脚本执行。在某些情况下,可能导致逻辑漏洞 \ No newline at end of file diff --git a/Chapter20/20-6.md b/Chapter20/20-6.md new file mode 100644 index 0000000..6e8751e --- /dev/null +++ b/Chapter20/20-6.md @@ -0,0 +1,37 @@ +### 反序列化时有哪些魔术方法是可以作为一个入手点去找的 + +**`__wakeup()`** + +当`unserialize()`函数被调用时,`__wakeup()` 方法会立即被调用。这个方法通常用于在对象被反序列化后重新建立其内部状态。 + +- **攻击思路:** 攻击者可以寻找 `__wakeup()` 方法中是否存在**危险函数调用**(例如 `system()`、`eval()` 等),或者其内部逻辑是否可控,从而导致一些意想不到的后果 + +**`__destruct()`** + +当一个对象被销毁时(例如脚本执行结束或对象被显式释放),`__destruct()` 方法会被调用 + +- **攻击思路:** `__destruct()` 是攻击者最喜欢的入手点之一,因为它**总是在脚本执行的最后被调用**,无论反序列化过程是否成功。如果该方法中存在文件删除、命令执行或其他敏感操作,攻击者可以通过构造恶意序列化字符串来触发它,从而达到攻击目的 + +**`__toString()`** + +当一个对象被当作字符串使用时,`__toString()`方法会被自动调用 + +- **攻击思路:** 攻击者可以寻找哪些函数会将对象作为字符串处理。例如,`echo`、`print`、`file_get_contents()`等函数都会触发 `__toString()`。如果该方法中包含敏感操作,或者可以将 `__toString()` 的返回值作为参数传递给其他危险函数,就可能导致漏洞。这通常被称为“**POP链**”中的一个重要环节 + +**`__call()`** + +当一个对象中不存在某个方法,但你却试图调用它时,`__call()` 方法会被自动调用 + +- **攻击思路:** `__call()`可以用来触发其他方法。如果 `__call()` 方法能够通过某种方式调用到危险方法,攻击者就可以通过调用一个不存在的方法来间接触发漏洞 + +**`__callStatic()`** + +与 `__call()` 类似,但它在调用一个不存在的静态方法时触发 + +- **攻击思路:** 同样可以用于触发类中的敏感静态方法 + +**`__get()` 和 `__set()`** + +当试图访问一个不存在的或不可访问的属性时,`__get()` 会被调用。当试图给一个不存在的或不可访问的属性赋值时,`__set()` 会被调用 + +- **攻击思路:** 这两个方法经常用于创建所谓的“**属性链**”。通过控制 `__get()` 或 `__set()` 中的逻辑,可以间接控制其他对象的属性或触发其他方法。例如,`__get()` 返回的对象又可以触发其自身的魔术方法,形成一个连锁反应 \ No newline at end of file diff --git a/Chapter20/20-7.md b/Chapter20/20-7.md new file mode 100644 index 0000000..bc38ae5 --- /dev/null +++ b/Chapter20/20-7.md @@ -0,0 +1,43 @@ +### 常见的路由方法 + +**1. 静态路由** + +这是最简单、最直接的路由方式。你为每个固定的URL定义一个唯一的处理程序 + +- **示例:** + - `/about` -> `AboutController::index()` + - `/contact` -> `ContactController::show()` + +这种方法的优点是**清晰直观、性能高**,因为框架不需要进行复杂的模式匹配。缺点是**灵活性差**,无法处理动态变化的URL,比如文章 ID 或用户 ID + +**2. 动态路由** + +动态路由允许你在 URL 中定义可变参数。这通常通过在路由规则中使用占位符来实现 + +- **示例:** + - `/posts/{id}` -> `PostController::show($id)` + - `/users/{name}` -> `UserController::profile($name)` + +这种方法**非常灵活**,能很好地处理像博客文章、用户资料页等需要动态内容的场景。现代框架通常还支持为这些占位符添加正则表达式约束,以确保参数格式正确 + +**3. 命名路由** + +命名路由为每个路由规则分配一个唯一的名称。这个名称可以在应用中用来生成URL,而不是直接硬编码URL字符串 + +- **示例:** + - 定义:`Route::get('/profile/{id}', 'UserController@show')->name('user.profile');` + - 使用:`redirect(route('user.profile', ['id' => 1]));` + +**命名路由是最佳实践**。它的主要优点是**可维护性高**。如果将来 URL 结构发生变化,你只需要修改路由定义文件,而不需要在整个代码库中查找和替换所有硬编码的 URL + +**4. 路由群组** + +路由群组允许你将一组具有共同属性(如前缀、中间件或命名空间)的路由组合在一起 + +- **示例:** + - `Route::prefix('admin')->group(function () {` + - `Route::get('/dashboard', 'AdminController@dashboard');` + - `Route::get('/users', 'AdminController@users');` + - `});` + +上述代码会将 `/admin/dashboard` 和 `/admin/users` 这两个路由组合在一起。路由群组的主要好处是**减少代码重复**,让路由定义更加简洁和有条理 \ No newline at end of file diff --git a/Chapter20/20-8.md b/Chapter20/20-8.md new file mode 100644 index 0000000..01003d2 --- /dev/null +++ b/Chapter20/20-8.md @@ -0,0 +1,79 @@ +### 介绍下 PHP 的变量覆盖 + +有几个 PHP 函数在不安全地使用时,极易引发变量覆盖漏洞 + +**1. `extract()`** + +`extract()`函数从一个数组中导入变量到当前的符号表。它会**根据数组的键名创建同名的变量**,并将键值赋给这些新变量 + +- **漏洞示例:** + + ```php + + ``` + + 在这个例子中,攻击者可以通过URL `?username=admin&password=mypassword` 来覆盖 `$username` 和 `$password` 这两个变量,从而绕过身份验证 + +- **安全建议:** 使用 `extract()` 时,务必指定第二个参数 `$flags` 为 `EXTR_SKIP` 或 `EXTR_PREFIX_ALL`,以防止覆盖现有变量。例如:`extract($_GET, EXTR_SKIP);` + +**2. `parse_str()`** + +`parse_str()`函数用于解析URL参数字符串,并将其作为变量导入到当前作用域 + +- **漏洞示例:** + + ```php + + ``` + + 攻击者可以通过 `?username=admin` 来覆盖 `$username` 变量 + +- **安全建议:** 始终将 `parse_str()` 的第二个参数设置为一个数组变量,这样解析的结果会存入该数组,而不是直接创建全局变量。例如:`parse_str($_SERVER['QUERY_STRING'], $query_data);` + +**3. `import_request_variables()`** + +这个函数在PHP 5.4.0 版本后被移除。它的功能是把 `$_GET`、`$_POST` 或 `$_COOKIE` 中的变量导入到全局作用域。由于其固有的安全风险,**不应再使用** + +**4. `$$` (双重美元符)** + +双重美元符是一种特殊的变量语法,它会将一个变量的值作为另一个变量的名称 + +- **漏洞示例:** + + ```php + $value) { + // 动态地创建变量名 + $$key = $value; + } + + echo "Hello, " . $name; + ?> + ``` + + 如果URL为 `?name=hacker`,`$key` 的值为 `name`,`$value` 的值为 `hacker`。那么 `$$key` 实际上就是 `$name`,它的值被设置为 `hacker`。攻击者可以通过这种方式覆盖 `$name` 变量 + +- **安全建议:** 避免在没有严格过滤的情况下使用双重美元符来动态创建变量 \ No newline at end of file diff --git a/Chapter20/20-9.md b/Chapter20/20-9.md new file mode 100644 index 0000000..f7eebe4 --- /dev/null +++ b/Chapter20/20-9.md @@ -0,0 +1,33 @@ +### 远程文件包含和本地文件包含这两种涉及的 PHP 设置有什么 + +**1. 本地文件包含(LFI)** + +本地文件包含漏洞是指攻击者能够包含服务器本地文件系统上的任意文件。这种漏洞的利用通常不依赖于特定的 `php.ini` 设置,而是完全取决于**代码本身的不安全实现** + +**关键的 PHP 设置:** + +- **`allow_url_include`**:这个设置**通常与 LFI 无关**。它只控制是否允许包含远程文件。即使 `allow_url_include` 为 `Off`,LFI 漏洞仍然可以存在 +- **`open_basedir`**:这是一个重要的安全设置,它可以**限制 PHP 脚本能够访问的文件目录**。如果配置得当,它可以有效缓解LFI的危害。例如,将 `open_basedir` 设置为 `/var/www/html/`,那么PHP脚本就无法包含该目录之外的文件,例如 `/etc/passwd` + +**总结**:对于 LFI,PHP 配置本身提供的防御措施相对有限。`open_basedir` 是最有用的一个,但**代码层面的白名单验证和输入过滤**才是最根本的防御手段 + +**2. 远程文件包含(RFI)** + +远程文件包含漏洞是指攻击者能够包含**来自外部服务器**的任意文件。这种漏洞的利用**直接依赖于 PHP 的特定配置**。 + +**关键的 PHP 设置:** + +- **`allow_url_include`**:这是**RFI 漏洞的核心开关** + - **`allow_url_include = On`**:允许通过 URL(如 `http://` 或 `ftp://`)来包含远程文件。这是导致 RFI漏洞的直接原因 + - **`allow_url_include = Off`**:**禁止**通过 URL 来包含远程文件。**这是默认和推荐的安全设置**。只要这个设置是 `Off`,即使代码本身存在缺陷,也无法触发远程文件包含攻击 +- **`allow_url_fopen`**:这个设置**间接影响** RFI。它控制是否允许 URL 作为文件来处理,比如在 `file_get_contents()` 或 `fopen()` 函数中。虽然它本身不直接影响 `include`,但在某些攻击场景中,如果攻击者需要远程获取文件内容再进行处理,这个设置就会起到作用。然而,**`allow_url_include` 才是决定性的** + +**总结**:`allow_url_include` 的值是判断一个 PHP 应用是否存在RFI漏洞风险的最关键因素。在生产环境中,**始终建议将其设置为 `Off`** + +| 特性 | 本地文件包含(LFI) | 远程文件包含(RFI) | +| ----------- | ------------------------------------- | --------------------------------------- | +| 漏洞类型 | 包含服务器本地文件 | 包含外部服务器文件 | +| 核心函数 | include($filename) | include($url) | +| 关键PHP设置 | open_basedir(缓解) | allow_url_include(决定性) | +| 防御重点 | 代码层面的白名单和输入过滤 | php.ini 中将 allow_url_include 设为 Off | +| 风险 | 读取敏感文件,配合其他漏洞可能导致RCE | 直接导致RCE | \ No newline at end of file diff --git a/Chapter20/README.md b/Chapter20/README.md index 8b13789..9eecb4f 100644 --- a/Chapter20/README.md +++ b/Chapter20/README.md @@ -1 +1,20 @@ +# 网安面试题(涵盖护网、红队、逆向、二进制) +上万道安全面试题已经全部为您划分好,适用于网络安全所有岗位!!! + +HR:请问………… + +我:叽里咕噜说啥呢,看看八股文上写了没 + +(Summary.md 是目录噢!!) + +**🙏 特别感谢名单** + +在整理和完善本项目的过程中,以下朋友给予了宝贵的帮助与支持,在此表示诚挚的感谢!(排名不分先后) + +- **@用户名1** —— 提供了大量安全面试题方向的补充 +- **@用户名2** —— 纠正了多个问题的答案与表述 +- **@用户名3** —— 贡献了真实面试题经验分享 +- **@用户名4** —— 对内容结构与目录提出改进建议 + +如果您也愿意参与本项目,欢迎通过 **微信: XR3327026244** 投稿面试题或反馈问题,我们会在后续版本中加入您的名字