Breaking Parser Logic! Take Your Path Normalization Off and Pop 0Days Out
Tsai, Orange
We propose a new exploit technique that brings a whole-new attack surface to defeat path normalization, which is complicated in implementation due to many implicit properties and edge cases. This complication, being under-estimated or ignored by developers for a long time, has made our proposed attack vector possible, lethal, and general. Therefore, many 0days have been discovered via this approach in popular web frameworks written in trending programming languages, including Python, Ruby, Java, and JavaScript. Being a very fundamental problem that exists in path normalization logic, sophisticated web frameworks can also suffer. For example, we've found various 0days on Java Spring Framework, Ruby on Rails, Next.js, and Python aiohttp, just to name a few. This general technique can also adapt to multi-layered web architecture, such as using Nginx or Apache as a proxy for Tomcat. In that case, reverse proxy protections can be bypassed. To make things worse, we're able to chain path normalization bugs to bypass authentication and achieve RCE in real world Bug Bounty Programs. Several scenarios will be demonstrated to illustrate how path normalization can be exploited to achieve sensitive information disclosure, SMB-Relay and RCE. Understanding the basics of this technique, the audience won't be surprised to know that more than 10 vulnerabilities have been found in sophisticated frameworks and multi-layered web architectures aforementioned via this technique.
 Okay, hi. Thanks for coming. In the next 15 minutes, I will present breaking puzzle logic, take your personalization of MPAR-0. Othopaste 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.dustlash. In this talk, I will try to pay more attention on analyzing puzzle logics and personalizations. During this process, we find, 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 theories and attack surface. And also a member of HitCon. We hold the largest hacker conference in Taiwan. Apart from that, I know so as 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 dust. 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 open, 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 every system 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 workaround 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-passer. Everyone follows RFC as their standard. RFC defined a 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 features 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 main set get pass only return the part before the question mark. But the file system still recognize all SSIF pass. So here is an inconsistency. On the other hand, the main set get file or to external phone return all the URL part. But if the check rely on the normalized result from then, we can forge a valid pass to bypass the track and read actually file on the Linux. So back to our topic. Why I target 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 check 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 Modura 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 my faces by a patch and Modura by all local. While reading advice service, I noticed a report that revealed Modura 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 adversary 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. Modura 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 into the path normalization 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 escaped the path 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 encroaches the current file separator with sgapq and sgape. Because of the misuse, Grails will recognize the sgap regular expression as literal string. As the 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-bite slash fail on engine X. The first time this problem was shown was in the end of 2016 and this created two uglys. Although this is not new, it still was 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 specified 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 static file on engine X on Google or a stack overflow and you will find numbers and search with misstacks. 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 give a private bug bounty cache here. From direct access in the S3 folder, engine X will return for VOC forbidden. However, when we try the slash and third dot dot slash, it also returns for VOC. It looks like we have successfully traversed a label to parent directory. But how to prove this? We append a slash slash app dot this 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 drengle secret key and the SQLite database. Thank you. So for the past several months, I start to review the path normalization and pass the path 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 order to prevent similar bugs again, Spring applies several security mechanisms. From the method name, we know Spring first track whether the path is valid or not and use its results on the location of the list guardians to ensure the path on the property at locations. This is the simple file version of method is invalid path. It's just a simple blacklist. 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. 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 repressed backslash to forward slash. Spring also separate the path with the forward slash, check the element one by one and store the result into path 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, that's 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 path 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 path, things start going wrong. The main set is invalid 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 exploit? We crone 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 secured 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 lots of 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 parser is really hard. So it just copied the code from Spring. As the result, Spark also copied a 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 a 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 skin 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 skin, you can override some internal options with your query string. As an answer pipeline system, Spark it 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, your upload and malicious file to temp folder and ask you to code by Spark keys. Are you okay? The boring part is over. You can stretch yourself a little bit. Okay, here is 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 exploit 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 code executions. In addition, I would like to thank Amazon and Binder for the open-mind vulnerability disclosure and their quick response time. It's a very good experience working with them. Yeah. We start with a 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 balance 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 substatic file directly and pass the business logic to backend service. I have talked about it by a sledge 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? UL pass parameter is defined in HTTP specification, but not all web servers 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 an end 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 blacklist or whitelist. It can also escape from current context maping 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. Baskara, 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 is posed the application portal in localhost. MFs 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 to traverse one label to touch the root of tongue cat. A patch first handle this request. From the view of a patch, tongue cat is a normal folder name and matches the context maping. So it pass to backend service. But in tongue cat, tongue cat is a parent directory and will normalize with the portal. As a result, we can access all application on the tongue cat, including the management in the fast. Everything looks good from this side. But when they put all together, everything starts goes wrong. Okay, by knowing the theory, let's see real world cases. The first case is Uber. Uber direct access to the domain. From the name, we know this is the domain for internal purpose. Once we access, it redirects us to one login single sign on service. And this redirection was done by engine X. We find the domain. And we also know that Jira 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 trick again. It looks good in engine X and match the white list prefix. So pass to Jira. As a result, we can access the Jira internal and see the internal project. We can see the Jira dashboard and see the internal project. And this is another portal 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 cache 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 cache, I will use this site as example. This is the screen shot 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 on the reverse proxy or not. We applied our traversal trick again and got a cool patch. This is a full zero full patch, but the spatial 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 a server configuration in our mind. Engine X just rewrite the request to backend index.cfn. But for the data 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, the file extension is cfn. The cofusion might call language. From the extension, we can guess what backend engine is it. In this case, it is running on the railroad and open source the cfn engine. From the railroad menu, we also know that the management in the fast is on the railroad contacts at the main slash web.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 refreshed several times, the patch changed. So I don't know why. So what's wrong with it? With a little bit investigation, I think I find a root clause. 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 clause to invite you to enter the new password. However, not all instances are vulnerable. 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 arrest and won 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 trying 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 Railroad, 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. Railroad 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 exploring this, we face a problem. The log file is too large to be asked. 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 cloud launch a new instance and exploit another instance. Okay, now every 404 patch is our backdoor. 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 gain 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... We know most... Sorry. 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 the current patch to compare with? It retrieved the patch from the HTTP sublet request. So what's the problem? In order to handle URL patch parameter, Naseel trunked the patch by semicolon. As I mentioned before, the behavior in URL patch parameter are various. Every web server has own implementation. The Naseel's way may be saved in the container such as Widerfly and Weblogic. But now it's on the Tunk Hat. The difference between the Naseel and the Tunk Hat will lead to the security problem. So due to the transaction, 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 null 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 notice that holdNaseel is based on scene framework. I have reviewed scene several years ago and find numbers hacker-friendly features. So for me, the next step is training the first bug to access the unauthorized scene framework. So let's talk about the scene feature. In order to control the browser, scene framework introduces a series of HTTP parameters. Action method is one of them. It can invoke specific expression language from the chorus 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.sgap by the following URL. The feature looks good. You cannot control any file on remote server, therefore you can 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, scene 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 find a good gadget. This is very similar to the ROP, a return-oriented programming in binary exploitation. 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 ask you the partial tag. Okay. By training with the first access control by pass, we can now ask you arbitrary EL without any authentication. But it's still not over yet. We fail to pop our shell. Scene also knows that EL is risky. So there is a blacklist to block dangerous invocations. However, it's just a simple string 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 sensor blade, we use the feature and choose the good gadget so that we can control the return value. We also prepared our second-stage payload in the URL and use array like operator to bypass the blacklist. The last step is to write our, write, write a 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 by pass. In order to bypass the whitelist, we choose login.jsp as our prefix. Now, Ciel will scan all the required paths and truncate 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 server, we use the option method to invoke partial expression language in a known file. Here we choose the gadget on the file with the long name. So why we choose this? It's because the return value of the class.getPermat 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 feature, same framework will invoke value as expression language again. In order to avoid the bad pattern, we use a red like operator to bypass the blacklist. We also use Java reflection API to get all methods from Java.ln. The element index seven is the method get runtime to return the runtime object. And the index 15 is the method exe 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 sides. 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 policy 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 pass processor and pass normalization, including inconsistency, misuse method, and the off-bice latch problem in engine X. Then we introduce a new attack service on the reverse proxy architecture that can bypass ASSYS control and as gap 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 latest post. This is the end of my presentation. Thank you for being here. Thanks.
 Okay, hi. Thanks for coming. In the next 15 minutes, I will present breaking  puzzle logic, take your personalization of MPAR-0.  Othopaste 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 .dustlash. In this talk, I will try to pay more attention on analyzing puzzle  logics and personalizations. During this process, we find, 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 theories and attack surface. And also  a member of HitCon. We hold the largest hacker conference in Taiwan. Apart from  that, I know so as 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 dust. 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 open, 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 every  system 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 workaround 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-passer. Everyone follows  RFC as their standard. RFC defined a 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  features 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 main set get pass only return the part before the  question mark. But the file system still recognize all SSIF pass. So here is an  inconsistency. On the other hand, the main set get file or to external phone  return all the URL part. But if the check rely on the normalized result from  then, we can forge a valid pass to bypass the track and read actually file on  the Linux. So back to our topic. Why I target 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 check 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 Modura 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 my  faces by a patch and Modura by all local. While reading advice service, I  noticed a report that revealed Modura 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  adversary 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. Modura 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 into the path normalization 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 escaped the  path 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  encroaches the current file separator with sgapq and sgape. Because of the  misuse, Grails will recognize the sgap regular expression as literal string. As  the 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-bite slash fail on engine X. The first time this  problem was shown was in the end of 2016 and this created two uglys. Although  this is not new, it still was 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  specified 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 static file on engine X on Google or a stack  overflow and you will find numbers and search with misstacks. 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 give a  private bug bounty cache here. From direct access in the S3 folder, engine  X will return for VOC forbidden. However, when we try the slash and third  dot dot slash, it also returns for VOC. It looks like we have successfully  traversed a label to parent directory. But how to prove this? We append a  slash slash app dot this 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 drengle secret key  and the SQLite database. Thank you. So for the past several months, I start to  review the path normalization and pass the path 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 order to prevent  similar bugs again, Spring applies several security mechanisms. From the  method name, we know Spring first track whether the path is valid or not and use  its results on the location of the list guardians to ensure the path on the  property at locations. This is the simple file version of method is  invalid path. It's just a simple blacklist. 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. 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 repressed backslash to forward  slash. Spring also separate the path with the forward slash, check the  element one by one and store the result into path 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, that's 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 path 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 path, things start going  wrong. The main set is invalid 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 exploit? We crone 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  secured 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 lots of  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 parser is really hard. So it just  copied the code from Spring. As the result, Spark also copied a 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 a 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 skin 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 skin, you can override some internal  options with your query string. As an answer pipeline system, Spark it 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, your upload and malicious file to temp  folder and ask you to code by Spark keys. Are you okay? The boring part is over. You  can stretch yourself a little bit. Okay, here is 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 exploit 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 code executions. In addition, I would like to thank Amazon  and Binder for the open-mind vulnerability disclosure and their quick  response time. It's a very good experience working with them. Yeah. We start with a  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 balance 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  substatic file directly and pass the business logic to backend service. I have  talked about it by a sledge 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?  UL pass parameter is defined in HTTP specification, but not all web servers  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 an end 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 blacklist or whitelist. It can also escape from current  context maping 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.  Baskara, 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 is posed the  application portal in localhost. MFs 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 to traverse one label to touch the root of  tongue cat. A patch first handle this request. From the view of a patch,  tongue cat is a normal folder name and matches the context maping. So it  pass to backend service. But in tongue cat, tongue cat is a parent directory and  will normalize with the portal. As a result, we can access all application on  the tongue cat, including the management in the fast. Everything looks good from  this side. But when they put all together, everything starts goes wrong. Okay, by  knowing the theory, let's see real world cases. The first case is Uber. Uber  direct access to the domain. From the name, we know this is the domain for  internal purpose. Once we access, it redirects us to one login single sign on  service. And this redirection was done by engine X. We find the domain. And we  also know that Jira 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 trick again. It looks good in engine X and match the white  list prefix. So pass to Jira. As a result, we can access the Jira  internal and see the internal project. We can see the Jira dashboard and see  the internal project. And this is another portal 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 cache 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 cache, I will use this site as example. This is the screen  shot 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 on the reverse  proxy or not. We applied our traversal trick again and got a cool patch. This is  a full zero full patch, but the spatial 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 a server configuration in our  mind. Engine X just rewrite the request to backend index.cfn. But for the  data 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, the file extension is  cfn. The cofusion might call language. From the extension, we can guess what  backend engine is it. In this case, it is running on the railroad and open source  the cfn engine. From the railroad menu, we also know that the management in the  fast is on the railroad contacts at the main slash web.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  refreshed several times, the patch changed. So I don't know why. So what's  wrong with it? With a little bit investigation, I think I find a root  clause. 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 clause to invite you to enter the  new password. However, not all instances are vulnerable. 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 arrest and won 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 trying 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 Railroad, 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. Railroad 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 exploring this, we face a problem. The log file is too large to be  asked. 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 cloud launch a new  instance and exploit another instance. Okay, now every 404 patch is our  backdoor. 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 gain 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... We know most... Sorry. 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 the current patch to compare  with? It retrieved the patch from the HTTP sublet request. So what's the problem?  In order to handle URL patch parameter, Naseel trunked the patch by semicolon.  As I mentioned before, the behavior in URL patch parameter are various. Every web  server has own implementation. The Naseel's way may be saved in the  container such as Widerfly and Weblogic. But now it's on the Tunk Hat. The  difference between the Naseel and the Tunk Hat will lead to the security  problem. So due to the transaction, 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 null  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 notice that holdNaseel is based on scene framework.  I have reviewed scene several years ago and find numbers hacker-friendly  features. So for me, the next step is training the first bug to access the  unauthorized scene framework. So let's talk about the scene feature. In order  to control the browser, scene framework introduces a series of HTTP parameters.  Action method is one of them. It can invoke specific expression language from  the chorus 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.sgap by the following URL. The feature  looks good. You cannot control any file on remote server, therefore you can  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, scene 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 find a good gadget. This is very  similar to the ROP, a return-oriented programming in binary exploitation.  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 ask you the partial tag.  Okay. By training with the first access control by pass, we can now ask you  arbitrary EL without any authentication. But it's still not over yet. We fail to  pop our shell. Scene also knows that EL is risky. So there is a blacklist to  block dangerous invocations. However, it's just a simple string 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 sensor blade, we use the  feature and choose the good gadget so that we can control the return value. We  also prepared our second-stage payload in the URL and use array like operator to  bypass the blacklist. The last step is to write our, write, write a 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 by pass. In order to bypass the whitelist, we  choose login.jsp as our prefix. Now, Ciel will scan all the required paths and  truncate 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 server, we use the option method to  invoke partial expression language in a known file. Here we choose the gadget on  the file with the long name. So why we choose this? It's because the return value  of the class.getPermat 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 feature, same framework will invoke value as expression language again. In  order to avoid the bad pattern, we use a red like operator to bypass the  blacklist. We also use Java reflection API to get all methods from Java.ln.  The element index seven is the method get runtime to return the runtime object.  And the index 15 is the method exe 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 sides. 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 policy 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 pass processor and pass  normalization, including inconsistency, misuse method, and the off-bice latch  problem in engine X. Then we introduce a new attack service on the reverse  proxy architecture that can bypass ASSYS control and as gap 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 latest post. This is the end of my  presentation. Thank you for being here. Thanks.
DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_0_1403.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_1404_2135.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_2136_2951.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_2952_4751.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_4752_5687.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_5688_8567.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_8568_10991.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_10992_12491.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_12492_13403.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_13404_13799.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_13800_13871.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_13872_13967.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_13968_14327.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_14328_14423.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_14424_18191.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_18192_18575.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_18576_19091.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_19092_19811.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_19812_21875.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_21876_23603.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_23604_24275.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_24276_24371.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_24372_24995.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_24996_25187.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_25188_25259.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_25260_27791.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_27792_28307.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_28308_29363.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_29364_29411.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_29412_29687.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_29688_30479.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_30480_34019.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_34020_35087.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_35088_35975.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_35976_37079.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_37080_37463.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_37464_39107.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_39108_39287.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_39288_39479.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_39480_39527.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_39528_40319.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_40320_40559.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_40560_43655.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_43656_44075.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_44076_44915.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_44916_44987.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_44988_47111.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_47112_47699.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_47700_48059.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_48060_48851.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_48852_49043.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_49044_49139.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_49140_51623.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_51624_52559.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_52560_52655.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_52656_54995.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_54996_55487.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_55488_55703.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_55704_56183.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_56184_56231.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_56232_57827.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_57828_61847.png DEF_CON_26_-_Orange_Tsai_-_Breaking_Parser_Logic_Take_Your_Path_Normalization_Off_61848_64911.png
Okay, hi. Thanks for coming. In the next 15 minutes, I will present breaking puzzle logic, take your personalization of MPAR-0. Othopaste 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.dustlash. In this talk, I will try to pay more attention on analyzing puzzle logics and personalizations. During this process, we find, 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 theories and attack surface. And also a member of HitCon. We hold the largest hacker conference in Taiwan. Apart from that, I know so as 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 dust. 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 open, 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 every system 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 workaround 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-passer. Everyone follows RFC as their standard. RFC defined a 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 features 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 main set get pass only return the part before the question mark. But the file system still recognize all SSIF pass. So here is an inconsistency. On the other hand, the main set get file or to external phone return all the URL part. But if the check rely on the normalized result from then, we can forge a valid pass to bypass the track and read actually file on the Linux. So back to our topic. Why I target 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 check 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 Modura 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 my faces by a patch and Modura by all local. While reading advice service, I noticed a report that revealed Modura 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 adversary 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. Modura 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 into the path normalization 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 escaped the path 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 encroaches the current file separator with sgapq and sgape. Because of the misuse, Grails will recognize the sgap regular expression as literal string. As the 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-bite slash fail on engine X. The first time this problem was shown was in the end of 2016 and this created two uglys. Although this is not new, it still was 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 specified 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 static file on engine X on Google or a stack overflow and you will find numbers and search with misstacks. 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 give a private bug bounty cache here. From direct access in the S3 folder, engine X will return for VOC forbidden. However, when we try the slash and third dot dot slash, it also returns for VOC. It looks like we have successfully traversed a label to parent directory. But how to prove this? We append a slash slash app dot this 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 drengle secret key and the SQLite database. Thank you. So for the past several months, I start to review the path normalization and pass the path 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 order to prevent similar bugs again, Spring applies several security mechanisms. From the method name, we know Spring first track whether the path is valid or not and use its results on the location of the list guardians to ensure the path on the property at locations. This is the simple file version of method is invalid path. It's just a simple blacklist. 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. 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 repressed backslash to forward slash. Spring also separate the path with the forward slash, check the element one by one and store the result into path 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, that's 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 path 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 path, things start going wrong. The main set is invalid 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 exploit? We crone 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 secured 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 lots of 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 parser is really hard. So it just copied the code from Spring. As the result, Spark also copied a 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 a 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 skin 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 skin, you can override some internal options with your query string. As an answer pipeline system, Spark it 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, your upload and malicious file to temp folder and ask you to code by Spark keys. Are you okay? The boring part is over. You can stretch yourself a little bit. Okay, here is 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 exploit 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 code executions. In addition, I would like to thank Amazon and Binder for the open-mind vulnerability disclosure and their quick response time. It's a very good experience working with them. Yeah. We start with a 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 balance 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 substatic file directly and pass the business logic to backend service. I have talked about it by a sledge 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? UL pass parameter is defined in HTTP specification, but not all web servers 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 an end 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 blacklist or whitelist. It can also escape from current context maping 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. Baskara, 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 is posed the application portal in localhost. MFs 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 to traverse one label to touch the root of tongue cat. A patch first handle this request. From the view of a patch, tongue cat is a normal folder name and matches the context maping. So it pass to backend service. But in tongue cat, tongue cat is a parent directory and will normalize with the portal. As a result, we can access all application on the tongue cat, including the management in the fast. Everything looks good from this side. But when they put all together, everything starts goes wrong. Okay, by knowing the theory, let's see real world cases. The first case is Uber. Uber direct access to the domain. From the name, we know this is the domain for internal purpose. Once we access, it redirects us to one login single sign on service. And this redirection was done by engine X. We find the domain. And we also know that Jira 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 trick again. It looks good in engine X and match the white list prefix. So pass to Jira. As a result, we can access the Jira internal and see the internal project. We can see the Jira dashboard and see the internal project. And this is another portal 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 cache 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 cache, I will use this site as example. This is the screen shot 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 on the reverse proxy or not. We applied our traversal trick again and got a cool patch. This is a full zero full patch, but the spatial 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 a server configuration in our mind. Engine X just rewrite the request to backend index.cfn. But for the data 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, the file extension is cfn. The cofusion might call language. From the extension, we can guess what backend engine is it. In this case, it is running on the railroad and open source the cfn engine. From the railroad menu, we also know that the management in the fast is on the railroad contacts at the main slash web.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 refreshed several times, the patch changed. So I don't know why. So what's wrong with it? With a little bit investigation, I think I find a root clause. 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 clause to invite you to enter the new password. However, not all instances are vulnerable. 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 arrest and won 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 trying 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 Railroad, 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. Railroad 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 exploring this, we face a problem. The log file is too large to be asked. 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 cloud launch a new instance and exploit another instance. Okay, now every 404 patch is our backdoor. 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 gain 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... We know most... Sorry. 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 the current patch to compare with? It retrieved the patch from the HTTP sublet request. So what's the problem? In order to handle URL patch parameter, Naseel trunked the patch by semicolon. As I mentioned before, the behavior in URL patch parameter are various. Every web server has own implementation. The Naseel's way may be saved in the container such as Widerfly and Weblogic. But now it's on the Tunk Hat. The difference between the Naseel and the Tunk Hat will lead to the security problem. So due to the transaction, 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 null 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 notice that holdNaseel is based on scene framework. I have reviewed scene several years ago and find numbers hacker-friendly features. So for me, the next step is training the first bug to access the unauthorized scene framework. So let's talk about the scene feature. In order to control the browser, scene framework introduces a series of HTTP parameters. Action method is one of them. It can invoke specific expression language from the chorus 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.sgap by the following URL. The feature looks good. You cannot control any file on remote server, therefore you can 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, scene 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 find a good gadget. This is very similar to the ROP, a return-oriented programming in binary exploitation. 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 ask you the partial tag. Okay. By training with the first access control by pass, we can now ask you arbitrary EL without any authentication. But it's still not over yet. We fail to pop our shell. Scene also knows that EL is risky. So there is a blacklist to block dangerous invocations. However, it's just a simple string 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 sensor blade, we use the feature and choose the good gadget so that we can control the return value. We also prepared our second-stage payload in the URL and use array like operator to bypass the blacklist. The last step is to write our, write, write a 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 by pass. In order to bypass the whitelist, we choose login.jsp as our prefix. Now, Ciel will scan all the required paths and truncate 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 server, we use the option method to invoke partial expression language in a known file. Here we choose the gadget on the file with the long name. So why we choose this? It's because the return value of the class.getPermat 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 feature, same framework will invoke value as expression language again. In order to avoid the bad pattern, we use a red like operator to bypass the blacklist. We also use Java reflection API to get all methods from Java.ln. The element index seven is the method get runtime to return the runtime object. And the index 15 is the method exe 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 sides. 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 policy 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 pass processor and pass normalization, including inconsistency, misuse method, and the off-bice latch problem in engine X. Then we introduce a new attack service on the reverse proxy architecture that can bypass ASSYS control and as gap 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 latest post. This is the end of my presentation. Thank you for being here. Thanks.
pitfalls and edge cases that programmers may frameworks and find bugs from them. We will show chat function will be bypassed. It's just like my is a very fundamental library, but since there is mention. This is a good attack vector without too very common in web architectures. In practical problem in real world? We give a private bug information such as the drengle secret key and consideration and our new finding is more element in path array. During the normalization, element, when there is more than one slash in the repeat yourself. And Spring is a popular vulnerability. The next case is Ruby on Rails. this exploit. But because of the time, you can perfectly exploit on multi-layered architectures. for the open-mind vulnerability disclosure and Reverse proxy is a common web architecture, and business logic to backend service. I have talked blacklist or whitelist. It can also escape from huge attack surface. Think about how many reverse way, this is also a good methodology to know different backend servers. For example, if the shell. But due to the request being dispatched to applications. It's written in Java. But in that Every web server has own implementation. The feature. To make things worse, if the previous return-oriented programming in binary long name. Why we choose this? It is because the the access control by pass. In order to bypass container, we can bypass the authentication and pass normalization, including inconsistency, on the reverse proxy architecture that can bypass