[00:09.460 --> 00:13.440] Hi, welcome. Thanks for attending our talk. This is Room for Escape, [00:13.440 --> 00:16.100] Scribbling Outside the Lines of Template Security. [00:16.460 --> 00:20.140] So, my name is Alvaro Munoz, also known as Pwntested in the social media. [00:20.420 --> 00:23.520] I'm a security researcher with the GitHub security lab. [00:23.560 --> 00:27.960] And with me, my colleague, Alexander Mirosh, also known as Oleg Mirosh in Twitter. [00:27.960 --> 00:31.760] And he is a security researcher with Micro Focus Fortify team. [00:31.840 --> 00:36.600] So, today, we will be reviewing the security of content management systems, or CMS. [00:36.600 --> 00:41.720] And, basically, we will be focusing on the security of the template systems [00:41.720 --> 00:48.040] that are used by CMSs. So, a content management system is basically an application that is used [00:48.040 --> 00:53.940] to manage different types of web content, so that users can actually create, upload, [00:53.940 --> 00:59.480] and publish different types of content. So, normally, this content is based on some [00:59.480 --> 01:05.500] structures and some kind of documents called templates, which are used to generate and [01:05.500 --> 01:12.120] create dynamic content. So, these templates normally allow a subset of different programming [01:12.120 --> 01:18.060] language capabilities. So, they are powerful in the sense that they can be used to run arbitrary [01:18.060 --> 01:23.620] code. Because of that, they are normally sandboxed in order to prevent arbitrary code execution and [01:23.620 --> 01:31.340] remote code execution. So, our research will focus on both .NET and Java-based content [01:31.340 --> 01:37.340] management systems, because these are the languages that are more prevalent across enterprises. [01:37.460 --> 01:43.900] And our assumption is that the attacker can control the templates, right? So, we don't really [01:43.900 --> 01:48.520] care about how the attacker gets control of these templates in the first place, if it's through [01:49.000 --> 01:54.640] a server-side template injection, or if it's maybe through our cross-site scripting that allows him [01:54.640 --> 02:01.680] to submit arbitrary templates in behalf of someone else. Or maybe they have permissions, [02:01.680 --> 02:06.660] like if you are a user, for example, in SharePoint, if you have an account in SharePoint, you are [02:06.660 --> 02:14.720] allowed to create your own sites and content. So, no matter how the attacker can edit the content [02:14.720 --> 02:22.520] of a template, our research will focus on escaping and breaking all the mitigations put in place to [02:22.520 --> 02:30.240] prevent arbitrary code execution. So, we will first start with .NET. Basically, we will focus [02:30.240 --> 02:36.540] on SharePoint. We will present five different ways we were able to break the sandbox used by [02:36.540 --> 02:41.660] SharePoint to prevent arbitrary code execution. And then we will move into the Java part, where [02:41.660 --> 02:48.080] we will present four different template engines, including the most popular ones, such as Velocity [02:48.080 --> 02:53.340] and FreeMarker. And then we will present 10 different content management systems, and we will [02:53.340 --> 02:58.160] try our bypasses on them. So, we will wrap up with some takeaways and conclusions, and then open the [02:58.160 --> 03:05.500] floor for Q&A. So, let's start with the .NET part. Thank you, Alvaro. In this part of our presentation, [03:05.500 --> 03:10.680] we will present different types of security problems in content management systems, and give [03:10.680 --> 03:16.480] examples of them in SharePoint. But before that, we need to explain some basics of SharePoint [03:16.480 --> 03:25.000] security. SharePoint has two types of ASPx pages. The first type is application pages. Each of these [03:25.000 --> 03:30.820] pages are the part of SharePoint server and implement some application logic. They are stored [03:30.820 --> 03:36.500] in specific folders on the file system. Of course, users are not able to change them. They are regular [03:36.500 --> 03:43.160] ASPx pages and are processed by server without any restrictions. In opposite to them, there are [03:43.160 --> 03:49.320] side pages. They are stored in database and they can be customized even by users. SharePoint parses [03:49.320 --> 03:54.840] them in special mode, also known as safe mode. Actually, they are more like some sort of templates [03:54.840 --> 04:01.860] for presenting dynamic content. On this slide, we can see a diagram how server works with these [04:01.860 --> 04:09.560] pages. Virtual provider can fetch content from file system or database. Based on the virtual path of [04:09.560 --> 04:16.980] the current page, ASP page parse filter will decide either it is side page and safe mode should be [04:16.980 --> 04:23.180] applied, or it is an application page and it will be processed without any restrictions. So, page [04:23.180 --> 04:33.280] filter is a critical element from security design. Let's have a look on a simple ASPx page. [04:33.280 --> 04:38.900] For our attacks, we are only interested in server-side components. For example, directives. [04:38.900 --> 04:44.120] There are special instructions on how server should process the current page. Often, they have [04:44.120 --> 04:50.660] some number of attributes. We can include server-side code either in special blocks or as [04:50.660 --> 04:57.380] embedded server-side code. To be processed by server, control should have the runout server [04:57.380 --> 05:04.780] attribute. The next element is server-side common block. It is ignored by server. And [05:04.780 --> 05:09.890] server-side include directives allow us to include raw content of arbitrary file. [05:10.760 --> 05:17.620] Now, we can better understand what safe mode means. Side page will not be compiled, so we cannot use [05:17.620 --> 05:24.060] server-side code. We are not able to include files from file system. We can only use allowed [05:24.060 --> 05:30.880] controls. This list is defined in safe control section of web config file. Page filter also [05:30.880 --> 05:37.240] applies an allow list for directives and even for attributes of most of them. There are many [05:37.240 --> 05:43.940] other restrictions. For example, event binding is blocked as well. As we can see, it is a set of [05:43.940 --> 05:52.480] quite strong restrictions how it can be bypassed. As we know, safe mode is enforced by page filter. [05:52.820 --> 05:59.920] So, our first question was, is there any place where SharePoint does not use it? And answer yes, [05:59.920 --> 06:06.760] there are such places. Page filter will not be applied for the content argument of the parse [06:06.760 --> 06:12.560] control method if it's called only with one argument or if the second one that actually has [06:12.560 --> 06:20.040] name ignoreParseFilter is true. In addition, page filter is used at rendering time but is ignored [06:20.040 --> 06:29.080] at design time. But even if page filter is not applied, SharePoint uses another way to verify [06:29.080 --> 06:37.360] the input. It is a verify control on safe list method from editing page parse type that aims to [06:37.360 --> 06:45.260] do the same task at the original page filter, block markup with unsafe elements. But let's [06:45.260 --> 06:50.780] imagine for a second that we are able to bypass either this method or page filter. By the way, [06:50.780 --> 06:55.760] each such bypass is separate vulnerability and we will present them in a few minutes. [06:55.760 --> 07:02.120] So, how could we get remote code execution after escaping the safe mode? Remember, [07:02.120 --> 07:06.360] since parse control method never calls compilation, we are not able to use [07:06.360 --> 07:13.520] server-side code or perform any other attack that require compilation. But if we escape [07:14.300 --> 07:20.080] safe mode, we can use unsafe controls or directives. Let's review several of them. [07:21.000 --> 07:28.420] One of the most interesting unsafe controls is object data source. It allows us to invoke public [07:28.420 --> 07:34.200] methods from arbitrary public type. We can see an example of payload that uses start method from [07:34.200 --> 07:40.140] process type to launch calculator. So, actually, it is arbitrary code execution, jackpot. But let's [07:40.140 --> 07:47.380] review a couple other unsafe controls. XML data source and XML controls allow us to get content [07:47.380 --> 07:52.640] of arbitrary XML files. The similar results we can get by server-side include directives [07:52.640 --> 07:59.140] that return us content of any text files. Let's see how we can escalate from arbitrary file read [07:59.140 --> 08:05.820] to arbitrary code execution. If we can access web.config file, we will be able to get validation [08:05.820 --> 08:13.260] key from machine key section. By the way, this value may be present in other places such as [08:13.260 --> 08:19.240] internal SharePoint properties. We will see this example a bit later. With validation key, [08:19.240 --> 08:26.840] we can generate a valid view state that will execute arbitrary code commands on the target [08:26.840 --> 08:35.660] server. We can use tools such as userserial.net for this. Now, when we know what safe mode is and [08:35.660 --> 08:41.500] how we can compromise SharePoint server if it is bypassed, we can move to our next part of this [08:41.500 --> 08:47.220] talk. Here we will present five different types of security problem in content management system. [08:47.540 --> 08:54.160] We will show examples of each type in SharePoint. We would like to stress here that our target is [08:54.160 --> 08:59.080] SharePoint server with default configuration. All vulnerabilities allowed us to execute arbitrary [08:59.080 --> 09:06.300] code on the target and all attacks were performed by regular user. No admin rights were needed. [09:06.860 --> 09:13.780] Let's start. The first type of security problems is access to resources with sensitive information. [09:13.780 --> 09:19.560] It can be configuration or business information in various files, logs, database, or even process [09:19.560 --> 09:25.880] memory. Of course, proper sandbox should prevent this problem, but it is not always the case. [09:26.220 --> 09:30.260] We already mentioned that page filter blocks server-side includes directives [09:30.260 --> 09:35.820] and verify control on safe list method should do this as well, and actually it does. [09:35.980 --> 09:42.360] But if it's called with false in block server-side includes argument, it will not block them. [09:42.540 --> 09:47.220] And we found such usage of this method. It was used for design mode. [09:48.060 --> 09:54.540] The next building block for our talk, how we can provide our markup for this mode. We can send it [09:54.540 --> 10:01.480] in web part XML parameter of the render web part for edit method of the web page services. [10:01.480 --> 10:07.600] So we can try to include web config file there. Here we can see the full payload for the mentioned [10:07.600 --> 10:13.260] parameter and address to relevant web services. Server returned us the entire web config with [10:13.260 --> 10:18.560] validation key. We use it for view state-based deserialization attack, which led us to [10:18.560 --> 10:21.120] executing arbitrary OS command on the server. [10:22.740 --> 10:27.180] Time for our next type of security problems in content management system. [10:27.640 --> 10:30.500] Allow dangerous element that can be used for attacks. [10:31.600 --> 10:34.840] We have found an example in SharePoint safe control list, [10:35.340 --> 10:39.880] or should we call it not so safe control list in this case. [10:42.100 --> 10:48.280] It is contact link suggestion micro view control. We can see snippet with interesting code from [10:48.280 --> 10:54.060] implementation where request parameter is passed to data set read XML method. [10:54.160 --> 10:59.160] If we can control input for this method, we can get our data deserialized by XML serializer [10:59.160 --> 11:04.840] with control type. We already showed in one of our previous work that in this case we can get [11:04.840 --> 11:09.840] arbitrary code execution. Unfortunately, this payload is too big for slides, but you can find [11:09.840 --> 11:17.580] it in our white paper. The last piece of the puzzle is our site page with this dangerous control. [11:17.580 --> 11:23.320] You can see it on this slide. For the attack, we just need to place the payload into the text box [11:23.320 --> 11:28.370] and click on submit button and desired command will be executed on the SharePoint server. [11:29.820 --> 11:35.020] For us, the next type of security problems looks quite interesting, so we will explain it with [11:35.020 --> 11:41.460] more details and present two separate examples from SharePoint server. Dynamic content usually [11:41.460 --> 11:47.160] means that we will have at least read access to some properties or attributes of some objects. [11:47.580 --> 11:54.500] For some system like SharePoint, we can even write values there. Of course, some box should filter out [11:54.500 --> 12:00.560] the access to dangerous property or attributes. Let's review basic type of such filtering. [12:00.960 --> 12:05.580] The first case is when only one level of properties or attributes is allowed. [12:05.580 --> 12:11.360] We can see examples on the slide. Name property of user object of select value from menu. [12:11.360 --> 12:16.500] We can imagine the object and its properties like a branch with only leaves. [12:17.740 --> 12:22.460] If an allow list is applied, it's relatively easy to review all elements. And after such review, [12:22.460 --> 12:27.940] we can make sure that there is no dangerous elements. What if block list is used instead? [12:28.100 --> 12:32.320] We still need to verify available objects and it can be a bit difficult. [12:32.600 --> 12:36.500] So in general, we do not consider a block list a safe approach because of potential [12:36.500 --> 12:41.340] gaps there. We will see in Java part a couple of examples of such bypasses. [12:42.300 --> 12:47.300] The most interesting case for us is where access to nested properties or attributes [12:47.300 --> 12:54.520] is allowed. For example, request.authUser.name or menu.selectedItem.text. [12:54.700 --> 13:00.460] Because of branch-leaves analogy, many developers may imagine this case as branch with branches [13:00.460 --> 13:08.040] and leaves. And they may apply a filter only for the first level objects. But it is not true. [13:08.040 --> 13:14.200] It is a network. And we may jump from one branch to another branch or even to the trunk. [13:14.200 --> 13:19.460] For example, on this slide, we can see how we can access application instance from a new web [13:19.460 --> 13:25.140] control. Let's illustrate this problem by examples from SharePoint. [13:25.660 --> 13:31.660] There is wikiContentWebParseControl. It is allowed and can pass our markup into the [13:31.660 --> 13:37.640] parseControl method. Please note, it is called with false value in ignoreParseFilter argument. [13:37.640 --> 13:44.480] So, PageFilter will not be ignored. The following snippet shows that in this case, [13:44.480 --> 13:48.620] the virtual path will be created from AppRelativeVirtualPath property. [13:48.900 --> 13:53.110] And if you remember, PageFilter will apply restriction based on this virtual path. [13:53.440 --> 13:59.700] So, if we are able to change it, we can fool the PageFilter to not apply any restriction to our [13:59.700 --> 14:08.200] markup. Let's try to graph such payload. First snippet fails, because when ASPxParser tries to [14:08.200 --> 14:14.760] assign a new value to AppRelativeVirtualPath, the Page property of our control is not defined yet. [14:14.760 --> 14:21.040] So, we need to delay this assignment a little bit. We can do this by data binding. So, by the time [14:21.040 --> 14:26.620] the property is bound, the Page property will be already defined. [14:27.340 --> 14:35.860] Here is our final payload. We can notice that our new path points to application page setting ASPx. [14:36.240 --> 14:42.960] It is assigned to ToolTip property and later will be transferred to AppRelativeVirtualPath. [14:43.020 --> 14:48.360] So, the PageFilter will think that this is system page and will allow any unsafe markup. [14:48.360 --> 14:51.960] For example, we can use ObjectDataSource control to start calculator. [14:52.860 --> 14:55.480] Let's see how the real attack may look. [14:59.240 --> 15:04.720] We can see a site page with our payload. Path to system page. It will be assigned to [15:05.500 --> 15:10.680] AppRelativeVirtualPath. Unsafe markup contains ObjectDataSource control. [15:11.080 --> 15:19.400] We will invoke start method of the process type and we'll start calculator. Let's save it here. [15:20.360 --> 15:24.760] For our attack, we need to upload it to the target server. In our case, it's SharePoint [15:24.760 --> 15:30.100] with default configuration. That means regular users have access to their own personal sites [15:30.100 --> 15:36.120] and we can use them to host our site page. We are notificated as regular user with name attacker. [15:36.400 --> 15:43.340] Sneaky, isn't it? And here is his personal site. Let's upload our page here. [15:44.100 --> 15:50.220] Now, to trigger our attack, we just need to click on it. But before that, let's take a look on the [15:50.220 --> 15:56.500] right slide of our screen. We can see task manager on our SharePoint server and we will notice if [15:56.500 --> 16:02.680] calculator start. Now, let's start our attack and here is our calculator. [16:03.680 --> 16:09.360] Let's move to our next vulnerability in SharePoint. Now, we will try to exploit read access to nested [16:09.360 --> 16:15.260] properties. We will use control parameter. It allows to bind value of property from another [16:15.260 --> 16:22.440] control to select prop parameter. Also, it supports nested properties. We need to deliver value of [16:22.440 --> 16:30.040] target property back to us. To do this, we will use XML URL data source control that sends value [16:30.040 --> 16:37.180] of select parameters to external server. Now, we need to find accessible property with sensitive [16:37.180 --> 16:42.980] information. Here, we should explain a little bit configuration process of SharePoint online [16:42.980 --> 16:48.060] servers. Obviously, they are installed and configured automatically. But what about [16:48.060 --> 16:53.680] configuration parameters that are unique for each installation? They will be provided in special [16:53.680 --> 17:00.280] file that will be used for unintended configuration. What is important for our attack? All such [17:00.280 --> 17:07.060] parameters, including validation key, will be stored in initialization setting property. So, we just need [17:07.060 --> 17:14.940] to find a path of nested property to it from any allowed control. And here it is. Here is the whole [17:14.940 --> 17:21.820] page that will send value of validation key to attackers.server.com. With this value, we [17:21.820 --> 17:26.970] successfully got arbitrary code execution by unsafe deserialization in view state. [17:28.220 --> 17:33.980] Now, let's move to the next type of security problems. It is connected with our previous work [17:33.980 --> 17:40.940] on unsafe deserialization. Such kind of problem is relevant when text or binary data is converted [17:40.940 --> 17:49.340] to an object and the type or class of this object is under attacker control. Plus, it is not properly [17:49.340 --> 17:56.880] limited. Actually, it doesn't really matter what mechanism is used. Classical deserializers, [17:56.880 --> 18:03.480] JSON unmarshalers, type converters, or even some custom approach. All of them are potentially [18:03.480 --> 18:09.560] dangerous. For successful exploitation, attacker just may need to find proper gadget on the system. [18:10.240 --> 18:15.980] We have found examples of such problems in SharePoint and were able to perform arbitrary [18:15.980 --> 18:22.320] code execution attack using it. But patch is not available yet. So, we are going to publish all [18:22.320 --> 18:28.740] details of this problem when fix is released. The last type of security problems in this part [18:28.740 --> 18:35.640] is the classical time of check to time of use problems. They occur when the server invalidates [18:35.640 --> 18:42.540] some input, but this input is later changed before the server uses it. We have found such problem in [18:42.540 --> 18:48.580] web part editing surface page. User input is validated by the already mentioned verify control [18:48.580 --> 18:56.200] on safe list method, but later the server may modify the input and remove substring that match [18:56.200 --> 19:05.760] specific regex pattern. Let's look on the next input. For validation control on safe list, it is [19:05.760 --> 19:13.220] just one server-side comment block, so it will pass validation. But SharePoint removes the highlighted [19:13.220 --> 19:21.020] yellow substring and pass control will see two comments and some markup. Note, pass control has [19:21.020 --> 19:28.100] only one argument, so patch filter will be ignored. Time for our payload. We can notice our unsafe [19:28.100 --> 19:35.100] object data source control and calculator command. In this part of our talk, we saw multiple ways [19:35.540 --> 19:41.160] to achieve arbitrary code execution on the SharePoint server by regular user. [19:41.720 --> 19:47.180] These vulnerabilities revealed five different types of security problems in content management [19:47.180 --> 19:53.340] system. Now let's switch back to Alvaro and he will present even more vulnerabilities with [19:53.340 --> 19:59.740] templates for dynamic content in different Java frameworks and products. Thank you, Alexander. [19:59.740 --> 20:04.860] So switching to the Java part, we will be reviewing four of the most popular Java template engines, [20:04.860 --> 20:10.680] including FreeMarker, Velocity, Pebble, and GeneJava. And also we will be reviewing 10 different [20:10.680 --> 20:17.100] content management systems that are using these engines and then we will be trying our bypasses on [20:17.100 --> 20:22.300] these content management systems. So a brief introduction into what template engines are. [20:22.300 --> 20:27.340] Basically these are systems that take two different inputs. One is the template where [20:27.340 --> 20:34.020] we are mixing static and dynamic expressions and also the template context where we store objects [20:34.020 --> 20:39.920] that are required by the engine in order to resolve the dynamic expressions in the template. [20:39.920 --> 20:46.220] For example, here we have the user.name expression. In order to resolve it, we need to get access to [20:46.220 --> 20:52.380] the user object in the context and then invoke the getName method. So because it's invoking Java [20:52.380 --> 20:57.820] methods, it's basically dangerous in the sense that attackers can execute arbitrary Java code [20:57.820 --> 21:03.500] and that's the reason why most of them are sandboxed in order to prevent arbitrary code execution. [21:04.460 --> 21:09.500] So apart from the objects that are normally and directly used by the template, [21:09.500 --> 21:14.780] there are a number of other objects that are exposed as part of a template API that is normally [21:14.780 --> 21:22.440] provided by the content management systems, which basically provides objects such as, for example, [21:22.440 --> 21:28.220] the request, the response, the separate context, or even the HTTP session. So those objects are [21:28.220 --> 21:34.960] available in most of the template APIs and also many more that are part of this API. [21:35.440 --> 21:41.500] So we will be discussing first some generic bypasses. That means that are independent [21:41.500 --> 21:48.340] of which engine is used, no matter if it's FreeMarker, Velocity, Pebble, or GeneJava, right? [21:48.340 --> 21:57.120] So those bypasses are based on finding different objects that we can use to get arbitrary code [21:57.120 --> 22:02.800] execution. So we need to inspect the template context and look for this kind of objects. [22:02.800 --> 22:07.360] In order to do that, if we have access to the JVM, we can basically debug it or we can [22:07.360 --> 22:13.980] instrument it, dump the template context, and inspect and analyze all the objects in there. [22:14.040 --> 22:21.920] However, if we don't have access to the JVM, we will have to read the template API documentation, [22:21.920 --> 22:27.540] maybe do some brute forcing in order to guess names like, for example, request or rec or [22:27.540 --> 22:32.440] response resp and things like that. And also in some of the engines, like, for example, [22:32.440 --> 22:38.660] FreeMarker, it is possible to list all the variables or objects that are exposed in the [22:38.660 --> 22:45.400] context. So apart from those objects that are directly exposed to the context, we have some [22:45.400 --> 22:50.600] objects that are indirectly exposed. Like, for example, if we are exposing the HTTP session [22:50.600 --> 22:56.760] because it contains some attributes, all of those attributes will be available for the users and [22:56.760 --> 23:02.080] attackers to access and use. Same thing with the servlet request and same thing with the servlet [23:02.080 --> 23:08.100] context. So those are stores of attributes, stores of objects that the attacker can get access to [23:08.100 --> 23:14.180] and use to look for interesting objects. So let's see how many objects we can find in one [23:14.180 --> 23:19.000] simple content management systems. In this case, it will be LiveArray. And in order to do that, [23:19.000 --> 23:27.540] we will be generating this template that I'm showing you, which basically is listing all of [23:27.540 --> 23:35.740] the context variables, then all of the request attributes, then we will show all the request, [23:35.740 --> 23:40.940] sorry, the session attributes, then the servlet context attributes. And because the servlet [23:40.940 --> 23:49.120] context will expose the Spring framework context, we will be also listing all of the Spring bins, [23:49.120 --> 23:56.260] all the objects registered in the Spring context. So if we render that, [23:56.960 --> 24:02.000] you will see that we have a bunch of objects directly exposed to the context. Those are part [24:02.000 --> 24:08.200] of the template API. And some of them are very interesting. Others are exposed as part of the [24:08.200 --> 24:13.840] request attributes, session attributes, and servlet context attributes. So as we can see here, [24:13.840 --> 24:19.840] we have interesting objects like an instance manager or, for example, the web application [24:19.840 --> 24:25.640] context for Spring that we use to list and access all the Spring bins. So as you can see, there are [24:25.640 --> 24:32.000] hundreds and thousands of objects here. There is a total of almost 900 objects. And because [24:32.000 --> 24:37.260] some of them will have public fields that we can get access to, then this number will increase to [24:37.260 --> 24:43.880] thousands of objects. So back to the slides. This is why we call it object dumpster diving, [24:43.880 --> 24:50.040] because this is how we felt when trying to find very few interesting objects that can lead to [24:50.040 --> 24:56.520] remote code execution among, you know, thousands and thousands of objects. So now we will be [24:56.520 --> 25:02.400] reviewing the top three objects that we found that lead to remote code execution. So for example, [25:02.400 --> 25:07.480] the first one, the class loaders, was available in 10 out of the 10 content management systems [25:07.480 --> 25:13.320] that we analyzed. So normally you can get access to this class loader instance through the get [25:13.320 --> 25:20.460] class loader method in the class type. But that is normally blocked by any block list by any [25:20.460 --> 25:25.300] sandbox. So you can still get access if you get access to a protection domain or a servlet context [25:25.300 --> 25:31.780] as we saw before. So once that you get access to a class loader, you can obviously load arbitrary [25:31.780 --> 25:38.100] classes and then also load arbitrary resources from the class path. But apart from that, you get [25:38.100 --> 25:44.280] access to a URL object and then from there you can access any file from the file system that the [25:44.280 --> 25:50.660] application server has permissions to access. So here you have an example. You get the URL using [25:50.660 --> 25:56.280] the get resource method and then you point the URL to the password file and then you open a [25:56.280 --> 26:06.560] connection and read all the bytes from that file. So apart from the standard class loaders, [26:06.560 --> 26:12.100] because content management systems are normally deployed on top of servlet containers or [26:12.100 --> 26:18.440] application servers, the instance of the class loader that you will be able to access is normally [26:18.440 --> 26:23.180] an instance of a web application class loader that are slightly different because of the way that [26:23.180 --> 26:29.620] class loading delegation work, but also because they expose a number of additional methods that [26:29.620 --> 26:35.560] are not part of the abstract class loader class. So here are just some examples. Just mentioned [26:35.560 --> 26:39.840] because we don't have time to cover them in this talk, although it's explained in the white paper [26:39.840 --> 26:45.560] that we are publishing as part of this talk, there are different ways of using these [26:45.560 --> 26:50.420] methods in this web application class loader to get remote code execution. Just to mention some of [26:50.420 --> 26:57.820] the vectors, we will be able to upload web cells, instantiate arbitrary objects, perform JNDI [26:57.820 --> 27:10.280] injections, or even initialize attacker-controlled classes. So we were able to find web application [27:10.280 --> 27:15.400] class loaders in nine out of the ten content management systems that we analyzed. And then [27:15.400 --> 27:23.280] the second object, the second most easy to find object in this template context was the instance [27:23.280 --> 27:29.960] manager or the object factory. So this was found in nine out of the ten content management systems [27:29.960 --> 27:36.240] and is normally found as part of the self-led context attributes, but also it can be accessed [27:36.240 --> 27:41.300] through one of these web application class loaders. So if you get access to an instance manager, [27:41.300 --> 27:46.580] what you can do is basically instantiate arbitrary types. So with that, it's very easy to [27:46.580 --> 27:52.500] escalate to remote code execution. Here we have an example using the script engine manager, but [27:52.500 --> 27:57.920] there are a bunch of classes that can lead to remote code execution, ones that you can instantiate [27:57.920 --> 28:06.200] them and then invoke arbitrary methods on them. So the number three object was a Spring application [28:06.200 --> 28:13.580] context. It was only available in four out of the ten CMSs that we analyzed. Actually, the only four [28:13.580 --> 28:18.620] that were using the Spring framework underneath. And it's normally accessible through one of the [28:18.620 --> 28:25.760] self-led context attributes, but also if the content management system is using a Spring MVC [28:25.760 --> 28:32.600] framework for the model, controller, and view layers, then Spring will inject some additional [28:32.600 --> 28:40.180] objects in the template context, like this Spring macro request context that will provide access to [28:40.180 --> 28:45.400] the Spring application context. So once that we have access to the Spring context, we can get an [28:45.400 --> 28:50.980] instance of a class loader and initiate a class loader-based attacks like we saw before. We can [28:50.980 --> 28:56.300] access the Spring environment that will give us access to the system environment and also the [28:56.300 --> 29:01.660] system properties and also Spring properties, including things like encryption keys and so on. [29:01.660 --> 29:07.380] But probably more interesting, it will give us access to the Spring bins registered in this [29:07.380 --> 29:13.420] Spring application context. So being able to access and manipulate those bins, we can basically [29:13.420 --> 29:20.500] control the application logic and do things like register new users, delete users, perform [29:20.500 --> 29:26.420] transactions, anything that the application is normally doing. So that's normally behind an [29:26.420 --> 29:31.060] authorization layer. So no matter what roles we have, we will be able to perform [29:34.200 --> 29:40.800] this kind of application logic control. So apart from that, we will also be able to disable the [29:40.800 --> 29:46.240] template engine sandboxes if we are able to get access to the template engine configuration bins [29:46.240 --> 29:53.340] and also instantiate arbitrary objects, like we will see later, by accessing JSON or XML and [29:53.340 --> 30:01.360] marshalers. So those were like genetic bypasses, independent of what template engine was used [30:01.360 --> 30:07.020] underneath. And now we will be reviewing some specific sandboxes bypasses for each of these [30:07.020 --> 30:11.720] four different template engines. So we will start with FreeMarker because it's probably the most [30:11.720 --> 30:19.500] popular one and also because, well, it was analyzed and researched by different researchers in the [30:20.020 --> 30:25.460] Like, for example, James Kettle back in 2015, when he presented server-side template injection [30:26.060 --> 30:31.120] vulnerability class. By the way, if you haven't watched this talk, it's highly recommended. [30:31.120 --> 30:38.040] He presented a bypass that is based on a kind of add-on or module that is deployed on the [30:38.380 --> 30:44.080] default configuration of FreeMarker. So Tony Torralba last year presented a different bypass, [30:44.080 --> 30:49.360] but this one is not universal in the sense that it depends on a non-default configuration [30:49.360 --> 30:56.940] and also being able to find gadgets in third-party libraries that may or may not be [30:56.940 --> 31:04.240] available in a specific target. Then Ryan Hanson this year, probably at the same time that we were [31:04.240 --> 31:08.900] doing this research, presented a vector that leads to remote code execution by uploading [31:09.560 --> 31:14.320] a web shell, but this is not universal in the sense that it only works with Tomcat servers. [31:14.320 --> 31:22.780] So FreeMarker sandbox is a method-based block list, which basically means that, for example, [31:22.780 --> 31:27.780] methods like the getClassLoader method in the java.lang class is blocked and you cannot [31:27.780 --> 31:31.420] get an instance of a class loader using this method. But as we mentioned before, [31:31.420 --> 31:35.620] you can still use the separate context or the protection domain to get access to these [31:35.620 --> 31:40.600] class loaders. Once you get access to a class loader, the class loader methods are not blocked [31:40.600 --> 31:46.460] by the block list, so you can still interact with them, load classes, get resources, [31:46.460 --> 31:51.620] or initiate remote code execution attacks that we saw before. And also reflection is [31:51.620 --> 31:58.320] forbidden to set fields values, but is allowed to get and read field values. [31:58.960 --> 32:04.420] So we use that to perform an attack, but this attack is not universal in the sense [32:04.420 --> 32:08.540] that it depends on being able to find an instance of a URL class loader. [32:08.540 --> 32:13.760] So this is normally the case in Tomcat, GlassFish, and Jetty, but it's not universal for other [32:13.760 --> 32:18.880] application servers. So in this case, we are basically getting the URL class loader from [32:18.880 --> 32:25.540] the protection domain or from the separate context. And then we are basically instantiating, [32:25.540 --> 32:31.200] by invoking this new instance method, a new URL class loader that is pointing to the attacker [32:31.200 --> 32:37.280] control jar file, in this case the pawn.jar file. Once we get access to this class loader, [32:37.280 --> 32:43.600] we can load arbitrary classes from our own jar file, and we will be loading the pawn class. [32:43.600 --> 32:49.820] And now the class is loaded, but it's not initialized. If we want to run arbitrary code, [32:49.820 --> 32:55.260] we need to initialize the class. We cannot instantiate the class, we cannot invoke static [32:55.260 --> 33:01.720] methods. So those vectors, those ways of initializing the class, are not a possibility [33:01.720 --> 33:08.200] for us, but we can get access to public static fields. So just by adding a public static field [33:08.200 --> 33:12.500] and getting access to that, the class will be initialized and the payload will be executed. [33:13.240 --> 33:19.600] So that was not a universal bypass in the sense that we are required to find an instance of a URL [33:19.600 --> 33:25.120] class loader, and we want to find something that works no matter if we are able to find that kind [33:25.120 --> 33:31.060] of class loader or not. So we are interested in finding some classes that contains public static [33:31.060 --> 33:38.180] fields of a given type, which contains a method that we can use to instantiate arbitrary types. [33:38.180 --> 33:44.160] To find them, we use CodeQL, which is a language that you can use to query your source code in the [33:44.160 --> 33:51.360] same way that you use, for example, SQL to query a database. And what we wrote was this query that [33:51.360 --> 33:56.260] basically says, okay, find me all the public static fields which are of a given type that [33:56.260 --> 34:02.160] can instantiate arbitrary types. We run this query on FreeMarker source code, and we found [34:02.160 --> 34:09.260] four different results. Those are four different fields of different types, but all those types [34:09.260 --> 34:16.040] extend from the bins wrapper type, which contains a new instance method, which we can use to [34:16.040 --> 34:23.840] instantiate arbitrary types. Now, this is the universal remote code execution bypass for [34:23.840 --> 34:28.980] FreeMarker. Basically, we need to get us access to any type of class loader from either the [34:28.980 --> 34:36.700] protection domain, separate context, and then load the object wrapper interface and get the default [34:36.700 --> 34:42.920] wrapper field from this interface. And then we can use that to instantiate arbitrary classes. [34:42.920 --> 34:48.440] Since we want to have this payload basically contained in FreeMarker classes, we are using [34:48.440 --> 34:53.680] the execute class in order to run arbitrary system commands. But you can use other payloads, [34:53.680 --> 35:00.220] to get arbitrary code execution. This was fixed in version 2.30 of FreeMarker. [35:01.280 --> 35:06.520] And also, if you get access to the Spring Bins, and you can get access to the FreeMarker [35:06.520 --> 35:10.580] configuration, as we saw in some of the content management systems that we analyzed, [35:10.580 --> 35:15.740] you can basically disable the sandbox. For example, you can get the class resolver for [35:15.740 --> 35:20.960] the default configuration that is non-sandboxed, and then set that class resolver as the class [35:20.960 --> 35:26.000] resolver for the current and sandboxed configuration. So effectively disabling [35:26.000 --> 35:33.520] the sandbox and being able to execute the old payload from JamesKettle once again. [35:33.900 --> 35:38.740] So now we will be reviewing eight different ways to escape the sandbox [35:38.740 --> 35:44.460] and get remote code execution in LiveArray. So let's see [35:47.560 --> 35:52.080] our LiveArray instance here. And what we will be doing is basically [35:54.360 --> 36:03.650] using this template. And here, what we are going to do basically is, first of all, we are going to [36:03.650 --> 36:10.970] use the class loader payload, which will allow us to read the password file using the URL trick [36:10.970 --> 36:16.050] that we explained before. Then, because the instance of the class loader is a web application [36:16.050 --> 36:22.010] class loader, we will be using that class loader to upload a web cell by using the write method. [36:22.790 --> 36:30.270] This will be available in the shell JSP file. Then we will be also using the web application [36:30.270 --> 36:36.950] class loader to get access to an instance manager and then instantiate arbitrary classes. In this [36:36.950 --> 36:43.010] case, we are instantiating an expression language processor and then running the ID process. [36:43.010 --> 36:49.570] Then we will be also showing a different payload that depends on using an instance manager. This [36:49.570 --> 36:55.410] time is taken from the self-led context. And again, we are using the EL processor to run the ID [36:55.410 --> 37:01.230] command. And then we will be using a JSON deserializer as an instance manager in the sense [37:01.230 --> 37:08.230] that we will be using that to instantiate arbitrary types. We will be getting access to the [37:08.230 --> 37:13.730] JSON deserializer from the Spring application context. And because this JSON deserializer uses [37:14.110 --> 37:19.890] a while list and allow list here, we need to register or we can actually register any arbitrary [37:19.890 --> 37:28.990] types for us to use in the JSON payload. So, now by deserializing this JSON payload, [37:28.990 --> 37:35.490] we are effectively instantiating an EL processor and then again running the ID command. [37:35.490 --> 37:41.410] Same thing, but instead of getting the JSON deserializer from the Spring context, [37:42.110 --> 37:48.610] LiveRay directly exposed this JSON factory util, which we can use to create a JSON deserializer [37:48.610 --> 37:53.730] and then once again use that to instantiate arbitrary types. And then we will see the two [37:53.730 --> 38:00.370] free market specific bypasses that we explained a few minutes ago. The first one is using the URL [38:00.370 --> 38:06.490] class loader that is the case here because LiveRay is deployed on Tomcat. And then we can [38:07.010 --> 38:12.850] basically access our own jar file, load it, and then by getting a public static field, [38:12.850 --> 38:18.410] the class will be initialized and the payload will be executed. And we will be able to check [38:18.410 --> 38:25.710] the output of this payload by checking the standard output. And the last payload that worked [38:25.710 --> 38:32.450] in LiveRay, actually there's a couple more, but eight was more than enough, [38:32.450 --> 38:39.430] is this universal RC. So we are loading the object wrapper interface, loading the default [38:39.430 --> 38:43.770] wrapper field, and then using that field to instantiate arbitrary types, in this case [38:43.770 --> 38:50.610] the execute type that we will be using to run the ID. So now if we save this template and [38:51.910 --> 38:59.590] we will be showing the results of these payloads. The first one was reading the password file, [38:59.590 --> 39:05.390] the second one was deploying a web cell that we can now access and run arbitrary commands. [39:05.550 --> 39:11.590] The third one was using different methods to run the ID command, as you can see here, [39:11.590 --> 39:19.170] all of them worked. So also the URL class loader was basically running the static initializer [39:19.170 --> 39:24.870] block of this class, which is basically printing pound in the standard output console. We can [39:24.870 --> 39:33.230] check that. And here it is, so it worked. And back to the payloads, the universal RC [39:33.230 --> 39:38.910] payload also worked, as we can see here. So switching to the Velocity Sandbox, [39:38.910 --> 39:43.890] this one is based on a class and package-based block list. So things like, for example, [39:43.890 --> 39:49.730] the whole Java lang reflect package is forbidden and you can get access to it. [39:49.790 --> 39:55.650] All the methods in Java lang class and class loader are also blocked and you cannot use them. [39:55.650 --> 40:01.650] But when we reviewed the implementation, we found that there is a flaw in the way that [40:01.650 --> 40:07.770] this sandbox is checking the block list. So, for example, when you run the request [40:07.770 --> 40:13.050] and then you get access to a class loader and run the load class method, [40:13.050 --> 40:19.290] basically the execution of this method will be checked against the block list. [40:19.290 --> 40:24.670] And the class name of the current class loader will be checked against the block list. [40:24.670 --> 40:31.370] Instead of checking the whole hierarchy of classes, only the current object class will [40:31.370 --> 40:35.870] be checked against the block list, which means that because Java lang class loader is an abstract [40:35.870 --> 40:42.690] class, it won't never be the case that the current object class will be a Java lang class loader. [40:42.690 --> 40:47.110] In this case, it's a parallel web app class loader, which is not present in the block list, [40:47.110 --> 40:51.150] and therefore class loader methods are effectively allowed. [40:51.330 --> 40:58.230] There is a feature in Velocity, which allows you to invoke a static method from a Java lang [40:58.230 --> 41:04.250] class object. So once that we are able to load a class, we can just invoke any static method and [41:04.250 --> 41:11.130] use that to get remote code execution easily. So now moving to GeneJava sandbox. This one is [41:11.130 --> 41:17.270] based on a method block list. This is actually very short, only nine methods. [41:17.330 --> 41:23.190] And what it contains is a piece of code that is pretty effective in protecting the sandbox. [41:23.190 --> 41:28.350] So every time that method invocation happens as part of the evaluation of the template, [41:28.350 --> 41:32.590] the result type will be checked. And if it's an instance of a Java lang class, [41:32.590 --> 41:38.690] then it will throw an exception and it will refuse to return a Java lang class instance. [41:38.690 --> 41:44.630] By not being able to get in access to arbitrary classes, we are normally not able to get [41:45.290 --> 41:52.130] or to be able to instantiate arbitrary types. However, we found a flaw. As you can see here, [41:52.130 --> 41:58.190] the invocation of a class cannot return a Java lang class instance, but it can return an array [41:58.190 --> 42:03.790] of Java lang classes or a map including Java lang classes. So what we can do is find a method [42:03.790 --> 42:08.990] returning an array of classes and then accessing any arbitrary item of this array. [42:09.550 --> 42:16.850] So the second part of this bypass was basically being able to access a secret or hidden variable [42:16.850 --> 42:24.810] in the context that is called __interpreter in lit speech. So by using this hidden variable, [42:24.810 --> 42:30.570] we were able to access a bunch of different objects, including all the context objects. [42:30.570 --> 42:37.150] And we were able to use those two parts to get an instance of a class loader. [42:37.150 --> 42:41.710] So as you can see here, we use the interpreter to get the context. And from the context, [42:41.710 --> 42:46.990] we got all the functions. And from the functions, we got the underlying methods, [42:46.990 --> 42:53.410] which are instances of Java lang reflect method. And this class contains this get parameter types [42:53.410 --> 43:01.010] method, which returns an array of Java lang classes. So as I explained before, [43:01.010 --> 43:08.750] we are able to get an instance of any individual item of this array. And by doing that, we are [43:08.750 --> 43:14.110] finally getting an instance of a Java lang class. From there, we can get the protection domain, [43:14.110 --> 43:19.150] get the class loader, and then initiate any class loader-based attack. [43:19.850 --> 43:24.930] So last, Pebbles and Box, we were able to find a couple of bypasses that we reported [43:24.930 --> 43:30.230] to the maintainers. Unfortunately, they didn't have time to fix them on time. So we decided [43:30.230 --> 43:37.010] not to leak these bypasses yet. And we are keeping them classified for a few months. [43:37.890 --> 43:44.230] So with that, we will switch back to Alexander, who will wrap up the talk with some conclusions. [43:44.230 --> 43:49.230] Thank you, Arvara. First of all, let's summarize our results after this research. [43:49.230 --> 43:53.630] More than 30 new vulnerabilities were found and reported to the vendor. [43:53.630 --> 43:59.690] More than 20 different products are affected. We can see their names on this slide. Based on [43:59.690 --> 44:06.670] these results, we can make the next conclusions. These are not the problems of specific product [44:06.670 --> 44:13.370] or framework. And content management system as a class should be on Red Team radar. Templates for [44:13.370 --> 44:19.150] dynamic content that can be managed by user is the main target for such system. There are specific [44:19.150 --> 44:25.050] areas with higher risk from security point of view. It's a good idea to perform security review and [44:25.050 --> 44:32.930] testing for such places. Always try to reduce attack surface as much as you can. And stay safe!