Security Audit — mRemoteNG 1.78.2-NB (3405)
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
[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//TODOconfirms known-but-unfixed.
Fix
- Remove hardcoded key. Force a user-set password, OR protect at rest with DPAPI (per-user):
// 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
mR3mfiles, 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
//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
connectionInfo.Password = _decryptor.Decrypt(xmlnode.GetAttributeAsString("Password"));
//connectionInfo.Password = _decryptor.Decrypt(...).ConvertToSecureString(); // line 219 disabledConsumption: 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.
stringis immutable → cannot zero → survives until GC. Memory dump = all passwords in cleartext.CredentialRecord.Password:37alreadySecureString; legacyConnectionInfomodel 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
<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(orWarnOnFailedAuth). - Review interaction with
RdpProtocol7.cs:35 NegotiateSecurityLayer = falsealongside CredSSP.
M-1 — Weak key derivation
Files:
mRemoteNG/Security/SymmetricEncryption/AeadCryptographyProvider.cs:34
public virtual int KeyDerivationIterations { get; set; } = 1000; // code defaultUI/settings default:
Properties/OptionsSecurityPage.settings:15→10000.Security/KeyDerivation/Pkcs5S2KeyGenerator.cs→ BouncyCastlePkcs5S2ParametersGenerator= 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)
LegacyRijndaelCryptographyProvider cryptographyProvider = new();Provider: LegacyRijndaelCryptographyProvider.cs
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.cs→XmlResolver=null,DtdProcessing.Prohibit,MaxCharactersFromEntities=0. ✓ (verify all XML loaders route through it) - Updater hardened:
App/Checks/AppUpdater.cs+Tools/Authenticode.cs→WinVerifyTrust+WTD_REVOKE_WHOLECHAIN+ thumbprint match +WTD_DISABLE_MD2_MD4, plus SHA512 compare. Channel URLhttps://mremoteng.org/. ✓ runtimeconfig.json:EnableUnsafeBinaryFormatterSerialization=false. ✓- No
http://in runtime code (comments only). ✓
Fix priority
- H-1 + H-2 together → actually close CVE-2023-30367 (hardcoded key + in-memory cleartext).
- H-3 → one-line default change, high impact (RDP MITM).
- 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
SecureXmlHelpercoverage across loaders. - Line numbers from tag
ff3da2c.
Source: mRemoteNG/mRemoteNG