Source Engine: Crashing clients in another map
October 18, 2018
I’ve wanted to write something about this for a long time, as for a long time I argued that this was possible, and even demo’d it, but time and again I was told that there was no way to interfere with a game from a map once the server unloads it. This isn’t true…
What is this?
Source engine doesn’t really have a sandbox as it were, when the game changes level, the current one is fully unloaded, and the new one loaded, both on the client and server. This would mean in theory that your map can’t modify the next map to be loaded in any way.
It would suck if a malicious map could mess up the experience for players once that map has finished right? Of course, the fact that such a map would make it onto the server is a separate issue, but auditing of maps is pretty much non-existant; i guess due to the trust that the game doesn’t actually provide any programming mechanism itself inside the maps, and the VScripting feature in newer games is pretty much separate.
Unfortunately however, I did discover a way, by accident, to modify (and crash if so desired) clients that remain connected to a server after the malicious map is finished. There is quite a scope on what you can do with this exploit, if you can call it an exploit.
Essentially, you can replace any model, with any other model in subsequent maps, this includes viewmodels, and playermodels, and its trivial.
How do I exploit it then?
So, as it turns out, when the client unloads a map, it doesn’t actually unload all the content it loaded up in the first place, but does look inside the next loaded maps pakfile and loads all that content there.
I imagine you can already see where I’m going with this?
Literally all you need to do to modify a loaded map subsequent to your own, is to pack any model inside your bsp that a subsequent map is likely to use, and not include in its own pakfile (so pretty much 100% of official game content). Your map need not even use the model yourself, requiring a very manual audit of checking every packed model for both validity and genuine use.
The malicious map contains a payload of a custom viewmodel. This example is a simple model-swap, that won’t cause any harm.
Targetted map for exploit
Now see that the next map loaded has the same viewmodel as was packed into the malicious map.
This is troublesome, as a malicious actor could produce a genuinely desirable map, that packs a malicious model that is used in another designers map, that said actor has a grudge against. If a server/client plays the malicious map, then the targets map, they will have successfully modified that map, whether it be introduce a crash (due to some specific corruption in the model), or something more subtle, such as moving the models attachment points, or providing a modified collision model. Targets map then receives negative feedback for issues that they cannot possibly replicate or understand the cause of.
Is it worth actually exploiting?
Not really, because:
- Crashing clients doesn’t serve enough purpose for a designer who created something desirable enough to be put on a server to do
- There are better ways to show dislike for a rival mapper/designer than some kind of drive-by with the hope of causing sufficient frustration.
- Lots of maps can just occassionally crash Source (and it may not even be the maps fault). There is a good chance that with the rarity of this situation occuring, noone would even notice the pattern of the target map crashing.
Workarounds for the client are pretty easy; you reload the game and reconnect to the server. Workarounds for the server are not quite so easy. I’m currently unsure of any workaround besides auditing maps before adding to rotation, and removing suspicious maps already on rotation.