Wednesday, April 21, 2021

SSRF in ColdFusion/CFML Tags and Functions

TL;DR: Several ColdFusion/CFML tags and functions can process URLs as file path arguments -- including some tags and and functions that you might not expect.  This can lead to Server-Side Request Forgery (SSRF) vulnerabilities in your code.  Developers should be sure to validate any user input passed to the affected tags and functions.

 Overview

I recently observed some CFML tags and functions that could be used to perform Server-Side Request Forgery (SSRF), if they processed user-controlled input.  Based on this, I decided to do some fuzzing to identify all of the tags and functions that were potentially impacted by this type of attack.  There are many legitimate cases where applications need to process URLs and file paths.  And the security pitfalls of a few “dangerous” CFML tags and functions are well-known and well-documented.  However, there are other instances where the underlying functionality that leads to SSRF is unexpected, and user input is incorrectly assumed to be safe.  

Since I haven’t seen anything written about SSRF in CFML, I wanted to share some of my findings to help CFML developers secure their applications. Additionally, since there isn't a ColdFusion equivalent to something like PHP's allow_url_fopen (to prevent some functions from treating a URL as a valid file path) [1] [2], it's up to the developer to ensure that safe, validated input is passed to these tags and functions.

Some CFML Background

Maybe you’re not familiar with ColdFusion and CFML. (If you are, just skip ahead to the next section.) ColdFusion Markup Language (CFML) is a web application development language, first released in 1995.  Adobe now owns and maintains the original ColdFusion implementation, and there have been other commercial and open source implementations, including Lucee, Railo, and BlueDragon.  CFML use remains popular for both legacy applications and new development in organizations across healthcare, education, government, and various commercial industries.  Just ask Google and take a look at the 89 million+ results.

Server-side request forgery (SSRF)

Server-Side Request Forgery (SSRF) is a web application security vulnerability where an attacker is able to abuse functionality and make the application server request an arbitrary URL.   Some of the specifics can be application and language/platform dependent, but requests can typically be made for all supported URL schemes, such as http://, https://, ftp://, file:// and more.  An attacker can leverage SSRF to:

  • Make requests back to the server, including localhost-only services
  • Access internal hosts and services, including things like cloud metadata services
  • Access external hosts and services
  • Potentially send raw network requests

The techniques to turn an SSRF vulnerability into part of an exploit chain for a high-impact compromise are beyond the scope of this post, and will often depend on details in the affected application and target environment.  As a very simple example, consider an internal service that isn’t accessible from the public Internet.  An SSRF vulnerability within that environment may let an external attacker make requests to that internal service, breaking the security assumption that it should be inaccessible.  While this is only a high-level overview of SSRF, there’s lots more in-depth material available elsewhere -- such as here and here.  And for a ridiculously awesome look at some novel SSRF exploitation techniques, have a look at this presentation from Orange Tsai.

SSRF and CFML

Some CFML tags and functions, by design, perform actions that could be dangerous or have security implications.  For example, most developers are aware that if you let a user specify the arguments to <cfexecute> or <filedelete> tags, this could have disastrous consequences. 

 But what about SSRF?  Any tag or function that processes and requests a URL as a parameter is potentially vulnerable to SSRF.  Some of these are obvious, such as <cfhttp>.  In the contrived example below, the user is able to control the URL that the cfhttp call will request.  And code like this should set off all kinds of security alarms for developers:

<cfhttp url="#url.requestURL#">

However, there are other tags and functions that will process and request URLs passed in parameters, where this functionality may be less obvious.  If any of these tags and functions consume user-controlled input in the affected parameters, an attacker will be able to perform SSRF.  Consider the code below:

<cfscript>

/* Some file processing stuff */

[...]

mimeType = fileGetMimeType(form.file);

/* Do more stuff to validate the MIME type and process the file */

[...]

</cfscript>

 The developer may be expecting form.file to contain an uploaded file object.  However, an attacker can pass a URL to fileGetMimeType() instead, and exploit SSRF.

Testing Results - Affected Tags and Functions

The following tags and functions can be vulnerable to SSRF, if they pass unvalidated user input into affected parameters.  These results are based on testing against Lucee and Adobe ColdFusion 2018.


Tags

cfcache

cfcontent

cfdocument

cfdocumentsection

cfdump*

cfexecute*

cfhttp

cfpdf*

cfvideoplayer*

cfzip

 

 


Functions

callstackdump*

contractpath*

directorycreate

directorydelete

directoryexists

directorylist

fileappend*

filecopy*

filedelete

fileexists

filegetmimetype

fileinfo*

filemove

fileopen

fileread

filereadbinary

filesetaccessmode*

filesetattribute*

filesetlastmodified

filetouch*

filewrite

filewriteline*

getcanonicalpath*

getfileinfo

getfreespace*

getprofilesections*

getprofilestring*

gettempfile*

gettotalspace*

imagegetblob*

imageinfo*

imagenew

imageread

isimagefile

ispdfobject*

isvideofile

iszipfile*

manifestread*

objectload

setprofilestring*

storeaddacl*

storegetacl*

storegetmetadata*

storesetacl*

xmlchildpos

xmlelemnew*

xmlgetnodetype*

xmlparse

xmlsearch

xmlvalidate

 

 (* Lucee only)

 Avoiding These Types of SSRF Vulnerabilities in your CFML Code

Developers should make sure to validate any user-controlled input before they’re passed to any affected tags and functions.  If a URL is not expected input, or if following URLs is not intended behavior, additional validation logic should be added to prevent bad data or malicious activity.  For example, some functions will process both URLs/file paths and file objects as function arguments.   Validation in this case might enforce that only file objects are treated as valid input.  The specific techniques and logic to validate the user input may depend on the tag/function and necessary application functionality, and are beyond the scope of this post. 

Examples of user-controlled data can be any of the following:

  • Variables in the URL Scope
  • Variables in the FORM Scope
  • Some Variables in the CGI Scope
  • Cookies (Variables in the COOKIE Scope)
  • Secondary variables derived from URL, FORM, CGI, and Cookie Scopes

 

Bottom line -- make sure that you validate any user-controlled input passed to the tags and functions above.


[1] Update - Thanks to feedback from Brad Wood and Zac Spitzer, adding a note that various Resource providers (http, https, etc.) can be disabled in Lucee by commenting out the appropriate lines in lucee-server.xml.  I haven't tested this exhaustively, but it looks like this will prevent URLs with the disabled schemes (e.g., http://...) from being processed in some of these functions, but may still allow them in other functions.  

[2] Update - Adobe PSIRT has provided the following response:

"Thank you for the opportunity to review and respond to your blog post. Our ColdFusion engineering team has confirmed they leverage Apache Commons VFS in these tags/functions. This API provides a way to disable schemes like [[http://%5Dhttp:/]http://]http://, [[ftp://%5Dftp:/]ftp://]ftp://, ram:// etc by editing the file "org/apache/commons/vfs2/impl/providers.xml" within the commons-vfs jar file. It is strongly recommended for the ColdFusion developer to incorporate input validation in the supported schemes to prevent a risk of SSRF, even if certain schemes are disabled.

However, thanks to your research, our engineering team has determined it would be advantageous to make it easier for ColdFusion developers to disable schemes in an easier and intuitive way. Please keep an eye out for this change in a future release of ColdFusion."

5 comments:

  1. Excellent write up. It's worth noting that basically any function that accepts a file path will allow a URL. In Lucee, there is an abstraction where a Resource interface can be a file path, and zip file, a URL, etc. It's also worth noting that not all the functions in your list are capable of being exploited. For instance callStackDump('https://www.google.com') just returns an error:

    "this is a read-only resource, can't write to it [https://www.google.com/]"

    ReplyDelete
    Replies
    1. Thanks for the feedback, Brad!

      But in terms of exploitability, all of the tags and functions above can be used in an SSRF attack. SSRF vulnerabilities can be basic/non-blind (where the attacker can see the response) or blind (where the attacker can make the request but doesn't see the response).

      While callStackDump() returns an error and doesn't show the URL contents, an attacker is still able to request the URL from the application server. Blind SSRF could, for example, be used to exploit the recent TestBox remote code execution vulnerability (CVE-2020-15929) against an internal server running TestBox that was only reachable from an Internet-facing application server with a blind SSRF vulnerability.

      Delete
  2. An additional note I just got from Zac Spitzer is that Lucee Server allows you to disable any of the Resource providers by commenting out that provider in the XML config inside the "" block. Lucee supports the following resource providers:

    * File (default provider)
    * FTP
    * Zip
    * Tar
    * TGZ
    * HTTP
    * HTTPS
    * SMB (disabled by default)
    * S3

    That would, in theory, disable the default behavior of any tag or function that accepts a "Resource" in Lucee as being capable of interpreting it as anything other than a file (if you removed all providers except the file one).

    ReplyDelete
    Replies
    1. Thanks Brad (and Zac)! This is a great tip, and I wasn't aware of it. I've updated the post with a note. I haven't tested this exhaustively, but it looks like "disabled" resources/schemes are still fetched by some functions. For example, after disabling http, callStackDump() didn't fetch the URL, but cfhttp() still did.

      Delete
    2. Yes to be clear, cfhttp doesn't follow URLs because of the "Resource" abstraction, but simply because hitting URLs is literally what what function does! So disabling the HTTP resource wouldn't have any affect on the cfhttp tag, whose sole purpose is... to hit HTTP endpoints. Unlike the other tags and and functions in the language where this behavior is generally unexpected, a developer should be aware of what cfhttp does.

      Delete