Diary of a Hacker - Part 1
Here's the first of many writeups for my "Hacker Challenge". Keep in mind, this isn't a penetration test- it's just a train-of-thought writeup of how I cracked an application. The idea is to demonstrate instances of various attacks in use, rather than the theoretical proof-of-concepts that appear in most security web sites.
The site is a file repository- basically customers can pay a monthly fee to have access to a virtual filing cabinet-type-thing. I don't think that's a fabulous business model, but that's not the point of this blog. After familiarizing myself with the site, my first attempts were file upload attacks (naturally, given the purpose of the site). Fortunately, the site used several layers of protection for uploaded files- first, it only allowed a whitelist of filetypes, preventing malicious files from being uploaded. Next, it stored those files in a non-web-accessible directory. Even if I could get a malicious file uploaded, I could not access it directly. Finally, the filenames were randomly generated- if I found a way to circumvent the access control, I still would not know the name of my malicious file.
Basically, this type of attack didn't work; I moved on.
Throughout the site, inputs were validated thoroughly (excessively in some cases). No matter where I looked and how much I mangled the inputs, I could not find an SQL injection hole. I did find a reflected XSS hole in an obscure stock script, so I decided to work with that. My goal was to
steal an admin session using Javascript, and after setting up my evil little javascript-session-stealing kit (I'm quite proud of it), found out that this also wouldn't work so easily. The developer had added the following directive to php.ini:
I'm rather lazy, so I moved on.
I went to myipneighbors.com and found a list of sites on the server. It didn't take me long to find one with some known vulnerabilities, and next thing I knew, I had filesystem access. Faithful readers already know where I'm going with this, but mass-hosted servers are a Bad Idea. Even so, it is possible to configure file permissions and code a site so that an attacker can't simply walk in and read your configuration files.
I whipped up a quick script and ran it on the compromised account (The server runs FreeBSD and cPanel). This script monitored the output of `ps -aux` while fetching a page from the target account. Because of suexec, I immediately knew the username of the targeted website.
With this information, I tried to read files from the public_html directory, but the permissions were set up (mostly) correctly and prevented access. While I couldn't list the files in the directory, I could guess at their filenames, and eventually landed on one file that was readable- php.ini.
Reviewing the site's php.ini file, I could tell the server was relatively locked down, but one line in particular caught my attention:
hours that I waited.
While this tactic would eventually work, I wanted to speed things up. I sent the following email to the programmer:
So what could have been done to prevent this attack? A few little things.
First, making the ~/tmp directory globally unreadable would have prevented me finding session IDs. This isn't failproof, as there are other ways I could have found them, but every little bit helps.
Second, adding further session validation would have made hijacking the session very difficult. This can be as simple as storing the source IP address in the $_SESSION array on login, then comparing it on each pageload to make sure the user isn't suddenly coming from the other side of the world. Admittedly, there are legitimate uses that would have issues (web proxies and Tor, specifically), but it would have closed the hole. If the site's user base are likely to be behind proxies, there is other information that can be used to identify the browser uniquely- client's user agent, supported protocols, OS, connection latency, etc.
The biggest lesson here, though, is to follow the 'defense in depth' mantra.
The site is a file repository- basically customers can pay a monthly fee to have access to a virtual filing cabinet-type-thing. I don't think that's a fabulous business model, but that's not the point of this blog. After familiarizing myself with the site, my first attempts were file upload attacks (naturally, given the purpose of the site). Fortunately, the site used several layers of protection for uploaded files- first, it only allowed a whitelist of filetypes, preventing malicious files from being uploaded. Next, it stored those files in a non-web-accessible directory. Even if I could get a malicious file uploaded, I could not access it directly. Finally, the filenames were randomly generated- if I found a way to circumvent the access control, I still would not know the name of my malicious file.
Basically, this type of attack didn't work; I moved on.
Throughout the site, inputs were validated thoroughly (excessively in some cases). No matter where I looked and how much I mangled the inputs, I could not find an SQL injection hole. I did find a reflected XSS hole in an obscure stock script, so I decided to work with that. My goal was to
steal an admin session using Javascript, and after setting up my evil little javascript-session-stealing kit (I'm quite proud of it), found out that this also wouldn't work so easily. The developer had added the following directive to php.ini:
session.cookie_httponly = 1This directive made it so that session IDs were inaccessible to client-side Javascript. I could have still used the XSS hole for other things, such as forcing the administrator to perform actions on my behalf, but this would require work and inside knowledge to code, and would have a relatively low chance of success.
I'm rather lazy, so I moved on.
I went to myipneighbors.com and found a list of sites on the server. It didn't take me long to find one with some known vulnerabilities, and next thing I knew, I had filesystem access. Faithful readers already know where I'm going with this, but mass-hosted servers are a Bad Idea. Even so, it is possible to configure file permissions and code a site so that an attacker can't simply walk in and read your configuration files.
I whipped up a quick script and ran it on the compromised account (The server runs FreeBSD and cPanel). This script monitored the output of `ps -aux` while fetching a page from the target account. Because of suexec, I immediately knew the username of the targeted website.
With this information, I tried to read files from the public_html directory, but the permissions were set up (mostly) correctly and prevented access. While I couldn't list the files in the directory, I could guess at their filenames, and eventually landed on one file that was readable- php.ini.
Reviewing the site's php.ini file, I could tell the server was relatively locked down, but one line in particular caught my attention:
session.save_path = /home/theSiteUsername/tmp/I tried to list the files in that directory and was able to view a list of open sessions' IDs. This was the hole I needed to compromise the account:
$ ls -la /home/theSiteUsername/tmp/ | grep sessI then manually set the SESSID cookie in my browser to those found in the session filenames, and confirmed that I could hijack other accounts' sessions. Unfortunately, none of those sessions were administrators. I wrote a shell script to watch the directory in question and send a text message to my cell phone when a new session is created, but no admins logged in over the 50-something
-rw------- 1 theSiteUsername theSiteUsername 5068 Sep 18 09:20 sess_1a1aexxxxxxx5e282e1a5747694ec8e2
-rw------- 1 theSiteUsername theSiteUsername 5023 Sep 18 09:19 sess_462fexxxxxxx13dafa331bc15e962e22
-rw------- 1 theSiteUsername theSiteUsername 5109 Sep 18 10:51 sess_717edxxxxxxx653df341f91d096e0484
-rw------- 1 theSiteUsername theSiteUsername 5079 Sep 18 09:14 sess_91850xxxxxxxef480524c23412b23dc1
-rw------- 1 theSiteUsername theSiteUsername 5011 Sep 18 10:38 sess_9246dxxxxxxxe6e710a9e623af23ca95
-rw------- 1 theSiteUsername theSiteUsername 5079 Sep 18 09:25 sess_a4cdcxxxxxxx065ede6ecb062d443f86
hours that I waited.
While this tactic would eventually work, I wanted to speed things up. I sent the following email to the programmer:
Log into the admin section and check the 'edit_users.php' page.The developer and I have done a fair amount of trash-talking about this account in the past, so worried that I had successfully hacked the site, he logged in to check the admin section. As soon as his new session was created, I hijacked it, accessed the admin page, and snagged a screenshot as proof.
;)
So what could have been done to prevent this attack? A few little things.
First, making the ~/tmp directory globally unreadable would have prevented me finding session IDs. This isn't failproof, as there are other ways I could have found them, but every little bit helps.
Second, adding further session validation would have made hijacking the session very difficult. This can be as simple as storing the source IP address in the $_SESSION array on login, then comparing it on each pageload to make sure the user isn't suddenly coming from the other side of the world. Admittedly, there are legitimate uses that would have issues (web proxies and Tor, specifically), but it would have closed the hole. If the site's user base are likely to be behind proxies, there is other information that can be used to identify the browser uniquely- client's user agent, supported protocols, OS, connection latency, etc.
The biggest lesson here, though, is to follow the 'defense in depth' mantra.
Labels: Audits, Diary of a Hacker, Web Applications


0 Comments:
Post a Comment
Subscribe to Post Comments [Atom]
<< Home