 Welcome to the five o'clock, track three. Unfortunately, Orange Psy cannot be here today. However, we are going to try to stream, I'm sorry, play his presentation for you guys. All right, enjoy. Hi, sorry I couldn't be on the stage because of the issue of visa. I hope one day we can meet fast to fast in Vegas. About 10 years ago, I failed my air grease and course at university. But I'm not here to talk about the hash table. This is a big achievement for me. And Orange, today my topic is less dance in the cache, destabilizing hash table on Microsoft IIS. Before the talk, I would like to give you a showcase. If there is a super secret area, which is protected by a super secure password, you cannot look in only if you know this long password. However, under the design of IIS, all of these passwords are valid and can look into the system. Amazing, right? I guess you might have several questions in your mind. This is one of the attacks I will present today. And you will learn the details later. Hi, I'm Orange, and now the Principal Security Researcher at Devcore. I am a zero day researcher and focusing on web and application security. My job is to discover the most severe bugs and attacks service that can impact the world ahead of the bad guys. My research has also received several awards, such as the best server sidebar of pounding awards and the champion of pound to own. If you are interested, we'll come to follow my Twitter or chat with me later. This is the online today. First, we will introduce several essential concepts. Those concepts are important to let you into Microsoft IIS internals and our topic today. After having a good understanding of IIS internal and the cache mechanism, we will elaborate on our research followed by three different types of vulnerabilities. Also, we will demonstrate how we applied attacks to Microsoft exchange server as a showcase. Of course, we will provide mitigations, recommendations, and future works to those components. So first, what is the hash table? Hash table is the most fundamental data structure in computer science and its purpose is to store data. No matter what the data is, hash table can hold the data in memory very well. Hash table is especially good at handling the key value pair and can operate data with a high performance. Due to those benefits, hash table is used extensively in computer infrastructures, such as the operating system, programming language, database, or web server. Here is an example of the hash table usage in programming language. Programming language uses the hash table widely. However, you don't know because they wrap the hash table into a more high level structure such as the array, dictionary, or object. So if you are a developer, you must have used hash table. As the internal, I assume that everyone here is a good student at university. So I skip the hash table internal this time. First, for what is the hash folding attack? Also, we are not going to talk about this attack only. We still give it a slot because I believe that the hash folding attack is the best cast to learn the mindset of how an attacker abuse the hash table. The idea of hash folding attack is to drop all the records into the same bucket. Since the hash algorithm is public, an attacker can predict its hash and make all records fall into the same bucket. At the time, the attacker degenerate the hash table which can store numbers records into a single link list. For example, the attacker has craft several malicious records on the left side. The hash function in the middle will process and convert the record into an index. The first record is converted to the index four and put into the corresponding bucket. The second is also put into the same bucket. The third, the fourth. The fifth. And the attacker can drop all records into the same bucket. And the table now becomes a single link list. So the hash folding attack can make the table always sit on on the world's cast. That means for inserting n records, the time complexity comes to n squared. We should all agree that n squared is in a terrible performance. Okay, with a good understanding of the hash table, let's discuss the relationship between the hash table and IIS. First, IIS loves hash table. As the well-known and the only web server in Windows, IIS uses the hash table extensively in X architecture to store information such as HTTP header, server variables, configuration, and cache. Due to the massive use of this data structure, Microsoft has designed its own hash table implementation from a very early stage. The following two are all the implementation that will be used in IIS. One is called tree hash table and the other is called LKR hash table. The tree hash table should be the most common like the simple code in your textbooks. It use the link list to resolve the collision and rehash the table when it's in an unhealthy state. The rehash is a series of rebuilding process. It first enlarges the table, recalculates all records, and repostation them to their new index. As for what hash function is used, we will have a future discussion later. The other table is the LKR hash, an implementation that aims to build a scalable and high-concurrent hash table under the multi-threading and multi-core environment. The name LKR is an acronym for the name of the creators. This implementation was also patterned by Microsoft in 1999. The LKR hash is the successor of linear hashing, which is used another beta algorithm to resolve the expensive rehash to enhance the performance. The creators put a lot of effort to make this implementation portable, flexible, and usable. The application can define its own table-related functions to adapt to multiple products across Microsoft. It's interesting to note that part of the creators are also the AIS developer, which should be the reason why we fight loss of this implementation in AIS. Now we have a complete understanding of the hash table. It's time to go deep into our research. In this section, we will show the AIS internals and define the scope we really cared about. We will first explain our mindset and idea to uncover bugs. We are mainly focusing on the hash table implementation and its usage. Since most of the hash tables are used in AIS are cache-related, we also study and look into ex-mechanism. Because Microsoft has designed its own hash table without open source, the implementation should be an unexplored area to discover bugs. So in this context, we hunt not only for memory corruption, but also logic bugs. Here I would like to highlight the bug CVE 2006-3017, it's a logic bug in the onset function of PHP. The hash table implementation didn't distinguish the key type of an array so that an attacker can delete arbitrary elements with an index number. When I saw this bug, it amassed me and I believe this is just a bug I'm looking for. Of course, we also look for the algorithm complexity problems such as the hash building attack. However, since it's already a 20 years old attack, most of the low handing fruit should be disappeared. So in this context, we put more effort into the implementation. As for the usage, we mentioned that the LKR hash is designed to be a portable, flexible, and easy to use algorithm that can be applied to any situation. The convention requires the application to configure its own table-related function during initialization. This kind of extensibility gives us more opportunities to uncover bugs. When I saw this, I was curious that is the particular function good? Is the key calculation good? Or how does the function select the correct record when a collision happens? These types of questions all interested me. So in this context, we care more about the relationship between the record, the key, and the function. When an HTTP request is coming, the kernel HTTP.sys will first handle the connection and dispatch the request. The kernel checks if there is an active IIS worker. If not, it knocks the IIS service to spawn a new process. The WIS windows activation service first reads the configuration to note several specific caches for the process initialization. And spawn the worker process. Several IIS components are loaded here. The worker then loads the modules which are defined in the configuration. IIS by default loads several modules for different purpose, such as the compression, redirection, authentication, and the cache. Among all modules, the following four are the global cache provider to manage the cache between modules. Each module is responsible for handling a different cache, such as the cache for static file, the cache for configuration, and the cache for Windows token. Once the modules are loaded, the worker enters the request lifecycle. The lifecycle is an event loop that process all the notifications from the request. There are several events in a lifecycle. A module can subscribe to its interesting events to complete its logic. There are also global events that a module can subscribe to. For example, the cache provider subscribes to the event cache cleanup and the cache operation to manage the cache between modules. So our research is not only focusing on the cache between the request lifecycle, but also the global cache providers, especially those four are our golden targets. The following section is about our research and the bugs. In this section, we will first elaborate on our idea and the direction we are trying to find bugs. We will attach three different types of vulnerabilities to prove our idea works. Our bugs include a hash-fueling DOS, a cache poisoning, and authentication bypass. We will also talk about the exploitation of how we maximize the severity to make these bugs impactful. Of course, a real-world authentication bypass on Microsoft Exchange Server will be detailed and demonstrate. Okay, the first cache we would like to share is the hash-fueling DOS. First, we would like to give you a spoiler that all hash tables implement by Microsoft are affected by hash-fueling attack. The tree hash table is vulnerable by default, and the LKR hash is vulnerable only if a pooled hash function is configured. However, vulnerable is not equal to exploitable. Besides finding the entrance point, we still have several obstacles to overcome. We find that URI cache module seems to be a good target. The purpose of this module is to cache configuration for URLs. Because grid configuration is costly, so cache is the best strategy. In this module, every HTTP access triggers the cache operation. And the most important thing is that the module uses tree hash table as its cache storage. Well, an accessible by default tree hash table sounds good to us. This is the time chart of every thousand new records in tree hash table. Because it's not open-sourced, we must reverse the structure and code the table dynamically to get the dataset. The line in blue is the time of inserting random records, and the line in orange is the records with collisions. You should be able to figure out there's a huge difference between the two lines. However, the jitters along 35,000 and 75,000 are real. What's the jitter? So radically, the line screws in orange should be in linear time. So what actually makes the time increase unsmoothly? The answer is rehash. This is the part of the insert operation. The implementation first traverses the link list to ensure no duplicates and do its internal job. However, after the internal app operation, there is a call to the function rehash table if needed. The function checks the number of records and rehash the table if the number is greater than two times of the threshold. The threshold is selected from a list of prime numbers. And once rehashed, the function enlarges the table by the next prime number and remaps all records to their corresponding bucket. This is a huge and expensive operation, and that's the reason why the chart increased unsmoothly. To exploit that, there are still several questions to be solved. For example, how much of the cache key we can control? Or how to construct the coalition catalog? There are several elements in a cache key, and the only element we can control is the URL path, which reflected at the end of the cache key. The implementation will first convert all the tags to our cache and send a key to the hash function. The hash function simply multiplies each byte of the cache key by 101. And the sounds then are. The function also uses an lcg to scramble the result. However, is this hash function good? This is the answer from Alec and Zary in their Olsen talk at 28c3. This multiply then add method is a variant of djb hash. And this algorithm has been proven that collidable by equivalent substrings. When two keys have the same hash, such as the ps and q2, they must be equal no matter what you add before or after that. For example, after you add the later a, the hash of ps a and q2 a are still equal. By knowing this feature, it's not difficult to understand that two equivalent substrings can be combined to form different keys, such as the ps ps, ps q2, q2 ps, and q2 q2. They all share the same hash. Since you can repeat the string many times, constructing the payload is easy. You just need to find a few strings with the same hash and arrange them in combinations. So all of these share the same hash value. This is handy for our exploitation. However, there is a fatal flaw in this attack. That is too weak. To get a noticeable slowdown, you must have sent about 35,000 requests at least. For our one request at one record exploiting, it's too slow. And the hospital ridiculous is that there is a catch scavenger to recycle records regularly. The scavenger is a set to delete unused records every 30 seconds. Those two obstacles makes our attack not so practical. To overcome this, we have to dive into the implementation more. During our investigation, we find an interesting behavior that can rescue our attack. The implementation will standard key recursively. It trace all sub directories as new records and ask all of them to the table. For example, in our imagination, the URL will only trigger one search and one insert operation. However, each sub directory will also be checked as a new record so that the URL will trigger multiple insert operations. What's more interesting is that all new keys will be packed with a newer record. The scavenger is nice to do more records and only deletes them one by one instead of killing all of them in a batch. So the only question left is how to construct the coalition in this new context. Because all sub directories are trade-offs independent keys, we have to construct a payload that satisfies all the following equations. It may be a little hard to imagine how to make this happen through our previous equivalent feature. But if we make all the results to be zero, then things come much easier. Zero multiplied anything is zero, and zero plus zero is also zero. So we can satisfy all the equations if we make the hash of each sub directory to zero. So we can prepare a set of zero hashes and amplify the attack 10 times at least by a slight modification. The result is that we can make a server unresponsive with about 13 connections per second. This is not an unreasonable number because IIS can handle thousands of connections easily and concurrent. Because this bug affects the windows by default, we also award a good amount of bounty. Let's check out the demo. We first double-check and ensure the server has 8 cores and 32 gigabytes of RAM. The window in the lower left is the script that monitors the status of the IIS. It's a while loop and checks the server every second. OK, we first run the render test. We send render test to the IIS. You can see the loading is less than 10%. OK, we now run the collision mode. As you can see, the CPU is not under high loading. OK, 100% CPU load. OK, as you can see, the monitor enters the timeout loop. Here we speed a little bit up. OK, as you can see, the server is unavailable and can't handle any requests anymore. OK, the second test is the catch poisoning attack. There are two types of response catch in IIS. One is the static catch support by the kernel, such as the picture, the CSS, and the JavaScript resources. The other is dynamic catch, which is usually used to catch responses that rarely change. For example, the product information of an online shop or the news announcement of NCNS. The benefit of the dynamic catch is that you can reduce the number of the database assets. Dynamic catch is handled by the HTTP catch module, and you can configure the catch by the output catching component. To use the catch, you must first set out your own rule. The rule can best on several connections, such as the file extension, the query stream, or the HTTP header. Here we set out a rule for the extension of SPX and catch the result best on the ID. So the root cause of the catch poisoning is that the module used a bad parser to handle the query stream. Assign that you have already set out a rule to catch a specific parameter. An inconsistency between the module and the backend may lead IIS to catch the wrong result. In the real world, the most common backend is SP.NET, and a simple HTTP parameter pollution can rule them all. For the key do be cast in the query stream, the module only uses the first occurrence as the catch key. However, the SP.NET concatenate all together. These inconsistent parser behaviors cause the IIS to catch the wrong response. For example, if a patch just prints out your name best on the ID, the attacker can poison the result by repeating the ID on the URL. The IIS only recognize the orange as the catch key. However, the SP.NET will concatenate both values and show them all. So the result is that the next time the user answers the patch, he got hacked. OK, our last cast is the authentication bypass. Back to our opening, a super secret area which is protected by a super strong password. Under the design of the IIS, all of these passwords are valid. I guess you might have several questions and be thinking, post the root codes, or how do I get those passwords? Or suspect this must be an edge cast. What kind of the scenario is vulnerable? First, look on is an expensive operation. To not reduce the performance, IIS catches all tokens for password best authentication by default. The implementation uses the LKR hash instead of the tree hash table and configures a scavenger to delete unused record every 15 minutes. As we mentioned, LKR hash is highly customized. During initialization, the module defines several functions, such as the hash function, the logic of how to extract the key from the record, and how to decide which one is the correct record when the collision happened. And this is the hash function defined by the token cache module. It simply uses the DJB to hash the username and the password and then makes them together by XOR. And this is the function used to decide which one is the correct record when the collision happens. The function first checks whether the logon method of both records are equal or not, and then compare the username and compare the username again. You may be wondering, why did this function compare the username twice? I guess the original intent of IIS was to compare the password. However, the developer copied and passed the code but forgot to repress the name to the password. It's a big fail. The failure creates an inconsistency between the hash calculation and the cache comparison. The hash calculation invokes both the username and the password. However, when the collision occurs, the table only compares the username to get the correct entry. Since we can adjust the field of the password to change the hash, if the hash hits a record that is already in the table, the module will return that to us the directory. So the result is that you can reuse another user's login token with random passwords. However, there are still a few prerequisites. First, each password attempt only has the success rate of $3.2 billion because the hash is a 32-bit integer. The other prerequisites is that there must be a successful login before our attack. But once the login is done and the token is cached in the memory, you have unlimited attempts during the 15-minute time window. Both of the above prerequisites makes this bug unusable. It's just like playing the lottery in the space of the 32-bit integer. So to make this bug a more severe vulnerability, we have developed several ways to win the lottery. The first enhancement is to increase the probability of the collision. A vulnerability that requires user interaction is too late. So for the second, we must find a way to exploit without user interaction. The last is to defeat the restriction of the 15-minute time window. We figure out a way to cache the token forever. OK, the first is to increase the probability. As we mentioned, that the four billion possible records are a ridiculous number. The LKR hash even used an LCG to make the result more random. But just because of this LCG, we can lower the key space because the LCG is not one-to-one mapping under the key space of 32-bit integer. So there must be results that will never appear. So we can pre-compute a dictionary that excludes the password whose hash is not in the results. This development can reduce a number of the key space. Although there are still billion possible records, we have increased our success rate by 13% at least. The second enhancement is to regain the initially. There is a feature called connect us that is usually used in the virtual hosting because the vendor has to separate IIS process for their customers. With this feature, each IIS process can be under a different user context. Under the feature, IIS will auto log on the user to specify while responding the new process. This token will also be cached. That means we can reuse the customer's identity and no longer to wait for user interaction. In this case, we have regained the initially. To prove it works, we did a test in our lab environment. Windows Server can handle about 1,000 and 800 logging attempts per second. Because every attempt costs nothing, you can run this all day. And the success rate is about 4.2%. This is already higher than the SSR in your GATRA games. And you can also run it for longer, 5 days for 20%, 12 days for 50%, and the success rate of running for 24 days can get 100%. We have reproduced in our lab environment and can get a password in about five days. The last enhancement is to defeat the tiny window. Our idea is simple. In modern software architecture, it's common to see the pattern of a background demon monitors the system's health. Our several Chrome jobs access the internal APIs regularly. So we can assign a situation that a credential is attached with the Chrome job. And the gap between each access is less than 15 minutes. In this assumption, the token will be cached forever. OK, I know it's very ideal. Is there any real cash? Sure, let's talk about the exchange server again. There is a service called Active Monitoring, which is enabled by default and responsible for monitoring all services. It checks the OWA and ActiveSafe service every 10 minutes with the test credential. Thanks for the health check. The token of the credential will be cached forever. So you can try as many as you like until you get a successful looking. And the password is also usable to log into the OWA. The account for the health check has its own mailbox too. This is useful for further exploitations, such as phishing or training another post-ORS RCE together. That's our last catch. Let's talk about the mitigations and future works. For the design of the hash table, it's recommended to use the pseudo-random functions such as the SIP hash or a highway hash that can reduce the collision and make the attacker more custom. For the design of the cache, inconsistency is still the key. Just like our cache today, the cache poisoning due to the different password behaviors and authentication bypass due to the un-keyed password. Since the hash floating attack is by design attack, there are several work-arounds to mitigate the problem, such as the input size limitation or a state to randomize the hash. Each solution has its limitation, so the last recommendation is to learn the attacker and defense from the history. There are still several cool future works in my mind, such as using Tyler's timing attack to reduce the key space. However, since I am lazy, we'll come to pick them up if you are interested. This is the end of my presentation. If you have any questions, here is my contact information. Thank you again for being here. Thanks.