DoS Exploit patch#6490
Conversation
|
GOIDA |
|
vouch, kills servers in an instant |
| private ISawmill _loggerPacket = default!; | ||
| private ISawmill _authLogger = default!; | ||
|
|
||
| private readonly Dictionary<IPAddress, int> _decryptFailCounts = new(); |
There was a problem hiding this comment.
There is some flaws, such as memory leaks when registering IPs. Attackers can just spoof IP address, use botnets and such.
Dictionary is not thread safe, use ConcurrentDictionary<TKey, TValue> instead
| _logger.Warning($"{remoteEndPoint}: Failed to decrypt message (fail #{failCount}), disconnecting. Exception: {e.Message}"); | ||
| if (failCount >= DecryptFailBanThreshold) | ||
| { _authLogger.Warning($"[DECRYPTBAN] {remoteIp} reached {failCount} decryption failures. Consider banning this IP."); } | ||
| channel.Disconnect("Decryption failure"); |
There was a problem hiding this comment.
You are also kicking users on first decrypt failure, your variable only works on logging.
| private ISawmill _authLogger = default!; | ||
|
|
||
| private readonly Dictionary<IPAddress, int> _decryptFailCounts = new(); | ||
| private const int DecryptFailBanThreshold = 10; |
There was a problem hiding this comment.
Hard coding config variables isn't a best option, consider using it as CVar.
|
Ok |
|
I'm checking now, but I don't have the tool to attack myself |
|
Exceptions are themselves an extremely easy DoS vector, consider actually fixing Decrypt to not throw upon receiving this kind of malformed packet, instead. |
done |
|
(Not an engine maint, so this comment does not serve as review.) The approach in this PR appears to add an upfront This PR additionally fails to address the actual root cause of the DoS exploit it's attempting to fix, going so far as to remove the exception entirely instead of addressing the bug that leads to the exception. |
CleanupDecryptFailCounts exits immediately via a single DateTime comparison on every call the dictionary iteration only runs once every N minutes, so per-packet cost is O(I), not O(n). |
|
Either way, I've deployed it to my own server and will be rolling it out to a few others soon for broader testing |
the PR author has a valid point, tho it still would be nice to see some benchmarks on how it affects the CPU performance |
|
I think #6491 |
|
Moving to Draft - the original exploit is fixed by #6491. This PR adds additional botnet mitigation on top: per-IP failure tracking (IPv6 masked to /64), a memory cap on tracked IPs, throttled logging to prevent log I/O DoS, and a [DECRYPTBAN] warning for automated IP blocking. Useful if you're dealing with targeted botnet attacks, but not critical for most servers. |

Fix: DoS via malicious encrypted packets
Problem
The server accepted UDP packets from clients that had completed the Lidgren handshake, but whose contents were forged or intentionally corrupted.
NetEncryption.Decrypt()threw aSodiumExceptionthat was not caught anywhere in the call chain:GameLooplogged the error and continued, but all packets remaining in the current tick were dropped - legitimate clients stopped receiving state updates and disconnected withFailedNotConnected.This allowed a single attacker witgh an established Lidgren connection to continuously kick all players from the server by flooding it with corrupted packets.
Changes
Robust.Shared/Network/NetEncryption.csDecrypt()now returnsboolinstead of throwingSodiumExceptionon MAC failure. A bad packet is now a branch, not an exception.Robust.Shared/Network/NetManager.cstry/catchwithif (!channel.Encryption.Decrypt(msg))._decryptFailCounts- tracks failures per IP. IPv6 addresses are masked to/64to prevent subnet hopping. Failure count never resets on cleanup to prevent threshold bypass by waiting.net.dos_fail_max_trackedto prevent mewmory exhaustion from botnets.Robust.Shared/CVars.csnet.dos_fail_kick(default:true) - disconnect upon reachimg threshold.net.dos_fail_ban_threshold(default:10) - failures before[DECRYPTBAN]warning and optional kick.net.dos_fail_cleanup_interval(default:2) - minutes between cleanup passes.net.dos_fail_max_tracked(default:10000) - max IPs tracked simultaneously.Before / Aftewr
[ERRO] runtime: Caught exception in "gameLoop Input"[WARN] net: X.X.X.X: First decryption failure[DECRYPTBAN]is emittedWhy this matters
** Media



Before:
After
Server after patch don't falling from attacks