Ashen-Shugar's MUSH security tips
Editor's note: This information applies to all MUSH servers
Security is a growing concern on MUD's (mush, mux, penn, etc) today because of the constantly growing experience and abilities of the player base on it and, let's face it, because of the growing number of twinks on these platforms.
The largest concern, and easiest to exploit, area to be aware of is master room code. This is the number one attack point of twinks. Twinks go to extreme efforts to find out both where the master room is, and what functions or attributes exist on objects inside there. They can do this a number of ways.
PERCENT SUBSTITUTIONS AND PROBLEMS THEY CAUSE
Any softcode that stores %N or %0-%9 directly to attribute is very very wrong. Why? This allows the twink to be able to design their own command for abuse. I will not explain how it's done (for obvious reasons) but I will show you a few ways it can be avoided.
1. Store a %b before the attribute. i.e.: &attribute thing=%b
2. escape out the string. i.e.: &attribute thing=[escape(stuff)]
3. use secure to strip out nasties: &attribute thing=[secure(stuff)]
4. Put any type of string before the percent substitution.
Basically, for any situation where the user is allowed to store text, you should go to extreme lengths to secure it out. And never NEVER store the name unless it's under controlled situations. The dbref# (%#) should work for most of your needs and can't be abused like %N can.
SIDE EFFECTS. ARE THEY REALLY A GOD SEND?
Actually, I consider side effects to be Satan's spawn. Why? Because they are the easiest thing to abuse on any server. Because of how MUSH parses, it is possible, with code that hasn't been totally gone over, to execute side-effects arbitrarily and gain access and/or set information that wasn't intended.
The use of side-effects without proper reasoning can also choke the CPU. Side-effects bypass the queue of their matching @commands and in so doing, poorly written code can process everything immediately thereby eating up large amounts of system resources. You can code switchless without using side-effects and manage not choking the cpu as badly, but like any piece of code, you need to weigh the benefits verse the costs. The CPU being one of the costs to be concerned with.
It is generally wise to disable side-effects unless absolutely needed, but if you do plan to use them, make SURE to adjust your code so that players can't embed side-effects into functionality or commands that would enable them improper access. Code well, code wisely.
MASTER ROOM DO's AND DON'TS
Generally, when you set up your master room, you should NEVER have the master room in the first 20 or so rooms of the mush. On mushes I run, as soon as the DB hits over 1000, I re-set the master room to one of those dbref#'s. It's harder for twink players to find a room when it's not in the first 100 or so rooms. Players generally give up after that (twinks are generally lazy) and it takes very little time on your part to do it. [ Editorial note: This advice isn't very useful on PennMUSH, where any player can type '@config master_room' and find the dbref. - Javelin ]
Master Rooms should also NEVER be named 'Master Room' for obvious reasons (like it being easy to identify by the name for instance). Call it Jane's Jungle Gym if you want. The name does not effect anything but if it's something innocuous it's harder to find and again, takes little time to do.
Unlike MUX, TinyMUSH or it's derivatives, PENN checks $commands on parent objects on the master room. Therefore, for the master room, NOTHING should be parented as it does a check on every single attribute on every single parent in the master room for every single command typed. This is a lot of unnecessary overhead. Again, this only effects PENN. For all other servers, you may @parent w/o it going through and checking all attributes of all parents. [Editor's note: the cpu overhead isn't really an issue with modern servers.]
Any attribute on any object in the master room should ONLY have $commands on them (or listens if they were hacked to do so). For every object in the master room, and for every attribute on every object in the master room, it will be parsed for $commands. This can be an ENORMOUS amount of overhead. To get around this, store any 'functionality' or other non-$command on separate objects OUTSIDE the master room (or inside objects in the master room) so that they will not be parsed for $commands. This will increase the overall performance of the mush, and also remove extra possibilities for twinks to hack your master room.
The master room should only have access to people you want to hack the master room. Even if other wizards have access to it, you should make it clear that they are not to mess with it if you don't want them to. Remember, too many hands in the cookie jar means more crumbs to clean up.
PARENTING OBJECTS AND PROBLEMS IT MAY HAVE
Parenting objects actually is a very good thing. It takes up far less in memory, far less in data storage, and the evaluation time it takes is next to nil for the work of it. It's also very handy in organizing data. However, parenting does have some problems. And yes, all of these are user errors.
When you are a player, before you parent something make ABSOLUTELY sure that the parent in question is TOTALLY secure and can't be changed on a whim. Why? Because you will be executing commands that can, at any time, be changed/modified/added that will effect you in a unfavorable way. Let's say that there's a simple command that shows who's on. The code will look something like:
&CMD_WHO parent=$+whoon:@pemit %#=[iter(lwho(),name(##))].
There, that's very simple. Well, let's say the person in question decides to be abusive, and makes a change to the command and does this:
&CMD_WHO parent=$+whoon:@pemit %#=[iter(lwho(),name(##))].;&ABUSE me=$fo *:@fo owner(me)=%0;@unlock/use me;@set loc(me)=enter_ok; @unlock/enter loc(me)
You still get the same results, but now, the object is unlocked, has a command that will let ANYTHING force you to do anything, and makes it so anything can enter you. And you would be totally oblivious to this as the output as far as you were concerned did exactly the same thing it did before. This is why you *ALWAYS* examine/parent and NEVER set your object inherit (or on penn wizard/royalty/etc) without first being absolutely sure the parent is secure and incorruptible.
For wizards, this is a BIG taboo. In the above example the player in question could just have easily done @dolist search(type=player)=@nuke ## Then congratulations, you do +whoon, and you now have no players. Time to restore the database. For this reason, wizards should NEVER under ANY circumstance have parents that are NOT wizard owned. If you want to parent something to something not wizard owned, get permission from the author first then @clone it for your own use. This way you have control of it. If you still decide to have parents owned by mortals when you are a wizard, you're asking for trouble and expect to have problems. People, as a whole, are not trustworthy, especially when power is in question. Be smart, don't do it.
COMMAND CATCHERS AND OTHER NASTIES
A problem that has been creeping up again is command catchers. This is done when a player has a command of $*:@pemit me=%0. Thereby making it so any command that is mistyped OR any command that's from the master room will be issued to the player instead. This can be bad especially with soft coded mail systems as it allows the player to see private information. This is the primary reason why commands on players are disabled on mushes I run. It makes it difficult for players to make macros, but is generally more secure than hoping players remember to uselock themselves. Likewise, similar can be done with objects or rooms and on some systems, exits. This is, at least to me, highly abusive and grounds for some serious punishment, but should at the very least, be taken care of when discovered.
If you have a problem with this on your mushes, you may wish to notify to the players to type gibberish before doing something that will require some privacy. For example type 'jrtjso'. I doubt there'll be a command with that name and it should return a huh? message. If it doesn't, then someone is logging commands. Listening things are harder to detect this way, but if enabled and allowed, just @sweep for them. It'll find most of the annoyances so you can be relatively safe.
Privacy is always an issue on mushes, but you need to keep in mind. NOTHING on the internet is 100% private and secure. Someone (most likely the fbi or other government agency) is seeing everything you do and type anyway. What you should do is follow simple advise. Never do anything that you'd not want to see on the 6 o'clock news. If you do, then just be careful and also prepared incase it finds itself in the open. Lots of sick individuals log personal information and put it on public web pages. They do this for two reasons. First, that they could and it gives them a twisted form of thrill, and second, because they may or may not have something against you. When you do anything on the internet, always be prepared for the consequences for any action you do, and take responsibility for it. It not only keeps yourself safe, but keeps others safe, too.
QUOTA AND WHY IT SHOULD BE ENFORCED
Quota is generally a good thing to install. Even if you give people a ridiculously large amount of quota, you should still have limits. This keeps some twink from making the great rabbit farm that constantly triggers rabbits to be made which can, in just a few short hours, bring your entire mush to it's knees and force a recovery to an older database. And the twink, being clever, may make it a trojan so it would exist in prior databases as well. With the quota limit, they'd still have a bunch of rabbits, but it'd stop at the maximum quota you set up for that player, thus, saving your database from the great '/home/mush/blah' device full message.
MONEY IS NOT IMPORTANT. OR IS IT?
Yes, actually, money is very important. Money controls how much a person can queue and how many db-intensive functions and commands that can be issued. If you give someone a few million mush credits (or whatever you call it on your server) you basically hand them the key to the code as they can essentially do everything they want and not worry about the code auto-halting because of lack of money. Yes, function limits and queue limits are still in effect, but money is a very good way to keep twinks from pounding the queue endlessly (and also to avoid those constantly moving puppets that people seem to love to make and let loose). There's generally no reason to give people more than a thousand gold at any given time, but again, use your own judgement.
THE QUEUE AND WHAT TO WATCH FOR
The queue is a big issue with security as well. This is the main reason I am heavily against any code with nested @switches or other queue parsed commands. The more the code is executed, the more it tosses it into the queue. If it's something that's rapidly executed, it has the possibility to really hit the queue hard. I have seen systems with queue's filled with THOUSANDS of requests. Needless to say, the queue was pretty slammed causing the mush to lag terribly.
There are a few solutions to this. First, code wisely. You can get away with fewer waits, triggers, switches, or other queued code and have the same functionality. Second, consolidate the code. For area effects like birds chirping or singing, have a centralized object do the triggering. Myrddin has a wonderful cron system that can be used on every flavor of mush (mux, penn etc) that is very useful for scheduling jobs. Only one thing will sit on the queue no matter how many entries that you have. TinyMUSH 3.0 also has a hardcoded @cron. It's a very nice idea, but in all honesty it buys you little in performance compared to a softcode alternative which Myrddin has made available. Besides, I get nervous when something is scheduled and you can't eyeball it with @ps.
GROWTH OF PROCESS AND MEMORY
Every server but PENN allows you to list the current allocations. [Editorial note: God in PennMUSH can use @uptime to get this information] As a wizard, @list alloc shows you the current allocations of resources. Keep an eye in the 'in use' section. If you see that growing at a constant rate and never decrease, you have a memory leak somewhere and you need to alert your hardcode hack (or the development team of that mush code) and tell them they have a leak somewhere. It's always best if you can identify the command/function that is causing the leak, but generally the developers are bright enough individuals to find it relatively quickly. For PENN (and yes the other servers as well) you can check the process size of the mush on the platform you're running. Do a ps on the process and check the memory and resource as well as the CPU. The CPU shouldn't ever go much above 1 or 2 percent for any period of time (for slower boxes), and memory growth shouldn't grow that much (no more than a few megs at most from when it started). If it does, you need to keep an eye on processes in the queue, and what is ran. It could mean two things.
First, it could mean that the mush server that you are currently running has some really bad memory leaks. TinyMUX 1.5 is bad for this for instance. It also could mean that someone is trying to grow your process size by adding a lot of code or queued information. To verify this, check the database size and make sure the database doesn't grow too fast. If it does, you need to immediately take care of it as someone obviously has put an effort to bring your mush down. Best way is to immediately do a @halt/all, @wall a message of logins being disabled for the next 10 minutes, record everyone on, @boot everyone but the wizzes, and disable logins for 5 minutes or so to collect yourself and identify the source of problems. Yes, this is for a 'oh hell, my db is growing a meg a second' type of situations. For anything less major, you can take your time and identify the problem w/o alerting the twink in question then nail them after you garnish the facts.
Second, you could have a form of corruption. I have recently alerted the various development staff of a very major problem with attribute handling that will result in servers being heavily corrupted. This type of corruption can cause random effects, including major memory growth and/or database growth. There is no ready way to check for this type of corruption on any server except RhostMUSH currently but signs of effects are random SIGSEGV's, especially when accessing objects/players with examine, @destroy, nuke, etc. Worse case signs will be the changing of types (like players being turned into exits) or attributes changing objects or just disappearing altogether. If you see any of these signs, and can verify that it was not user-caused, then you need to definitely look into fixing it as soon as you can. It will most definitely require a fall back to a previous database but the sooner you catch it, the better you'll be at having a cleaner database. Anything that sets a large number of attributes on items (or that uses extensive ANSI on large number of attributes) are the most likely causes of this. Major problem points are brandy's mail system, amberyl's mail system, and myrddin's bbs system (but only if used extensively w/o clearing out old messages).
THE HASH TABLE IS YOUR FRIEND
Another way a player can really cause problems is by hosing your hash table. They can do this by making a ton of attributes on an item. The larger the hash table gets, the slower the overall performance of your server is. MUX has a @dbclean that cleans up unused attributes (as does MUSH 3.0). And MUX 2.0 has an enhanced version that not only cleans it, but renumbers the attributes. A definite speed boost. You should always keep an eye on this as much as you can and make sure it stays relatively small as much as possible. [Editorial note: PennMUSH doesn't have a disk-based hash table, so this doesn't apply.]
LOADING CODE FROM OTHER PEOPLE
Whenever you load code into your system, make sure that it comes from a reliable source. There is a LOT of stolen code floating around that people illegally have (a VERY bad thing to do that I tend to nuke people over, no questions asked) or that is very poorly done. Whenever you port code in, make SURE that the code is properly credited. If not, don't use it. You save yourself a lot of problems. Secondly, make sure the code you port in is secure. Make sure it doesn't use side-effects badly, that it doesn't allow the players to store attributes, that it handles the queue nicely, and everything else mentioned in this document. If it passes the general guidelines and if you feel comfortable with it, use at your leisure. If not, you're again, asking for some major headaches. When your mush invariably crashes or is compromised because of bad code, remember that you were the one that had a chance to fix it at the start.
HELP IS ALWAYS AVAILABLE
When you are ever unsure about a piece of code, or about how something should be done, ask around. There are a lot of people out in the mush community who are more than intimate with the parser and functionality and could help you. These people are also generally easy to get along with and will help you as long as you made some effort to find the problem. Please, for our own sakes, take time to learn and figure things out on your own first. If you don't, people start to feel used and that really annoys people. Trust me, it's happened to me more than I would care to count.
Likewise, word to those brilliant code people out there. Do what I do. When people come to you for an answer, don't just tell them. Don't just show them, have THEM do it and walk them through it. That way, they not only learn how to do it, but they, in turn, are now able to help others. You're just helping yourself by doing it this way. One less person that'll ask us for future issues, and it also helps interpersonal relationships. Always a good thing. Remember, we all started as newbies as well, but we didn't always have the knowledgeable that people today have.
I can be reached as Ashen-Shugar on Rhostshyl (amtgard.com 4201), Underground (www.palemoon.net 7000) and M*U*S*H (pennmush.org 4201). If I'm not around, you may email me as well. firstname.lastname@example.org