3-11〔OSCP ◈ 研记〕❘ WEB应用攻击▸存储型XSS攻击
郑重声明: 本文所有安全知识与技术,仅用于探讨、研究及学习,严禁用于违反国家法律法规的非法活动。对于因不当使用相关内容造成的任何损失或法律责任,本人不承担任何责任。 如需转载,请注明出处且不得用于商业盈利。
💥👉点赞❤️ 关注🔔 收藏⭐️ 评论💬💥
更多文章戳👉Whoami!-CSDN博客🚀
𖤐 嘿,经过前面的预热,我们正式打开这扇门,来吧 !
𖤐 𝓗𝓮𝔂, 𝓪𝓯𝓽𝓮𝓻 𝔀𝓪𝓻𝓶-𝓾𝓹,𝔀𝓮'𝓻𝓮 𝓷𝓸𝔀 𝓸𝓯𝓯𝓲𝓬𝓲𝓪𝓵𝓵𝔂 𝓸𝓹𝓮𝓷𝓲𝓷𝓰 𝓽𝓱𝓲𝓼 𝓭𝓸𝓸𝓻,𝓒𝓸𝓶𝓮 𝓸𝓷 !
→ 信息收集
→ 漏洞检测
→ 初始立足点▸WEB应用攻击▸存储型XSS攻击-----我们在这儿~ 🔥🔥🔥
→ 权限提升
→ 横向移动
→ 报告/分析
→ 教训/修复
目录
1.跨站脚本攻击(XSS)
1.1 两种常见XSS攻击策略
1.1.1 HTML元素注入攻击
1.1.1.1 攻击原理
1.1.1.2 攻击示例
1.1.2 JavaScript标签内注入攻击
1.1.3 防御策略
1.2 存储型XSS攻击详解(WordPress插件为例)
1.2.1 分析代码寻找注入点
1.2.1.1 数据收集代码分析
1.2.1.2 前端展示代码分析
1.2.2 攻击构造与利用
1.2.2.1 恶意User-Agent构造
1.2.2.2 验证XSS攻击是否成功
1.2.3 数据流与攻击影响
1.2.4 修复方案
1.2.4.1 输入过滤与验证
1.2.4.2 输出编码过滤
1.2.4.3 其他防御措施
💥创作不易💥求一波暴击👉点赞❤️ 关注🔔 收藏⭐️ 评论💬
1.跨站脚本攻击(XSS)
1.1 两种常见XSS攻击策略
跨站脚本攻击(XSS) 是攻击者通过向网页注入恶意代码(通常是JavaScript),从而窃取用户信息或执行未授权操作的攻击方式。攻击成功的关键在于确保恶意代码被浏览器正确解析和执行。
📊 两种XSS攻击策略对比
特征 | ① HTML元素注入 | ② JavaScript标签内注入 |
---|---|---|
攻击目标 | HTML元素内容 | 现有JavaScript代码 |
所需载荷 | 完整脚本标签 | 部分代码片段 |
特殊字符 | < > & | ' " ; {} |
转义要求 | 避免HTML编码 | 避免JS字符串编码 |
攻击复杂度 | 较低 | 较高 |
1.1.1 HTML元素注入攻击
1.1.1.1 攻击原理
攻击者向HTML元素(如<div>
、<span>
等)中注入完整的恶意脚本标签。
🎯 典型攻击载荷
<script>alert('XSS');</script>
代码部分 | 功能说明 |
---|---|
<script> | 开始JavaScript代码块 |
alert('XSS') | 执行弹窗操作,这里就是执行命令的内容,后续可改为其他攻击载荷 |
</script> | 结束JavaScript代码块 |
🔄 转义机制对比
如果代码正确转义,则仅显示文本内容;若未进行转义,则被当成程序被执行。
1.1.1.2 攻击示例
✅ 正确转义示例
<!-- 用户输入 -->
<script>alert('XSS')</script><!-- 安全输出 -->
<script>alert('XSS')</script>
结果:浏览器显示文本而非执行代码。
❌ 危险情况示例
<!-- 用户输入 -->
<script>alert('XSS')</script><!-- 危险输出 -->
<script>alert('XSS')</script>
结果:浏览器执行恶意代码,比如:呈现弹框效果。
1.1.2 JavaScript标签内注入攻击
攻击者利用现有JavaScript代码,通过注入特殊字符中断原有逻辑并插入恶意代码。
📝 原始安全代码
var userInput = '用户输入内容';
document.write('欢迎:' + userInput);
🎯 攻击载荷
'; alert('XSS'); //
📝 代码变异过程
// 原始安全代码
var userInput = '用户输入内容';
document.write('欢迎:' + userInput);// 攻击者输入:'; alert('XSS'); //
var userInput = ''; alert('XSS'); //';
document.write('欢迎:' + userInput);// 最终执行代码
var userInput = '';
alert('XSS'); //'; document.write('欢迎:' + userInput);
⚙️ 攻击技术分析
-
单引号 (
'
):终止原有字符串 -
分号 (
;
):结束当前语句 -
恶意代码:插入攻击载荷
-
注释符 (
//
):注释掉后续代码
1.1.3 防御策略
✅ HTML上下文防护
-
实施HTML编码:转换
< > & " '
等特殊字符 -
使用安全API:
textContent
代替innerHTML
-
启用CSP(内容安全策略)
✅ JavaScript上下文防护
-
实施JavaScript编码
-
使用JSON序列化处理数据
-
避免使用
eval()
和new Function()
🔧 通用防护措施
防护层 | 实施方法 |
---|---|
输入验证 | 白名单过滤,长度限制 |
输出编码 | 上下文相关编码 |
安全框架 | 使用现代前端框架 |
安全审计 | 定期代码安全检查 |
💡 关键安全实践
HTML编码:
// HTML编码
function encodeHTML(str) {return str.replace(/[&<>"']/g, function(match) {return {'&': '&','<': '<','>': '>','"': '"',"'": '''}[match];});
}
JavaScript编码:
// JavaScript编码
function encodeJS(str) {return str.replace(/[\\'"{};]/g, '\\$&');
}
1.2 存储型XSS攻击详解(WordPress插件为例)
本次分析针对WordPress的Visitors插件中存在的一个存储型XSS漏洞,攻击者可以通过篡改User-Agent头注入恶意脚本,当管理员查看访问记录时自动执行。
Visitors插件的主要功能是:记录网站的访问者数据,包括IP、来源和用户代理(User-Agent)字段。
🔍漏洞发现思路
组件 | 文件 | 漏洞类型 | 风险等级 |
---|---|---|---|
数据收集页面 | database.php | 未过滤输入 | 🔴 高危 |
数据展示页面 | start.php | 未编码输出 | 🔴 高危 |
🔍 漏洞分析流程
1.2.1 分析代码寻找注入点
1.2.1.1 数据收集代码分析
从WordPress组件的网站去下载Visitors插件的源代码:
Visitors Online by BestWebSoft – WordPress 插件 | WordPress.org China 简体中文
然后,检查一系列源文件。当检查到database.php文件源代码时,考虑验证数据是如何存储在WordPress数据库中的:
function VST_save_record() {global $wpdb;$table_name = $wpdb->prefix . 'VST_registros';VST_create_table_records();return $wpdb->insert($table_name,array('patch' => $_SERVER["REQUEST_URI"],'datetime' => current_time( 'mysql' ),'useragent' => $_SERVER['HTTP_USER_AGENT'], // 重点看该字段,数据来源于HTTP请求。'ip' => $_SERVER['HTTP_X_FORWARDED_FOR']));
}
这个函数的主要作用是:将当前访问请求的一些信息(如请求的URI、当前时间、浏览器信息和IP地址)保存到WordPress数据库中的VST_registros表。这种功能通常用于:记录用户访问日志、进行分析或者审计等目的。
代码详细解释如下:
·global $wpdb;
global关键字使得函数能够访问WordPress的$wpdb对象,它是WordPress内置的数据库操作类,用于与WordPress数据库进行交互。
·$table_name = $wpdb->prefix . 'VST_registros';
拼接了一个数据库表名,$wpdb->prefix是WordPress中的表前缀,通常默认为wp_。所以如果表前缀是 wp_,则最终的表名会是 wp_VST_registros。
·VST_create_table_records();
这是一个函数调用,假设它的作用是创建名为VST_registros的数据库表。这个函数的具体实现不在当前代码中,但从名字可以推测它的作用是确保数据库中有一个适合保存记录的表。如果表不存在,它应该会创建表。
·$wpdb->insert(...)
insert() 方法用于将一条记录插入到数据库中。它接受两个参数:
第一个参数是表名,$table_name 变量存储了要插入数据的表。
第二个参数是一个关联数组,包含要插入的字段和对应的值:
'patch' 存储的是当前请求的URI(即用户访问的页面路径),从 $_SERVER["REQUEST_URI"] 中获取。
'datetime' 存储当前的时间,使用 current_time('mysql') 来获取MySQL格式的时间。
'useragent' 存储用户的浏览器信息,来自 $_SERVER['HTTP_USER_AGENT']。
'ip' 存储用户的IP地址,来自 $_SERVER['HTTP_X_FORWARDED_FOR']。需要注意的是,HTTP_X_FORWARDED_FOR 是一个代理服务器传递的用户原始IP地址,但并不一定总是可靠,因为它可以被伪造。
·return $wpdb->insert(...);
最后,函数返回wpdb->insert()的结果。insert()方法会返回一个布尔值,表示插入是否成功。true表示成功,false表示失败。
重点关注:'useragent' => $_SERVER['HTTP_USER_AGENT'], 从HTTP请求中的USER_AGENT字段直接获取数据,并未对数据进行过滤。因此,判断此处可以尝试进行XSS注入。
1.2.1.2 前端展示代码分析
因为在database.php文件源代码中,获取的字段入库时没有进行数据过滤。接下来,每当WordPress管理员加载Visitors插件时,从start.php开始,函数将执行以下代码段:
$i=count(VST_get_records($date_start, $date_finish));
foreach(VST_get_records($date_start, $date_finish) as $record) {echo '<tr class="active" ><td scope="row" >'.$i.'</td><td scope="row" >'.date_format(date_create($record->datetime),
get_option("links_updated_date_format")).'</td><td scope="row" >'.$record->patch.'</td><td scope="row" ><a href="https://www.geolocation.com/es?ip='.$record-
>ip.'#ipresult">'.$record->ip.'</a></td><td>'.$record->useragent.'</td> // ❌ 直接输出useragent变量内容,未编码</tr>';$i--;
}
代码详细解释如下:遍历VST_get_records()函数获取的记录,每个记录会在HTML表格中显示,并且在表格中的每行输出一个倒序编号i,记录的日期、补丁、IP地址和用户代理等信息。IP地址被嵌入到一个指向地理位置查询页面的链接中。
HTML页面输出示例:
根据代码逻辑,输出的HTML 表格的每一行形如所示:
浏览器页面输出示例:
【分析】:
·useragent记录值是从数据库中检索出来的;
·数据库的useragent来自database.php中 $_SERVER['HTTP_USER_AGENT']收集的;
·$_SERVER['HTTP_USER_AGENT']是来自用户使用的浏览器请求头的字段。
这个过程中,数据是直接插入到表格数据(td)的HTML标签中,没有任何形式的数据消毒。
!!!由于useragent的内容是由用户发送来的,因此考虑:
通过BP来重放包之前,构造用户请求头的HTTP_USER_AGENT的值,比如可以通过插入一个调用alert()方法生成弹出消息的脚本标签来构造XSS攻击。
因为alert()方法具有弹框作用,具有直接的视觉效果,常用于验证应用程序是否容易受到XSS攻击。
1.2.2 攻击构造与利用
1.2.2.1 恶意User-Agent构造
将Burp配置为代理并禁用拦截,然后修改。
1.首先,使用Firefox浏览器访问http://offsecwp/,然后转到Burp Proxy >HTTP History,在请求上右键单击,然后选择Send to Repeater。
2.转到Repeater选项卡,将默认的User-Agent值替换为包含alert方法的脚本标签(<script> alert(42)</script>),然后发送Send请求。
3.确定注入数据库是否成功。
如果服务器以200 OK消息响应,说明执行成功。我们的payload现在存储在WordPress数据库中。
注意:在这个时候start.php源代码的内容由:
将变为:
,start.php代码发送回浏览器,并被执行的预期结果是:这个网页会弹出一个对话框,显示数字42!
1.2.2.2 验证XSS攻击是否成功
为了验证这一点,我们使用admin/password凭据登录到管理控制台 http://offsecwp/wp-login.php。
然后,导航到visitors插件控制台,也就是刚刚注入payload的start.php页面,网址为http://offsecwp/wp-admin/admin.php?page=visitors-app/admin/start.php,浏览器执行了返回的start.php代码。
我们会看到一个弹框,显示数字42,证明XSS代码注入成功。由于把XSS有效payload注入到Web应用程序的数据库中,因此是存储型XSS攻击。
任何管理员在加载start.php页面时,每次打开这个页面,都会出现弹框。(非管理员到不了start.php页面。)
1.2.3 数据流与攻击影响
🔄 漏洞利用链
💀 潜在危害
攻击类型 | 影响程度 | 业务风险 |
---|---|---|
管理员劫持 | 🔴 极高 | 完全控制网站 |
数据泄露 | 🔴 极高 | 用户信息泄露 |
恶意软件分发 | 🔴 高 | 感染访问者 |
SEO垃圾注入 | 🟡 中 | 搜索排名下降 |
1.2.4 修复方案
1.2.4.1 输入过滤与验证
// 修复后的database.php
$user_agent = sanitize_text_field($_SERVER['HTTP_USER_AGENT']);
$ip = filter_var($_SERVER['HTTP_X_FORWARDED_FOR'], FILTER_VALIDATE_IP);$wpdb->insert($table_name, array('useragent' => $user_agent, // ✅ 已过滤'ip' => $ip ? $ip : 'Invalid IP' // ✅ 已验证
));
- sanitize_text_field():WordPress 的函数,用于过滤输入值,确保其中没有潜在的恶意代码或不安全的字符。它会移除掉不必要的HTML 标签、脚本或危险字符,使得
$user_agent
变量变得更安全。 - filter_var():这个PHP函数用于验证和过滤数据。这里使用
FILTER_VALIDATE_IP
来检查$ip
是否是一个有效的IP地址。如果是有效 IP,$ip
将返回该 IP 地址;如果无效,则返回false
。 'ip' => $ip ? $ip : 'Invalid IP'
:如果$ip
是有效的 IP 地址,就将其插入;如果无效,则插入字符串'Invalid IP'
。这确保了即使无法获取有效的 IP 地址,也有一个占位值。
1.2.4.2 输出编码过滤
// 修复后的start.php
echo '<td>' . esc_html($record->useragent) . '</td>'; // ✅ 安全输出
esc_html()
:该函数用于将输出的字符串进行HTML 转义,防止 XSS 攻击(即防止恶意代码通过浏览器执行)。这确保输出内容在浏览器中安全显示,避免潜在的跨站脚本攻击。
1.2.4.3 其他防御措施
-
实施内容安全策略(CSP)
-
启用HTTPOnly和Secure Cookie标志
-
定期安全审计和代码审查
-
使用Web应用防火墙(WAF)
💥创作不易💥求一波暴击👉点赞❤️ 关注🔔 收藏⭐️ 评论💬
您的支持是我创作最大的动力!