自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

深入剖析HashiCorp Vault中的身份驗(yàn)證漏洞(上篇)

安全 漏洞
在這篇文章中,我們將為讀者深入講解HashiCorp Vault中的兩個(gè)身份驗(yàn)證漏洞。

[[346414]]

簡(jiǎn)介

在這篇文章中,我們將為讀者深入講解HashiCorp Vault中的兩個(gè)身份驗(yàn)證漏洞。實(shí)際上,我們不僅會(huì)介紹這兩個(gè)漏洞的利用方法,同時(shí),還會(huì)演示如何在“云原生”軟件中找到這種類型的安全漏洞。這兩個(gè)漏洞(CVE-2020-16250/16251)均已得到了HashiCorp公司的妥善處理,并在8月份發(fā)布的1.2.5,1.3.8,1.4.4和1.5.1版本Vault中進(jìn)行了修復(fù)。

Vault是一種廣泛使用的工具,用于安全地存儲(chǔ)、生成和訪問API密鑰、密碼或證書等機(jī)密信息。盡管它也能夠用作人類用戶的共享密碼管理器,但是它的功能卻主要是針對(duì)基于API的訪問進(jìn)行優(yōu)化的。Vault的應(yīng)用場(chǎng)景包括為某些服務(wù)(Web服務(wù)器、數(shù)據(jù)庫或第三方資源(如AWS S3 bucket)等)提供臨時(shí)的登錄憑據(jù)。

使用像Vault這樣的中心化機(jī)密信息存儲(chǔ)設(shè)施能夠帶來許多安全優(yōu)勢(shì),例如集中審計(jì),強(qiáng)制憑證輪換或加密數(shù)據(jù)存儲(chǔ)。然而,對(duì)于攻擊者來說,中心化的機(jī)密信息存儲(chǔ)也是一個(gè)非常值得關(guān)注的攻擊目標(biāo)——一旦得手,攻擊者就能訪問各種重要的機(jī)密信息,從而可以訪問大部分的目標(biāo)基礎(chǔ)設(shè)施。

在深入研究這些漏洞的技術(shù)細(xì)節(jié)之前,下一節(jié)將概述Vault的身份驗(yàn)證架構(gòu)及其與云提供商集成的方式。熟悉Vault的讀者可以跳過本節(jié)。

基于Vault的身份驗(yàn)證架構(gòu)

與Vault進(jìn)行交互時(shí),首先需要進(jìn)行身份驗(yàn)證;Vault支持基于角色的訪問控制,以管理對(duì)存儲(chǔ)的機(jī)密信息的訪問權(quán)限。在身份驗(yàn)證方面,它支持可插拔的auth方法,范圍從靜態(tài)憑證、LDAP或Radius到完全集成到第三方OpenID Connect (OIDC)提供商或云身份訪問管理(IAM)平臺(tái)。對(duì)于在支持的云提供商上運(yùn)行的基礎(chǔ)設(shè)施來說,使用云提供商的IAM平臺(tái)進(jìn)行身份驗(yàn)證是一個(gè)非常合乎邏輯的選擇。

下面,我們將以AWS為例進(jìn)行介紹。我們知道,幾乎每一個(gè)在AWS中運(yùn)行的工作負(fù)載都是以特定的AWS IAM用戶的身份來執(zhí)行的。通過啟用和配置aws auth方法,您可以在某些IAM用戶或角色與Vault角色之間創(chuàng)建相應(yīng)的映射。

想象一下,如果您有一個(gè)AWS Lambda函數(shù),并希望讓它訪問存儲(chǔ)在Vault中的數(shù)據(jù)庫密碼。Vault管理員可以使用vault CLI為Lambda函數(shù)的執(zhí)行角色分配一個(gè)vault角色,而不是在函數(shù)代碼中存儲(chǔ)硬編碼的憑證。

  1. vault write auth/aws/role/dbclient auth_type=iam \ 
  2.   
  3. bound_iam_principal_arn=arn:aws:iam::123456789012:role/lambda-role policies=prod,dev max_ttl=10m 

這將在名為dbclient的vault角色和AWS IAM角色lambda-role之間創(chuàng)建一個(gè)映射。這樣,就可以通過vault策略來授予dbclient角色對(duì)數(shù)據(jù)庫秘密的訪問權(quán)了。

當(dāng)lambda函數(shù)執(zhí)行時(shí),它通過向/v1/auth/aws/login API端點(diǎn)發(fā)送請(qǐng)求,以通過Vault進(jìn)行身份驗(yàn)證。我將在后面介紹這個(gè)請(qǐng)求的具體結(jié)構(gòu),但現(xiàn)在只是假設(shè)該請(qǐng)求允許Vault驗(yàn)證調(diào)用者的AWS IAM角色。如果驗(yàn)證成功,Vault會(huì)將dbclient角色的臨時(shí)API令牌返回給lambda函數(shù)?,F(xiàn)在,就可以使用該令牌從Vault獲取數(shù)據(jù)庫密碼了。根據(jù)數(shù)據(jù)庫后端的不同,這個(gè)密碼可以是一個(gè)靜態(tài)的用戶密碼組合,一個(gè)臨時(shí)的客戶端證書,甚至是一個(gè)動(dòng)態(tài)創(chuàng)建的證書對(duì)。

以這種方式使用Vault有一些不錯(cuò)的安全優(yōu)勢(shì):lambda函數(shù)本身不需要包含引導(dǎo)憑證,而且每次訪問數(shù)據(jù)庫的憑證都是可以審計(jì)的。輪換舊的或被破壞的數(shù)據(jù)庫憑證非常簡(jiǎn)單,并且可以集中執(zhí)行。

然而,這種操作上的簡(jiǎn)單性,完全是將復(fù)雜性隱藏在AWS iam auth方法中結(jié)果。那么,/v1/auth/aws/login API端點(diǎn)究竟是如何工作的,未經(jīng)認(rèn)證的攻擊者是否有辦法冒充隨機(jī)的AWS IAM角色呢?

sts:GetCallerIdentity

在其內(nèi)部,Vault的aws auth方法支持兩種不同的認(rèn)證機(jī)制:iam和ec2。在這里,我們感興趣的是iam,我們之前的Lambda示例中曾用過該機(jī)制。Iam認(rèn)證機(jī)制是建立在名為GetCallerIdentity的AWS API方法之上的,它是AWS安全令牌服務(wù)(STS)的一部分。

顧名思義,GetCallerIdentity將返回IAM角色或用戶的詳細(xì)信息,其憑證被用于調(diào)用API。要了解Vault如何使用該方法對(duì)客戶進(jìn)行身份驗(yàn)證,我們需要了解AWS API如何進(jìn)行身份驗(yàn)證的。

AWS不是將某種形式的身份驗(yàn)證令牌或憑據(jù)附加到API請(qǐng)求中,而是要求客戶端使用調(diào)用者的秘密訪問密鑰為(規(guī)范化的)請(qǐng)求計(jì)算HMAC簽名,并將此簽名附加到請(qǐng)求中。這種機(jī)制使得預(yù)先對(duì)請(qǐng)求進(jìn)行簽名并將其轉(zhuǎn)發(fā)給另一方,從而實(shí)現(xiàn)一定程度的身份冒充成為可能。一個(gè)流行的用例是,賦予客戶端S3的文件上傳權(quán)限,而無需授予他們?cè)L問具有寫權(quán)限的憑據(jù)的權(quán)限。

實(shí)際上,Vault aws認(rèn)證機(jī)制就是這種技術(shù)的一個(gè)簡(jiǎn)單變體。 

客戶端向STS GetCallerIdentity方法預(yù)先對(duì)一個(gè)HTTP請(qǐng)求進(jìn)行簽名,并將其序列化版本發(fā)送給Vault服務(wù)器。Vault服務(wù)器將預(yù)簽名的請(qǐng)求發(fā)送到STS主機(jī),并從結(jié)果中提取AWS IAM信息。這個(gè)流程的服務(wù)器端部分是由builtin/credential/aws/path_login.go文件的pathLoginUpdate函數(shù)實(shí)現(xiàn)的。

  1. func (b *backend) pathLoginUpdateIam(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { 
  2.   
  3.     method := data.Get("iam_http_request_method").(string) 
  4.   
  5.     ... 
  6.   
  7.     // In the future, might consider supporting GET 
  8.   
  9.     if method != "POST" { 
  10.   
  11.             return logical.ErrorResponse(...), nil 
  12.   
  13.     } 
  14.   
  15.     rawUrlB64 := data.Get("iam_request_url").(string) 
  16.   
  17.     ... 
  18.   
  19.     rawUrl, err := base64.StdEncoding.DecodeString(rawUrlB64) 
  20.   
  21.     ... 
  22.   
  23.     parsedUrl, err := url.Parse(string(rawUrl)) 
  24.   
  25.     if err != nil { 
  26.   
  27.             return logical.ErrorResponse(...), nil 
  28.   
  29.     } 
  30.   
  31.     bodyB64 := data.Get("iam_request_body").(string) 
  32.   
  33.     ... 
  34.   
  35.     bodyRaw, err := base64.StdEncoding.DecodeString(bodyB64) 
  36.   
  37.     ...        
  38.   
  39.     body := string(bodyRaw) 
  40.   
  41.     headers := data.Get("iam_request_headers").(http.Header) 
  42.   
  43.     
  44.   
  45.     endpoint := "https://sts.amazonaws.com" 
  46.   
  47.     ... 
  48.   
  49.     callerID, err := submitCallerIdentityRequest(ctx, maxRetries, method, endpoint, parsedUrl, body, headers) 

該函數(shù)從存儲(chǔ)在數(shù)據(jù)中的請(qǐng)求正文中提取HTTP方法、URL、正文和標(biāo)頭。然后調(diào)用submitCallerIdentity將請(qǐng)求轉(zhuǎn)發(fā)到STS服務(wù)器,并利用ParseGetCallerIdentityResponse來獲取和解析結(jié)果:

  1. func submitCallerIdentityRequest(ctx context.Context, maxRetries int, method, endpoint string, parsedUrl *url.URL, body string, headers http.Header) (*GetCallerIdentityResult, error) { 
  2.   
  3.     ... 
  4.   
  5.     request := buildHttpRequest(method, endpoint, parsedUrl, body, headers) 
  6.   
  7.     retryableReq, err := retryablehttp.FromRequest(request) 
  8.   
  9.     ... 
  10.   
  11.     response, err := retryingClient.Do(retryableReq) 
  12.   
  13.     responseBody, err := ioutil.ReadAll(response.Body) 
  14.   
  15.     ... 
  16.   
  17.     if response.StatusCode != 200 { 
  18.   
  19.             return nil, fmt.Errorf(..) 
  20.   
  21.     } 
  22.   
  23.     callerIdentityResponse, err := parseGetCallerIdentityResponse(string(responseBody)) 
  24.   
  25.     if err != nil { 
  26.   
  27.             return nil, fmt.Errorf("error parsing STS response"
  28.   
  29.     } 
  30.   
  31.     return &callerIdentityResponse.GetCallerIdentityResult[0], nil 
  32.   
  33.   
  34.   
  35.   
  36. func buildHttpRequest(method, endpoint string, parsedUrl *url.URL, body string, headers http.Header) *http.Request { 
  37.   
  38.     ... 
  39.   
  40.     targetUrl := fmt.Sprintf("%s/%s", endpoint, parsedUrl.RequestURI()) 
  41.   
  42.     request, err := http.NewRequest(method, targetUrl, strings.NewReader(body)) 
  43.   
  44.     ... 
  45.   
  46.     request.Host = parsedUrl.Host 
  47.   
  48.     for k, vals := range headers { 
  49.   
  50.             for _, val := range vals { 
  51.   
  52.                     request.Header.Add(k, val) 
  53.   
  54.             } 
  55.   
  56.     } 
  57.   
  58.     return request 
  59.   

buildHttpRequest函數(shù)會(huì)根據(jù)用戶提供的參數(shù)創(chuàng)建一個(gè)http.Request對(duì)象,并使用硬編碼常量https://sts.amazonaws.com來構(gòu)建目標(biāo)URL。

如果沒有這個(gè)限制,我們可以簡(jiǎn)單地觸發(fā)對(duì)我們控制的服務(wù)器的請(qǐng)求,并返回調(diào)用者身份。

然而,由于完全缺乏對(duì)URL路徑、查詢、POST正文和HTTP標(biāo)頭的驗(yàn)證,所以這看起來仍然是一個(gè)非常有希望的攻擊面。下一節(jié)將介紹如何將這個(gè)安全缺陷變成一個(gè)認(rèn)證繞過漏洞。

STS(調(diào)用方)身份盜用

我們的目標(biāo)是欺騙Vault的submitCallerIdentityRequest函數(shù),使其返回一個(gè)攻擊者控制的調(diào)用方身份。實(shí)現(xiàn)這個(gè)目標(biāo)的方法之一是操縱Vault服務(wù)器,使其向我們控制的主機(jī)發(fā)送請(qǐng)求,從而繞過硬編碼的端點(diǎn)主機(jī)。通過查看buildHttpRequest方法的源代碼,我想到了兩種方法:

· 用于計(jì)算targetUrl的代碼,即targetUrl := fmt.Sprintf("%s/%s", endpoint, parsedUrl.RequestURI()) ,看起來在URL解析問題方面并不是很健壯。但是,嵌入偽造的用戶信息(https://sts.amazonaws.com/:foo@example.com/test)之類的技巧和類似的想法對(duì)健壯的Go URL解析器是行不通的。

· 即使Vault將始終創(chuàng)建一個(gè)指向硬編碼端點(diǎn)的HTTPS請(qǐng)求,攻擊者也可以完全控制Host http標(biāo)頭(request.Host = parsedUrl.Host)。如果STS API前面的負(fù)載平衡器根據(jù)Host標(biāo)頭做出路由決策的話,這可能就是一個(gè)問題,但針對(duì)STS主機(jī)的盲測(cè)并沒有取得成功。

在排除了簡(jiǎn)單的方法后,我們還有另一種方法可以使用。Vault并沒有限制URL查詢參數(shù)。這意味著,我們不僅可以創(chuàng)建GetCallerIdentity的預(yù)簽名請(qǐng)求,還可以對(duì)STS API的任何操作創(chuàng)建請(qǐng)求。STS支持8個(gè)不同的操作,但沒有一個(gè)操作能讓我們完全控制響應(yīng)。這時(shí),我開始感到沮喪,于是決定看看Vault的響應(yīng)解析代碼。

  1. func parseGetCallerIdentityResponse(response string) (GetCallerIdentityResponse, error) { 
  2.   
  3.         decoder := xml.NewDecoder(strings.NewReader(response)) 
  4.   
  5.         result := GetCallerIdentityResponse{} 
  6.   
  7.         err := decoder.Decode(&result) 
  8.   
  9.         return result, err 
  10.   
  11.   
  12. type GetCallerIdentityResponse struct { 
  13.   
  14.  XMLName                 xml.Name                 `xml:"GetCallerIdentityResponse"
  15.   
  16.  GetCallerIdentityResult []GetCallerIdentityResult `xml:"GetCallerIdentityResult"
  17.   
  18.  ResponseMetadata        []ResponseMetadata        `xml:"ResponseMetadata"
  19.   

我們可以看到,只要狀態(tài)代碼為200,就會(huì)對(duì)從STS接收到的每個(gè)響應(yīng)調(diào)用parseGetCeller IdentityResponse。該函數(shù)將使用Golang標(biāo)準(zhǔn)XML庫將XML響應(yīng)解碼成GetCallerIdentityResponse結(jié)構(gòu),如果解碼失敗則返回錯(cuò)誤。

這個(gè)代碼有一個(gè)容易被忽略的問題:Vault從未強(qiáng)制驗(yàn)證STS響應(yīng)是否為XML編碼。雖然STS響應(yīng)在默認(rèn)情況下是XML編碼的,但是對(duì)于發(fā)送Accept:Application/json HTTP標(biāo)頭的客戶端來說,它也能夠支持JSON編碼。

但是對(duì)于Vault來說,這就變成了一個(gè)安全問題,因?yàn)間o XML解碼器有一個(gè)驚人的特性:解碼器會(huì)悄悄地忽略預(yù)期的XML根之前和之后的非XML內(nèi)容。這意味著使用(JSON編碼的)服務(wù)器響應(yīng)(如‘{“abc” : “xzy}’)調(diào)用parseGetCallIdentityResponse函數(shù)將會(huì)成功,并返回一個(gè)(空的)CallIdentityResponse結(jié)構(gòu)。

小結(jié)

在本文中,我們?yōu)樽x者介紹了Vault的身份驗(yàn)證架構(gòu),以及冒用調(diào)用方身份的方法,在下一篇文章中,我們將繼續(xù)為讀者介紹利用Vault-on-GCP的漏洞的過程。

本文翻譯自:https://googleprojectzero.blogspot.com/2020/10/enter-the-vault-auth-issues-hashicorp-vault.html如若轉(zhuǎn)載,請(qǐng)注明原文地址。

 

責(zé)任編輯:姜華 來源: 嘶吼網(wǎng)
相關(guān)推薦

2020-10-17 10:44:24

漏洞

2021-07-19 10:10:15

身份驗(yàn)證漏洞Windows Hel

2022-05-19 14:39:41

VMware漏洞惡意攻擊

2014-09-12 09:58:45

2012-02-20 09:55:41

ibmdw

2010-09-06 11:24:47

CHAP驗(yàn)證PPP身份驗(yàn)證

2025-04-25 07:00:00

身份驗(yàn)證CISO無密碼

2010-01-07 17:41:19

VB.NET驗(yàn)證LDA

2010-07-17 00:57:52

Telnet身份驗(yàn)證

2023-11-30 13:13:14

2012-04-10 09:36:58

2014-10-30 09:14:28

2021-10-06 14:36:36

身份驗(yàn)證漏洞黑客

2011-02-21 10:54:45

2013-07-21 18:32:13

iOS開發(fā)ASIHTTPRequ

2022-06-05 00:15:31

驗(yàn)證身份網(wǎng)絡(luò)

2022-11-14 08:17:56

2024-08-06 16:00:06

2012-10-23 16:12:35

2010-11-30 15:31:38

SharePoint Kerberos
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)