/******************************************************************************* * * booby.c * * AUTHOR: * Dan Harkless * * COPYRIGHT: * This file is Copyright (C) 1999 by Dan Harkless, and is released under the * GNU General Public License . * * DESCRIPTION: * A little boobytrap. If you find an evil binary on your system, like some * kind of cracker tool, and rather than deleting it you want to be notified * next time someone uses it, you can move it to some odd location and replace * it with an executable compiled from this file. The wrapper will do a little * snooping and then run the real executable as if nothing's amiss. * * Note that before compiling this file, you must define Email_Recipient and * Real_Executable_Loc at the top of main(). Note they are not string * constants, but rather dynamically-initialized automatic arrays. Each * character is offset so that your unfriendly user can't run strings(1) on * this executable and be able to easily figure out what's going on. The * strings are unoffset at runtime with the u() function. * * DATE MODIFICATION * ========== ================================================================== * 1999-11-05 Original. * *******************************************************************************/ #include /* needs to precede */ #include /* for printf(), etc. */ #include /* for strrchr() */ #include /* for umask(), etc. */ #include /* for waitpid() */ #include /* for execv(), etc. */ #define BUF_SIZE 512 /* don't shrink this w/o looking at sprintf() call */ #define CHAR_OFFSET -95 /* make printable ASCII range unprintable */ #define NUL '\0' #define O(c) ((c) + CHAR_OFFSET) /* offset c to hide from strings(1) */ /* _U_noffset the passed-in string. The function has a one-character name so as to make it much more difficult to glean what's going on with strings(1). */ static char* u(char* s) { char* rover = s; while (*rover != NUL) { *rover -= CHAR_OFFSET; rover++; } return s; } /* _s_ystem() equivalent. The function has a one-character name so as to make it much more difficult to glean what's going on with strings(1). */ static void s(char* path, char* arg1) { char Fork_Paren_Paren[] = {O('f'), O('o'), O('r'), O('k'), O('('), O(')'), NUL}; char Printf_Format[] = {O('%'), O('%'), O(' '), O('%'), O('s'), O(' '), O('%'), O('s'), O('\n'), NUL}; int child_pid, packed_exit_status; child_pid = fork(); if (child_pid < 0) /* fork() failed. */ perror(u(Fork_Paren_Paren)); else if (child_pid == 0) { /* We are the child. */ char* arg0; char* last_slash_in_path = strrchr(path, '/'); if (last_slash_in_path == NULL) arg0 = path; else arg0 = last_slash_in_path + 1; if (arg1 == NULL) printf(u(Printf_Format), arg0, ""); else printf(u(Printf_Format), arg0, arg1); fflush(stdout); execl(path, path, arg1, (char*)0); _exit(0); /* will only be reached if the execl() fails */ } else { /* We are the parent. Reap the child. */ waitpid(child_pid, &packed_exit_status, 0); write(STDOUT_FILENO, "\n", 1); } } int main(int argc, char** argv) { /* YOU MUST DEFINE THE FOLLOWING TWO VALUES: */ char Email_Recipient[] = {O('n'), O('o'), O('b'), O('o'), O('d'), O('y'), O('@'), O('l'), O('o'), O('c'), O('a'), O('l'), O('h'), O('o'), O('s'), O('t'), NUL}; char Real_Executable_Loc[] = {O('/'), O('b'), O('i'), O('n'), O('/'), O('e'), O('c'), O('h'), O('o'), NUL}; /* You'll need to adjust these paths if they're incorrect on your system: */ char Sendmail_Path[] = {O('/'), O('u'), O('s'), O('r'), O('/'), O('l'), O('i'), O('b'), O('/'), O('s'), O('e'), O('n'), O('d'), O('m'), O('a'), O('i'), O('l'), NUL}; char Ps_Path[] = {O('/'), O('u'), O('s'), O('r'), O('/'), O('b'), O('i'), O('n'), O('/'), O('p'), O('s'), NUL}; char Tty_Path[] = {O('/'), O('u'), O('s'), O('r'), O('/'), O('b'), O('i'), O('n'), O('/'), O('t'), O('t'), O('y'), NUL}; char W_Path[] = {O('/'), O('u'), O('s'), O('r'), O('/'), O('b'), O('i'), O('n'), O('/'), O('w'), NUL}; /* You'll need to change this to "gaxuw" if you have a Berkeley-style ps. */ char Dash_Ef[] = {O('-'), O('e'), O('f'), NUL}; char Sprintf_Format[] = {O('%'), O('s'), O(' '), O('%'), O('s'), NUL}; FILE* temp_FILE; int stderr_backup_fileno = dup(STDERR_FILENO); int stdout_backup_fileno = dup(STDOUT_FILENO); int temp_fileno; /* For that split-second that the temp file has a directory entry, make sure only we can do anything with it. */ umask(S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH); /* 077 */ temp_FILE = tmpfile(); temp_fileno = fileno(temp_FILE); if (dup2(temp_fileno, STDERR_FILENO) > 0 && dup2(temp_fileno, STDOUT_FILENO) > 0) { /* We successfully redirected stderr & stdout to the temp file. Do some snooping. */ char buf[BUF_SIZE]; FILE* sendmail_pipe_FILE; int read_chars; int sendmail_pipe_fileno; s(u(Tty_Path), NULL); s(u(W_Path), NULL); s(u(Ps_Path), u(Dash_Ef)); /* The buffer is no doubt big enough that we won't overflow here. */ sprintf(buf, u(Sprintf_Format), u(Sendmail_Path), u(Email_Recipient)); fflush(stdout); sendmail_pipe_FILE = popen(buf, "w"); sendmail_pipe_fileno = fileno(sendmail_pipe_FILE); /* Send everything we wrote to the temp file down the pipe. */ rewind(temp_FILE); while ((read_chars = read(temp_fileno, buf, BUF_SIZE)) > 0) write(sendmail_pipe_fileno, buf, read_chars); /* Restore stderr and stdout and close the extra file descriptors. */ dup2(stderr_backup_fileno, STDERR_FILENO); dup2(stdout_backup_fileno, STDOUT_FILENO); close(stderr_backup_fileno); close(stdout_backup_fileno); } /* Execute the program we're wrapping. */ execv(u(Real_Executable_Loc), argv); return 1; /* will only be reached if the execv() fails */ }