Skip to content

Commit

Permalink
update legacy support
Browse files Browse the repository at this point in the history
  • Loading branch information
kmahyyg committed Jul 31, 2022
1 parent dd4392d commit 49ea283
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 92 deletions.
14 changes: 9 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
# mRemoteNG Decrypt

Use for Decrypt mRemoteNG v1.75+ Config. For v1.74 and lower, use Python version with `_legacy` suffix.
# Python Version

Usage: `python3 mremoteng_decrypt.py [-f FILE | -s STRING | -rf XML_FILE] [-p CUSTOM_PASSWORD] [-L IS_LEGACY]`

If version < v1.75, make sure you specify `-L true`.

# Java Version

Use for Decrypt mRemoteNG v1.75+ Config.

Usage: `java -jar <JAR FILE> <ENCRYPTED TEXT> [Custom Password]`

Expand All @@ -12,10 +20,6 @@ org.apache.commons.codec

org.bouncycastle

## Python Script

Usage: `python3 mremoteng_decrypt.py [-f FILE | -s STRING] [-p CUSTOM_PASSWORD]`

## Where's the file?

Carefully check the page.
132 changes: 94 additions & 38 deletions mremoteng_decrypt.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,47 +3,103 @@
import hashlib
import base64
from Cryptodome.Cipher import AES
from Cryptodome.Util.Padding import unpad
import argparse
import sys
import xml.etree.ElementTree as ET


def decrypt_legacy(encrypted_data, password):
try:
encrypted_data = encrypted_data.strip()
encrypted_data = base64.b64decode(encrypted_data)
initial_vector = encrypted_data[:16]
ciphertext = encrypted_data[16:]
key = hashlib.md5(password.encode()).digest()

cipher = AES.new(key, AES.MODE_CBC, initial_vector)
plaintext = unpad(cipher.decrypt(ciphertext), AES.block_size)
return plaintext
except Exception as e:
print("Failed to decrypt the password with the following error: {}".format(e))
return b''

def decrypt(encrypted_data, password):
try:
encrypted_data = encrypted_data.strip()
encrypted_data = base64.b64decode(encrypted_data)
salt = encrypted_data[:16]
associated_data = encrypted_data[:16]
nonce = encrypted_data[16:32]
ciphertext = encrypted_data[32:-16]
tag = encrypted_data[-16:]
key = hashlib.pbkdf2_hmac(
"sha1", password.encode(), salt, 1000, dklen=32)

cipher = AES.new(key, AES.MODE_GCM, nonce=nonce)
cipher.update(associated_data)
plaintext = cipher.decrypt_and_verify(ciphertext, tag)
return plaintext
except Exception as e:
print("Failed to decrypt the password with the following error: {}".format(e))
return b''


def main():
parser = argparse.ArgumentParser(description="Decrypt mRemoteNG passwords.")
group = parser.add_mutually_exclusive_group()
group.add_argument("-f", "--file", help="name of file containing mRemoteNG password")
group.add_argument("-s", "--string", help="base64 string of mRemoteNG password")
parser.add_argument("-p", "--password", help="Custom password", default="mR3m")

if len(sys.argv) < 2:
parser.print_help(sys.stderr)
sys.exit(1)

args = parser.parse_args()
encrypted_data = ""
if args.file != None:
with open(args.file) as f:
encrypted_data = f.read()
encrypted_data = encrypted_data.strip()
encrypted_data = base64.b64decode(encrypted_data)

elif args.string != None:
encrypted_data = args.string
encrypted_data = base64.b64decode(encrypted_data)

else:
print("Please use either the file (-f, --file) or string (-s, --string) flag")
sys.exit(1)

salt = encrypted_data[:16]
associated_data = encrypted_data[:16]
nonce = encrypted_data[16:32]
ciphertext = encrypted_data[32:-16]
tag = encrypted_data[-16:]
key = hashlib.pbkdf2_hmac("sha1", args.password.encode(), salt, 1000, dklen=32)

cipher = AES.new(key, AES.MODE_GCM, nonce=nonce)
cipher.update(associated_data)
plaintext = cipher.decrypt_and_verify(ciphertext, tag)
print("Password: {}".format(plaintext.decode("utf-8")))
parser = argparse.ArgumentParser(
description="Decrypt mRemoteNG passwords.")
if len(sys.argv) < 2:
parser.print_help(sys.stderr)
sys.exit(1)

group = parser.add_mutually_exclusive_group()
group.add_argument(
"-f", "--file", help="Name of file containing mRemoteNG password")
# Thanks idea from @KingKorSin
group.add_argument(
"-rf", "--realFile", help="Name of the Real mRemoteNG connections file containing the passwords")
group.add_argument(
"-s", "--string", help="base64 string of mRemoteNG password")
parser.add_argument("-p", "--password",
help="Custom password", default="mR3m")
parser.add_argument("-L", "--legacy", help="version <= 1.74", type=bool, default=False)
args = parser.parse_args()

decrypt_func = decrypt
if args.legacy:
decrypt_func = decrypt_legacy

if args.realFile != None:
tree = ET.parse(args.realFile)
root = tree.getroot()
for node in root.iter('Node'):
if node.attrib['Password']:
decPass = decrypt_func(node.attrib['Password'], args.password)
if node.attrib['Username']:
print("Username: {}".format(node.attrib['Username']))
if node.attrib['Hostname']:
print("Hostname: {}".format(node.attrib['Hostname']))
print("Password: {} \n".format(decPass.decode("utf-8")))
sys.exit(1)

elif args.file != None:
with open(args.file) as f:
encrypted_data = f.read()
decPass = decrypt(encrypted_data, args.password)

elif args.string != None:
encrypted_data = args.string
decPass = decrypt(encrypted_data, args.password)

else:
print("Please use either the file (-f, --file) or string (-s, --string) flag")
sys.exit(1)

try:
print("Password: {}".format(decPass.decode("utf-8")))
except Exception as e:
print("Failed to find the password property with the following error: {}".format(e))


if __name__ == "__main__":
main()
main()
49 changes: 0 additions & 49 deletions mremoteng_decrypt_legacy.py

This file was deleted.

0 comments on commit 49ea283

Please sign in to comment.