Posts tagged ‘sandbox’

Lately I have posted a number of posts on the state of shared hosting security. Unfortunately we have to conclude that only by taking drastic measures a hoster can begin to protect his customers from eachother. And even when the hoster locks dow everything to the best of his abilities, which disables lots of useful functionality, there are some significant holes left. Therefore I have compiled this wishlist of things I would like to see improved in Centaur to make shared hosting security a bit better and easier to deal with.

Documentation

Setting up shared hosting is largely a process of trial-and-error. There is absolutely no documentation available that tells us which tags will blow up when we Sandbox the temp folder. That cfdocument will error out if the fonts folder is not allowed in the Sanbox. There is nothing to warn us that cfdump will break if we disable createObject(JAVA). What we need is better documentation and preferably a whitepaper that shows us how to configure a secure shared hosting environment step by step.

A locked down application scope

Frameworks are storing more and more data in the application scope. The application scope is currently completely unprotected: everybody can see everything. We need a way to lock down the application scope so we can only access it from just one Sandbox.

Fine grained Java permissions

The biggest useful feature we need to disable in order to protect servers is access to Java objects. We need much more control over which actions a Java class can perform before we can open up access to Java. For starters, we need knobs to disable many actions from the Runtime class. We need to be able to disable the loading of arbitrary classes by users (what is the point in disabling createObject(COM) if users can load their own version of JIntegra?), we need to stop users from killing the server with exitVM, halt etc., we need to stop them from spawning other processes etc. Then we need to have all access to SecurityPermission disabled so that users can’t simply reset the security and we need to have ReflectPermission disabled to keep our private stuff private.

Java provides all the API we need for that, we just don’t have any knobs in ColdFusion to switch them on for our Sandboxes

Sane default settings for Sandboxes

If you create a new Sandbox from scratch it has access to many things it shouldn’t. A secure by default configuration would for instance disable all datasources and leave it up to the administrator to enable them on an as needed basis. Same goes for tags like cfexecute and cfobject.

On the other hand the default Sandboxes do not have access to to for instance the /WEB-INF/cftags/ folder. Without that access cfinterface may not work. What is the harm in giving Sandboxes Read and Execute access to that folder by default? Isn’t the code in those folders written by and trusted by Adobe?

There are many more issues that would help ColdFusion becomming a better hosted platform, and I will address a few more in the future, but these are the 4 most important issues in the area of shared hosting security that Adobe needs to address. All of these have been submitted to Adobe, but I am sure a few more votes and ideas won’t hurt.

So far we have seen that to secure our shared hosting customers from each other we need to place them in a Sandbox limiting file system access, datasource access and disabling access to cfexecute, cfobject and CreateObject(JAVA/COM/.NET) . Typically I add cfregistry to the list of disallowed tags as well. While not strictly necessary for security (you are running ColdFusion with a non-privileged account, aren’t you?), the registry is a shared resource that is easily fragmented and has a limited size, so I just want to keep customers out.

cfdump

The problem we have now is that apart from the functionality we intended to disable we have inadvertently disabled some more functionality, including the cfdump tag. In the directory /WEB-INF/cftags/ are a number of .cfm templates that implement tags and one of them is dump.cfm. But since this tag is included much like a customtag would be included, it runs with the same permissions that a normal customtag would be running. And those permissions disable the use of CreateObject(JAVA), causing cfdump to throw an error when some datatypes are dumped.

The workaround (go ask Adobe for a solution) is to replace /WEB-INF/cftags/dump.cfm with a custom dump template. I have made the one I use available as a download. It isn’t pretty, it doesn’t dump Java objects (but shared hosting customers can’t create them anyway), but it does the job.

cfinterface

cfinterface is another one of the tags implemented in CFML in /WEB-INF/cftags/. If you try to use a component implementing an interface you will notice that this throws an error. Apparently we need to grant read and execute permissions on that directory to every Sandbox (you can adapt the script I posted before for that). I just ran into this this weekend when I updated my dump template to show interface information as well, so I guess that shows how much I use shared hosting myself.

The ColdFusion Administrator and Admin API

In ColdFusion 8 Adobe introduced multiple user accounts and permission delegation for the ColdFusion Administrator and the Admin API.  I have my doubts about delegating access to the ColdFusion Administrator in a shared hosting environment since the delegation is based on functionality and not on Sandboxes. So that means you can delegate access to see certain features, such as the logfiles, but not certain features for a specific Sandbox, i.e. the logfiles of a specific customer. Since pretty much every feature in the Administrator I can delegate has security implications, I can not delegate anything.

With the  Admin API the situation is even worse. Internally the Admin API has been implemented in CFML and it suffers from the same problem as cfdump: it uses cfobject and createobject(JAVA) functionality that we can not enable without giving users the ability to upgrade themselves to root administrator. The only way we can use them is in our own management scripts and as a backend invoked through some facade we need to write first.

Application scope variables

ColdFusion piggybacks its application scope variables on the Java application scope. This allows for an integration in the application scope between for instance ColdFusion and JSP code: variables you write in one are available in the other. The downside is that on the Java side the application scope is considered an instance wide scope and all data is accessible. That means that whatever customer A puts in the application scope is accessible to customer B. Put the following in your Application.cfc to see how that works:

<cfcomponent>
 
	<cfset this.name = "" />
 
	<cffunction name="onRequestStart">
		<cfdump var="#application#" />
		<cfabort />
	</cffunction>
 
</cfcomponent>

This sharing of the application scope is by design and as a result it is unsafe to store data in the application scope on a shared host.

In the first part we have set the stage for this series: the goal is to protect one shared hosting customer from an ‘inside attack’ by another shared hosting customer on the same ColdFusion instance. In the second part we have gone into the reason why we need ColdFusion Enterprise Edition to secure the filesystem from direct access through cffile and cfdirectory. In this part we will see why we need to take additional steps to secure the filesystem against the other languages we can use in / call from ColdFusion.

Java

Since ColdFusion is written in Java the integration with Java is pretty tight and we can easily use Java code from ColdFusion. So what happens if we try not to use a CFML tag to access a file from some other customer, but use Java directly. You don’t need any Java knowledge to do so, if you Google for some code you will find plenty of examples. For this I downloaded the code from Ben Nadel’s Java Exploration in ColdFusion: java.io.LineNumberReader blogpost, changed the ExpandPath(”./data.txt”) to my template name and ran the code. It displayed the sourcecode of the template, so the code was good. Next I changed the code so the file it pointed to was “c:\\test\\secret.txt”, which is outside my Sandbox. And the code promptly returned an error.

So far so good: our Sandbox protects against reading files directly through Java.

CFEXECUTE

So if we can’t read files from elsewhere on the filesystem directly, perhaps we can copy them to our Sandbox first  using the native functionality of the operating system, and then read them once they are in our Sandbox. (And if you don’t know which files you need, just use xcopy and copy them all recursively.) For that we turn to the cfexecute tag. In the default form that tag would be used like this:

<cfexecute name="c:\windows\system32\cmd.exe" arguments="/c copy #source# #target#" />

But because we are in a Sandbox that will most likely not work  because your Sandbox will not allow you to access the c:\windows\system32\cmd.exe file. To circumvent that, simply upload a copy of cmd.exe to your Sandbox and use that one. With that the code to copy files and then read them through cffile becomes:

So by now it should be clear that CFEXECUTE needs to be disabled to maintain security in a shared hosting environment. The bottom line is that with CFEXECUTE you start a process, that process runs as the same user as ColdFusion, the ColdFusion user by definition has access to the templates of other customers, so the process you started has access to them as well. And this means that useful functionality (albeit used by a limited number of users) needs to bes disabled.

COM, .NET and Java again

The problem is that CFEXECUTE is not the only way to start a new process. COM, .NET and Java can do so as well. Below is a simple code example that shows how to dynamically generate a batchfile, write that to the filesystem inside the Sandbox, execute it through Java, and read the result.

<!--- target file outside our Sandbox --->
<cfset secretFile = server.coldfusion.rootdir & "\lib\neo-datasource.xml" />
<!--- batch file inside our Sandbox --->
<cfset batchFile = ExpandPath("./copy.bat") />
<!--- location where we copy the file inside our Sandbox --->
<cfset readableCopyOfSecretFile = ExpandPath("./readableCopyOfSecretFile.xml") />
<!--- copy command for in our batchfile --->
<cfset batchFileContent = 'cmd /c "copy #secretfile# #readableCopyOfSecretFile#"' />
 
<!--- write the batchfile inside our Sandbox --->
<cffile action="write" file="#batchFile#" output="#batchFileContent#" />
 
<!--- execute the batchfile --->
<cfset CreateObject("java", "java.lang.Runtime").getRuntime().exec(batchFile) />
 
<!--- read the copy of file inside the sandbox --->
<cffile action="read" file="#readableCopyOfSecretFile#" variable="fileContent" />
<!--- display the contects of the file --->
<cfoutput>#HTMLCodeFormat(fileContent)#</cfoutput>

We can prevent this by modifying the Sandbox configuration and disabling the execute permission from the Sandbox, but since ColdFusion itself needs execute permissions to run CFML that will kill ColdFusion as well.  Executing processes from COM works the same as from Java. From .NET it works slightly different because the actual .NET service runs in another process and could potentially have different permissions from the ColdFusion account, but the inability to differentiate the permissions between different users remains.

So the hoster is left with a hard choice: disable CFEXECUTE, CFOBJECT, CreateObject(.NET), CreateObject(COM) and CreateObject(JAVA) or accept that there is no security whatsoever in the shared hosting configuration. If you disable these tags a lot of applications and frameworks won’t work anymore. For instance Transfer ORM needs Java access, so any application build on top of it will not work in a secured shared hosting environment.

Warning

A long time ago I had some other code examples online that could be used to extend the functionality of a shared hosting environment. I have taken these examples down not just because with the arrival of the Admin API they are obsolete, but also because I was informed that somebody had wrecked a shared hosting server with them. So please before you start uploading and running these examples on your shared host, please take a moment to consider the following points:

  • If you want to look further into this code, why not do that on your own development environment?
  • In most jurisdictions accessing other peoples data / code is illegal.
  • Some of the code examples (especially if you replace copy with xcopy) can consume lots of resources.
  • You will never be able to test whether your hosting account is protected from others. You will only be able to test if others are protected from you. So really, why not on your own development environment?

In the first part we have set the stage for this series: the goal is to protect one shared hosting customer from an ‘inside attack’ by another shared hosting customer on the same ColdFusion instance.

If no precautions have been taken, attacking is a simple job. The starting point is a template that does a directory listing of every drive from “a:\” to “z:\” using cfdirectory. When you find something interesting, like the “coldfusion8″ directory, the “jrun4″ directory or a “customers” directory, just drill down from there. Not elegant, but very effective. The only way to hide from it is to use netwerk shares with hard to guess names, but even then it is just a matter of drilling down from the #server.coldfusion.rootdir# to the logfiles and see what the directory paths in some of the mappings and logged errors are.
Hiding (i.e. obscurity) provides no effective hurdle against an inside job and hence no real security.

To get real security against this reading of directories we need to enable Sandbox Security. Sandbox Security allows us to define a directory on the filesystem as a Sandbox and subject every request that starts from that Sandbox to a set of constraints. These constraints can include which tags are allowed, i.e. forbid cfregistry outright, or which resources can be accessed. Typically each Sandbox is defined at the root of a customers FTP and / or WWW directory and then allows for access of only some directories and datasources. Setting up the allowed resources and tags in a Sandbox can occasionally be a bit counterintuitive, for instance to allow a file to be used in a cfinclude it needs execute permissions and several extra directories need to be accessible for some tags.

The thing with Sandbox Security is that it is a feature that is only available in Enterprse Edition. ColdFusion 8 Standard Edition has the ability to restrict the usage of tags, functions and resources as well, but everybody operates in the same Sandbox. So while we can disallow customer A from reading the files of customer B through cfdirectory, that would also disallow customer B from reading his own files. And disabling tags and functions won’t be foolproof either because there is always a way around that. For instance, even if you can’t read a certain file with cffile that doesn’t stop you from mailing it to yourself using cfmailparam.

So here we see the first issue with shared hosting and security: in order to combine them and get a system that is even remotely securable, the hoster needs to invest significantly in a ColdFusion 8 Enterprise Edition license and needs to figure out how to configure Sandbox Security properly. Obviously (if the hoster even decides to bother with all that in the first place) that expense gets charged to the hosted customers, making ColdFusion hosting more expensive then for instance PHP hosting.