#3416·mRemoteNG

Security Audit — mRemoteNG 1.78.2-NB (3405)

Author: obtimCreated Aug 9, 2026Updated Sep 10, 2026
LabelsIn progress

Security Audit — mRemoteNG 1.78.2-NB (3405)

  • Tag: 20260222-v1.78.2-NB-(3405) · Commit: ff3da2c · TFM: net10.0
  • Method: static source review (762 .cs). No runtime/build. No PoC included.
  • Baseline: CVE-2023-30367 (CVSS 7.5, CWE-312/316) — checked for regression.

Severity: HIGH = credential compromise realistic · MEDIUM = weakens crypto/needs conditions · LOW/INFO = hardening.


Summary table

ID Severity Issue Location
H-1 HIGH Hardcoded default encryption key mR3m Tree/Root/RootNodeInfo.cs:54
H-2 HIGH Passwords held in memory as plaintext string Connection/AbstractConnectionRecord.cs:259
H-3 HIGH RDP default AuthenticationLevel = NoAuth (no server auth) Properties/Settings.settings:236
M-1 MEDIUM Weak KDF: 1000–10000 iters, PRF = SHA-1 AeadCryptographyProvider.cs:34, Pkcs5S2KeyGenerator.cs
M-2 MEDIUM SQL backend writes passwords with MD5-key + AES-CBC (no MAC) SqlConnectionsSaver.cs:106,157
L-1 LOW Legacy Rijndael provider (MD5/CBC/no-MAC) reachable LegacyRijndaelCryptographyProvider.cs
L-2 INFO Logging level ALL; verify no secrets/cmdline leak log4net.config

H-1 — Hardcoded default key mR3m

File: mRemoteNG/Tree/Root/RootNodeInfo.cs:54

csharp
[Browsable(false)] public string DefaultPassword { get; } = "mR3m"; //TODO move password away from code to settings
  • If user sets no custom config password, connection passwords are encrypted under a key derived from the public constant mR3m.
  • Anyone decrypts confCons.xml. This is the root of CVE-2023-30367. Vendor //TODO confirms known-but-unfixed.

Fix

  • Remove hardcoded key. Force a user-set password, OR protect at rest with DPAPI (per-user):
csharp
// System.Security.Cryptography.ProtectedData.dll already shipped
var protectedBytes = ProtectedData.Protect(plain, optionalEntropy, DataProtectionScope.CurrentUser);
  • If backward-compat needed: keep read-only fallback for old mR3m files, but never write with it; prompt migration.

H-2 — Cleartext passwords in memory (CVE-2023-30367 not fully fixed)

File: mRemoteNG/Connection/AbstractConnectionRecord.cs:258-262

csharp
//public virtual SecureString Password
public virtual string Password
{
    get => GetPropertyValue("Password", _password);
    set => SetField(ref _password, value, "Password");
}

Also RDGatewayPassword:601, VNCProxyPassword:1073 — all string.

Decrypt into plaintext: Config/Serializers/ConnectionSerializers/Xml/XmlConnectionsDeserializer.cs:218

csharp
connectionInfo.Password = _decryptor.Decrypt(xmlnode.GetAttributeAsString("Password"));
//connectionInfo.Password = _decryptor.Decrypt(...).ConvertToSecureString();  // line 219 disabled

Consumption: Connection/Protocol/RDP/RdpProtocol.cs:430,568 — passed as string (SecureString path commented out).

  • Decrypted secrets sit in managed heap for the whole app lifetime. string is immutable → cannot zero → survives until GC. Memory dump = all passwords in cleartext. CredentialRecord.Password:37 already SecureString; legacy ConnectionInfo model is not.

Fix

  • Enable the SecureString path across AbstractConnectionRecord + deserializer + all protocol consumers.
  • Decrypt just-in-time at connect, zero buffers after use.
  • Do not eagerly decrypt whole config at startup.

H-3 — RDP does not authenticate server by default

File: mRemoteNG/Properties/Settings.settings:236

xml
<Setting Name="ConDefaultRDPAuthenticationLevel" Type="System.String" Scope="User">
  <Value Profile="(Default)">NoAuth</Value>
</Setting>

Applied in Connection/Protocol/RDP/RdpProtocol.cs:844 (SetAuthenticationLevel()).

  • Default NoAuth = client does not validate RDP host identity → MITM / session + credential interception (CWE-295). Insecure out of the box.

Fix

  • Default → AuthRequired (or WarnOnFailedAuth).
  • Review interaction with RdpProtocol7.cs:35 NegotiateSecurityLayer = false alongside CredSSP.

M-1 — Weak key derivation

Files:

  • mRemoteNG/Security/SymmetricEncryption/AeadCryptographyProvider.cs:34
csharp
public virtual int KeyDerivationIterations { get; set; } = 1000;  // code default
  • UI/settings default: Properties/OptionsSecurityPage.settings:1510000.

  • Security/KeyDerivation/Pkcs5S2KeyGenerator.cs → BouncyCastle Pkcs5S2ParametersGenerator = PBKDF2-HMAC-SHA1.

  • OWASP 2023 for PBKDF2-HMAC-SHA1 ≈ 1,300,000 iters. Here 1,000–10,000 = 2–3 orders too low → fast GPU brute-force (CWE-916).

  • Mismatch: parameterless AeadCryptographyProvider() ctor yields 1000, not 10000. Audit every provider-construction path.

Fix

  • PBKDF2-HMAC-SHA256/512, ≥600k iters; better: Argon2id (available in BouncyCastle).
  • Unify default between code ctor and settings.

M-2 — SQL multiuser backend writes weak crypto

File: mRemoteNG/Config/Connections/SqlConnectionsSaver.cs:106,157 (also SqlConnectionsLoader.cs:38,55)

csharp
LegacyRijndaelCryptographyProvider cryptographyProvider = new();

Provider: LegacyRijndaelCryptographyProvider.cs

csharp
byte[] key = md5.ComputeHash(Encoding.UTF8.GetBytes(strSecret.ConvertToUnsecureString()));
// AES, default CBC, no MAC/auth tag
  • Key = MD5(password), no salt, no iterations → instant brute-force. AES-CBC without authentication → tampering / padding-oracle (CWE-327, CWE-916). Active on the write path, not just legacy read.

Fix

  • Route SQL storage through AeadCryptographyProvider (AES-GCM + strong KDF), same as XML path.

L-1 — Legacy Rijndael reachable

Security/SymmetricEncryption/LegacyRijndaelCryptographyProvider.cs — MD5 key, CBC, no MAC. Acceptable only as read-only migration. Ensure no write callers remain beyond M-2.

L-2 — Logging

log4net.config: root level=ALL, logger DEBUG, sink %APPDATA%\mRemoteNG\mRemoteNG.log.

  • Verify no credentials reach the log. Check LogCmdLineArgs — cmdline args may carry secrets.

Confirmed good (do not regress)

  • AES-256-GCM AEAD for new configs: random salt+nonce via SecureRandom, 128-bit tag — AeadCryptographyProvider.cs. ✓
  • XXE closed: Security/SecureXmlHelper.csXmlResolver=null, DtdProcessing.Prohibit, MaxCharactersFromEntities=0. ✓ (verify all XML loaders route through it)
  • Updater hardened: App/Checks/AppUpdater.cs + Tools/Authenticode.csWinVerifyTrust + WTD_REVOKE_WHOLECHAIN + thumbprint match + WTD_DISABLE_MD2_MD4, plus SHA512 compare. Channel URL https://mremoteng.org/. ✓
  • runtimeconfig.json: EnableUnsafeBinaryFormatterSerialization=false. ✓
  • No http:// in runtime code (comments only). ✓

Fix priority

  1. H-1 + H-2 together → actually close CVE-2023-30367 (hardcoded key + in-memory cleartext).
  2. H-3 → one-line default change, high impact (RDP MITM).
  3. M-1 + M-2 → modern KDF + kill MD5/CBC SQL path.

Scope / limitations

  • Static review only. Not runtime-verified: actual memory-dump contents, every crypto-provider construction path, full SecureXmlHelper coverage across loaders.
  • Line numbers from tag ff3da2c.