之前搞了一个论坛来出 xss 的题目 <del> 本意其实是方便以后搞 SQL 注入的时候可以复用 </del>

不过当时使用 flask 来写的,并且并不是在标签之内的地方,所以现在加 waf 时有有些问题:

首先想到的过滤当然是黑名单,因为这样最不安全,于是有:

def fil(raw):
    replace={
        'script': 'scr_ipt',
        'href': 'hr_ef',
        'on': 'o_n',
        'src': 'sr_c'
    }
    for old,new in replace.items():
        pattern = re.compile(re.escape(old),re.IGNORECASE)
        raw =pattern.sub(new,raw)
        raw = raw.replace('&', '$').replace('\\', '/').replace("%", "%*1")
    filtered=raw
    return filtered

主要是防止了大小写绕过,html 实体,以及使用 unicode 之类的绕过

以及 script,on,src,href 这些较为常见的标签或者属性(的一部分)

最开始的思路其实是希望使用 base64 编码绕过:

<iframe src="data:text/html;base64,payload">

但是实际上由于浏览器的同源策略,即使使用 parent 或者 top,跳转也是不生效的。随后为了防止这种情况,单独设置了 CSP:Origin="*"。不过实际上现在的浏览器即使是设置后的,在跳转时依旧会给用户提醒,决定是否跳转。这使得正常情况下 bot 并不会跳转到指定页面。

考虑到各种限制条件,以及我们学习到的绝大多数 xss 漏洞都是基于 php 的,而非 python,尤其还是对这些较为成熟的框架,只有在很特殊的情况下才可能 xss(比如属性注入时 html 中没有加引号,这使得攻击者完全不需要任何会被转义的特殊字符)这不在我们的讨论范围内。
当然由于获取 flag 的条件十分固定,所以即使出成这样依旧可解:

<meta http-equiv=refresh content=0;url=http://www.baidu.com>

但是这并不是我们的目的

随后极大的降低了难度:

def fil(raw):
    raw=raw.lower()
    replace={
        '.': '',
        'script':'scr_ipt',  #使用 onerror 等执行 js
    }
    for old,new in replace.items():
        pattern = re.compile(re.escape(old),re.IGNORECASE)
        raw =pattern.sub(new,raw)
    raw = raw.replace('&', '$').replace('\\', '/').replace("%", "%*1")
    filtered=raw
    return filtered

在网上随便看的时候,偶然发现其实浏览器会把 url 中的。自动转为。作为一个简单的绕过。不过这依旧很容易就能从 ai 处得到答案。

没辙,最后只能随便加点东西了,疲了:

def fil(raw):
    replace={
        " ": 'N O?',
        "href": 'N O!',
        'on': "Y E S!",
        'script': 'Y E S?',
        'src': 'Y E S',
        '.': 'N O',
        "+" : "N O.",
        "-" : "Y E S.",
        "meta":"YOU CANT DO THAT"
    }
    raw=raw.lower()
    for old,new in replace.items():
        pattern = re.compile(re.escape(old))
        raw =pattern.sub(new,raw)
    filtered = raw.replace('&', 'NO').replace('\\', 'YES').replace("%", "???")
    return filtered

期望的答案,只是示例,思路类似即可:

<textarea/**/name=.nfocus="a='locatio';eval(`${a}n='https://www。baidu。com'`)"/**/autofocus>

用过滤时的 N O 接出需要的 on 属性(需要通过随便加一个无关属性吸收掉前面的 N),然后就是简单的空格绕过,以及在属性的内容时可以使用 js 的语法来桡过对 loaction 中 on 的限制,最后输入网址时使用。代替。利用浏览器特性跳转到目标网页。

这道题最后还附赠了个垂直越权,只对 post 路由进行了鉴权,但是仍然可以通过 edit_post 来查看内容(把上一题的 edit_post 的鉴权稍加修改直接搬运过来)