 Okay. Hi. Thanks for coming. In the next 15 minutes, I will present Breaking Passer logic, tag your personalization of MPaP0.org. OsoPath traversal is a common problem in web applications, but it's still hard to apply the good security mechanism. There are lots of pitfalls and edge cases that programmers may ignore. But the only thing they care about is still .data.slash. In this talk, I will try to pay more attention on analyzing past the logics and personalizations. During this process, we notice an interesting feature that could be perfectly applied on multi-layered architectures. We will detail this attack surface and give several case studies. Okay. Let's go. Hi. I'm Orange, a security researcher from Devcore. We provide the most professional writing service and penetration testing in Asia. My job is researching and finding new thoroughness and attack surface. And also a member of HitCon. We hold the largest hacker conference in Taiwan. Apart from that, I'm also a speaker, bounty hunter and CTF player. This is our agenda today. We will first highlight the brand site on past normalization and talk about why I focus on that. By knowing the brand site, we try to review existing web frameworks and find bugs from them. We will show the updates on both Ruby and Rails and Spring framework. Lastly, the new attack surface. Of course, in order to convince this is awesome, we will give several bug bounty cases. Okay. First, let's learn a new word. Normalize. To make standard, determine the value by comparison to an item of non-standard value. The definition is easy, but if everything has their own standards, it must be problems. And the next, why normalization? In security, it means that you need to protect something. In order to fix a bug without impacting business logic, it's common to apply the work around or filter instead of patching the bug directly. To apply the filter, you need to pass the data first. But it's hard to implement a real decide pass. Everyone follows RFC as their standard. RFC defined the specification, but didn't tell you how to implement. So the more complicated the data format, the more hard it is to pass. So what's wrong with normalization? Yes, inconsistency. This is a typical dangerous pattern and easy to find problems on it. The behavior in chat must be the same as the behavior in use. Otherwise, the chat function will be bypassed. It's just like my SSIF talk in last year. Finding inconsistency between URL passes and URL fetches that lead to whole SSIF bypass. So for the past two years, I paid more attention on the bug inconsistency. For example, this is an interesting implementation in Java. There are different file handles for each operating instance. In Windows, Java treats the file as UNC pass, but Linux treats it as URL. The most difference between each other is the URL supports the correct string, but UNC doesn't. Once we know that there are several dangerous patterns. For example, the method get pass only return the part before the question mark. But the file system still recognize all as its pass. So here is an inconsistency. On the other hand, the method get file or to external phone returned all the URL part. But if the track rely on the normalized result from then, we can forge a valid pass to bypass the track and read arbitrary file on the Linux. So back to our topic, why I can't get pass normalization? Because most websites handle files. Also, pass traversal is an old problem in many web applications, but that is also the press with lots of protections and bypasses. As I mentioned before, there are lots of dangerous patterns so that if you can find a difference between the track and the use, you can bypass the protection. Another reason is, in large projects, the code change too fast and lack an overall security review. For the new commit, is there any side effect or bypass existing security mechanism? Who knows? Let's talk about a Mojara story. Java server faces is a standard on the Java EE. But it's just a standard, need someone to implement. So the top two implementation in the world are the my faces by a patch and Mojara by Oracle. While reading advice service, I noticed a report that revealed Mojara and find CVE 2013, C827. The report also inspired me to dig more into source. With a couple of days, I find a new vulnerability. It's a very obvious pass traversal. Just read the file from query string. While I find this, I was very curious about why the advisory didn't notice that. With a little bit investigation, I find a reason. The bug was commit in 2015, but the code review was done in 2013. This points out a serious problem. Mojara is a very fundamental library, but since there is no one to do a formal security review since 2015. So that is the reason to push me dig into the personalization on web application and frameworks. Okay, so let's start our topic. First, how passers could be failed? Here is a very obvious programming errors. Can you spot a bug? This code was copied from Grails. Grails is a powerful, groovy, best web application framework. If you want to use groovy as your back-end language, you must have heard about Grails. This is the part of static file handling. The argument relative to pass is attacker-controllable. In order to be compatible with Windows environments, the code repress current file separator with forward slash. So, did you have you find a bug? Okay, the answer is the method repress. Grails would like to repress current file separator with regular expression, so Grails escape the pass by pattern.cord. This is the prototype of method repress, but in Java repress has a big border and his name is repress O. Both methods are very similar, but the only difference between each other is the meaning of the first argument. The first argument in repress is the literal string to be repressed, but the other is the regular expression to be executed. Both arguments are the string type. It seems the developer used the wrong method. The pattern that cropped in cross the current file separator with S gap Q and S gap E. Because of the misuse, Grails will recognize the S gap regular expression as literal string. As a result, there is a new dot dot slash in Grails. Yes, fails everywhere. Even worse, the buggy code was committed in 2014, so the bug has been there for several years. The next topic is how single slash could be failed. Maybe you have set out several paths in the past, but does your past end with a slash? This is a good question. Is it important? Yes. Let me show you how single slash could be failed. This is an off by slash fail on engine X. The first time this problem was shown was in the end of 2016, and this created two uglies. Also, this is not new. It's still worth to mention. This is a good attack vector without too much people known, and the idea appears in the world again and again. In engine X, there is the alias directive, and it can define a replacement for the space file location. This directive is very common in web architectures. In practical applications such as Django and Rails, are not familiar with handling static files. So it's a prevailing pattern to put the engine X in front of them. But due to the lack of churning slash in the location rule, the slash static dot dot will also hit the alias block. As the result, engine X will append the remaining part to the home slash app slash static, and we can traverse one label path to parent directory. So how single slash could be failed? You can search how to serve a static file on engine X on Google or a Stack Overflow, and you will find numbers and search with miss tags. This problem is also common in the implementation that you need to process the path by yourself. It's just like string copying in C language. To append a slash or not is a serious problem to you. So how to find this problem in real world? We keep a private dark bounty cache here. From direct access in the S3 folder, engine X will return 403 forbidden. However, when we try the slash S3 dot dot slash, it also returns 403. It looks like we have successfully traversed a label to parent directory. But how to prove this? We append S3 slash app.js again and check the counter. Yes, the send. So now we can download all the source and configuration file on the web loop. In this case, we get several sensitive information such as the Django secret key and the SQLite database. Thank you. So for the past several months, I start to review the path normalization and parser part on web applications. Of course, we find several problems in diverse implementations. And here is the list. So the next section is in depth review of existing implementations. Due to the time consideration and our new finding is more important, we will only show you two cases. The first one, directory traversal on spring framework. We all agree that spring is the famous framework in Java web ecosystem. So we start from the patch of CVE 2014, C825. It's also a patch traversal. So in all cases, in order to prevent similar bugs again, spring applies several security mechanisms. From the method name, we know spring first check whether the patch is valid or not and use its results on the location of the list guardians to ensure the patch on the appropriate locations. This is the simple file version of method. It's invalid patch. It's just a simple black list. And the most important is if there is any dot dot in the path, spring will normalize the path and check and return a boolean. As I mentioned before, this is a dangerous pattern because spring just rely on this boolean to protect all the things turn. So if you can find problems in the clean path or inconsistency between the check and the use, you can bypass the protection. So how clean path works in order to compatible with windows environment is simply repress backslash to forward slash. Spring also separate the path with the forward slash, check the element one by one and store the result into past elements. If the element is a single dot, spring just do nothing. But if it is the parent directory, spring will set effect to remove item in next iteration. In the end, spring use the forward slash to join all the elements. Okay, not all. Did you find the problem in this method? Okay, the problem is spring allows the empty element. That means you can forge an empty element in past array. During the normalization, it will be normalized with the parent directory and cause the inconsistency with the file system. It seems to be a small problem, but the impact is huge. This table shows the difference between the clean path and the file system. Due to the empty element, when there is more than one slash in the past, things start going wrong. The main set is in body path return true because there is no dot dot in the result. So spring believe without any dot and read the file with user supplied path. So how to explore it? We crown the spring official sample from GitHub. As you can see the payload, there are six slash normalized the next six dot dot slash. This exploit also works on the container such as tongue cat. As the security container tongue cat by default enables several security features. But this exploit perfect by path or restrictions. As the result, we can read arbitrary file on windows. So how to fix? Do not use windows. Yeah, this is the real mitigation from spring official website. Excellent. As a bonus, let's talk about the code infectivity. Programmer follows the dry principle. Don't repeat yourself. And spring is a popular framework under free software license. So last of the projects refer to code from spring. Spark is also famous and a micro framework for web applications. In 2014, Spark want to improve their security mechanism on static file handling. But since writing a good password is really hard. So it just copy the code from spring. As the result, Spark also copy the similar problem into their code base. So Spark also suffer from this vulnerability. The next case is Ruby on Rails. Spark is the answer pipeline system in Rails. Which means that all static files will be managed, compiled, and served by Spark. And of course, we find the problem here. But unfortunately Rails only use the answer pipeline system on development mode. Also, this only affect development mode. The default Rails command is on the thread. So you can simply reproduce the bug by just two commands, Rails new and Rails server. Due to the time consideration, I will not go into too much details. The root cross is the Spark support and undocumented file scheme in the past. There are several pieces in this exploit. But because of the time, you can check the detail after this talk. We will just go to the next page. But it still was to say this is possible for code execution. Because of the support of file scheme, you can override some internal options with your query string. As an answer pipeline system, Spark will compile the content while processing the file. If the file extension is ERB, Spark it will interpret the file as Ruby template engine. This feature could be combined with the file upload attack, you upload a malicious file to temp folder and ask you the code by Spark keys. Are you okay? The boring part is over. You can stretch yourself a little bit. Okay, here's the cat and let's go to the most interesting part. While I was reading the source, I noticed a feature that could be perfectly exploited on multi-layered architectures. In the following page, I will introduce the idea and several cases, including an access control bypass in Uber and two remote core executions. In addition, I would like to thank Amazon and Vanda for the open mind vulnerability disclosure and their quick response time. It's a very good experience working with them. Yeah. We start with the HTTP feature, URL pass parameter. It can define information to the specified pass segment. Some researchers have already pointed out this feature may lead to security problems, but their concerns still depend on programming fails. When I saw this, I was thinking about how to make this feature more severely. Yes, I find reverse proxy. Reverse proxy is a common web architecture, and there are several benefits, resource sharing, low balance, cash, and security. For example, you can share different services on the same port and IP address or use low variance to distribute the request to different backend service. As the security, reverse proxy can isolate the server from outside and configure the access control in proxy layer. This is a classic reverse proxy architecture, as I said before it's a prevailing pattern to sub static file directly and pass the business logic to backend service. I have talked about the process of backslash problem, but now we focus on the interaction between the proxy and backend servers. Engine X will survey directly if the incoming request match the static pattern such as files and scripts. But if it is the request for business logic, Engine X will pass to backend servers. Okay, so back to our topic. What will happen when the feature makes the reverse proxy? URL pass parameter is defined in HTTP specification, but not all web server care about it. However, Java mostly support this feature. Reverse proxy is not a single request single server handling architecture. The same request will be interpreted by different web servers. So the inconsistency between the proxy and backend servers will lead to security problems. So I keep a name for this. Okay, not really. The domain is still available to buy. Just kidding. So how dangerous this could be? In the reverse proxy, it can bypass access control list no matter it's backlist or whitelist. It can also escape from current context mapping to access the management in the fast and other contexts on the same server. Dev apps always believe that no one can touch their internal service. But today, this is posed to outside and there must be lots of fun for hackers. And not effect by this. This is the architecture's problem and vulnerable by default without any programming errors. So if you are using reverse proxy with Java as your backend service, you are under threat. Basically, this is a huge attack surface. Think about how many reverse proxy in the world could be bypassed so that you can touch many internal service from outside. For an easy example to understand, tongue cat exposed the application portal in local host and maps to outside by a patch. Due to the normalization of a patch, we cannot direct access the backend management in the fast. However, we can use our traversal trick that does semicolon to traverse one label to touch the root of tongue cat. A patch first handle this request. From the view of a patch, that does semicolon is a normal folder name and matches the context mapping. So it passed to backend service. But in tongue cat, that does semicolon is a parent directory and will normalize with the portal. As the result, we can access all application on the tongue cat including the management in the fast. Everything looks good from their side, but when they put all together, everything start goes wrong. Okay, by knowing the theory, let's see real world cases. The first cast is Uber. Uber this arrow direct access to the domain uberinternal.com. From the name, we know this is the domain for internal purpose. Once we access, it redirect us to one login single sign on service. And this red, and this redirection was done by engine X. We find a domain that looks good. And we also know that jura is the Java best application. It seems to be reverse proxy again. With a little bit searching, we find this website is post a status API. And this appears to be a white list for monitor purpose. We applied our traversal check again. It looks good in engine X and match the white legs pre-fixed. So pass to jura. As the result, we can access the jura internal and see the internal projects. We can see the jura dashboard and see the internal projects. And this is another protocol we accessed, an internal code review portal. Okay, so next, what can we do if we bypass the access control? We will give a code execution cast in binder. Basically, I find this code execution in another bounty program. Although I got a code execution, I find my target is not in their bounty scope because it's on a third party service. But fortunately, there's also a bounty program in that service provider. So in the following cast, I will use this set as example. This is the screenshot for the website. It's just a login patch without too much functionality. When I would like to hack something, the first thing I care about is the HTTP header. From the header, we can observe many interesting information. The header told you that it is running on the engine X. However, the response also set a special cookie, Z session ID. It says to be the default session name in tongue cat. But why engine X need this cookie? From our experience, we believe this is also the reverse proxy architecture. By the way, this is also a good methodology to know whether the target is running under reverse proxy or not. We applied our traversal trick again and got a cool patch. This is a false default patch, but the special is the patch was returned by tongue cat. This represents that we have already passed the first proxy and accessed the backend service. Another thing is from the error message, we got an important hint. The hint is that our request pass will be the path info in the backend index.cfn. From the hint, we can construct the server configuration in our mind. Engine X just rewrite the request to backend index.cfn. But for the dot dot slash, it will rest a 400 error because the path jumped out of the web loop. However, our trick can pass through the proxy and normalize the index.cfn so we can touch the loop in tongue cat. As you see in the file extension is cfn, the cofusion markout language. From the extension, we can guess what backend engine is it. In this case, it is running on the railroad and open sourced cfn engine. From the railroad menu, we also know that the management in the fast is on the railroad contacts admin slash web dot cfn. This is the screenshot for the management in the fast, but did you find something wrong? Yes, the interface just ask you to set a new password. But is that easy? No. The first time I saw it was not like this. It's a normal looking patch. However, when I refresh several times, the patch changed. So I don't know why. So what is wrong with it? With a little bit investigation, I think I find a root cause. When there is a large number of requests, the website will use the cloud to scale up automatically. But while scaling up, it seems to forget to pull the password file. So this is the root cause to invite you to enter the new password. However, not all instances are valuable. It seems to be only three to four misconfigurations. So we have about 16% probability to see the new password patch. Although that a successful login is still not easy because there is a capture in login process. And to make things worse, every request to the cloud will be dispatched randomly to different backend servers. For example, if the server in displaying the capture is different from the server in receiving the credential, it will rest in one capture error. So it's just like in playing a lottery. We need to keep the session and poke the same server on both capture and login process. With fucking much time in errors, we finally get into the management in the fast. Once we entered in the fast, the next question is how to pop our shell? In Redo, there are several ways to pop our shell. But due to the request being dispatched to different servers, we need to minify our steps. Here we choose log injection. Redo supports many features. One is the customized template file. So we modify the 404 patch to exception.log. And then we need to inject our malicious code into exception.log. However, while exploiting this, we face a problem. The log file is too large to be executed. But did you remember the website will scale up when there are lots of requests? So that we can use heavy request to force the crowd launch a new instance and exploit another instance. Okay, now every 404 patch is our back door. And we got the shell back. The last is our MSN cache. While searching for target, we find a spatial domain. From the name, it seems to be the collaboration system for internal purpose. And from the copyright, we know this system was built from an open source project, Naseel. Naseel is a content management system for business applications. It's written in Java. But in that time, I just want to improve my Java auditing skill. So I start to review the code. During the code review, we find several tiny bugs can be trained together to get a code execution. We first look at the access control in Naseel. While auditing the source, we find Naseel maps all URLs to a spatial authentication filter. And the first bug is lying on that. From the filter, we know most patches require a valid session, but some entrances can bypass that, like logging.jsp. But how did the filter retrieve current patch to compare with? It retrieved the path from the HTTP sublet request. So what's the problem? In order to handle URL patches, we Naseel truncasts the path by semicolon. As I mentioned before, the behavior in URL patches are various. Every web server has own implementation. The Naseel's way may be saved in the containers such as WiderFly and WebLogic. But now it's wrong on the tongue cat. The difference is that it's linked to the security problem. So due to the truncation, we can forge a request that matches the wireless in access control, but reach the unauthorized area in Naseel. However, we still could not do anything. In fact, most patches return a neural pointer access to the Naseel. So we need to do anything. In fact, most patches return a neural pointer exception, because the sublet logic was unable to obtain a valid credential. But this still gives us a chance to knock the door. From the configuration file, we noticed that holdNaseel is based on sync framework. I have a review since several years ago and find numerous hacker-friendly features. So for me, the next step is training the first bug to access the unauthorized sync framework. So let's talk about the sync feature. In order to control the browser, sync framework introduces a series of HTTP parameters. Action method is one of them. It can invoke specific expression language from the query string. It seems dangerous, however there are some preconditions before the invocation. The invoke expression language must be in a certain format and in a file on the context route. For example, there is a file named foo.xhtml and you can invoke the utl.scap by the following URL. The feature looks good, you cannot control any file on remote server, therefore you can't invoke any expression language. However, there is one more crazy feature. To make things worse, if the previous invocation returns a string, and the string looks like an expression language, sync framework will invoke again. Yes, it's double evaluation. But what the hell is the fucking double evaluation? Yeah, I don't really understand. With the crazy feature, if we can control the return value, we can ask you arbitrary EL. So we need to define the good gadget. This is very similar to the ROP, a return-oriented programming in binary exploitation. Oh, sorry. We choose the file with the long name. Why we choose this? It is because the request.get-performer returns a string that we can control from URL. Also, the whole tag is supposed to assign a variable. We can still execute the partial tag. Okay, by training with the first access control bypass, we can now execute arbitrary EL without any authentication. But it's still not over yet. We fail to pop our shell. Syn also knows that EL is risky, so there is a blacklist to block dangerous invocations. However, it's just a single stream matching, and we all know that blacklist is always a bad idea. So we simply use the array like operator to avoid the bad pattern. So let's summarize our steps and churn all together. We first find the personalization bug to bypass the access control. While we can access the unauthorized string sublet, we use the feature and choose the good gauges so that we can control the return value. We also prepared our second-stage payload in the URL and used a array like operator to bypass the blacklist. The last step is to write the shell code with Java reflection API and wait for our shell back. So this is the overview for Holder Explorer. I will explain each part one by one in detail. First, the yellow highlight is the access control bypass. In order to bypass the whitelist, we choose login.jsp as our prefix. Naseel will scan all the request paths and truncat until the first semicolon. So due to the inconsistency between the Naseel and the container, we can bypass the authentication and touch the create file.xhtml. We choose the file because it will be handled by same framework. Once we can touch the same sublet, we use the option method to invoke partial expression language in a long file. Here we choose the gauges on the file with the long name. So why we choose this? It's because the return value of the request.get parameter is a string and we can control it from URL. So we prepared our second-stage payload in the query string directory named for popup. As the crazy features seen framework will invoke the value as expression language again. In order to avoid the bad pattern, we use a array like operator to bypass the bracket list. We also use Java reflection API to get old methods from java.ln. runtime. The element index seven is the method get runtime to return the runtime object and the index 15 is the method exeC with a string type argument. Okay, the last thing is the shell command. Here we would like to pop a shell back and we got a shell. Okay, thanks. Okay, so how to prevent this type of text? This is hard to fix because the URL pass parameter is a normal feature and not a bug in both sites. According to my experience in bug reporting, most vendors cannot patch the bug completely in the first time. Their patch is bypassable. So we need to get from two aspects. One is to isolate your backend application, remove the management in the face and other context from your Java container. And the second is to ensure the behavior between the proxy and backend servers. But it seems there is no directive to disable the feature. So I write a patch for that. You can check the hyperlink after this talk. Okay, summary. In this talk, we first show the brand sign about the patch processor and patch normalization, including inconsistency, misuse method, and off by slash problem in engine X. Then we introduce a new attack service on the reverse proxy architecture that can bypass assist control and escape from context mapping. The last we show several case studies are not only open source applications but also bug bounty programs. Okay, the last page. Here is my contact information. Please let me know if you have any further questions or new findings. Also, we will release the whole story of our case study in my blog. You can follow my Twitter to know the lattice post. This is the end of my presentation. Thank you for being here. Thanks.