Apache vs httpd

Before starting, let’s clarify if Apache and httpd are different web servers. They are the same application, just that some Linux distributions refer to it differently within package managers and config files. RedHat-based distros (CentOS, Fedora) refer to it as httpd while Debian-based distros (Ubuntu) refer to it as apache. Gentoo, strangely enough, mostly refers to it as apache but config files have httpd in the naming conventions.

Content Negotiation

Apache HTTPD supports content negotiation as described in the HTTP/1.1 specification. It can choose the best representation of a resource based on the browser-supplied preferences for media type, languages, character set and encoding. It also implements a couple of features to give more intelligent handling of requests from browsers that send incomplete negotiation information.

Content negotiation is provided by the mod_negotiation module, which is compiled in by default.

A resource may be available in several different representations. For example, it might be available in different languages or different media types, or a combination. One way of selecting the most appropriate choice is to give the user an index page, and let them select. However it is often possible for the server to choose automatically. This works because browsers can send, as part of each request, information about what representations they prefer. For example, a browser could indicate that it would like to see information in French, if possible, else English will do. Browsers indicate their preferences by headers in the request. To request only French representations, the browser would send

Accept-Language: fr

Note that this preference will only be applied when there is a choice of representations and they vary by language.

As an example of a more complex request, this browser has been configured to accept French and English, but prefer French, and to accept various media types, preferring HTML over plain text or other text types, and preferring GIF or JPEG over other media types, but also allowing any other media type as a last resort:

1
2
Accept-Language: fr; q=1.0, en; q=0.5
Accept: text/html; q=1.0, text/*; q=0.8, image/gif; q=0.6, image/jpeg; q=0.6, image/*; q=0.5, */*; q=0.1

httpd supports ‘server driven’ content negotiation, as defined in the HTTP/1.1 specification. It fully supports the Accept, Accept-Language, Accept-Charset and Accept-Encoding request headers. httpd also supports ‘transparent’ content negotiation, which is an experimental negotiation protocol defined in RFC 2295 and RFC 2296. It does not offer support for ‘feature negotiation’ as defined in these RFCs.

Negotiation in httpd

In order to negotiate a resource, the server needs to be given information about each of the variants. This is done in one of two ways:

  • Using a type map (i.e., a *.var file) which names the files containing the variants explicitly, or
  • Using a ‘MultiViews’ search, where the server does an implicit filename pattern match and chooses from among the results.

We will focus on the first way.

A type map is a document which is associated with the handler named type-map (or, for backwards-compatibility with older httpd configurations, the MIME-type application/x-type-map). Note that to use this feature, you must have a handler set in the configuration that defines a file suffix as type-map; this is best done with

AddHandler type-map .var

in the server configuration file.

At this time you can be confused, just keep reading and everything will be clear.

XSS in .var file

Let’s create a simple Dockerfile to start an httpd container.

1
2
FROM httpd:alpine
COPY ./htdocs/ /usr/local/apache2/htdocs/

and copy xss.var file inside htdocs folder.

1
2
3
4
5
6
7
8
9
Content-language: en
Content-type: text/html
Body:----foo----

<script>
alert(1)
</script>

----foo----

Now we can start the container and check if the XSS is triggered.

1
2
docker build -t apache-xss .
docker run -dit --name apache-xss --rm -p 8081:80 apache-xss

Navigating to /xss.var nothing happened, the file is rendered as text. Ok, trust me, I am not lying, just keep reading.

Let’s first understand why this doesn’t work, this is the httpd.conf file line which prevents the XSS:

1
#AddHandler type-map var

So, in httpd, the var handler directive is commented and so disabled by default but this is not true for apache2 package in Debian-based distributions, let’s create another container.

1
2
3
4
FROM debian:buster
RUN apt update && apt install -y apache2
COPY ./htdocs/ /var/www/html/
CMD apachectl -D FOREGROUND

Start it again as we did before.

1
2
docker build -t apache-xss .
docker run -dit --name apache-xss --rm -p 8081:80 apache-xss

What happens if I navigate again to /xss.var? A picture is worth more than a thousand words.

If we check mods-available/mime.conf file, we can discover that the var handler is enabled by default:

1
2
3
4
5
# For type maps (negotiated resources):
# (This is enabled by default to allow the Apache "It Worked" page
# to be distributed in multiple languages.)
#
AddHandler type-map var

Conclusion

Remember to use whitelist if you accept file upload in your website, in other cases disable the type-map var handler or you can be vulnerable to stored XSS.