вторник, 30 апреля 2019 г.

Bypassing SOP Using the Browser Cache

(It's a repost from https://www.acunetix.com/blog/web-security-zone/bypassing-sop-using-the-browser-cache/)

Misconfigured caching can lead to various vulnerabilities. For example, attackers may use badly-configured intermediate servers (reverse proxies, load balancers, or cache proxies) to gain access to sensitive data. Another way to exploit caching is through Web Cache Poisoning attacks.

The browser cache may look like a very safe place to temporarily store private information. The primary risk is that an attacker may gain access to it through the file system, which is usually considered a low-hazard vulnerability. However, in some cases, misconfigured cache-related headers may cause more serious security issues.

Cross-Domain Interaction Risks

Some websites have several subdomains and need to share data between them. This is normally not possible due to the same-origin policy (SOP). There are some methods that enable such cross-domain interaction, for example, JSONP (JSON with Padding). Developers who use such methods must implement some kind of protection against data leaking to other sites.

Let’s say that an example site has two subdomains: blog.example.com and account.example.com. The account.example.com site has a JSONP endpoint that returns sensitive user data on the basis of the user cookie. To prevent leaks, this endpoint verifies the Referer header against a whitelist that includes blog.example.com.

With this setup, if the user is lured to visit a malicious site, the attacker cannot directly steal sensitive data. However, if the JSONP endpoint sets cache-related headers, the attacker may be able to access private information from the browser cache.

Browser Behavior

Browsers have slightly different cache implementations but certain aspects are similar. First of all, only GET responses may be cached. When the browser gets the response to its GET request, it checks response headers for caching information:
  • If the response contains a Cache-Control: private or Cache-Control: public header, the response is cached for Cache-Control: max-age=<seconds>.
  • If the response contains an Expires header, the response is cached according to its value (this header has less priority than Cache-Control)
  • If none of these headers is present, some browsers may check the Last-Modified header and typically cache the response for ten percent of the difference between the current date and the Last-Modified date.
  • If there are no cache-related headers at all, the browser may cache the response but usually revalidates it before using it.
Problems may arise due to the fact that there is just one browser cache for all websites and it uses only one key to identify data: a normalized absolute URI (scheme://host:port/path?query). It means that the browser cache has no additional information about the request that initiated a particular response (for example, the site/origin from which it came, the JavaScript function or tag that initiated it, the associated cookies or headers, etc.). Any site gets the cached response from account.example.com as long as it initiates a GET request to the same URI.

The Anatomy of the Attack

The following is a step-by-step explanation of how this vulnerability is used for an attack:
  1. The user visits blog.example.com.
  2. A script on blog.example.com needs user account information.
  3. The user’s browser sends a request to the JSONP endpoint at account.example.com.
  4. The response from the JSONP endpoint at account.example.com contains cache-related headers.
  5. The user’s browser caches the response content.
  6. The user is lured to a malicious site
  7. The malicious site contains a script that points to the JSONP endpoint at account.example.com.
  8. The browser returns the cached response to the script at the malicious site.
In this situation, the Referer header is never checked because the response comes from the cache. Therefore, the attacker gains access to cached private information.



Similar Vulnerabilities

The same approach may be used to exploit other variations of Cross-Site Script Inclusion (XSSI) and other SOP Bypass attacks. Such attacks may bypass other server-side checks, for example, the Origin header, the SameSite cookie attribute, or custom headers.

Let us assume that account.example.com uses Cross-Origin Resource Sharing (CORS) instead of the JSONP endpoint. It returns an Access-Control-Allow-Origin: * header but uses a special token from a custom header to authenticate the user and protect sensitive data.

If responses are cached, the attacker may steal private information by making a request to the same URI. There is no CORS protection (due to Access-Control-Allow-Origin: *) and the user’s browser will return cached data without checking for the custom header token.
You can see how these vulnerabilities work in practice by analyzing the outputs of the browser console at a dedicated test site.

How To Protect Against SOP Bypass

The described SOP bypass vulnerability is caused by misconfiguration. In the case of cross-origin interactions, you should disable the browser cache. Most frameworks and ready-made scripts either don’t set cache-related headers or set them correctly by default (Cache-Control: no-store). However, you should always double check these headers to be secure.

Browser vendors are now considering or implementing a stricter approach to caching. Hopefully, this change will prevent such cross-origin leaks.

The tricks invented for the purposes of this article were inspired by the HTTP Cache Cross-Site Leaks article by Eduardo Vela.

вторник, 22 января 2019 г.

A Fresh Look On Reverse Proxy Related Attacks


In recent years, several researches have been published about attacks deliberately or directly related to reverse proxies. While implementing various reverse-proxy checks on the scanner, I started analyzing implementations of reverse proxies.

Initially, I wanted to analyze how both reverse proxies and web servers parse requests, find out inconsistencies in the process between them and use this knowledge for some kind of bypasses. Unfortunately, I was stuck with analyzing web servers and application servers due to too many possible variations. For example, Apache web server behaves differently depending on how you connect it with PHP. Also, an implementation of a web application, framework or middleware used by a web application can influence the requests parsing process as well. In the end I realized that some attacks are still little-known or completely unknown.

The goal of this research is to portray the bigger picture of potential attacks on a reverse proxy or the backend servers behind it. In the main part of the article, I will show some examples of vulnerable configurations and exploitation of attacks on various reverse proxies, but the second goal of the research is to share the raw data about various implementations of reverse proxies so you can find your ways/tricks (depending on a backend server in each specific situation).

Terms

Actually, the research is not only about reverse proxies, but also about load balancers, cache proxies, WAFs and other intermediate servers between a user and web application which parses and forwards requests. However I haven’t found a good term which correctly describes such a server and is well-known in the community, so I will use “reverse proxy” even when I talk about load balancers or cache proxy. I will call a web application behind a reverse proxy a back-end server. Be aware that a backend server is so-called an origin server (this will make sense when we start talking about caching).

 

What is reverse proxy?

 

How proxies work

The basic idea of a reverse proxy is quite simple. It’s an intermediate server between a user and a back-end server. The purpose of it can be quite different: it can route requests depending on the URL to various backends or it can just be there “to protect” against some attacks or simply to analyze traffic. The implementations can be different too, but the main sequence of steps is quite the same.
A reverse proxy must receive a request, it must process it, perform some action on it and forward to a backend.

Processing of a request consists of several main steps:

 

A) 1. Parsing
When a reverse proxy receives a request, it must parse it: to get a verb, a path, a HTTP version, host header and other headers and body.
GET /path HTTP/1.1
Host: example.com
Header: something
Everything may look quite simple, but if you dive into details, you will see implementations are different.

Some examples:

– If a reverse supports Absolute-URI, how will it parse it? Does Absolute-URI have a higher priority than Host header?:
GET http://other_host_header/path HTTP/1.1
Host: example.com
 – URL consists of scheme:[//authority]path[?query][#fragment], and browsers don’t send #fragment. But how must a reverse proxy handle #fragment?

Nginx throws fragment off, Apache returns a 400 error (due to # in the path), some others handle it as a usual symbol.

– How does it handle symbols which must be URL-encoded?
GET /index.php[0x01].jsp HTTP/1.1
2. URL decoding
Due to standards, symbols with a special meaning in the URL must be URL-encoded (%-encoding), like the double quote (") or “greater than” sign (>). But practically, any symbol can be URL-encoded and sent in a path part. Many web servers perform URL-decoding while processing a request, so next requests will be treated in the same way by them.
GET /index.php HTTP/1.1
GET %2f%69%6e%64%65%78%2e%70%68%70 HTTP/1.1
 3. Path normalization
Many web servers support path normalization. Main cases are well-known:
/long/../path/here -> /path/here
/long/./path/here -> /long/path/here
But what about /..? For Apache, it’s an equivalent of  /../, but for Nginx it means nothing.
/long/path/here/.. -> /long/path/ - Apache
/long/path/here/.. -> /long/path/here/.. - Nginx
The same with // (“empty” directory). Nginx converts it to just one slash /, but, if it’s not the first slash, Apache treats it as a directory.
//long//path//here -> /long/path/here - Nginx
//long/path/here -> /long/path/here - Apache
/long//path/here -> /long//path/here - Apache
Here are some additional (weird) features which are supported by some web servers. For example: support of path parameters – /..;/ is valid for Tomcat and Jetty or traversal with backslash (\..\).

B) Applying rules and performing actions on a request

Once a request is processed, the reverse proxy can perform some actions on the request due to its configuration. Important to note that in many cases, rules of a reverse proxy are path (location) based. If the path is pathA, do one thing, if pathB – do another.

Depending on the implementation or on the configuration, a reverse proxy applies rules based on a processed (parsed, URL-decoded, normalized) path or on an unprocessed path (rare case). It’s also important for us to note if it is case-sensitive or not. For example, will the next paths be treated equally by a reverse proxy?:
/path1/ == /Path1/ == /p%61th1/ == /lala/../path1/

C) Forwarding to a back-end

The reverse proxy has processed a request, found appropriate rules for it and performed necessary actions. Now it must send (forward) it to a backend. Will it send the processed request or initial request? Obviously, if it has modified the request, then it sends the modified version, but in this case, it must perform all the necessary steps, for example, to perform URL-encoding of special symbols. But what if the reverse proxy just forwards all requests to only one backend, maybe forwarding the initial request is a good idea?

As you can see all these steps are quite obvious and there are not so many variations. Still, there are differences in implementations, which we, as attackers, can use for our goals.

Therefore, the idea of all attacks described below is that a reverse proxy processes a request, finds and applies rules and forwards it to a backend. If we find an inconsistency between the way a reverse proxy processes a request and the way a backend server processes it, we are then able to create such a request(path) which is interpreted like one path by the reverse proxy and a completely different path by the backend. So, we will be able to bypass or to forcefully apply some rules of the reverse proxy.

Here are some examples

Nginx

Nginx is a well-known web server, but is also very popular as a reverse proxy. Nginx supports Absolute-URI with an arbitrary scheme and higher priority than a Host header. Nginx parses, URL-decodes and normalizes a request path. Then it applies location-based rules depending on the processed path.

But it looks like Nginx has two main behaviors and each of them has its own interesting features:

- With trailing slash
location / {
    proxy_pass http://backend_server/;
}
In this configuration, Nginx forwards all requests to the `backend_server`. It sends the processed request to the backend, meaning that Nginx must URL-encode the necessary symbols. The interesting thing for an attacker is that Nginx doesn’t encode all the symbols which browsers usually do. For example, it doesn’t URL-encode ' " < >.

Even if there is a web application (back-end server) which takes a parameter from a path and which is vulnerable to XSS, an attacker cannot exploit it, because modern browsers (except dirty tricks with IE) URL-encode these symbols. But if there is Nginx as a reverse proxy, an attacker can force a user to send a URL-encoded XSS payload in the path. The Nginx decodes it and sends the decoded version to the backend server, which makes exploitation of XSS possible.
Browser -> http://victim.com/path/%3C%22xss_here%22%3E/ -> Nginx -> http://backend_server/path/<"xss_here">/ -> WebApp
- Without trailing slash
location / {
    proxy_pass http://backend_server;
}
The only difference between this config and the previous one is the lack of the trailing slash. Although seemingly insignificant, it forces Nginx to forward an unprocessed request to the backend. So if you send /any_path/../to_%61pp#/path2, after processing of the request, Nginx will try to find a rule for `/to_app`, but it will send /any_path/../to_%61pp#/path2 to the backend. Such behavior is useful to find inconsistencies.

Haproxy

Haproxy is a load balancer (with HTTP support). It doesn’t make much sense to compare it to Nginx, but it will give you an idea of a different approach.

Haproxy makes minimal processing of a request. So there is no “real” parsing, URL-decoding, normalization. It doesn’t support Absolute-URI either.

Therefore, it takes everything (with few exceptions) between a verb and HTTP version (GET !i<@>?lala=#anything HTTP/1.1) and, after applying rules, forwards it to a backend server. However it supports path-based rules and allows it to modify requests and responses.

How proxies are used

While I was working on this research, analyzing various configurations of reverse proxies, I came to the conclusion that we can both bypass and apply rules of a reverse proxy. Therefore, to understand the real potential of reverse proxy related attacks, we must have a look at their abilities.

First of all, a reverse proxy has access to both a request and a response (including those which it sends/receives from a backend server). Secondly, we need a good understanding of all the features which a reverse proxy supports and how people configure them.

How can a reverse proxy handle a request?:
  1. Routing to endpoint. It means that a reverse proxy receives a request on one path (/app1/), but forwards the request to a completely different one (/any/path/app2/) on a backend. Or it forwards the request to a specific backend depending on a Host header value.
  2. Rewriting path/query. This is similar to the previous one, but usually involves different internal mechanisms (regexp)
  3. Denying access. When a reverse proxy blocks a request to a certain path.
  4. Headers modification. In some cases, a reverse proxy may add or change headers of the request. It could be a cool feature for an attacker, but it’s hard to exploit with a black box approach.
How can a reverse proxy handle a response?:
  1. Cache. Many reverse proxies support caching of response.
  2. Headers modification. Sometimes a reverse proxy adds or modifies response headers (even security related), because it cannot be done on a backend server
  3. Body modification. Reverse proxies will sometimes modify the body too. Edge Side Includes (ESI) is an example of when this can happen.
All this is important for to see more potential attacks, but also understand that in many cases we don’t need to bypass, but apply rules. Which leads to a new type of attacks on reverse proxies – proxy rules misusing.

Server-Side attacks

Bypassing restriction

The most well known case about reverse proxy related attacks.

When someone restricts access (3. Denying access), an attacker needs to bypass it.

Here is an example.
Let’s imagine that there are Nginx as a reverse-proxy and Weblogic as a backend server. Nginx blocks access to an administrative interface of Weblogic (everything that starts with /console/).
Configuration:

location /console/ {
    deny all;
    return 403;
} 
location / {
    proxy_pass http://weblogic;
}
As you can see, proxy_pass here is without trailing slash, which means that a request is forwarded unprocessed. Another important thing to bypass the restriction is that Weblogic treats # as a usual symbol. Therefore, an attacker can access the administrative interface of Weblogic by sending such a request:
GET /#/../console/ HTTP/1.1
When Nginx starts processing the request, it throws off everything after #, so it skips the /console/ rule. It then forwards the same unprocessed path (/#/../console/) to the Weblogic, the Weblogic processes the path and after path normalization, we are left with/console/.

Request Misrouting

It’s about “1. Routing to endpoint” and, in some cases, “2. Rewriting path/query”.
When a reverse proxy forwards requests only to one endpoint, it can make an illusion that an attacker cannot reach other endpoints on a backend or that it cannot reach a completely different backend.

Example 1.
Let’s have a look at similar combinations: Nginx+Weblogic. In this case, Nginx proxies requests only to a certain endpoint of Weblogic (http://weblogic/to_app). So only requests, which come to a path /to_app on Nginx, are forwarded to the same path on Weblogic. In this situation, it may look like Weblogic’s administrative interface (console) or other paths are not accessible for an attacker.
location /to_app {
    proxy_pass http://weblogic;
}
In order to misroute requests to other paths, we need to know two things again. Firstly, the same as in the example above – proxy_pass is without a trailing slash.

Secondly, Weblogic supports “path parameters” (https://tools.ietf.org/html/rfc3986#section-3.3). For example, /path/to/app/here;param1=val1, and param1 will be accessible in a web app through API.

I think many are aware about this feature (especially after the Orange Tsai’s presentation from BlackHat in the context of Tomcat. Tomcat allows to perform really “weird” traversals like /..;/..;/. But Weblogic treats path parameters differently, as it treats everything after the first ; as a path parameter. Does it mean that this feature is useless for an attacker?

Nope. Let’s have a look at this “magic” which allows accessing any path on Weblogic in this configuration.
GET /any_path_on_weblogic;/../to_app HTTP/1.1
When Nginx receives such a request, it normalizes the path. From /any_path_on_weblogic;/../to_app it gets /to_app which successfully applied to the rule. But Nginx forwards /any_path_on_weblogic;/../to_app and Weblogic, during parsing, treats everything after ; as a path parameter, so Weblogic sees /any_path_on_weblogic. If it’s necessary, an attacker can go “deeper” by increasing the amount of /../ after ;.

Example 2.
This one is about a “bug” of Nginx. But this “bug” is just a consequence of how Nginx works (so will not be fixed)

A rule location /to_app means that all paths which start with /to_app (prefix) fall under the rule. So, /to_app, /to_app/, /to_app_anything (including special symbols) fall under it. Also, everything after this prefix(/to_app) will be taken and then concatenated with value in proxy_pass.
Look at the next config. Nginx, after processing /to_app_anything, will forward the request to http://server/any_path/_anything
location /to_app {
    proxy_pass http://server/any_path/;
}
If we put both features together, we will see that we can go to any path one level higher on almost any backend. We just need to send:
GET /to_app../other_path HTTP/1.1
Nginx applies /to_app rule, gets everything(../other_path) after the prefix, concatenates it with a value from proxy_pass, so it forwards http://server/any_path/../other_path to a backend. If the backend normalizes the path, we can reach a completely different endpoint.

Actually, this trick is similar to a well-known alias trick. However, the idea here is to show an example of possible misusing of reverse proxy’s features.

Example 3.
As I mentioned before, it’s a common case when a reverse proxy routes requests to different backends depending on the Host header in a request.

Let’s have a look at Haproxy configuration which says that all requests with example1.com in the Host header must be proxied to a backend example1_backend192.168.78.1:9999.
frontend http-in
acl host_example1 hdr(host) -i example1.com
use_backend example1_backend if host_example1
backend example1_backend
server server1 192.168.78.1:9999 maxconn 32
Does such a configuration mean that an attacker cannot access other virtual hosts of a backend server? It may look like that, but an attacker can easily do it. Because, as mentioned above, Haproxy doesn’t support Absolute URI, but most web-servers do. When Haproxy receives Absolute URI, it forwards this unprocessed Absolute URI to a backend. Therefore, just by sending next request, we can easily access other virtual hosts of the backend server.
GET http://unsafe-value/path/ HTTP/1.1
Host: example1.com
Is it possible to force a reverse proxy to connect to an arbitrary backend server? I’d say that in most cases (Nginx, Haproxy, Varnish), this cannot be done, but Apache (in some configurations/versions) is vulnerable to it. As Apache “parses” a host value from ProxyPass, we can send something like GET @evil.com HTTP/1.1, so Apache sees a value http://backend_server@evil.com and sends the request to `evil.com` (SSRF). Here you can see an example of such vulnerability.

Client-Side attacks

If we have a look at reverse proxy features again, we can see that all response-related have a potential for client-side attacks. It doesn’t make them useless. I’d say otherwise. But client-side attacks have additional limitations to possible inconsistencies between the reverse proxy and the web server, as the browser process a request before sending it.

Browser processing

In a client-side attack, an attacker needs to force a victim’s browser to send a special request, which will influence a response, to a server. But the browser follows the specifications and processes the path before sending it: ^The browser parses the URL (e.g. throws off a fragment part), URL-encodes all the necessary symbols (with some exceptions) and normalizes a path. Therefore, to perform such attacks, we can only use a “valid” request which must fit into the inconsistency between three components (browser, reverse proxy, backend server).

Of course, there are differences in browser implementations, plus some features which still allows us to find such inconsistencies:
  • For example, Chrome and IE don’t decode %2f, so a path like that /path/anything/..%2f../ will not be path normalized.
  • Older versions of Firefox didn’t URL-decode special symbols before normalization, but now it behaves in a similar way to Chrome.
  • There is information that Safari doesn’t URL-decode a path, so we can force it to sent such a path /path/%2e%2e/another_path/.
  • Also, IE, as usual, has some magic: it doesn’t process a path when it’s redirected with Location header. 

Misusing Header modification

A common task for reverse proxy is to add, delete or modify headers from a response of a backend. In some situations, it’s much easier than modification of the backend itself. Sometimes it involves modification of security-important headers. So as attackers, we may want to force a reverse proxy to apply such rules to wrong responses (from wrong backend locations) and then use it for attacks on other users.

Let’s imagine that we have Nginx and Tomcat as a backend. Tomcat, by default, sets header X-Frame-Options: deny, so a browser cannot open it in an iframe. For some reason, a part of the web application (/iframe_safe/) on the Tomcat must be accessible through iframe, so Nginx is configured to delete the her X-Frame-Options for this part. However, there is no potential for clickjacking attacks on iframe_safe. Here is the configuration:
location /iframe_safe/ {
    proxy_pass http://tomcat_server/iframe_safe/;
    proxy_hide_header "X-Frame-Options";
}
location / {
    proxy_pass http://tomcat_server/;
}
However, as attackers, we can make a request which falls under the iframe_safe rule, but it will be interpreted by Tomcat as a completely different location. Here it is:
<iframe src="http://nginx_with_tomcat/iframe_safe/..;/any_other_path">
A browser doesn’t normalize such a path. For Nginx it falls under the iframe_safe rule. Since Tomcat supports path parameters, after path normalization, it will get /any_other_path. Therefore, in such a configuration, any path of Tomcat can be iframed, so an attacker can perform clickjacking attacks on users.

Of course, with a similar approach, other security-related headers (e.g. CORS, CSP, etc) might be misused too.

Caching

Caching is one of the most interesting, with a good potential for various attacks, but is still a little-known feature of reverse proxies. Recently, cache-related attacks have gotten more attention in some awesome researches including Web Cache Deception and Practical Web Cache Poisoning. In my research, I’ve been focusing on caching too: I wanted to analyze various implementations of cache. As a result, I’ve got several ideas on how to improve both cache deception and cache poisoning attacks.

How it works
There are several factors on cache of a reverse proxy which help us with understanding attacks.
The idea of caching is quite simple. In some situations, a reverse proxy stores a response from a backend in the cache and then returns the same response from the cache without accessing the backend. Some reverse proxies support caching by default, some require configuration. Generally, a reverse proxy uses as a key of cache, a concatenation of Host header value with unprocessed path/query from a request.

To decide if it is Ok to cache a response or not, most reverse proxies check Cache-Control and Set-Cookie headers from a response of a backend. Reverse proxies don’t store responses with Set-Cookie at all, but Cache-Control, as it describes a caching policy and requires additional parsing. Format of Cache-control header is quite complex, but basically, it has several flags which allows caching or not, and sets for how long a response can be cached.

Cache-Control header may look like these:
Cache-Control: no-cache, no-store, must-revalidate 
Cache-Control: public, max-age=31536000
The first example forbids caching by a reverse proxy, the second – allows it. The absence of a Cache-Control header usually means that a reverse proxy is allowed to store a response.

Many web servers, application servers and frameworks set Cache-Control headers automatically and correctly. In most cases, if a web app uses session in an script, it will set Cache-Control headers which restricts caching, so usually programmers don’t need to think about it. However, in some situations, for example, if a web application uses its own session mechanism, Cache-Control header can be set incorrectly.

Attacks
A commonly used feature of a reverse proxy cache is “aggressive caching” (it’s not really an official term, but describes the idea). In some cases (for example, a backend can be too strict about caching and doesn’t allow to cache anything) an administrator, instead of changing the backend, changes rules of a reverse proxy, so it starts caching responses even with Cache-Control header which restricts caching. Usually such rules have some limitations. For example, to cache only responses of certain extensions (.jpg, .css, .js), or from specific paths (/images/).

If a reverse proxy has a path-based rule which allows aggressive caching, an attacker can create such a path which falls into the rule but will be interpreted as a completely different path by a backend server.

As an example let’s take Nginx+Tomcat again. Next rule intends to force Nginx to cache all the responses from the /images directory of Tomcat.
location /images {
    proxy_cache my_cache;
    proxy_pass http://tomcat_server;
    proxy_cache_valid 200 302 60m;
    proxy_ignore_headers Cache-Control Expires;
}
As attackers, we can misuse this rule to perform a web cache deception attack. All we need to do is to force a victim user to open the next URL (using img, for example):
<img src="http://nginx_with_tomcat.com/images/..;/index.jsp">
A victim’s browser then sends a request (with authentication cookies). Nginx sees /images, so forwards the request to Tomcat and then caches a response (it doesn’t care about Cache-Control headers). Again, for Tomcat, a path after normalization is completely different – /index.jsp. In this way an attacker can force Nginx to cache any page of Tomcat. To read this cached response, the attacker just needs to access the same path (/images/..;/index.jsp) and Nginx returns the victim’s sensitive data (e.g. csrf token).

In some way, it’s just a variation web cache deception, but not only.

Let’s think about a cache poisoning attack. The attack relies on finding unkeyed values from a request which can significantly (from a security point of view) influence a response, but at the same time, this response must be cached by a reverse proxy, so Cache-Control header must be permissive. If we mix everything together, we will be able to find more ways to exploit cache poisoning attacks.

Let’s imagine the situation. There is Nuster (it’s a cache proxy based on Haproxy) and a web application. The web application has a self-XSS vulnerability (which works only in an attacker’s account) in /account/attacker/. Nuster is configured to cache all the responses from /img/ directory on the web application:
nuster cache on
nuster rule img ttl 1d if { path_beg /img/ }
The attacker just needs to create a special URL (/img/..%2faccount/attacker/), so Nuster applies an “aggressive caching” rule, still, the web app returns a response of self XSS (it sees /account/attacker/). The response with an XSS payload will be cached by Nuster (with the key: Host + /img/..%2faccount/attacker/), so the attacker will be able to misuse this cache to XSS attack other users of the web application.From the self-XSS, we’ve got a usual XSS.

Conclusion

I have showed several examples of vulnerable configurations for each attack type. But exact cases are not so important. I wanted to give a fresh look on reverse proxy related attacks. If we know how a reverse proxy works, how it processes a request and what is the difference compared to a backend server, we (as attackers) will be able to reach more endpoints or perform more sophisticated attacks on users.

Regarding protections against such attacks, I see no “silver bullet” here (until we have a really good standard/specification on how to handle a request/path), but I think this project could help defenders as well. If you know your proxy and its limitations, you will be able to change its configuration accordingly.

Due to my desire to share my thoughts and explain stuff, the article has become very big. Still, I had to skip a bunch of tricks, you could see them in the presentation here. And the most important point of this research – “raw” results. The research is not finished yet. I will fulfill it step by step with other software. Push requests are really appreciated.

While preparing this research, I found several other kinds of similar ones, including – https://github.com/irsdl/httpninja. Through a combination of our projects, it’s possible to almost get a matrix of possible inconsistencies.

понедельник, 1 октября 2018 г.

Better Web-Pentesting in Windows with AHK

(It's a repost from  https://www.acunetix.com/blog/web-security-zone/better-web-pentesting-in-windows-with-ahk/)

Recently, I have moved to Malta. It’s quite hot here, but as I’m from colder country, I like it very much. Actually, I’m obsessed with everything hot, including hotkeys!

Every pentester / researcher / bugbounter / etc has their own approach to doing things in their own work environment. So in this article I’m not looking to give exact solutions, but the aim is to share some ideas (which I found useful), so you can have a fresh look at your approach and push your imagination in this area.

Windows is not a very popular OS for pentesters due to many reasons. Sometimes however we need to use it (at least on a virtual machine). I have been a pentester for 8 years and pentested many “windows-only” applications, I remember that pain, I even got used to it… But, nowadays, everything is not so bad and hacky.

Today I want to discuss AutoHotKey. This is an old tool and, I’m sure, many of you use it for some kind of automations. I suggest to look at it as a tool for pentesters.

Basics

AHK – a small tool which can set global hotkeys and perform a lot of actions in OS. Actually, it has its own scripting language, and, if you have enough knowledge (and patience), you can do whatever you want.
I will not explain the syntax of the scripts (there is better doc about it here), but I’ll give you a bunch of examples.

So, the basic idea of AHK is quite simple: In scripts you set global hotkeys and once you press one of them, AHK will make the necessary action. All you need to do is install AHK, create your scripts and run them.

We all use many programs at once, but we need to use ALT+TAB to switch between them, it could be worse if you use multiple-desktop.
Using next script you can focus on a necessary program (or run it, if it’s closed), even if you are on another desktop, just by pressing Shift+Ctrl+F4 (+ – Shift, ^ – Ctrl)
+^F4::
SetTitleMatchMode 2
IfWinExist Sublime Text
WinActivate, Sublime Text
else
run "C:\Program Files\Sublime Text 3\sublime_text.exe"
return

+^F5::
IfWinExist Google Chrome
WinActivate, Google Chrome
else
run "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe"
return

Rebinding

For researching/pentesting something related to web, you need to have all popular browsers at your hands. But it’s such a pain that they have different or lack of hotkeys.

For example, by clicking a hotkey (Ctrl+Tab) I can cycle through the last used tabs (not just next or previous tabs). It works out of the box for Firefox, but for Chrome you need an extension (CLUT: Cycle Last Used Tabs, for example). However even with the extension, you cannot bind Ctrl+Tab for this operation, because you cannot rebind Chrome’s hotkeys.

With AHK , you can easily achieve this. Firstly, AHK gives us an opportunity to set global hotkeys for specific applications. Secondly, we can “rebind” hotkeys. Here, only for Chrome, when we press Ctrl+Tab, AHK intercepts it and sends Alt+W into Chrome (! – Alt), so our extension shows us a last used tab.
#IfWinActive ahk_exe chrome.exe
^Tab::
Send, !w
return
#IfWinActive

Hotstrings

Also, AHK supports hotstrings. What is it? When we input a specific consequence of symbols anywhere in Windows, AHK replaces it with whatever you want.

Typical example: Wherever I input two symbols “a” and “@“, they will be replaced with my email.
 :*:a@::agrrrdog@gmail.com
Here are some cases which I found useful.

When I pentested Windows-only applications with fat clients, it was annoying to input credentials again and again, especially, if it has “several layers of protection” or if you need to test multiple roles.
Here is a solution. Create a script which you use only during a project (with AHK you can run or stop as many ahk-scripts as you want at any time) with necessary credentials.

:*:!t1::testAccount :*:!p1::VeryLoooooongP4ssword :*:!t2::adminTestAccount :*:!p2::p4ssw0rd


AHK

Now, you can input them fast without using a text-document and clipboard 🙂
We still do a lot of web hacking manually, therefore, we can set hotstrings for most useful things, which we enter again and again.

Here are some self-explaining examples (here I use % just to make string more unique):
::%lh::localhost
::%lhh::http://localhost
:*:%hs::https://
::%d.c::document.cookie
::%d.d::document.domain
::%js::javascript:
:*:%c.l::console.log('');{Left 3}
::%alrt::https://yourserver.com/xss_payload.js
::%man::¯\_(ツ)_/¯
AHK

But we can improve it. For example, we can set our favourite payloads and also add random parts to them, so it will be easier to track input/output down in proxy. Wherever we print %xss1, it will be replaced with “<svg/onload=alert(17384)> you see, lol?
:?*:%xss1::
Random, rand, 1, 99999
SendInput "<svg/onload=alert(%rand%)>
return
Or with our DNS/HTTP connection-checker:
::%xgl::
Random, rand, 1, 99999
SendInput http://x%rand%.yourserver.here/poc
return
web pentesting

Encode-everywhere

When pentesting or researching something, we often work with strings and their encoding, modifications. We have some tools which help us (like HackBar addon for browsers) or use online resources. What if we can make it (semi-)global? For example, we select a string in any application, press a hotkey and get its base64-(de/en)coded version? Or md5-hash of it? Or any other mutation?

To be honest, the AHK’s scripting language doesn’t look friendly to me, so the idea is to use “normal” language, such as python. I found several projects which try to join AHK and Python, but it looks like all of them are forgotten.

So, we use “a universal” way of calling a program from AHK and getting results from it:
!F10::
SendInput {Ctrl down}c{Ctrl up}
RunWait %ComSpec% /c ""python" "converter.py" "urldec" "%Clipboard%" > "%A_Temp%\tmp1.txt"",,HIDE
FileRead result, %A_Temp%\tmp1.txt
sleep, 100
Clipboard := result
SendInput {Ctrl down}v{Ctrl up}
return
Yep, it looks awful: We run new cmd (not just python) to be able to hide the “black window”, we get selected text using clipboard and get results from a file(1). However, it works pretty well and fast. So we select and copy text, press ALT+F10 and the script base64-decodes the text and replaces the selected one.

But if you set a lot of global-hotkeys, it could be hard to remember them and to use fast. So we can create a menu with internal hotkeys. As our selection may contain special symbols or to be multiline, it’s better to pass it using an additional file. Also, we can put all similar things into one function.
RunProgram(command)
{
SendInput {Ctrl down}c{Ctrl up}
;sleep, 200 ; it added some stability for one of my laptops
FileAppend, %Clipboard%, %A_Temp%\tmp_in.txt
RunWait %ComSpec% /c ""python" "C:\path_to_script\kostyli.py" "%command%" ",,HIDE
FileRead, Clipboard, %A_Temp%\tmp_out.txt
;sleep, 100 ; it added some stability for one of my laptops
SendInput {Ctrl down}v{Ctrl up}
FileDelete, %A_Temp%\tmp_in.txt
FileDelete, %A_Temp%\tmp_out.txt
}

Menu, EncoderMenu, Add, &Base64 Encode, B64EncHandler
Menu, EncoderMenu, Add, B&ase64 Decode, B64DecHandler
Menu, EncoderMenu, Add, &URL Encode, UrlEncHandler
Menu, EncoderMenu, Add, U&rl Decode, UrlDecHandler
return

B64EncHandler:
RunProgram("b64enc")
return

#c::Menu, EncoderMenu, Show
Here we define a menu and set various handlers for it. The approach is the same: select text, press `Win+C` and press a button of appropriate encoder/decoder (marked by &).


Some tips

  • Be careful with global hotkeys (which you set not only for one/group application), because you can “override” some useful hotkeys of app.
  • Hotstrings don’t work so well in smart text-editors (like Sublime or VS Code), because AHK just send keys instead of you, so autocompletion and similar features of a text editor come into play.
  • Be careful when you use SendInput if you have several keyboard layouts in OS.
  • AHK is quite a reliable tool, but sometimes it doesn’t work so fast and it’s hard to debug. So, keep things simple.
  • You can set a hotkey to reload the script which is very useful during development (!^+R::Reload).
  • AHK allows you to find the elements of a window and makes actions with them (click, input text). So you can set hotkeys even if an application doesn’t have them. Java Swing application is not supported by default, but by using Java Access Bridge and this library (https://github.com/Elgin1/Java-Access-Bridge-for-AHK) we can archive it. 

Conclusion

In the beginning of the article I wrote about “hacky-way”… ok. AHK is a totally hacky solution, but it works!

What about other similar tools? Similar tools of course exist and exist in other OS. They have some additional features or limits. For example, python package keyboard or pyautogui which work for Linux and Windows.

You may have a look at some final examples of AHK at my repository.

четверг, 19 июля 2018 г.

Deserialization Vulnerabilities: Attacking Deserialization in JS

(It's a repost from https://www.acunetix.com/blog/web-security-zone/deserialization-vulnerabilities-attacking-deserialization-in-js/)

At ZeroNights 2017 conference, I spoke about “Deserialization vulnerabilities in various languages”. For my presentation, I used an interesting article about two serialization packages of Node.js. I showed them as examples of vulnerable implementations of deserialization processes. In this post, I’d like to show results of my own research and a new approach of attacking deserialization in JS.

Previous research

The article mentioned above talks about two packages – node-serialize and serialize-to-js. Both of them can serialize an object in JSON format, but unlike standard functions (JSON.parse, JSON.stringify), they allow the serialization of almost any kind of object, such as Function, for example (i.e in JavaScript, a function is an object too). So, it’s a valid object:
var obj = {
    field1: "value1",
    field2: function(){
        return 1;
        }
}
But if we serialize it using JSON.stringify, we have only:
{ field1: "value1" }
To implement support of all kinds of objects, node-serialize, internally uses eval.
{"anything_here":"_$$ND_FUNC$$_function (){сonsole.log(1)}"}
This is what a serialized object with a function should look like. During the deserialization process, anything after a special tag $$ND_FUNC$$ goes directly to eval function. Therefore, we can use IIFE (as mentioned in the article) or write code directly (as mentioned in the article‘s comment).

With IIFE (Immediately-Invoked Function Expression), all we need to do is add () to a function and it will be automatically invoked just after it will be defined during deserialization.
{"anything_here":"_$$ND_FUNC$$_function (){сonsole.log(1)}()"}
{"anything_here":"_$$ND_FUNC$$_console.log(1)"}
The next example is serialize-to-js. Although it doesn’t support function as a type, its implementation is still insecure due to the fact that it uses next construction during the deserialization process:
return (new Function('"use strict"; return ' + str))()
where str is a value under the attacker’s control.
Practically, it’s just a variation of eval. So we can achieve RCE using the following payload as seen in the following issue:
console.log(`exploited`)
(function (){сonsole.log(1)}())

The safer way?

After my presentation at ZeroNights, I came across a package for serialization from Yahoo. It supports serialization of functions too. However, the package doesn’t include any deserialization functionality and requires you to implement it yourself. Their example uses eval directly. So I was interested to see if there were any packages supporting function serialization and did not use eval or similar functions.

Actually, there are a lot of serialization libraries (about 40 or 60). I looked through some of them and found that a safer way of deserialization is to use different constructors depending on an object type.

For example, a package returns new Function(params, body) for a function, where params and body are taken from specific JSON fields. In this case, the function is reconstructed, however an attacker cannot force its execution.

I’ve also found another vulnerable package funcster. It is vulnerable to the same attack using IIFE as previous ones, so we (as attackers) can execute our code during the deserialization process. Here is an example of a payload:
{ __js_function: 'function testa(){var pr = this.constructor.constructor("return process")(); pr.stdout.write("param-pam-pam") }()' }
The package uses another approach for serialization/deserialization. During deserialization it creates a new module with exported functions from a JSON file. Here is part of the code:
return "module.exports=(function(module,exports){return{" + entries + "};})();";
The interesting difference here is that the standard built-in objects are not accessable, because they are out of scope. It means that we can execute our code, but cannot call build-in objects’ methods. So if we use console.log() or require(something), Node returns an exception like "ReferenceError: console is not defined".

However, we can easily can get back access to everything because we still have access to the global context:
var pr = this.constructor.constructor("console.log(1111)")();
Here this.constructor.constructor gives us Function object, we set our code as a parameter there and call it using IIFE.

Step deeper with Prototype

While I was researching packages, I stumbled upon the idea to look at other approaches of attacks on deserialization, which are used in other languages. To achieve code execution we leverage functions with attacker’s controlled data which are called automatically during the deserialization process or after when an application interacts with a newly created object. Something similar to “magic methods” in other languages.

Actually, there are a lot of packages which work completely differently, still after some experiments I came to an interesting semi-universal attack. It is based on two facts.

Firstly, many packages use the next approach in the deserialization process. They create an empty object and then set its properties using square brackets notations:
obj[key]=value
where key and value are taken from JSON

Therefore we as attackers are able to control practically any property of a new object. If we look through the list of properties, our attention comes to the cool __proto__ property . The property is used to access and change a prototype of an object. This means that we can change the object’s behavior and add/change its methods.

Secondly, a call of some function leads to the invoking of the function arguments’ methods. For example, when an object is converted to a string, then methods valueOf, toString of the object are called automatically (more details here). So, console.log(obj) leads to invocation of obj.toString(). Another example, JSON.stringify(obj) internally invokes obj.toJSON().

Using both of these features, we can get remote code execution in process of interaction between an application (node.js) and an object.

I’ve found a nice example – package Cryo, which supports both function serialization and square bracket notation for object reconstruction, but which isn’t vulnerable to IIFE, because it properly manages object (without using eval&co).

Here a code for serialization and deserialization of an object:
var Cryo = require('cryo');
var obj = {
     testFunc : function() {return 1111;}
};

var frozen = Cryo.stringify(obj);
console.log(frozen)

var hydrated = Cryo.parse(frozen);
console.log(hydrated);
Serialized JSON looks like that. Pretty tangled:
{"root":"_CRYO_REF_1","references":[{"contents":{},"value":"_CRYO_FUNCTION_function () {return 1111;}"},{"contents":{"testFunc":"_CRYO_REF_0"},"value":"_CRYO_OBJECT_"}]}
For our attack we can create a serialized JSON object with a custom __proto__. We can create our object with our own methods for the object’s prototype, but as a small trick, we can set an incorrect name for __proto__ (because we don’t want to rewrite a prototype of the object in our application) and serialize it.
var obj = {
    __proto: {
        toString: function() {console.log("defconrussia"); return 1111;},
        valueOf: function() {console.log("defconrussia"); return 2222;}
    }
};
So we get serialized object and rename from __proto to __proto__ in it:
{"root":"CRYO_REF_3","references":[{"contents":{},"value":"_CRYO_FUNCTION_function () {console.log(\"defconrussia\"); return 1111;}"},{"contents":{},"value":"_CRYO_FUNCTION_function () {return 2222;}"},{"contents":{"toString":"_CRYO_REF_0","valueOf":"_CRYO_REF_1"},"value":"_CRYO_OBJECT"},{"contents":{"proto":"CRYO_REF_2"},"value":"_CRYO_OBJECT"}]}
When we send that JSON payload to an application, the package Cryo deserializes the payload in an object, but also changes the object’s prototype to our value. Therefore, if the application interacts with the object somehow, converts it to a sting, for example, then the prototype’s method will be called and our code will be executed. So, it’s RCE.

I tried to find packages with similar issues, but most of them didn’t support serialization of function. I didn’t find any other way to reconstruct functions in __proto__. Nevertheless, as many packages use square bracket notation, we can rewrite __proto__ for them too and spoil prototypes of newly created objects. What happens when an application calls any prototype method of such objects? It may crash due to an unhandled TypeError exception.

In addition, I should mention that the whole idea potentially works for deserialization from any format (not only JSON). Once both features are in place, a package is potentially vulnerable. Another thing is that JSON.parse is not “vulnerable” to __proto__ rewriting.

function stringify == eval

While Googling, I came across another approach of serializing objects with fuctions. The idea is to first stringify functions, then to JSON.stringify the whole object. “Deserialization” consists of the same steps in reverse order. Examples of such function-stringifiers are packages cardigan, nor-function and so on. All(?) of them are insecure (due to eval & co) and allow code execution using IIFE during unstringifying.

Conclusion

For pentesters: Look closely at square bracket notation and access to __proto__. It has good potential in some cases.

For developers: I’m writing here that some packages are vulnerable, but your application is only vulnerable when a user’s input comes to the vulnerable function. Some packages are created in such an “insecure” way ion purpose and will not be fixed. So don’t panic, and just check if you depend on a non-standard serialization package and how you handle user’s input in it.

I shared information about both vulnerabilities with their maintainers using HackerOne’s program. A warning message has been added to `funcster` package’s README. We were not able to reach cryo’s developers.

PS: Thanks @lirantal from HackerOne for his cooperation on the above mentioned vulnerabilities.

пятница, 12 января 2018 г.

Java Deserialization: Misusing OJDBC for SSRF


This year ZeroNights has got a new zone - Web Village. It was a special "track" for people who were interested in web security. The basic idea of the Web Village is to tell people about typical vulnerabilities and attack techniques. I made a speech about basics of deserialization vulns in various languages. I wanted to show common patterns which make serialization libs potentially vulnerable. There is that presentation.

In the presentation I showed an example of a new Java gadget in order to prove that it's stupid to "fix" gadgets or "blacklist" them instead of protecting/changing deserialization lib. Here I’d like to show some details of the example.

The gadget is a class in a library which is used to connect a Java application to a RDBMS Oracle - ojdbc. Actually, this exact class (OraclePooledConnection) is responsible for establishing a connection.
The example is very simple, because the class has a readObject method which goal is to reestablish connection to a database during a deserialization process.
In the bottom of the post you can read the code, but it's not necessary, because we are going to use it in the same way as it's supposed to be used.

As we control a field (connection_url) with a string where a java application tries to connect during deserialization process, it means that we have a SSRF vulnerability here.
At first glance, it looks pretty useless, because the Oracle's protocol is binary. But I played with Oracle DB some years ago and know that the client (and TNS protocol) is very flexible.
The "URL" consists of several fields:

jdbc:oracle:thin:login/password@//any.domain.name.here.com:8888/service_name

I think almost all of them are self-describing.
An important feature for us is that the "service name" field can contain a very long value and almost any ASCII symbols. So, potentially we can interact with text-based services. Yes, there will be binary garbage before the service name and after, but many servers don't care much about such things ("errors friendly").

So step-by-step, we create a serialized object with a specific payload as service name, send it to an application. The application runs readObject of "OraclePooledConnection" class and it forces the application to connect to wherever we want and to send our payload.

So, my point is pretty clear, the class doesn't really have any vulns, but we still can misuse its features for our attacks.


PS: The same "SSRF-attack" you can perform if you have access to Oracle DB with privs that allow you to create DB links.

P.P.S: Potentially, the attack can be improved somehow... As we control the "url" for connection, may be we can steal NetNTLM credentials (because oracle auth supports it) or perform TNS Poisoning attack?

 Code of readObject method of OraclePooledConnection class

пятница, 24 марта 2017 г.

Autobinding vulns and Spring MVC




Intro

If you don’t want to read all this text, you can watch video from the 29thmeeting of Defcon Russia Group (in Russian)

There is a not so well-known vulnerability type - "autobinding", or "mass assignment". The idea this type is based on a feature that is implemented in many frameworks. It allows a framework to automatically bind HTTP request parameters to objects and make them accessible to a developer. However, an attacker can add additional HTTP request params and they will possibly be bounded to an object. Depending on a victim software and its logic, the attacker can achieve some interesting results.

The autobinding feature is pretty widespread for frameworks, which makes attack surface rather wide. However, usually it's hard to find them without knowing source code and impact of a vuln strongly depends on an application.

You can read about this type of vulns on OWASP
There are also some simple examples, so if you are not familiar with it, I recommend that you look at it.

A "real" example of such vulnerability and some additional information for Spring MVC framework was published by Ryan Berg and Dinis Cruz in 2011 -  https://o2platform.files.wordpress.com/2011/07/ounce_springframework_vulnerabilities.pdf
  

Something new


It's passed much time since that publication and Spring MVC now is not like it was before. It's much much cooler :)
When I was preparing tasks for the last ZeroNigths HackQuest, I wanted to provide one with an autobinding vuln to make people more familiar with this type of vulns. During the creation of the task, I've spotted an unknown/hidden variation of the autobinding vuln and I'd like to tell you about it.

As I wrote before, Spring MVC has changed. It's much smarter and has more features now. One of the new things is using annotations for doing "magic" things.
Because of them and some misunderstanding in minds, we can find an autobinding vuln in unexpected places.
Let's look at some of them and their official description (taken from here http://docs.spring.io/spring/docs/3.1.x/spring-framework-reference/html/mvc.html)


1) @ModelAttribute on a method argument
"An @ModelAttribute on a method argument indicates the argument should be retrieved from the model..."

2) @ModelAttribute on a method
"An @ModelAttribute on a method indicates the purpose of that method is to add one or more model attributes. @ModelAttribute methods in a controller are invoked before @RequestMapping methods"

3) @SessionAttribute for controller
"The type-level @SessionAttributes annotation declares session attributes used by a specific handler. This will typically list the names of model attributes or types of model attributes which should be transparently stored in the session"

4) FlashAttribute
"Flash attributes provide a way for one request to store attributes intended for use in another."

If you are not familiar with them or don't know spring at all, don't panic, because it will be clearer with further examples :)

What do the examples 2-4 have in common? They are all somehow related to  "passing" data between methods.
One of the ways to get data that was passed to the method is to use @ModelAttribute on a method argument (look at 1). However, it could lead to autobinding vuln. Why? Because @ModelAttribute is pretty “smart”. Let's look at a full description of it.

"An @ModelAttribute on a method argument indicates the argument should be retrieved from the model. If not present in the model, the argument should be instantiated first and then added to the model. Once present in the model, the argument's fields should be populated from all request parameters that have matching names."

So, first, @ModelAttribute retrieves an object from the model (or somewhere else) and then it populates the object with a user request. Therefore, a coder expects trusted data (the object) from the model, but an attacker can change it by just sending a specially crafted request.
I've made 2 tasks for ZN HQ, and both of them contain variations of autobinding vulns. Let's have a look  at what's going on there.

Sources of the tasks - https://github.com/GrrrDog/ZeroNights-HackQuest-2016

The First School of Bulimia “Edik”


The application consists of 3 "pages": registration, authentication, home page. The goal is to perform an expression language injection in the home page. The obstacle is that a user can set values only during registration process...
There is a class of User and it has 3 fields (name, password, weight) in the application.
The registration controller looks like that:



As we can see, the controller gets User object from a user request, validates it, and if the object is validated, the controller puts it in "DB".


The validating process is very strict. Because of whitelisting, we can use only figures or symbols, but we need to put special symbols in the user object! How? There is no way for the registration controller.


So, what can we do as attackers? Let's take a look at the authentication and home controller.
Authentication and home controller:

Authentication method does pretty simple things:
1) gets a username and password from a request;
2) gets a user object from the db using the username and password;
3) puts the user object in FlashAttribute and redirects to home method (sends redirect response to "/home");
So, there is no way to change the user object too.




 What about the home method?
It just gets the user object from the flash attribute and shows it to us.
@modelAttribute is used in this case to get the user object, but it also can populate the user object with incoming request params! So, we can change values in the user object!
All we need to do is to authenticate (send a request to the authenticate method) and add an additional HTTP param during redirection.
So, our request will look like:

/home?name=${We_Can_Write_Here_wharever_we_want} 

The goal is achieved.

Populating

There is an interesting and maybe not so obvious fact about autobinding. During populating data, Spring MVC makes changes on a field basis; it doesn't create a new object if something comes from an HTTP request. It means if there is an object from the model and only one param is received from an HTTP request, the value of only one field (with the same name as the HTTP param) will be changed and other fields will stay the same.


Justice League

Another task. Actually, solution for this task doesn't involve using an autobinding vuln, but there is one.
The application consists of registration, authentication, home, and password recovering "pages". The latter is only one that is important for us.
Actually, recovering page is just one controller with several methods and it represents a way of creating "wizards" (multi-step forms).
Our goal for this task is to bypass authentication.

Overall logic is the following.
1) A user comes to a recovery page, inputs its username and send a request to submit the form
2) the resetHandler method receives the HTTP request. It gets a user object from the db using the username from the request. Then it puts the user object in the Model, and it automatically puts the object into a session (@SessionAttribute("user") for the controller). Then it redirects to next part of "wizard".
 

3) The user is redirected to the resetViewQuestionHandler method. Actually, the method takes the user object from the session (yeah-yeah, using @ModelAttribute). It requires that object because the method has to get a custom user security question and show it in a view (however, that hasn't been implemented :)




4) When the user sends an answer for the question, the resetQuestionHandler method handles it. The method gets the answer from "answerReset" param and compares with the value in answer field from the user object. If answers match, the method generates a new secure password and shows it to the user.
As you can see, there is no @ModelAttribute near User user (in the method argument). However, Spring MVC is smart and automatically gets value from the session. Actually, it uses the same logic: gets value from somewhere, populates it with a user request.

So, what we can do as attackers?
a) We can add "answer=any_value", when we send a request to resetViewQuestionHandler. Then our answer is populated with an object from a session. So, we can change a correct answer to any value and after that set the same value for the resetQuestionHandler method.
Therefore, we can start the recovery process for admin user, bypass answer checking, and get a new password for admin.
b) We can add "answer=any_value" on the last step too (resetQuestionHandler) and get the same results. Actually, we can change a whole object if we would like.



Session Puzzling

There is another interesting thing. When a method gets an object from a session and populates it with a user request, @SessionAttribute "forces" Spring to store this newly populated object in the session. Therefore, we are able to control values of the object that are stored in the session. How can we use it?
If there is another controller that uses the same name of session attribute and trusts it, then we can perform a Session Puzzling attack (Session Variable Overloading). https://www.owasp.org/index.php/Testing_for_Session_puzzling_(OTG-SESS-008) . As far as I remember, the documentation says that a session attribute (created using @SessionAttribute) is limited to a controller, but in practice, we can use it in other controllers too.


Real Examples

I was looking for real examples of such issues on GitHub and in articles about Spring MVC and even found some. But:
1) examples identified on GitHub look like someone’s experiments with Spring MVC (not like real stuff)
2) there are some articles that recommend "dangerous" using of @ModelAttribute, but their examples are too simple and there is no potential impact.

Detection

At first glance, finding autobinding vulns using the "blackbox" approach looks impossible. Nevertheless, both of tasks were solved, both autobinding vulns were found. Respect to these people :)

There are some things that can help us to find such type of vulns:
1) often, a param name is equal to the name of a field of an object (but not necessary, because it's configurable). As the fields are often named in specific way, we can distinguish them. Of note, autobinding can be used with hashmaps and arrays.
2) When autobinding in a controller's method is used and when we send two parameters with the same name, the value in the object will be a concatenation of parameters.
Example:
Request with params:
?name=text1&name=text2
Result:
ObjectWithNameField.name = text1,text2
3) As soon as we've collected all param names, we can send them to all entry points (URLs), even to those that, at first glance, don't accept params (like resetViewQuestionHandler), and check if replies are different or the same as without params.


Conclusion

I've not shown an example related to incorrect using of "@ModelAttribute on a method", but something similar could happen in this case too.
As you can see, the main idea,  is based on the fact that a programmer thinks that he or she gets an object from a trusted place, but in practice, the object can be modified by an attacker.

I'm not sure, that I’ve correctly described causes of such a vuln, why and how Spring MVC behaves in this way.

It's hard to say exactly how common this variation of autobinding vuln is (but it definitely can be somewhere ;) . In general, autobinding vulns are pretty widespread, because of the feature they are based on. Moreover, the autobinding is not just about HTTP params, theoretically, any incoming data (e.g. JSON or XML) can be converted and then populated. However, a possibility of exploitation and impact strongly depend on many things ranging from using annotations and names of attributes to business logic of an application. 

Sources of the tasks - https://github.com/GrrrDog/ZeroNights-HackQuest-2016