The Angband Security Guide
--------------------------
version 0.2 (1st March 2001) [incomplete Draft]
by Robert Ruehlmann < rr9@angband.org >
==========================================================================
1. Background
==========================================================================
1.1 Running a program with more privileges than the user normally has
---------------------------------------------------------------------
Angband uses a highscore file to record the standings of all the players.
The problem with such a file is that the game must be able to write to it,
while the players themselves can't be allowed to cheat by modifying the
highscores directly.
The savefiles have the same problem. Players can't be allowed to change
them, but the game needs the permission to do so. In addition the player
shouldn't even be able to read the savefiles. Reading the savefiles would
allow finding out secret information and give an unfair advantage.
Normally a program runs with the permissions of the user who starts it.
Making a program setuid or setgid changes this and grants the program the
privileges of the owner of the program (setuid) or the group the
program belongs to (setgid). This provides a way to solve the problems
mentioned above.
These extra privileges are a target for attackers.
For Angband the use of setgid is recommended since it grants less
privileges than setuid. An attacker who manages to hack into the game
just gains group membership instead of access as user owning the game.
For example group access doesn't allow changing the ownership of files.
- What kind of vulnerabilities are there?
- Buffer overflows
- Format string attacks
- Allowing the user write access to parts of the programs memory
- Running user-specified programs without dropping the privileges first
- ...
1.2 Reading data from untrusted sources
---------------------------------------
Even if the game doesn't run with additional privileges a malicious user
can still attack you directly to gain access to your account.
Most computer users know that running executable files or other "active
content" like Visual Basic scripts (remember Loveletter?) can be
dangerous. But most people overlook the fact that "non-executable" data
can be dangerous too. Bugs in programs like buffer overflows or format
string vulnerabilities can allow an attacker to hide executable code
inside the data.
Possible data types that might be vulnerable are the binary savefiles and
scores, but the processing of ASCII files like pref-files and Angband's
screen-dumps may also contain hidden bugs.
It may sound paranoid, but you should consider everybody as a source of
untrusted data. Always remember that even your best friend can
unknowingly forward a savefile touched by a cracker to you.
See also section 2.1 and 2.2
Further reading:
Malicious Data and Computer Security
http://www.fish.com/security/maldata.html
1.3 Writing files in world-writeable directories
------------------------------------------------
Writing to a directory that other users have write access to can allow an
attacker to trick the program into following a link and overwriting files
of the user running the program. This is known as a "symlink attack".
==========================================================================
2. Possible security holes
==========================================================================
2.1 Buffer overflows
--------------------
A buffer overflow is the result of stuffing more data into a buffer than
it can handle.
Buffer overflows usually happen when processing strings, since that is the
most common type of input in a program. The C standard library provides
many functions for manipulating strings and some of these functions don't
perform boundary checking. These dangerous string functions include
strcat(), strcpy(), sprintf(), and vsprintf().
Lets take a look at a small snippet of code:
char path[1024];
cptr env_path;
/* Get the environment variable */
env_path = getenv("ANGBAND_PATH");
if (env_path)
{
/* Use the angband_path, or a default */
strcpy(path, env_path);
}
This snippet is a simplified version of the function that initializes the
path to the lib/ directory of older Angband versions. The getenv()
function returns a pointer to the content of the "ANGBAND_PATH"
environment variable. This environment variable can be set by the user
and has an unknown length. The strcpy() function takes the content of this
variable and copies it character by character into the "path" buffer until
it reaches a '\0' character in "env_path". If "env_path" is longer than
the 1024 characters that we allocated earlier, then strcpy() will happily
write over the end of our buffer and overwrites parts of the stack.
To prevent this bug you have to use functions that do bounds-checking
instead like strncpy(), or check the length of the data before writing
it to the buffer.
The example above could be fixed by replacing the strcpy() call with the
following snippet:
strncpy(path, env_path, 1024);
path[1023] = '\0';
strncpy() takes an additional third argument containing the maximum length
of the string to be copied. Note that strncpy() doesn't automatically
place a null character ('\0') at the end of the string if it is longer
than the maximum, so the second line forces the string to be terminated.
Advise:
- Be paranoid.
- Always do proper bounds-checking (not only in security relevant parts),
and check all user inputs especially carefully. That also includes
command line arguments, environment variables, data from user-writeable
files, and even the name of the executable program.
- Don't use strcpy() unless you are absolutely certain that it can't
overflow your buffer. Use strncpy() instead and make sure to terminate
the result.
- *Never ever* use the gets() function. It is broken by design.
- ...
Further reading:
Smashing The Stack For Fun And Profit
http://www.2600.net/phrack/p49-14.html
Buffer Overflows: Attacks and Defenses for the Vulnerability of the Decade
http://immunix.org/StackGuard/discex00.pdf
2.2 Allowing the user write access to parts of the programs memory
------------------------------------------------------------------
This kind of vulnerability is the result of not checking user input and
using indices that are outside of the regular bounds of your data storage.
This allows an attacker to write to random memory locations. In many
cases it is possible to replace parts of your executable code with
malicious code pieces.
One example is not checking the indices of monsters or objects when
reading prf-files. The attacker can specify an index that it outside the
available range of monster indices and the game will happily access the
illegal address and write the char/attr values there.
Always be paranoid about bounds-checking all input processing functions.
2.3 Allowing the user access to files that he shouldn't be able to access
-------------------------------------------------------------------------
When running setgid the game runs with more privileges than the user
normally has. This could allow the player to read or write files that
he/she normally has no access to (like the savefiles). Normally the game
switches between the normal rights of the player and the enhanced rights
provided by "setgid" depending on what file is accessed. So savefiles and
scorefiles are opened with the setgid rights while character dumps and
*.prf files are opened with the normal rights of the player.
If there is a bug in the switching between these two modes then the
player could for example save a character dump over the savefile of
another player or read a file that is readable by group games but not
by the player.
Angband 2.9.2 introduced a new approach to file access.
In 2.9.2 the game drops all extra access rights granted by "setgid" at
startup and grabs them only when it needs them to open a protected file.
So most of the time the game is running without any extra rights and can
read and write files exactly like the player could outside the game. Only
when it needs to access one of the protected files it switches on the
extra rights, accesses the file with the rights of group "games", and then
drops the rights again.
In 2.9.1 and earlier it was the other way around. The game grabbed the
access rights at startup and dropped them when opening a file unless it
needed the extra rights for the access.
Old code that uses the "safe_setuid_grab()" and "safe_setuid_drop()"
functions to turn off the extra rights for a file access has to be
modified for Angband 2.9.2. The old code dropped the rights, opened the
file, and then grabbed the rights again. With the new method the initial
dropping of the rights does nothing since the rights already have been
dropped by the game at startup. Then the file is accessed without any
additional rights. And then the old code grabs the rights again.
From this moment on the game holds the rights till it accesses a protected
file like the savefile or scores and allows the player to access files
with the additional rights granted by setgid!
So the "safe_setuid_grab()" and "safe_setuid_drop()" calls have to be
removed from the old code when you want to use it in Angband 2.9.2 or
you'll introduce a security hole.
==========================================================================
A. Appendix
==========================================================================
A.1 Further reading
-------------------
Secure Programming for Linux and Unix HOWTO:
http://dwheeler.com/secure-programs/
Designing secure software
http://www.sunworld.com/swol-04-1998/swol-04-security.html
The Unix Secure Programming FAQ
http://www.sunworld.com/sunworldonline/swol-08-1998/swol-08-security.html
A Lab engineers check list for writing secure Unix code
ftp://ftp.auscert.org.au/pub/auscert/papers/secure_programming_checklist/
Make your software behave: Learning the basics of buffer overflows
http://www-4.ibm.com/software/developer/library/overflows/index.html
Secure UNIX Programming FAQ
http://www.whitefang.com/sup/secure-faq.html
Format String Attacks
http://www.guardent.com/docs/FormatString.PDF
How to find security holes
http://www.dnaco.net/~kragen/security-holes.html
Security Code Review Guidelines
http://www.homeport.org/~adam/review.html
A.2 Tools
---------
Fuzz Testing of Application Reliability
http://www.cs.wisc.edu/~bart/fuzz/fuzz.html
GCC bounds-checking patches
http://web.inter.nl.net/hcc/Haj.Ten.Brugge/
ITS4 - Software Security Tool
http://www.cigital.com/its4/
LCLint
http://lclint.cs.virginia.edu/
Electric Fence - malloc() debugger
http://www.perens.com/FreeSoftware/