In the drupal framework, the most classic and closest to us is the CVE-2018-7600 vulnerability in 2018. However, in the process of reading and studying this vulnerability analysis article, I found that they are all detailed analysis of this vulnerability point. People who are not very familiar with the running process of this framework may have difficulty understanding it after reading it.
The following is mainly divided into two parts:
The first part is an introduction to the drupal framework process (here mainly for the 8.x series), letting us know the basics of the symfony open source framework The drupal framework on this page uses the listener mode to support the entire complex processing process, and gives us a basic understanding of how the framework handles a request.
The second part combines the framework with a detailed interpretation of the running process of the vulnerability CVE-2018-7600. At the starting point of the vulnerability triggering, we first understand the processing process of the drupal framework by dynamically debugging normal data packets. This uses the controllable variables in the normal package to construct the POC package. Not only can we understand the beginning and end, but we can also make the middle process transparent. Be able to draw parallels.
Drupal is an open source content management framework (CMF) written in the PHP language. It is composed of a content management system (CMS) and a PHP development framework (Framework). It has won the world's best CMS award for many consecutive years and is the most famous WEB application based on PHP language.
The Drupal architecture consists of three parts: core, modules, and themes. The three are closely connected through the Hook mechanism. Among them, the core part is developed and maintained by a team composed of many famous WEB development experts in the world.
Drupal integrates powerful and freely configurable functions and can support website projects with various applications ranging from personal blogs (PersonalWeblog) to large community-driven websites (Community-Driven). Drupal was originally a set of community discussion software developed by DriesBuytaert. Later, due to its flexible architecture, convenient expansion and other features, thousands of programmers around the world joined the development and application of Drupal. Today, it has developed into a powerful system, and many large organizations use Drupal-based frameworks to build websites, including The Onion, Ain't ItCool News, SpreadFirefox, Ourmedia, KernelTrap, NewsBusters, etc. It is particularly common on community-led websites.
First, you can directly download the latest version through the official website download page https://www.drupal.org/download or through https ://www.drupal.org/project/drupal/releases/xxx xxx represents the version number you want to download to download the source code file of the corresponding version. You can also use the PHP package management tool composer to download.
2.2 drupal installation
Installation environment: WIN7 32-bit
Integrated environment: PHPSTUDY
Debugging environment: PHPSTORM
Possible during installation Problems and solutions:
1. PHP version problem: preferably PHP7.0 or above
2. Datetime problem
Solution:
Set in php.ini
3. Installation warning
These two problems (warning) do not need to be resolved.
Solution to problem 1: Upgrade the PHP version to 7.1 and above.
Solution to problem 2:
In php.ini, find [opcache] and add the following content here.
zend_extension="C:\xxx\xxx\php\php-7.0.12-nts\ext\php_opcache.dll"
opcache.memory_consumption =128
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=4000
opcache.revalidate_freq=60
opcache.fast_shutdown=1
opcache.enable_cli=1
4. Because drupal processes some requests too slowly, it may cause timeout exceptions. Just set the max_execution_time option in Php.ini to a larger value.
The following is the directory after decompression of the drupal 8.5.7 source code:
/core The core folder of drupal, please refer to the following description for details
/modules stores customized or downloaded modules
/profiles stores downloaded and installed custom configuration files
/sites folder, in drupal 7 or earlier versions, mainly stores themes and modules used by the site and other site files.
/themses stores customized or downloaded themes
/vendor stores code dependent libraries
Next let’s look at the directory structure under the core folder core
/core/assets - Various extension libraries used by drupal, such as jquery, ckeditor, backbone, normalizeCSS, etc.
/core/config - drupal The core configuration file
/core/includes – the underlying functional functions of the module, such as the modular system itself
/core/lib – the original core classes provided by drupal
/core/misc – front-end miscellaneous files required by the core, such as JS, CSS, images, etc.
/core/modules – Core modules, about 80 items
/core/profiles – Built-in installation configuration files
/core/scripts – Various components used by developers Hit script
/tests – Test related files
/core/themes – Kernel theme
Drupal is built on Based on the symfony open source framework, it can be seen from the symfony official website that sysmfony is a reusable PHP component set. You can use any component independently in your own application. On the symfony official website, each component has its own independent Documentation, some of these components are used directly by drupal, and some are modified according to drupal's own characteristics.
Let’s first take a look at the execution process of symfony
Drupal and symfony also use the same concept in design. They both believe that any A website system is actually a system that converts requests into responses.
In drupal's routing system, we can see the relationship between the various components:
Based on this, drupal's processing process for symfony It has been refined to form the current huge drupal processing and response process.
The image link address is https://www.drupal.org/docs/8/api/render-api/the-drupal-8-render-pipeline. If necessary, you can download the high-definition version yourself.
Finally, the corresponding global variables will be added to the request object and the encapsulated request object will be returned.
If the above operation is just a preliminary stage, then the next line of code $response = $kernel->handle($request); will start to get to the point, and the drupal kernel object kernel will handle the request request. .
#The core of Drupal's processing is the use of the listener pattern in the design pattern. It includes an event source, which contains different events and event levels. The other part is the program or function that needs to execute the event, we call it the listener. In the request processing process, every time a node is reached, a corresponding event will be dispatched, and the listener will perform corresponding operations based on the obtained event object and level.
The core events of the system continue to use the events in the symfony framework, located in kernelevents.php, which contains eight cores:
Const REQUEST = 'kernel.request' executes any event in the framework code The code is triggered before the start of request dispatch.
Const EXCEPTION = ‘kernel.exception’ Event triggered when an uncaught exception occurs.
Const VIEW = ‘kernel.view’ Triggered when the return value of the controller is not a response instance. At this time, the controller returns the rendering array for further rendering work.
Const CONTOLLER = ‘kernel.controller’ is triggered when the corresponding controller is found after parsing the request request, and this controller can be modified.
Const CONTROLLER_ARGUMENTS =‘kernel.controller_arguments’ Triggered when parsing the parameters of the controller, and the parameters can be changed.
Const RESPONSE = ‘kernel.response’ Triggered when creating a response reply request, and can modify or replace the response to be replied.
Const TERMINATE = ‘kernel.terminate’ will be triggered once the response is sent. This event will allow handling of heavy post-response tasks.
Const FINISH_REQUEST = ‘kernel.finish_request’ is triggered when the Request request is completed. It can reset the global and environmental state of the application when the application is changed during the request.
In addition to these core events, each listener in drupal also dispatches its own events. The locations of these files are in the corresponding folders under the \core\lib\Drupal\Core\ directory. They all end with events.php, and the corresponding static event variables are defined in the file.
Let’s take a look at the drupal core request process:
Start the request---》Parse the request to get the controller and correct it------》Parse the controller parameters-- --》Call the method according to the controller-----》Observe the return situation of the controller: return the response object response or continue rendering------》Send the response. If an exception occurs in the middle of the entire process, the exception event will be directly triggered for exception distribution. In the entire process, in addition to responding to core request events, the request object will also enter branches that respond to other common module events according to the actual situation. However, no matter how bumpy the process is, it will eventually return to the main process and return the response object response.
Next, observe the above specific behaviors from the source code:
Continue to follow up from index.php and enter the drupalkernel.php file. Let’s take a look at what operations were performed.
The next step is a series of processing function call chains. We can keep following the handle function, so that we can directly follow the core function handleaw
#Here we continue to follow up on the filterResponse function that is about to return.
The response objects here will be returned layer by layer (it should be noted that not all response results will go through this process), but they will eventually be encapsulated into response object, returned to the $response variable in the index.php file. Then call $response->send() to send the encapsulated response object.
Sometimes the content of the request operation we send will be too cumbersome, so when the above call ends, our drupal kernel will do the final processing before shutting down. The process enters the last line of the Index.php file and calls $kernel->terminate($request,$response). We follow the stackedhttpkernel.php file according to the call chain
At this point, the entire cycle has ended.
We found that the most common operation in the entire process above is the event dispatching. In fact, the process of all dispatching is the same. The specific dispatching process is in the ContainerAwareEventDispatcher.php file. We use the kernel.request event. Give examples.
There are 19 total listeners in the system, and each listener will have a service name related to it. We will match it based on the incoming event name. The corresponding listener then traverses and calls the function functions corresponding to the service names one by one. What we have here is the kernel.request event, and the calling method is callback calling.
Through the simple framework analysis in the third part, you may only have a vague concept of the process. Next We combine vulnerability examples and focus on the more classic Drupal framework vulnerability cve-2018-7600 to carefully observe the detailed operation process of this vulnerability in the framework. The version of the vulnerability trigger environment we use here is 8.5.0. This version of the vulnerability trigger is more intuitive, so the code version used in our subsequent analysis will be this version unless otherwise stated.
4.1 Patch comparison
Because this vulnerability was fixed in version 8.5.1, and there is only one subversion between 5.0 and 5.1, we can more clearly compare the differences in the source code. . Let’s see how the official fixes this vulnerability: In the source code of version 8.5.1, a new RequestSanitizer.php file is added, which filters the request part. In the stripDangerousValues method, it filters those starting with # and no longer whitelists them. The values of all key names in .
In the prehandle method, the new method added in the above file is called for filtering. The red part on the right side of the figure below is the filtering code added in 8.5.1.
The calling position of the filtering code here is before the drupal kernel processes the request. This will completely fix the vulnerability once and for all.
Then we entered the drupal official website to view the official documents and found that the drupal render api has special processing for the beginning of #. The key document link is below
https ://www.drupal.org/docs/8/api/render-api/render-arrays and according to the checkpoint security team released a report on the technical details of this vulnerability. The link is as follows: https://research.checkpoint.com/uncovering-drupalgeddon-2/. It was found that the source of the vulnerability trigger is the avatar upload function in the registered user function in version 8.5.0.
4.2 The running process of data packets in the framework
Now that we know the trigger source of the vulnerability, first upload a random picture and capture a normal Check out the initial package to see what's going on.
Then in the entry file index.php, after packaging the createfromglobals function, drupal encapsulates all the parameters we passed in into the request object.
4.2.1KernelEvents::REQUEST Dispatching Events
Since the framework process has been introduced above, the following is the stage of the drupal kernel processing our request. , here we directly set the breakpoint on handleRaw, and enter the first KernelEvents::REQUEST dispatch event to see what the listeners did to this request.
First, drupal tries to process the Option request. Unfortunately, ours is a POST request, so we don’t process it and let it go directly.
Then we will deal with the slash problem on the URL path, and will convert the path starting with multiple slashes into a single slash
Then the identity will be verified according to the request. We are not logging in here. We are tourists, so there is no special treatment here.
Next, the target parameters containing $_GET['destination'] and $_REQUEST ['destination'] will be cleaned up to prevent redirect attacks.
It will then be judged whether the request is an AJAX request based on the _drupal_ajax parameter in the POST request, and relevant attributes will be set.
The next step is to match the corresponding route according to the URL part in the request. Here drupal will first search for the corresponding match in the route cache, and if not, then proceed all Routing table lookup operation. (Due to the large amount of code, we will not intercept all the code here, but only part of the code). The processing function is in onKernelRequest. At the same time, we can also find relevant information in the user.routing.yml file.
The route is found, the next step is to check whether the route is available
The next step is to check whether the site is in Maintenance mode, if it is maintenance mode, log out of the account, check whether the site is offline, check the dynamic page cache, pre-process non-routing settings, and see whether to disable the replica server according to the parameters. The related functions of these operations are screenshots below.
After processing the request-related event dispatch in handleRaw and finding the corresponding controller from the request, it is time to find the corresponding processing function based on the controller. The controller in call_user_function below has been replaced by the closure callback function in the above picture. Calling the controller here is equivalent to directly entering the closure function in the above picture.
In drupal, controllers will be added to the rendering context to ensure that if there is any place that needs to be rendered during the processing of each controller, the rendering operation will be performed directly.
According to the controller entering the real calling method, which is getContenResult, the construction of the form officially begins.
4.2.4 Form Building
After entering the buildForm function, we will first get the POST information and store it in form_state.
In the uploadAjaxCallback function, we get the value of the element_parents parameter from the URL of the data packet, and use this as a key to get the result from the FORM form we finally processed, and then render the result and present it on the HTML page superior.
Based on the parameters of the URL in our POST package, we take out the first item in the widget array under user_picture in the FORM form.
The final object to be rendered in doRender is the element just taken out.
After rendering, the entire processing process is coming to an end, and the response begins to be constructed and returned layer by layer.
4.2.6 kernel.response event
Now that we have reached the response stage, we must start to trigger the response. Next, let’s take a look at what listeners the response has.
In the response dispatch function, it basically adds to the response object and does some corresponding expansion operations. For example, determine whether a dynamic page needs to be cached, whether it is necessary to add a cache context, handle placeholders, set additional headers in a successful response, etc. All the above operations will be in the kernel.response array under listeners, and will not be introduced in detail here.
Next, use the element_parents parameter value in the url to get the value in the form array. It is described in Section 4.2.5 of Part 4 and will not be repeated here. Finally, construct the corresponding variables and use call_user_func_array in the doRender function to trigger the vulnerability.
Based on the above description, we used the mail parameters to construct the following POC package
In addition to the above-mentioned mail parameters being controllable, the form_build_id parameter was also found during the analysis process Also controllable, another POC is as follows.
The above is the detailed content of How to conduct in-depth analysis of the drupal8 framework and dynamic debugging of vulnerabilities. For more information, please follow other related articles on the PHP Chinese website!