Intro to CakePHP for Bug Hunters

A short guide to help you fast track your hunt

Chris Lyne
Jun 12 · 8 min read

Introduction

In order to find security vulnerabilities in a web application, it is necessary to spend time upfront learning about the framework upon which it is built. This guide is here to help you fast track that process for an application built using CakePHP. After reading this, you will have the knowledge to get started hunting a CakePHP app for security bugs. However, this is not a comprehensive guide. I will assume you have the source code to whatever app you’re researching, and you should be familiar with PHP.

Framework Overview

CakePHP is a web development framework that runs on PHP. At the time of writing, the current version is 3.7. Like many other popular frameworks, it is designed with the Model-View-Controller (MVC) design pattern in mind. This pattern defines how HTTP requests are handled and how responses are presented to the user. Below is a graphic showing the CakePHP request cycle.

Source: CakePHP Request Cycle

The request cycle can be generalized as such. Requests originating from an HTTP client are handled by a controller. The controller then decides how to interact with the model (e.g. query a database). Finally, the client will be presented with a view (e.g. web page) containing the model (e.g. a list from the query results). Again, this is just a generalization. There are other pieces that come into play (e.g. middleware), but these are the core of the MVC architectural pattern.

Application Routes

The controller plays an important role with request handling. It is typical to see a path such as “/Articles” to be handled by the ArticlesController.php class. In fact, by convention, controllers will be named this way.

ArticlesController will handle /Articles

However, there is a “routes.php” configuration file that can be modified to define custom routing logic. For instance, if the following route were defined in routes.php, it would make the path “/Articles” instead route to the MyArticlesController index action.

Router::connect(
‘/Articles’,
array(‘controller’ => ‘MyArticles’, ‘action’ => ‘index’)
);

The resulting logic would look like this.

Custom route into MyArticlesController

The framework has a built in RoutesShell that can be used to list all of the routes. In the project directory, try running the command below. You might find routes you didn’t know existed:

bin/cake routes

I won’t get into all of the routing specifics here, so take a look at the CakePHP routing documentation to better understand the more complex routing possibilities.

Controller

Routing determines which controller handles a request. The bulk of controller logic is based around actions. Actions are defined as public methods in controller classes. These action methods will handle a request and create a response (typically a view). You’ll definitely start seeing user input in the action methods.

An example path to trigger the “update” action in the ArticlesController might look like “/Articles/update”.

Update Action in ArticlesController

And here is the code:

class ArticlesController extends AppController
{
public function update()
{
// some logic
}
}

Note: Any controllers you encounter will almost certainly extend (and inherit from) the AppController base class. Be sure to keep this in mind. There is also a default PagesController for serving static content. Controller classes will be located in the src/Controller directory.

Let’s talk about the beforeFilter callback method. The docs state that this method is “called during the Controller.initialize event which occurs before every action in the controller.” Something I specifically look for in this method is the usage of the AuthenticationComponent to allow an action to be publicly accessed. For instance, the following method definition would allow unauthenticated access to the add action in UsersController (snippet taken from authentication and authorization tutorial). So definitely keep an eye out for this type of logic.

class UsersController extends AppController
{
public function beforeFilter(Event $event)
{
parent::beforeFilter($event);
$this->Auth->allow('add'); // no auth required to add!
}
public function add()
{
// pre-auth functionality
}
}

HTTP Requests

CakePHP accesses parts of the HTTP request differently than the normal PHP syntax. Forget about $_GET and $_POST. CakePHP piles a bunch of stuff into the request object. Below are some common expressions to look for along with their normal PHP equivalents.

$this->request->getQuery('id');          // $_GET['id']
$this->request->getData('token'); // $_POST['token']
$this->request->env('SERVER_NAME'); // $_SERVER['SERVER_NAME']
$this->request->getHeaderLine('referer') // $_SERVER['HTTP_REFERER']
$this->request->getCookie('sid') // $_COOKIE['sid']

The request object also encapsulates session data. Session data is accessible from controllers, views, helpers, cells, and components. Forget the PHP $_SESSION variable! Below are examples of a read and write to the session. The session docs contain more examples as well.

$id = $this->getRequest()->getSession()->read(‘User.id’);
$this->getRequest()->getSession()->write(‘User.twitter’, ‘@lynerc’);

To gain a more comprehensive idea of what is contained in the request object, please take a look at the cake request docs.

Model

Like many other frameworks, CakePHP utilizes object-relational mapping (ORM) to make interactions with the database simple for the developer. ORM is the magic behind the model. The model is composed of Table and Entity objects, representing database tables and “individual rows or domain objects,” respectively. You’ll find table and entity classes in the project’s src/Model/Table and src/Model/Entity directories.

Model Directory Structure

As you may have guessed, the model might be susceptible to SQL injection (SQLi) if the developer wasn’t careful. Keep an eye out for database queries in controllers and table methods. If the developer is inexperienced, you might get lucky and find a bug in an execute() string parameter. Like this:

$name = $this->request->getQuery('name');
$query = “SELECT * FROM articles WHERE name=’$name’”;
$connection->execute($query)->fetchAll('assoc');

However, spotting an SQLi vulnerability isn’t going to be that obvious for the most part. The documentation actually provides a section dedicated to SQLi prevention. I’m not going to copy/paste their guidance here, so definitely take a look as it shows examples of vulnerable conditions.

View

The view is responsible for generating output that is sent back to the HTTP client. This could be in the form of HTML, XML, JSON, a PDF file, etc. CakePHP employs view template files (.ctp) to handle presentation of the data to be returned. You’ll find these files “in src/Template/, in a folder named after the controller that uses the files, and named after the action it corresponds to.” For example, the graphic below shows the project structure as it relates to a view for the update action in ArticlesController.

View Template Directory Structure

View templates “utilize the alternative PHP syntax for control structures and output,” so they may look a little funky at first. For example, the following is a foreach control structure:

<?php foreach ($mylist as $item): ?>
<li><?= $item ?></li>
<?php endforeach; ?>

In this case, $mylist is a view variable. These variables are often populated using the set method from within a controller or view template. For example, as shown in the documentation for setting view variables, the color view variable could be set like such:

$this->set(‘color’, ‘light blue’);

Then in the view, color would be written out.

The sky is <?= h($color) ?> .

At this point, I assume you might be wondering about cross-site scripting (XSS). As shown above, CakePHP provides a valuable h() function. It is a wrapper for htmlspecialchars(), and its sole purpose is to encode output. Needless to say, if you don’t see user-controlled data being output-encoded with h(), there might be an issue.

There are other view-related components to be aware of as well, as these can contain user-controlled data too. These components are layouts, elements, and view blocks.

Middleware

Now that we’ve discussed the core of the MVC logic, we need to touch on middleware. Middleware can be used to modify requests and responses on the fly. Any user-controlled data originating from an HTTP client is accessible by middleware.

Middleware wraps the application like an onion. Depending on the application, there can be multiple layers of middleware that handle a request before it reaches the controller. The graphic below shows an application wrapped with middleware for Routes, Assets, Exceptions, and CORS. Keep in mind every app will have different middleware requirements.

Source: CakePHP Middleware

In order to audit custom middleware classes in use, keep these guidelines in mind. A middleware can be applied to the entire application or applied to specific route scopes. Be sure to take a look at src/Application.php and config/routes.php to understand how middleware is used. Middleware classes should be located in the src/Middleware project directory.

I should also mention that CakePHP has several built-in middleware. Of particular interest are CsrfProtectionMiddleware, SecurityHeadersMiddleware, and EncryptedCookieMiddleware. Basically, all of these middleware add security enhancements, so if you come across an application that doesn’t employ these, there might be an easy “win.”

Security

In addition to the middleware mentioned above, CakePHP provides a few tools to help the developer enhance security. These include the Security Utility and Security Component. They handle tasks such as encryption, hashing, enforcing SSL, etc. If these aren’t being used, the developer may have rolled their own security or left some things out entirely.

Conclusion

At this point, you should be feeling confident in your ability to approach a bug hunt in a CakePHP-based web application. I have given you an overview of the framework itself, pointed you to relevant documentation, and discussed security implications of various components. Keep in mind that the process of auditing PHP code remains largely the same. The main difference is that the framework packages user input and data flow in its own way. Once you get the hang of how the framework works, off you go!

Tenable TechBlog

Learn how Tenable finds new vulnerabilities and writes the software to help you find them

Chris Lyne

Written by

Chris is a security researcher at Tenable, focused on finding 0-day vulnerabilities. He is a former developer and aims to make the cyber world more secure.

Tenable TechBlog

Learn how Tenable finds new vulnerabilities and writes the software to help you find them