Apache mod_python for red teams

Nettitude’s red team engagements are typically designed to be as highly targeted and as stealthy as possible. For the command and control (C2) infrastructure, this means layering several techniques.

  • We hide all of our C2 infrastructure behind a number of Apache web servers
  • Any traffic to the C2 is checked against an IP whitelist
  • IP addresses that do not match the whitelist are directed to a legitimate site
  • IP addresses matching the white list are filtered, any traffic that does not match our C2 traffic will be directed to the legitimate site
  • Any traffic that does not match those rules is directed to the C2 infrastructure

We have previously used Apache rewrite rules (mod_rewrite) to accomplish all of this, and it works very well to accomplish this goal. However, if you need to do anything more advanced than regular expression matching, rewrite rules are not applicable.

I’ve recently been looking into adding malleable-comms to our private, in-house red team implant, that is; comms which can be changed to look like something else such as Zeus Bot traffic, in a similar way to Cobalt Strike. While doing this, I was playing around with mod_python and it occurred to me that we could replace our mod_rewrite rules with mod_python in order to make them more manageable. This post will give an overview of how that can be achieved.

Some knowledge of Apache and Python is assumed here; you must be able to set up a basic virtual host and understand how to write Python scripts.

Enable Apache Python module

The Python module needs to be enabled on the server, on an Ubuntu installation. The following two commands, executed as root, will achieve this:

Example virtual host setup

For this example there are three virtual hosts; one internet facing which will run the Python code and redirect users to the correct location, a legitimate site and a C2 site. This example should be configured to match your own C2 setup.

Legitimate site

A legitimate looking site that non-whitelisted users will be directed to, running on port 8000.

A test index.html page can be added to the legitimate site directory, for testing purposes

Command and control

For illustration purposes only, here’s a command and control site, running on port 9000. In real life, you would redirect traffic to your real C2 infrastructure.

A test index.html containing the following can be added:

Internet facing virtual host

Finally, an internet facing host, which is bound to port 80. In real life you would want to also run this on port 443 with a valid SSL certificate appropriate to the engagement.

In order to be able to redirect users, we have hooked the PostReadRequestHandler using the PythonPostReadRequestHandler directive. All requests will be directed through this script and can then be redirected appropriately.

Python debug is also turned on using the PythonDebug directive, to allow us to easily see any errors in our scripts.

The handler script

For the handler, it is possible to write a Python class. The first class defined in the file will be instantiated. A class is overkill for this example, so instead a single function will suffice, which should be called postreadrequesthandler.

In this example, we will redirect curl clients to the C2 server and anyone else to the legitimate site. Log entries will be placed into the Apache error.log file.

The documentation for mod_python is quite sparse, so in order to work out how to perform a redirect correctly, I had to refer to both the mod_proxy and mod_rewrite source code. After some experimentation I found the correct method:

Once all of this is in place, after restarting the apache2 service you should get the following output from curl:

$ curl localhost:80

Changing the curl user agent will send you to the legitimate site:

$ curl localhost:80 --user-agent "hello"

Log Output

The Apache error log should show some useful output, thanks to mod_python.

Further Reading

Full documentation is available for mod_python here: