Ben provided some details morning on what happened to his server and I thought I'd follow that up with some precise details on how Galleon was hacked. As an open source developer whose work is used by many organizations, I take security risks with my software very seriously. When this hack was pointed out to me (more on that in a second), I got a quick fix up within about 20 minutes. I then followed that up with a more detailed fix later.
I want to personally apologize to anyone who may have impacted by this, and certainly extend my deepest regrets to Ben and Michael. I tried my best to correct this quickly, but at the same time, I didn't want to spell out the details until folks had a few days to patch up. Hence my twittering and vague blog post a few days ago.
Credit for this find goes to the engineers at Mura. Not only do they have a great product, they have great minds as well. They approached me personally with this before going public themselves, and I appreciate them giving me some time to fix things.
Again - folks - I take this very, very seriously. Please come to me if you think you see a security problem with any of my code. I can call myself a Jedi all I want, but at the end of the day I'm imperfect and need help from my users. Ok, so enough preamble, here are the details.
Galleon has two places where folks can upload files: avatars and message attachments. For both, the process was: Upload and then check the extension. Avatars were checked for image attachments and message attachments were checked against a list (defaulting to things like .txt, .pdf, etc).
So if you tried to be sneaky and upset a CFM file, ColdFusion would recognize this and then delete the file. However, all uploads were done to the proper folder for each time. So uploading a CFM for your Avatar put the file into the images/avatar folder. It would then check the extension and delete it. This wasn't instant, even though it may have looked liked it. There may have been 1-5 MS between the time the uploaded file was copied into the proper folder and the time it was checked.
The attacker used a load tester. A load tester is normally used to drive a lot of HTTP traffic to your site to see how well it responds. At a basic level though it's like someone sitting there with his browser and hitting reload really, really fast.
So if the attacker had a file named sss.cfm, he could begin the load tester driving traffic to galleoninstall/images/avatars/sss.cfm. He would then do the upload. His attack file was set up to first make copies so even though sss.cfm would be deleted, he would then be able to use the new file to perform other nefarious deeds.
So why did I upload files under web root? Galleon was meant to be installed under your web root itself. It was also meant to be installed easily by everyone, including folks using shared hosting where you - normally - don't get access to folders out of the web root. That was my thinking about why I needed to do the uploads like that. But I was wrong. It was easy enough to change the upload process to make use of getTempDirectory(). This is what I do now. The file is uploading into the temporary directory, checked, and then moved to the final destination if it passes the extension test. I also went the extra step and renamed the file to a UUID. My thinking here was that no one really cares what their Avatar file names are nor do they care about attachment file names since I can force the download to use the nicer, original name when you download.
I hope my screw up here helps others. If you thought uploading to a web root folder is ok because you "immediately" delete it, please remember that immediately on a machine isn't quite what you may think it is.


Comment 1 written by Dan G. Switzer, II on 21 September 2009, at 7:17 AM
Comment 2 written by Phillip Senn on 21 September 2009, at 7:38 AM
Comment 3 written by tony petruzzi on 21 September 2009, at 8:24 AM
http://github.com/rip747/cffileupload
Comment 4 written by andy matthews on 21 September 2009, at 8:34 AM
Comment 5 written by Neil Moncur on 21 September 2009, at 8:56 AM
Incidentally, one thing I have done in the past is:
If I have a directory that I know should not execute any files, I put a one line Application.cfm file in it. The Application.cfm has a cfabort in it, and that is all (or a cflog and then cfabort). This prevents any cfm files from executing in the directory. Just a little idea.
Comment 6 written by Harry on 21 September 2009, at 8:57 AM
Comment 7 written by Raymond Camden on 21 September 2009, at 8:59 AM
Can't be too anal about security.
Comment 8 written by Paul Dynan on 21 September 2009, at 9:09 AM
<CFIF ListLast(GetDirectoryFromPath(GetTemplatePath()), "\") IS "user_upload">
<CFLOCATION URL="http://www.#siteAddress#" ADDTOKEN="No">
</CFIF>
We could just as easily bounced them to "http://" oblivion, but we just send them back to the home page if they try to directly access anything in the upload folder.
Far from comprehensive, and not sure if it would have helped here, but it generally helps prevent shenanigans from those folders.
Comment 9 written by Raymond Camden on 21 September 2009, at 9:30 AM
Comment 10 written by David Boyer on 21 September 2009, at 9:53 AM
Comment 11 written by Daniel Budde on 21 September 2009, at 9:53 AM
<cffile action="upload" filefield="fileField" destination="#uploadPath##fileUUID#.gal" nameconflict="overwrite" result="fileInfo" />
We then store the new file name and the old file name (client file name from the upload result) and then serve up the orginal file name when the file is requested. We have an allowed file extension list as well that checks the original file name upon upload and then removes it if it is not in the list.
So, as I save the file as a UUID and different extension in the cffile upload, is it still susceptible to this same attack? Unfortunetly I do not know enough about the mechanics behind the <cffile upload process to tell.
I am more than likely going to add the blank application.cfm with the cfabort in it as an additional precaution (as Ray said, can't ever be too safe), but I would still be curious to know if renaming the extension within the upload is a good preventative.
Comment 12 written by Lola LB on 21 September 2009, at 10:03 AM
Comment 13 written by Pete Freitag on 21 September 2009, at 10:07 AM
I pointed out the potential for this issue in that article, I said there was a "a slight chance that I could execute that file before you can delete it if you uploaded it into the web root (and I could predict where it would be placed)."
After writing that article I did some testing with this method, and I found that a "slight chance" is probably not accurate, it did not take a great amount of load to accomplish this.
Thanks for the writeup about this Ray.
Comment 14 written by Simon on 21 September 2009, at 10:10 AM
Comment 15 written by Richard Davies on 21 September 2009, at 10:27 AM
Comment 16 written by Raymond Camden on 21 September 2009, at 11:59 AM
Comment 17 written by Sean on 21 September 2009, at 6:13 PM
Comment 18 written by Raymond Camden on 21 September 2009, at 6:22 PM
Comment 19 written by Sean on 21 September 2009, at 6:30 PM
Comment 20 written by Raymond Camden on 21 September 2009, at 7:01 PM
Comment 21 written by Joshua Curtiss on 21 September 2009, at 8:20 PM
Comment 22 written by Warren Koch on 22 September 2009, at 2:04 PM
Comment 23 written by Raymond Camden on 22 September 2009, at 2:06 PM
Comment 24 written by Warren Koch on 22 September 2009, at 2:31 PM
Comment 25 written by Don on 24 September 2009, at 4:03 PM
[Add Comment] [Subscribe to Comments]