### 漏洞概述 该网页截图展示了一个名为 `BuildHelper.php` 的 PHP 文件,其中包含一个潜在的 SQL 注入漏洞。漏洞位于 `where` 方法中,具体是在处理 `$where` 数组参数时,未对用户输入进行充分的过滤和转义,导致攻击者可以通过构造特殊的输入来注入恶意 SQL 代码。 ### 影响范围 - **影响模块**:`BuildHelper` 类中的 `where` 方法。 - **影响场景**:任何使用该方法的数据库查询操作都可能受到 SQL 注入攻击的影响。 - **潜在危害**:攻击者可能通过 SQL 注入获取、修改或删除数据库中的数据,甚至执行任意命令。 ### 修复方案 1. **输入验证**:对所有用户输入进行严格的验证,确保输入符合预期格式。 2. **参数化查询**:使用参数化查询或预编译语句,避免直接拼接用户输入到 SQL 语句中。 3. **转义特殊字符**:对输入中的特殊字符进行转义,防止其被解释为 SQL 语法的一部分。 ### POC 代码 以下是可能的 POC 代码示例,用于演示如何利用该漏洞: ```php // 假设 $where 数组由用户输入控制 $where = [ 'id' => '1 OR 1=1' ]; // 调用 where 方法 $result = BuildHelper::where($where); // 生成的 SQL 语句可能为: // SELECT * FROM table WHERE id = 1 OR 1=1 ``` ### 完整代码块 以下是 `BuildHelper.php` 文件中 `where` 方法的完整代码: ```php public static function where(array $where, $id = null) { $sql = ''; $params = []; foreach ($where as $key => $item) { $id++; $prefix = "{$sql}."; $length = count($item); // php switch continue 异常问题,所以用 if else if ($length == 2) { // 2 条件 if (is_array($item[0]) && is_array($item[1])) { $symbol = $item[0]; $subWhere = $item[1]; if (static::isMulti($subWhere)) { $subWhere = [$subWhere]; } $subSql = static::where($subWhere, $id); if (count($subWhere) > 1) { $subSql = "({$subSql})"; } if ($symbol == 'merge') { $sql = $subSql; } if ($key > 0) { throw new \PDOException(sprintf('This where can\'t be the first: %s', json_encode($item))); } } else { $sql .= " " . strtoupper($symbol) . " {$subSql}"; if ($key > 0) { throw new \PDOException(sprintf('This where can\'t be the first: %s', json_encode($item))); } } $params = array_merge($params, $subParams); continue; } // 无条件 if (is_string($item[0]) && is_string($item[1])) { $field = $item[0]; $operator = $item[1]; $condition = $item[2]; $subSql = "{$field} {$operator}"; $sql .= " AND {$subSql}"; if ($key == 0) { $sql = $subSql; } continue; } throw new \PDOException(sprintf('Invalid where format: %s', json_encode($item))); } elseif ($length == 3) { // 标准条件 (等于/不等于/在/不在/大于/小于/大于等于/小于等于) $field = $item[0]; $operator = $item[1]; $condition = $item[2]; $in = in_array(strtoupper($operator), ['IN', 'NOT IN']); $between = in_array(strtoupper($operator), ['BETWEEN', 'NOT BETWEEN']); if ( (is_string($field) && $field instanceof Expression) && is_string($operator) && is_scalar($condition) || (is_string($field) && ($in || $between) && is_array($condition)) ) { $subSql = ''; $name = $prefix . str_replace(['.', ' ', '(', ')'], ['', '', '', '', '', '', '', '', ''], $field); $operator = strtoupper($operator); if (is_array($condition)) { $subSql = "{$field} {$operator} ({$name})"; $params[$name] = $condition; } else { if ($in) { $subSql = "{$field} {$operator} ({$name})"; $params[$name] = $condition; } if ($between) { $name1 = $prefix . 'a' . str_replace(['.', ' ', '(', ')'], ['', '', '', '', ''], $field); $name2 = $prefix . 'b' . str_replace(['.', ' ', '(', ')'], ['', '', '', '', ''], $field); $subSql = "{$field} {$operator} ({$name1} AND {$name2})"; $params[$name1] = $condition[0]; $params[$name2] = $condition[1]; } } $sql .= " AND {$subSql}"; if ($key == 0) { $sql = $subSql; } continue; } throw new \PDOException(sprintf('Invalid where format: %s', json_encode($item))); } else { throw new \PDOException(sprintf('Invalid where format: %s', json_encode($item))); } return [$sql, $params]; } ```