taibeihacker
Moderator
NTLM Relay
1 NTLM 协议
1.1 简介
NTLM 協議是一個在微軟環境中使用的認證協議。該協議允許用戶向服務器證明其身份,以便使用該服務器提供的服務。
有兩種認證的場景:
工作組環境
用戶使用服務器本地帳戶的密鑰。由於服務器在其本地數據庫中擁有用戶的密鑰,能夠對用戶進行身份驗證;
域環境
在Active Directory 環境中,用戶在身份驗證期間使用域帳戶,在這種情況下,服務器將向域控發送用戶的認證信息。
在這兩種情況下,NTLM 認證始於客戶和服務器之間的「挑戰/響應」機制。
1.2 挑战 - 响应认证机制
挑戰/響應機制的目的是為了讓服務器驗證用戶的身份,且不通過網絡傳輸用戶密碼。整個認證過程有三步。协商 - Negotiation - type1客戶端向服務端發送認證請求(NEGOTIATE_MESSAGE)
挑战 - Challenge - type2服務端向客戶端發送64 位的隨機值(CHALLENGE_MESSAGE)
响应 - Response - type3客戶端使用其用戶的NT Hash 值對Challenge 進行加密,並將結果返回給服務端

下圖為1 次NTLM 認證過程:

為了完成身份驗證,服務器只需要檢查客戶端發送的響應的有效性。
1.3 认证
NT Hash 的計算:先將用戶密碼轉換為十六進制格式。
將十六進制格式的密碼進行Unicode 編碼。
使用MD4 摘要算法對Unicode 編碼數據進行Hash 計算
1
python2 -c 'import hashlib,binascii; print binascii.hexlify(hashlib.new('md4', 'p@Assword!123'.encode('utf-16le')).digest())'
如前文所述,NTLM 認證有兩種不同的場景。
1.3.1 本地账户
在使用本地帳戶完成身份驗證的場景下,服務器使用用戶的密鑰或用戶密鑰的MD4 散列(NT Hash)對其發送給客戶端的Challenge 進行加密。 然後它會檢查它的操作結果是否等於客戶端的響應,證明用戶身份。服務器需要存儲本地用戶及其密碼的哈希值。 此數據庫的名稱是SAM(安全帳戶管理器)。 SAM 可以在註冊表中找到,可以使用psexec 以SYSTEM 身份打開它:
1
psexec.exe -i -s regedit.exe

在C:\Windows\System32\SAM 下也有一份拷貝。
總結下工作組下的認證流程:

服務器發送一個Challenge(1)並且客戶端使用其密鑰的哈希值加密該質詢,然後使用其用戶對應的NT Hash 加密Challenge 並將其發送回服務器(2)。服務器將在其SAM 中查找用戶密碼的哈希值(3), 並加密之前用這個散列發送的Challenge(4),並將其結果與用戶返回的結果進行比較。 如果相同(5)則用戶已通過身份驗證,否則,認證失敗。
1.3.2 域账户
當用域帳戶進行認證時,用戶的NT Hash 不再存儲在服務器上,而是存儲在域控制器上。用戶要認證的服務器會收到客戶端對Challenge 加密的響應報文,但它不能檢查該響應是否有效,因此,服務端需要把驗證身份的任務委託給域控制器。為此,在服務端與域控進行通信時,使用了Netlogon 服務,該服務能夠與域控制器建立安全會話,被稱為安全通道(Secure Channel)。由於服務器知道自己的密鑰,而域控制器知道服務器密鑰的哈希,服務端與域控之間可以交換會話密鑰並安全地通信。
客戶端向域控發送NETLOGON_NETWORK_INFO,其中主要包括:
1
2
3
4
5
6
7
typedef struct _NETLOGON_NETWORK_INFO {
NETLOGON_LOGON_IDENTITY_INFO Identity;
LM_CHALLENGE LmChallenge;
STRING NtChallengeResponse;
STRING LmChallengeResponse;
} NETLOGON_NETWORK_INFO,
*PNETLOGON_NETWORK_INFO;
客戶端用戶名(Identity)
服務端向客戶端發送的Challenge (LmChallenge)
客戶端向服務端發送的Response (NtChallengeResponse)
域控將在其數據庫中查找對應用戶的NT Hash。對於域控制器,用戶的數據被存儲在NTDS.DIT 的文件中。一旦檢索到NT Hash,計算Challenge 的加密值,並將此結果與客戶端的響應進行比較。
總結下域環境下的認證流程:

和之前的情況類似,服務器發送一個挑戰(1),客戶端jsnow 用NT Hash 加密,並將它連同它的用戶名和域名(2)一起發送回服務器。服務器將使用Netlogon 服務(3)將此信息發送到安全通道中的域控制器。域控制器在其NTDS.DIT 數據庫(4)中找到用戶散列來加密Challenge,然後將兩個結果進行比較。如果是相同的(5),則用戶已通過身份驗證。 否則認證失敗。在這兩種情況下,域控制器都會將信息傳輸到服務器(6)。
2 NTLM Relay
2.1 几种 Hash
為了避免混淆,總結下相關Hash 的名詞:NT Hash 和LM Hash 是用戶密碼的散列版本。 LM Hash 已經完全過時,本文不再討論。 NT Hash 通常又被稱為NTLM Hash。此名稱與協議名稱NTLM 存在混淆。因此,當談論用戶的密碼哈希時,將其稱為NT Hash。
NTLM 是身份驗證協議的名稱。目前有兩個版本的NTLM 協議。
NTLMv1 響應和NTLMv2 響應將是用於指代客戶端發送的Challenge 響應的術語,適用於NTLM 協議的版本1 和2。
Net-NTLMv1 和Net-NTLMv2 是當NT Hash 稱為NTLM 哈希時使用的偽新術語,用於將NTLM Hash與協議區分開來。由於我們不使用NTLM Hash 術語,因此不會使用這兩個術語。
Net-NTLMv1 Hash 和Net-NTLMv2 Hash 也是避免混淆的術語,但也不會在本文中使用。
2.2 简介
顧名思義,NTLM Relay 攻擊依賴於NTLM 身份驗證。攻擊存在下面的場景中:攻擊者設法在客戶端和服務器之間處於中間人的位置,並簡單地將信息從一端轉發到另一端。中間人的位置意味著:從客戶端的角度來看,攻擊者的機器是他想要認證的服務器,而從服務器的角度來看,攻擊者是一個像其他想要認證訪問資源的客戶端。
當然,攻擊者並不只是想對目標服務器進行認證,而是偽造成受害的用戶身份來控制服務端。但是,由於攻擊者不知道用戶的密鑰,即使他監聽了對話,由於這個密鑰從未在網絡上傳輸,攻擊者也無法提取任何信息。那麼,它是如何工作的呢?
2.3 消息中继
在NTLM 認證過程中,客戶用其NT Hash 加密服務器提供的Challenge 來向服務器證明其身份。因此,攻擊者唯一要做的就是讓客戶端做好加密,並把信息從客戶端傳給服務器,以及把服務器的回复傳給客戶端。客戶端向服務器發送的所有信息,攻擊者都會收到,並把信息重放給真正的服務器。而服務器向客戶發送的所有信息,攻擊者也會收到,並將其原封不動的轉發給客戶端。

實際上,從客戶的角度來看,在圖的左側,攻擊者和它之間進行了NTLM 身份驗證。 客戶端在其第一條消息中發送協商請求,攻擊者以Challenge 回复該請求。 收到此Challenge 後,客戶端使用其密鑰構建Response,並最終發送包含加密質詢的最後一條身份驗證消息。
但是,攻擊者不能用這個交換做任何事情。因此,需要思路轉向上圖的右半邊。實際上,從服務器的角度來看,攻擊者是一個和其它用戶一樣的客戶端。它發送了第一條消息要求認證,而服務器用挑戰來回應。由於攻击者向真正的客户发送了这个同样的 Challenge,真正的客戶端用它的密钥对这个挑战进行了加密,並以一個有效的响应進行回复。因此,攻擊者可以向服務器發送這個有效的響應。
這就是攻擊的點所在。從服務器的角度來看,它不知道攻擊者正在向客戶重放其信息。
因此,從服務器的角度來看,這就是所發生的事情:

在這些交換結束時,攻擊者在服務器上使用客戶端的憑據進行身份驗證。
2.4 Net-NTLMv1 and Net-NTLMv2
攻擊者在type 3 中轉發的這個有效響應,通常稱為Net-NTLMv1 Hash 或Net-NTLMv2 Hash。 但在本文中,它將被稱為NTLMv1 響應或NTLMv2 響應,如前文所述。確切地說,這並不是Challenge 的加密版本,而是使用客戶端密鑰計算出的哈希值。 以NTLMv2 為例,NTLMv2 Hash=HMAC-MD5(unicode(hex(upper(username+domain))), NT Hash),這種類型的哈希只能用暴力破解。
3 实战
IP 地址為192.168.56.221 的DESKTOP01 客戶端和IP 地址為192.168.56.211 的WEB01 服務器。 IP 地址為192.168.56.1 為中間人。攻擊場景如下:
使用impacket 包中的ntlmrelayx 進行攻擊。
1
python ntlmrelayx.py -t 192.168.56.221
網絡流量如下:

綠色的是DESKTOP01 客戶端和攻擊者之間的流量,紅色是攻擊者和WEB01 服務器之間的流量。 可以清楚地看到DESKTOP01 和攻擊者之間以及攻擊者和WEB01 服務器之間的3 條NTLM 消息。
為了理解中繼的概念,通過驗證當WEB01 向攻擊者發送質詢時,攻擊者向DESKTOP01 發送回完全相同的內容。
這是WEB01 向攻擊者發送的Challenge:

當攻擊者收到這個挑戰時,它不加任何修改地將其發送到DESKTOP01。 在上面的過程中,Challenge 值是b6515172c37197b0。
然後客戶端將使用它的密鑰來計算響應,將計算好的響應值連同用戶名(jsnow)、主機名(DESKTOP01) 一起發送,在這個例子中是一個域用戶,因此主機名是本域的域名(ADSEC)。

得到Response 的攻擊者將完全相同的信息發送到服務器。於是中間人冒充了DESKTOP01 上的jsnow,是ADSEC 域的域用戶,它還發送了客戶端計算出來的響應,在這些截圖中稱為NTLM 響應。將此響應稱為NTLMv2 Hash。
從流量上可以看到,攻擊者只是在轉發數據。 它只是將客戶端的信息轉發給服務器,反之亦然,只不過最後服務器認為攻擊者認證成功,然後攻擊者就可以代表ADSEC\jsnow 在服務器上執行操作。
4 认证与会话
上文闡述了NTLM 中繼的基本原理,接下來出現的問題是,在中繼NTLM 身份驗證後,如何在目標服務器上執行具體地操作?要回答這個問題,必須首先澄清一個基本的事實。當客戶端向服務器進行身份驗證以執行某些操作時,必須區分兩件事:
身份驗證(Authentication),允許服務器驗證客戶端是它聲稱的身份。
會話(Session),在此期間客戶端將能夠執行操作。
如果客戶端通過了正確的身份驗證,那麼它將能夠訪問服務器提供的資源,例如網絡共享、對LDAP 目錄的訪問、HTTP 服務器或SQL 數據庫等等。
為了管理這兩個步驟,所使用的協議必須能夠封裝身份驗證,從而交換NTLM 消息。

如果所有協議都集成NTLM 技術細節,是不符合軟件工程中的解耦思想的。因此,微軟提供了一個接口來處理身份驗證,並且專門開發了包來處理不同類型的身份驗證。
4.1 SSPI NTLNSSP
SSPI 接口(Security Support Provider Interface)是Microsoft 提出的用於標準化身份驗證的接口,不同的協議都可以使用這個接口來處理不同類型的身份驗證過程。在NTLM 認證中,使用的是NTLMSSP(NTLM 安全支持提供程序)。SSPI 接口提供了幾個函數,包括AcquireCredentialsHandle、InitializeSecurityContext 和AcceptSecurityContext。在NTLM 身份驗證期間,客戶端和服務器都會使用到這些函數。簡述這些步驟:
客戶端調用AcquireCredentialsHandle 獲得對用戶憑據的間接訪問。
客戶端然後調用InitializeSecurityContext,該函數在第一次調用時將創建類型為NEGOTIATE 的type 1 消息。對於研發來說,這條消息是什麼並不重要,重要的是將它發送到服務器。
服務器在收到消息時調用AcceptSecurityContext 函數。 這個函數然後將創建類型為Challange 的type 2 數據。
收到此消息時,客戶端將再次調用InitializeSecurityContext,但這次將CHALLENGE 作為參數傳遞。 NTLMSSP 負責通過加密Challenge 來計算響應的內容,並生成最後的AUTHENTICATE 消息。
服務器收到該消息後,也會再次調用AcceptSecurityContext,自動進行鑑權驗證。

這意味著這5 個步驟完全獨立於客戶端的類型或服務器的類型。 無論使用何種協議,只要該協議具有允許這種不透明結構,以一種或另一種方式從客戶端交換到服務器的內容,它們就可以工作。

因此,協議通過將NTLMSSP、Kerberos 或其他身份驗證結構放入特定字段,如果客戶端或服務器看到該字段中有數據,它只會將其傳遞給InitializeSecurityContext 或AcceptSecurityContext。
應用層(HTTP、SMB、SQL 等)完全獨立於身份驗證層(NTLM、Kerberos 等)。 因此,認證層和應用層都需要安全措施。
通過SMB 和HTTP 的兩個示例幫助讀者更好地理解。其它協議也十分相似。
4.2 HTTP NTLM
一個HTTP 的基本請求:1
2
3
4
5
GET /index.html HTTP/1.1
Host: www.geekby.site
User-Agent: Mozilla/5.0
Accept: text/html
Accept-Language: zh-cn
此示例中的必需元素是HTTP 動詞(GET)、請求頁面的路徑(/index.html)、協議版本(HTTP/1.1) 或主機標頭(Host: beta.hackndo.com)。
但是可以還添加其它的HTTP 頭。最好的情況是,服務器知道這些標頭會存在,並且知道如何處理。最壞的情況是直接忽略。
正是HTTP 的此項特性,能夠將NTLM 的相關信息從客戶端傳輸到服務器。即在客戶端添加Authorization 的HTTP 頭,在服務端添加一個WWW-Authenticate 的頭。如果客戶端嘗試訪問需要身份驗證的網站,服務器將通過添加WWW-Authenticate 標頭來響應,內容包含其支持的不同身份驗證機制。如對於NTLM,返回:WWW-Authenticate: NTLM。
客戶端知道需要NTLM 身份驗證,將發送Authorization 頭中的第一條消息,並base64 編碼(因為該消息僅包含不可打印的字符)。 服務器將在WWW-Authenticate 填充Challenge,客戶端將計算響應並將其放到Authorization 頭中。如果認證成功,服務器通常會返回200 返回碼。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
GET /index.html HTTP/1.1
Host: www.geekby.site
User-Agent: Mozilla/5.0
Accept: text/html
Accept-Language: en
HTTP/1.1 401 Unauthorized
WWW-Authenticate: NTLM
Content type: text/html
Content-Length: 0
GET /index.html HTTP/1.1
Host: www.geekby.site
User-Agent: Mozilla/5.0
Accept: text/html
Accept-Language: zh-ch
=Authorization: NTLM NEGOTIATE in base64
HTTP/1.1 401 Unauthorized
=W