ColdFusion Muse

Cfinclude for Good or Evil

Mark Kruger May 14, 2009 11:23 AM ColdFusion, Coldfusion Security Comments (6)

Yesterday I was doing some searches on a sick server to troubleshoot the Iframe Injection issue. A user had posted some additional information regarding a file that appeared on his server that had this issue. The file was named "fection.cfm" so we now know the hacker casually removes his prefixes (or I should say 'emoves his 'efixes). I began my search by looking for the file specifically, then moved on to look for the string "cfexecute" in all of the *.cfm files. But that got me thinking. A clever hacker might know some things about ColdFusion. He could in fact, further obscure his code with some knowledge of cfinclude and IIS. Such a technique can be used to secure your code as well. You can create code that is only runnable by ColdFusion using cfinclude. Here's the skinny.

First, understand that IIS 6 excludes all files unless it is specifically tasked with serving it. It does this by examining the file extension. It knows, for example, to serve an *.html file as text/html. In the old days you could create any extension you wanted, throw it on the web server and then call it from a browser. IIS would assume (given lack of instruction to the contrary) that it was an HTML file and serve it. So if you created a hello world page, named it "hello.bob" and then called /hello.bob from a browser, the web server would happily serve your file. Try that on IIS 6 and you get "page cannot be found".

On the other hand, cfinclude doesn't know or care about file extensions. You could create hello.bob and then create hello.cfm with this code:

<cfinclude template="hello.bob"/>
And your hello world would display correctly. In fact, you can put any kind of CFML in hello.bob that you wish and ColdFusion will execute it happily as if it was a cfm page.

Using for Good, Not for Evil

When is this useful? Actually it can be a very useful technique for excluding certain pages from direct execution. Consider a folder structure like this:

/
/events
/display
/queries

Let's suppose I have index.cfm in my root (/) directory and I am including an event template, a query template and a display template:
<!--- /index.cfm --->
<!--- some event logic --->
<cfinclude template="events/handler.cfm"/>
<!--- some lookups --->
<cfinclude template="queries/qry.cfm"/>
<!--- display stuff --->
<Cfinclude template="display/default.cfm"/>
This is pretty common stuff. In fact most frameworks have some similar features (although CFCs further abstract the logic blocks). What you may not notice is that it might be possible to browse directly to a script. For example, I might be able to do something like www.mydomain.com/events/handler.cfm. Sure, this could throw an error, but it could also serve as a new vector for attack. For the sake of argument let's say your index.cfm file looked like this:
... logic to set up some variables ...
<!--- --->
<Cfif someconditionIsMet>
    <cfset siteID = 5/>
<cfelse>
    <cfset siteID = 10/>
</CFIF>

<cfinclude template="queries/qry.cfm">
The included qry.cfm file looks like this:
<cfquery name="getsiteProps" datasource="#dsn#">
    SELECT    siteProps
    FROM    sites
    WHERE    siteID = #siteId#
</cfquery>

Are you with me so far? Good. Now looking at the code above you might think, "Hey Muse, my query code is safe. After all I'm explicitly setting the siteID to either 5 or 10 in the preceding code. I don't even need cfqueryparam." Yes, and you are free to make faces at the dinner table too - but if your face sticks like that don't come crying to me. Actually, the issue here is that I (the clever hacker) can bypass index.cfm and browse to www.mydomain.com/queries/qry.cfm. ColdFusion has a convenient (and risky if you don't understand it) order of precedence in evaluating scopes (variables, then url, then form). To hack your site table I could use the following:

/queries/qry.cfm?siteID=5%20OR%201%3d1
Which translates to:
<cfquery name="getsiteProps" datasource="#dsn#">
    SELECT    siteProps
    FROM    sites
    WHERE    siteID = 5 OR 1 = 1
</cfquery>
Of course with the clever use of a line break (%0A) I could add "truncate table sites" and really cause a aneurysm.

But let's say you are clever too and you decide you don't want to be able to serve qry.cfm from the address bar. You have a few choices. You could move the included files outside of the web root and use a ColdFusion mapping (this is pretty common). You could add code to the application.cfc or application.cfm files that exclude any direct access by examining the template path (this is the way some of the frameworks handle it). Or you could change all of your included sub files to be non-CFM files (qry.inc for example). Your index.cfm page would then look like this:

... logic to set up some variables ...
<!--- --->
<Cfif someconditionIsMet>
    <cfset siteID = 5/>
<cfelse>
    <cfset siteID = 10/>
</CFIF>

<cfinclude template="queries/qry.inc">
If someone tried to browse to /queries/qry.inc they would get a page not found error. Now if you were to choose this approach I have one very important tip. Do not choose an extension served by IIS. For example, if you changed the extension to .txt, someone browsing to /queries/qry.txt would actually be served the file without any CF involvement. In other words they would be looking at your source code (Yikes - like sic em to a dog or sending Uncle Harry to Golden Corral).

What About Using it for Evil

My original point had something to do with Iframe injection right? Remember what I was doing when I started? I was looking for cfexecute in all the *.cfm files. What if my clever hacker, who obviously has the ability to add files to the server, has put the malicious code into a file with some other extension and is simply using cfinclude. My search would never pick it up. So now I'm forced to search all files instead - a much slower process.

On a side note (for those of you dealing with this), this attack seems unlike others I have battled. It seems very much customized to the server in question - as if I was matching wits with an actual person who continues to tap tap tap away at the server. That would also be a good reason why the signature of the attack is not picked up by common scans and security tools I guess.

  • Share:

Related Blog Entries

6 Comments

  • Seb Duggan's Gravatar
    Posted By
    Seb Duggan | 5/14/09 11:38 AM
    Personally, I always locate any files that will not be directly accessible from a web browser (includes, custom tags, CFCs) outside the web root directory.
  • Mark Kruger's Gravatar
    Posted By
    Mark Kruger | 5/14/09 11:47 AM
    @Seb,

    Yes... a good practice. I follow that as well. But not everyone can do it - shared hosting precludes it in some cases for example.

    -Mark
  • Misty's Gravatar
    Posted By
    Misty | 5/14/09 1:24 PM
    Tell me one way that i can add in my Application.cfc to stop from executing the included files.

    case 1: all included files are scattered everywhere.

    case 2: all files in a include folder.

    case 3: include some script funda in each included file, but this breaks ajax calls or load full page context in alert box if we include one like this:

    <cfif listlast(cgi.script_name, "/") eq "avc.cfm">
    <cflocation url="index.cfm?action=avc" addtoken="no">
    </cfif>
  • Eric Hoffman's Gravatar
    Posted By
    Eric Hoffman | 5/15/09 11:21 AM
    on our include files, we use the following to prevent direct execution:

    <cfif getBaseTemplatePath() eq getCurrentTemplatePath()>
    Direct execution denied.
    <cfabort>
    </cfif>

    Seems to work out for us.
  • Mark Kruger's Gravatar
    Posted By
    Mark Kruger | 5/15/09 11:28 AM
    @Misty,

    In case number 3 there is nothing you can do or should do - since your ajax calls are calling the files directly you do not WANT to exclude direct access.

    In one or 2 you can add something to the application.cfc or .cfm file that grabs "getbasetemplatepath()" and examines it against known good templates. If it's not "on the list" then it is excluded. Many Fusebox aps work this way (it may be part of the core actually). If the base template path is not "index.cfm" then execution is stopped.

    Eric's example is a good choice if you want to lock down some specific included files.
  • Paul Areekattel's Gravatar
    Posted By
    Paul Areekattel | 9/8/16 4:33 AM
    Hello Eric,

    How come comparing base template path and current template path and aborting will help in preventing the include files from being executed? for i know we can have subfolders in root folder and the include file can be in in one of this subfolders and the hacker can try using this subfolder path.

    On second thought are you saying the hacker might not know the subfolder name? so he might possibly be using only base template path.

    Please suggest your thought on the code you wrote.