diff --git a/.gitmodules b/.gitmodules index 8a6dc53..c9617c8 100644 --- a/.gitmodules +++ b/.gitmodules @@ -9,3 +9,6 @@ [submodule "armbian"] path = armbian url = https://github.com/armbian/build +[submodule "package/bhtui/third-party/TermOx"] + path = package/bhtui/third-party/TermOx + url = https://github.com/a-n-t-h-o-n-y/TermOx diff --git a/README.md b/README.md index 30e0f51..ee3b04a 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,11 @@ # Flipper Blackhat OS -A WiFi security testing OS built on Linux for penetration testing and network analysis. Designed to with with the Flipper Blackhat. +A WiFi and security testing OS built on Linux for penetration testing and network analysis. Designed to run on the [Flipper Blackhat](https://github.com/o7-machinehum/flipper-blackhat). -## Documentation -For complete functionality reference and usage examples, see [BLACKHAT_REFERENCE.md](BLACKHAT_REFERENCE.md). +There are two possible builds in this repository... -## Releases -The best way to get your hands on all the most recent features is the [nightly build](https://github.com/o7-machinehum/flipper-blackhat-os/actions) here. Just click the most recent "Nightly" and you will find the OS artifacts at the bottom. These can then be flashed to an SD card using unix dd, or whatever Windows application you would use to flash a RPI SD card. +## Buildroot -## Build (Buildroot) +### Building Make sure submodules are initialized: git submodule update --init @@ -24,8 +22,8 @@ And compile: make -## Build (Armbian) +## Armbian + +### Building The armbian build is pretty simple... ./armbian_build.sh - - diff --git a/armbian_config/dotfiles/alacritty.toml b/armbian_config/dotfiles/alacritty.toml new file mode 100644 index 0000000..4a66712 --- /dev/null +++ b/armbian_config/dotfiles/alacritty.toml @@ -0,0 +1,25 @@ +[font] +size = 8.0 + +[font.bold] +family = "monospace" +style = "Bold" + +[font.bold_italic] +family = "monospace" +style = "Bold Italic" + +[font.italic] +family = "monospace" +style = "Italic" + +[font.normal] +family = "monospace" +style = "Regular" + +[window] +opacity=0.85 + +[[keyboard.bindings]] +key = "F1" +action = "ToggleViMode" diff --git a/armbian_config/dotfiles/i3_config b/armbian_config/dotfiles/i3_config new file mode 100644 index 0000000..53fddb4 --- /dev/null +++ b/armbian_config/dotfiles/i3_config @@ -0,0 +1,193 @@ +# This file has been auto-generated by i3-config-wizard(1). +# It will not be overwritten, so edit it as you like. +# +# Should you change your keyboard layout some time, delete +# this file and re-run i3-config-wizard(1). +# + +# i3 config file (v4) +# +# Please see https://i3wm.org/docs/userguide.html for a complete reference! + +set $mod Mod4 + +# Font for window titles. Will also be used by the bar unless a different font +# is used in the bar {} block below. +font pango:monospace 7 + +# This font is widely installed, provides lots of unicode glyphs, right-to-left +# text rendering and scalability on retina/hidpi displays (thanks to pango). +#font pango:DejaVu Sans Mono 8 + +# Set the wallpaper +exec_always feh --randomize --bg-fill /root/kali.png + +# Start XDG autostart .desktop files using dex. See also +# https://wiki.archlinux.org/index.php/XDG_Autostart +exec --no-startup-id dex --autostart --environment i3 + +# The combination of xss-lock, nm-applet and pactl is a popular choice, so +# they are included here as an example. Modify as you see fit. + +# xss-lock grabs a logind suspend inhibit lock and will use i3lock to lock the +# screen before suspend. Use loginctl lock-session to lock your screen. +exec --no-startup-id xss-lock --transfer-sleep-lock -- i3lock --nofork + +# NetworkManager is the most popular way to manage wireless networks on Linux, +# and nm-applet is a desktop environment-independent system tray GUI for it. +exec --no-startup-id nm-applet + +# Use pactl to adjust volume in PulseAudio. +set $refresh_i3status killall -SIGUSR1 i3status +bindsym XF86AudioRaiseVolume exec --no-startup-id pactl set-sink-volume @DEFAULT_SINK@ +10% && $refresh_i3status +bindsym XF86AudioLowerVolume exec --no-startup-id pactl set-sink-volume @DEFAULT_SINK@ -10% && $refresh_i3status +bindsym XF86AudioMute exec --no-startup-id pactl set-sink-mute @DEFAULT_SINK@ toggle && $refresh_i3status +bindsym XF86AudioMicMute exec --no-startup-id pactl set-source-mute @DEFAULT_SOURCE@ toggle && $refresh_i3status + +# Use Mouse+$mod to drag floating windows to their wanted position +floating_modifier $mod + +# move tiling windows via drag & drop by left-clicking into the title bar, +# or left-clicking anywhere into the window while holding the floating modifier. +tiling_drag modifier titlebar + +# start a terminal +bindsym $mod+Return exec "alacritty" + +# kill focused window +bindsym $mod+Shift+q kill + +# start dmenu (a program launcher) +bindsym $mod+d exec --no-startup-id dmenu_run +# A more modern dmenu replacement is rofi: +# bindcode $mod+40 exec "rofi -modi drun,run -show drun" +# There also is i3-dmenu-desktop which only displays applications shipping a +# .desktop file. It is a wrapper around dmenu, so you need that installed. +# bindcode $mod+40 exec --no-startup-id i3-dmenu-desktop + +# change focus +bindsym $mod+j focus left +bindsym $mod+k focus down +bindsym $mod+l focus up +bindsym $mod+semicolon focus right + +# alternatively, you can use the cursor keys: +bindsym $mod+Left focus left +bindsym $mod+Down focus down +bindsym $mod+Up focus up +bindsym $mod+Right focus right + +# move focused window +bindsym $mod+Shift+j move left +bindsym $mod+Shift+k move down +bindsym $mod+Shift+l move up +bindsym $mod+Shift+semicolon move right + +# alternatively, you can use the cursor keys: +bindsym $mod+Shift+Left move left +bindsym $mod+Shift+Down move down +bindsym $mod+Shift+Up move up +bindsym $mod+Shift+Right move right + +# split in horizontal orientation +bindsym $mod+h split h + +# split in vertical orientation +bindsym $mod+v split v + +# enter fullscreen mode for the focused container +bindsym $mod+f fullscreen toggle + +# change container layout (stacked, tabbed, toggle split) +bindsym $mod+s layout stacking +bindsym $mod+w layout tabbed +bindsym $mod+e layout toggle split + +# toggle tiling / floating +bindsym $mod+Shift+space floating toggle + +# change focus between tiling / floating windows +bindsym $mod+space focus mode_toggle + +# focus the parent container +bindsym $mod+a focus parent + +# focus the child container +#bindsym $mod+d focus child + +# Define names for default workspaces for which we configure key bindings later on. +# We use variables to avoid repeating the names in multiple places. +set $ws1 "1" +set $ws2 "2" +set $ws3 "3" +set $ws4 "4" +set $ws5 "5" +set $ws6 "6" +set $ws7 "7" +set $ws8 "8" +set $ws9 "9" +set $ws10 "10" + +# switch to workspace +bindsym $mod+1 workspace number $ws1 +bindsym $mod+2 workspace number $ws2 +bindsym $mod+3 workspace number $ws3 +bindsym $mod+4 workspace number $ws4 +bindsym $mod+5 workspace number $ws5 +bindsym $mod+6 workspace number $ws6 +bindsym $mod+7 workspace number $ws7 +bindsym $mod+8 workspace number $ws8 +bindsym $mod+9 workspace number $ws9 +bindsym $mod+0 workspace number $ws10 + +# move focused container to workspace +bindsym $mod+Shift+1 move container to workspace number $ws1 +bindsym $mod+Shift+2 move container to workspace number $ws2 +bindsym $mod+Shift+3 move container to workspace number $ws3 +bindsym $mod+Shift+4 move container to workspace number $ws4 +bindsym $mod+Shift+5 move container to workspace number $ws5 +bindsym $mod+Shift+6 move container to workspace number $ws6 +bindsym $mod+Shift+7 move container to workspace number $ws7 +bindsym $mod+Shift+8 move container to workspace number $ws8 +bindsym $mod+Shift+9 move container to workspace number $ws9 +bindsym $mod+Shift+0 move container to workspace number $ws10 + +# reload the configuration file +bindsym $mod+Shift+c reload +# restart i3 inplace (preserves your layout/session, can be used to upgrade i3) +bindsym $mod+Shift+r restart +# exit i3 (logs you out of your X session) +bindsym $mod+Shift+e exec "i3-nagbar -t warning -m 'You pressed the exit shortcut. Do you really want to exit i3? This will end your X session.' -B 'Yes, exit i3' 'i3-msg exit'" + +# resize window (you can also use the mouse for that) +mode "resize" { + # These bindings trigger as soon as you enter the resize mode + + # Pressing left will shrink the window’s width. + # Pressing right will grow the window’s width. + # Pressing up will shrink the window’s height. + # Pressing down will grow the window’s height. + bindsym j resize shrink width 10 px or 10 ppt + bindsym k resize grow height 10 px or 10 ppt + bindsym l resize shrink height 10 px or 10 ppt + bindsym semicolon resize grow width 10 px or 10 ppt + + # same bindings, but for the arrow keys + bindsym Left resize shrink width 10 px or 10 ppt + bindsym Down resize grow height 10 px or 10 ppt + bindsym Up resize shrink height 10 px or 10 ppt + bindsym Right resize grow width 10 px or 10 ppt + + # back to normal: Enter or Escape or $mod+r + bindsym Return mode "default" + bindsym Escape mode "default" + bindsym $mod+r mode "default" +} + +bindsym $mod+r mode "resize" + +# Start i3bar to display a workspace bar (plus the system information i3status +# finds out, if available) +bar { + status_command i3status +} diff --git a/armbian_config/dotfiles/i3status_config b/armbian_config/dotfiles/i3status_config new file mode 100644 index 0000000..7e03735 --- /dev/null +++ b/armbian_config/dotfiles/i3status_config @@ -0,0 +1,49 @@ +# i3status configuration file. +# see "man i3status" for documentation. + +# It is important that this file is edited as UTF-8. +# The following line should contain a sharp s: +# ß +# If the above line is not correctly displayed, fix your editor first! + +general { + colors = true + interval = 5 +} + +# order += "ipv6" +order += "wireless _first_" +# order += "ethernet _first_" +# order += "disk /" +order += "load" +order += "memory" +order += "tztime local" + +wireless _first_ { +# format_up = "W: (%quality at %essid) %ip" + format_up = "%ip" + format_down = "W: down" +} + +ethernet _first_ { + format_up = "E: %ip (%speed)" + format_down = "E: down" +} + +disk "/" { + format = "%avail" +} + +load { + format = "%1min" +} + +memory { + format = "U: %used |F: %available" + # threshold_degraded = "1G" + # format_degraded = "MEMORY < %available" +} + +tztime local { + format = "%Y-%m-%d %H:%M:%S" +} diff --git a/armbian_config/dotfiles/xinitrc b/armbian_config/dotfiles/xinitrc new file mode 100644 index 0000000..e62801b --- /dev/null +++ b/armbian_config/dotfiles/xinitrc @@ -0,0 +1,6 @@ +#!/bin/bash + +picom --backend=xrender & +unclutter -idle 1 & +xrandr --output DSI-1 --rotate inverted +exec i3 diff --git a/armbian_config/kali.png b/armbian_config/kali.png new file mode 100644 index 0000000..f5eecce Binary files /dev/null and b/armbian_config/kali.png differ diff --git a/armbian_config/userpatches/customize-image.sh b/armbian_config/userpatches/customize-image.sh index abce5bc..3f15387 100644 --- a/armbian_config/userpatches/customize-image.sh +++ b/armbian_config/userpatches/customize-image.sh @@ -18,6 +18,18 @@ fi systemctl enable bh-boot +# These are started manually +systemctl disable nginx + +systemctl disable hostapd +systemctl unmask hostapd + +systemctl unmask dnsmasq +systemctl disable dnsmasq + +systemctl unmask kismet +systemctl disable kismet + # Force Realtek dongles to _not_ come up as USB MSD # https://linux.die.net/man/1/usb_modeswitch echo 'ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="0bda", ATTR{idProduct}=="1a2b", ATTR{bConfigurationValue}!="1", ATTR{bConfigurationValue}="1"' \ @@ -38,18 +50,34 @@ done # Also remove the "not logged in yet" flag if present rm -f /root/.not_logged_in_yet || true -# Detect a likely serial console. For most boards this is ttyS0 or ttyAMA0; adjust if needed. -SERIAL_TTY="ttyS0" +echo 'FONT="Lat7-Terminus12x6.psf.gz"' >> /etc/default/console-setup -mkdir -p /etc/systemd/system/serial-getty@${SERIAL_TTY}.service.d -cat >/etc/systemd/system/serial-getty@${SERIAL_TTY}.service.d/autologin.conf < /etc/hostname -echo 'FONT="Lat7-Terminus12x6.psf.gz"' >> /etc/default/console-setup +## Remove network manager requirement from systemd-user-sessions +install -D -m 0644 /usr/lib/systemd/system/systemd-user-sessions.service \ + /etc/systemd/system/systemd-user-sessions.service + +# Remove network.target from the After= line(s) +sed -i 's/[[:space:]]network\.target//g' /etc/systemd/system/systemd-user-sessions.service +sed -i 's/network\.target[[:space:]]//g' /etc/systemd/system/systemd-user-sessions.service + +# Alias python -> python3 +ln -sf /usr/bin/python3 /usr/bin/python + +# This is something that makes the terminal more fancy (remove it) +rm /etc/profile.d/80-systemd-osc-context.sh + +# Use old wlanX names +echo "extraargs=net.ifnames=0 biosdevname=0" >> /boot/armbianEnv.txt + +# Bjorn requirements +pip install smbprotocol --break-system-packages +pip install pysmb --break-system-packages +cd /root/bhtui +sudo make install echo "Customization complete." diff --git a/armbian_config/userpatches/extensions/kali.sh b/armbian_config/userpatches/extensions/kali.sh index bfb37f9..9e95f7d 100644 --- a/armbian_config/userpatches/extensions/kali.sh +++ b/armbian_config/userpatches/extensions/kali.sh @@ -26,6 +26,8 @@ function pre_customize_image__install_kali_packages(){ display_alert "Updating package lists with Kali Linux repos" "${BOARD}:${RELEASE}-${BRANCH} :: ${EXTENSION}" "info" do_with_retries 3 chroot_sdcard_apt_get_update - display_alert "Installing Top 10 Kali Linux tools" "${EXTENSION}" "info" - chroot_sdcard_apt_get_install kali-tools-top10 + chroot_sdcard_apt_get_install kismet + + # display_alert "Installing Top 10 Kali Linux tools" "${EXTENSION}" "info" + # chroot_sdcard_apt_get_install kali-tools-top10 } diff --git a/armbian_config/userpatches/overlay/etc/hostname b/armbian_config/userpatches/overlay/etc/hostname new file mode 100644 index 0000000..29d2e06 --- /dev/null +++ b/armbian_config/userpatches/overlay/etc/hostname @@ -0,0 +1 @@ +bh diff --git a/armbian_config/userpatches/overlay/etc/systemd/system/getty@tty1.service b/armbian_config/userpatches/overlay/etc/systemd/system/getty@tty1.service new file mode 100644 index 0000000..0c1bc9b --- /dev/null +++ b/armbian_config/userpatches/overlay/etc/systemd/system/getty@tty1.service @@ -0,0 +1,27 @@ +# Write an explicit tty1 unit that does NOT reference rc-local + +[Unit] +Description=Getty on tty1 +Documentation=man:agetty(8) man:systemd-getty-generator(8) +After=systemd-user-sessions.service getty-pre.target basic.target +Before=getty.target +IgnoreOnIsolate=yes +Conflicts=rescue.service +Before=rescue.service +ConditionPathExists=/dev/tty0 + +[Service] +ExecStart=-/usr/sbin/agetty --noreset --noclear --issue-file=/etc/issue:/etc/issue.d:/run/issue.d:/usr/lib/issue.d tty1 $TERM +Type=idle +Restart=always +RestartSec=0 +UtmpIdentifier=tty1 +StandardInput=tty +StandardOutput=tty +TTYPath=/dev/tty1 +TTYReset=yes +TTYVHangup=yes +TTYVTDisallocate=no + +[Install] +WantedBy=getty.target diff --git a/armbian_config/userpatches/overlay/etc/systemd/system/serial-getty@ttyS0.service.d/autologin.conf b/armbian_config/userpatches/overlay/etc/systemd/system/serial-getty@ttyS0.service.d/autologin.conf new file mode 100644 index 0000000..79f39a1 --- /dev/null +++ b/armbian_config/userpatches/overlay/etc/systemd/system/serial-getty@ttyS0.service.d/autologin.conf @@ -0,0 +1,5 @@ +# I want a shell automatically + +[Service] +ExecStart= +ExecStart=-/sbin/agetty --autologin root --keep-baud 115200,38400,9600 %I \$TERM diff --git a/armbian_config/userpatches/overlay/etc/systemd/system/serial-getty@ttyS0.service.d/override.conf b/armbian_config/userpatches/overlay/etc/systemd/system/serial-getty@ttyS0.service.d/override.conf new file mode 100644 index 0000000..9da82ac --- /dev/null +++ b/armbian_config/userpatches/overlay/etc/systemd/system/serial-getty@ttyS0.service.d/override.conf @@ -0,0 +1,4 @@ +# Put term in dumb mode (needed to talk serial with Flipper zero) + +[Service] +Environment=TERM=dumb diff --git a/build_armbian.sh b/build_armbian.sh index e102ba1..fea2fdf 100755 --- a/build_armbian.sh +++ b/build_armbian.sh @@ -3,6 +3,7 @@ set -e cd "$(dirname "$0")" kver="edge" # Edge or current +os_release="sid" cd armbian git reset --hard @@ -13,6 +14,22 @@ cd .. rsync -av armbian_config/userpatches/ armbian/userpatches/ rsync -av armbian_config/config/ armbian/config/ +# Copy over dotfiles +DOTFILES="armbian_config/dotfiles" +ROOTDIR="armbian/userpatches/overlay/root" +mkdir -p $ROOTDIR/.config/i3/ +cp $DOTFILES/i3_config $ROOTDIR/.config/i3/config + +mkdir -p $ROOTDIR/.config/i3status/ +cp $DOTFILES/i3status_config $ROOTDIR/.config/i3status/config + +cp $DOTFILES/xinitrc $ROOTDIR/.xinitrc + +mkdir -p $ROOTDIR/.config/alacritty/ +cp $DOTFILES/alacritty.toml $ROOTDIR/.config/alacritty/ + +cp armbian_config/kali.png $ROOTDIR/ + # Add kernel patches if [[ ${kver} == "edge" ]]; then cp patches/linux/0002-rtw88.patch armbian/userpatches/kernel/archive/sunxi-6.16/rtw88.patch @@ -24,24 +41,85 @@ else exit fi +armbian_rootfs="armbian/userpatches/overlay/" + # Install packages needed for bh scripts -install -D package/blackhat/src/blackhat.sh armbian/userpatches/overlay/usr/local/bin/bh -install -D package/blackhat/src/evil_portal.py armbian/userpatches/overlay/usr/local/bin/ -install -D package/blackhat/src/telegram.py armbian/userpatches/overlay/usr/local/bin/ -install -D -m 0644 package/blackhat/src/blackhat.conf armbian/userpatches/overlay/boot/bh/blackhat.conf +install -D package/blackhat/src/blackhat.sh "$armbian_rootfs"/usr/local/bin/bh +mkdir -p "$armbian_rootfs"/root/bjorn +cp -r package/bjorn/bjorn/* "$armbian_rootfs"/root/bjorn/ +install -D -m 0644 package/blackhat/src/blackhat.conf "$armbian_rootfs"/boot/bh/blackhat.conf + +# Copy build files over for bhtui +cp -r package/bhtui "$armbian_rootfs"/root/ mkdir -p armbian/userpatches/overlay/boot/bh/scripts -cp -a package/blackhat/scripts/. armbian/userpatches/overlay/boot/bh/scripts/ +cp -a package/blackhat/scripts/. "$armbian_rootfs"/boot/bh/scripts/ # Install the init script -install -D rootfs_overlay/etc/init.d/S51bh_init armbian/userpatches/overlay/usr/local/bin/bh_init +install -D rootfs_overlay/etc/init.d/S51bh_init "$armbian_rootfs"/usr/local/bin/bh_init + +mkdir -p $armbian_rootfs/etc/nginx/ +cp rootfs_overlay/etc/nginx/nginx.conf "$armbian_rootfs"/etc/nginx/ + +mkdir -p $armbian_rootfs/etc/hostapd/ +cp rootfs_overlay/etc/hostapd.conf "$armbian_rootfs"/etc/hostapd/ +cp rootfs_overlay/etc/dnsmasq.conf "$armbian_rootfs"/etc/ +cp rootfs_overlay/etc/ep-rules.nft "$armbian_rootfs"/etc/ + +mkdir -p "$armbian_rootfs"/var/www/ +cp rootfs_overlay/var/www/index.html "$armbian_rootfs"/boot/bh/ + +cp package/blackhat/src/evil_portal.py "$armbian_rootfs"/usr/local/bin/evil_portal # Add additional packages -PKG_CONF="armbian/config/cli/trixie/main/packages.additional" +PKG_CONF="armbian/config/cli/${os_release}/main/packages.additional" echo usb-modeswitch >> $PKG_CONF +echo xorg >> $PKG_CONF +echo i3 >> $PKG_CONF +echo feh >> $PKG_CONF +echo vim >> $PKG_CONF +echo alacritty >> $PKG_CONF +echo picom >> $PKG_CONF +echo dmenu >> $PKG_CONF +echo nano >> $PKG_CONF +echo nmap >> $PKG_CONF +echo unclutter >> $PKG_CONF +echo brightnessctl >> $PKG_CONF + +echo nginx >> $PKG_CONF +echo python3-flask >> $PKG_CONF +echo python3-requests >> $PKG_CONF +echo hostapd >> $PKG_CONF +echo dnsmasq >> $PKG_CONF +echo nftables >> $PKG_CONF +echo chocolate-doom >> $PKG_CONF +echo doom-wad-shareware >> $PKG_CONF +echo cmake >> $PKG_CONF +echo libicu-dev >> $PKG_CONF +echo libicu-dev >> $PKG_CONF + +# Bjorn requirements +echo python3-pandas >> $PKG_CONF +echo python3-pil >> $PKG_CONF +echo python3-numpy >> $PKG_CONF +echo python3-rich >> $PKG_CONF +echo python3-netifaces >> $PKG_CONF +echo python3-ping3 >> $PKG_CONF +echo python3-getmac >> $PKG_CONF +echo python3-paramiko >> $PKG_CONF +echo python3-pymysql >> $PKG_CONF +echo python3-sqlalchemy >> $PKG_CONF +echo python3-nmap >> $PKG_CONF +echo python3-pip >> $PKG_CONF +echo python3-legacy-cgi >> $PKG_CONF cd armbian +# CLEAN_LEVEL=all \ +# CLEAN_LEVEL=images,cache \ +# ./compile.sh docker-purge # <- This might be required +# ./compile.sh docker-shell # <- Get a shell + ./compile.sh build \ BOARD=flipper-blackhat \ BRANCH=${kver} \ @@ -49,7 +127,7 @@ cd armbian KERNEL_CONFIGURE=no \ ENABLE_EXTENSIONS="kali" \ KEEP_ORIGINAL_OS_RELEASE=yes \ - RELEASE=forky + RELEASE=${os_release} echo ************ Built Image ************ echo "sudo dd if=armbian/output/images/Armbian-unofficial_26.02.0-trunk_Flipper-blackhat_forky_edge_6.16.8-kali.img of=/dev/sdd bs=4M conv=fsync status=progress" diff --git a/package/bhtui/CMakeLists.txt b/package/bhtui/CMakeLists.txt new file mode 100644 index 0000000..7a71e80 --- /dev/null +++ b/package/bhtui/CMakeLists.txt @@ -0,0 +1,26 @@ +cmake_minimum_required(VERSION 3.20) + +project(bhtui LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +add_subdirectory(third-party/TermOx) + +add_executable(bhtui + src/main.cpp + src/menu_app.cpp + src/menu_builder.cpp + src/menu_item.cpp +) + +target_link_libraries(bhtui + PRIVATE + TermOx +) + +if (MSVC) + target_compile_options(bhtui PRIVATE /W4) +else() + target_compile_options(bhtui PRIVATE -Wall -Wextra -Wpedantic) +endif() diff --git a/package/bhtui/Makefile b/package/bhtui/Makefile new file mode 100644 index 0000000..9e4d840 --- /dev/null +++ b/package/bhtui/Makefile @@ -0,0 +1,18 @@ +.PHONY: all build install clean + +BINARY := bhtui +BUILD_DIR := build +PREFIX ?= /usr/local + +all: build + +build: + cmake -S . -B $(BUILD_DIR) + cmake --build $(BUILD_DIR) --target $(BINARY) + +install: build + install -d $(DESTDIR)$(PREFIX)/bin + install -m 0755 $(BUILD_DIR)/$(BINARY) $(DESTDIR)$(PREFIX)/bin/$(BINARY) + +clean: + rm -rf $(BUILD_DIR) diff --git a/package/bhtui/src/main.cpp b/package/bhtui/src/main.cpp new file mode 100644 index 0000000..a984d63 --- /dev/null +++ b/package/bhtui/src/main.cpp @@ -0,0 +1,78 @@ +#include +#include +#include +#include + +#include + +#include "menu_app.h" +#include "menu_builder.h" + +int main() +{ + try { + auto menu = menu_() + .menu("Networking", "") + .item("Network Manager", "nmtui") + .item("IP Address", "ip a") + .item("Routes", "ip r") + .item("DNS (resolvectl)", "resolvectl status") + .item("Sockets", "ss -tulpen") + .item("Ping", "ping -c 4 1.1.1.1") + .item("Firewall (nft)", "nft list ruleset") + .end() + .menu("System", "") + .item("System Info", "fastfetch") + .item("Uptime/Load", "uptime") + .item("Kernel/OS", "uname -a") + .item("Kernel Logs", "dmesg") + .item("Top", "timeout 5 htop") + .item("Memory", "free -h") + .item("CPU Info", "lscpu") + .item("USB Info", "lsusb") + .item("Block Devices", "lsblk") + .end() + .menu("Files", "") + .item("List Files", "ls -lah") + .item("Disk Usage", "du -sh *") + .item("Filesystem Usage", "df -h") + .end() + .menu("Services", "") + .item("Service Status", "systemctl --failed") + .item("All Services", "systemctl list-units --type=service") + .item("Timers", "systemctl list-timers") + .item("Startup Time", "systemd-analyze") + .end() + .menu("Storage", "") + .item("fstab", "cat /etc/fstab") + .item("blkid", "blkid") + .end() + .menu("Security", "") + .item("Who Is Logged In", "who") + .item("Sudo Version", "sudo -V | head -n 1") + .item("Open Ports", "ss -lntup") + .end() + .build(); + + std::string output; + int code = 0; + { + auto term = ox::Terminal{}; + auto app = MenuApp{std::move(menu), output}; + code = ox::process_events(term, app); + } + if (!output.empty()) { + std::cout << output << '\n'; + return std::system(output.c_str()); + } + return code; + } + catch (std::exception const& e) { + std::cerr << "Error: " << e.what() << '\n'; + return 1; + } + catch (...) { + std::cerr << "Unknown error\n"; + return 1; + } +} diff --git a/package/bhtui/src/menu_app.cpp b/package/bhtui/src/menu_app.cpp new file mode 100644 index 0000000..2dd64db --- /dev/null +++ b/package/bhtui/src/menu_app.cpp @@ -0,0 +1,255 @@ +#include "menu_app.h" + +#include +#include +#include + +#include + +using namespace ox; + +MenuApp::MenuApp(std::vector menu, std::string& output) + : menu_{std::move(menu)}, output_{output} +{ +} + +EventResponse MenuApp::handle_key_press(Key k) +{ + switch (k) { + case Key::ArrowDown: select_next(1); return {}; + case Key::ArrowUp: select_next(-1); return {}; + case Key::ArrowLeft: go_back(); return {}; + case Key::ArrowRight: + case Key::Enter: + if (enter_selected()) { return QuitRequest{0}; } + return {}; + default: return {}; + } +} + +EventResponse MenuApp::handle_resize(Area) +{ + return {}; +} + +Terminal::Cursor MenuApp::handle_paint(Canvas c) +{ + fill(c, U' '); + + if (c.size.width < 32 || c.size.height < 8) { + put(c, {0, 0}, "Terminal too small"); + return std::nullopt; + } + + draw_menu(c); + return std::nullopt; +} + +auto MenuApp::current_items() -> std::vector& +{ + auto* items = &menu_; + for (auto index : path_) { + if (index >= items->size()) { return *items; } + items = &(*items)[index].children; + } + return *items; +} + +auto MenuApp::current_items() const -> std::vector const& +{ + auto const* items = &menu_; + for (auto index : path_) { + if (index >= items->size()) { return *items; } + items = &(*items)[index].children; + } + return *items; +} + +auto MenuApp::current_selection() -> std::size_t& +{ + return selections_.back(); +} + +auto MenuApp::current_selection() const -> std::size_t +{ + return selections_.back(); +} + +void MenuApp::select_next(int delta) +{ + auto const& items = current_items(); + if (items.empty()) { + current_selection() = 0; + return; + } + + auto const size = static_cast(items.size()); + auto index = static_cast(current_selection()); + index = (index + delta + size) % size; + current_selection() = static_cast(index); +} + +auto MenuApp::enter_selected() -> bool +{ + auto& items = current_items(); + if (items.empty()) { return false; } + + auto const selection = clamp_selection(current_selection(), items.size()); + auto& item = items[selection]; + if (item.children.empty()) { + output_ = selected_print_path(); + return true; + } + + path_.push_back(current_selection()); + selections_.push_back(0); + return false; +} + +void MenuApp::go_back() +{ + if (path_.empty()) { return; } + path_.pop_back(); + selections_.pop_back(); +} + +auto MenuApp::breadcrumb() const -> std::string +{ + auto text = std::string{"Menu"}; + auto const* items = &menu_; + for (auto index : path_) { + if (index >= items->size()) { break; } + text += " > " + (*items)[index].display; + items = &(*items)[index].children; + } + return text; +} + +auto MenuApp::selected_print_path() const -> std::string +{ + auto const& items = current_items(); + if (items.empty()) { return ""; } + + auto out = std::string{}; + auto const* walk = &menu_; + for (auto index : path_) { + if (index >= walk->size()) { break; } + if (!out.empty()) { out += ' '; } + out += (*walk)[index].print; + walk = &(*walk)[index].children; + } + + auto const selection = clamp_selection(current_selection(), items.size()); + if (!out.empty()) { out += ' '; } + out += items[selection].print; + return out; +} + +auto MenuApp::clamp_selection(std::size_t selection, std::size_t size) -> std::size_t +{ + if (size == 0) { return 0; } + return selection >= size ? size - 1 : selection; +} + +auto MenuApp::items_at_path(std::vector const& path) -> std::vector* +{ + auto* items = &menu_; + for (auto index : path) { + if (index >= items->size()) { return nullptr; } + items = &(*items)[index].children; + } + return items; +} + +auto MenuApp::items_at_path(std::vector const& path) const + -> std::vector const* +{ + auto const* items = &menu_; + for (auto index : path) { + if (index >= items->size()) { return nullptr; } + items = &(*items)[index].children; + } + return items; +} + +void MenuApp::draw_column(Canvas c, + std::vector const& items, + std::size_t selection, + int x, + int y, + int width, + bool active) +{ + auto const max_y = c.size.height - 2; + for (std::size_t i = 0; i < items.size(); ++i) { + auto const row = y + static_cast(i); + if (row >= max_y) { break; } + + auto line = items[i].display; + auto const selected = (i == selection); + if (static_cast(line.size()) > width - 1) { + line.resize(static_cast(std::max(0, width - 1))); + } + + if (selected) { + put(c, {x, row}, line | (active ? Trait::Standout : Trait::Dim)); + } + else if (active) { + put(c, {x, row}, line); + } + else { + put(c, {x, row}, line | Trait::Dim); + } + } +} + +void MenuApp::draw_menu(Canvas c) +{ + auto const title = std::string_view{"Blackhat TUI Menu"}; + auto const title_x = std::max(0, (c.size.width - (int)title.size()) / 2); + put(c, {title_x, 0}, title | Trait::Bold); + + auto const crumb = breadcrumb(); + put(c, {2, 2}, crumb | Trait::Dim); + + auto const start_y = 4; + auto const left_margin = 2; + auto const gap = 1; + auto const available = c.size.width - left_margin * 2 - gap * 2; + auto const column_width = std::max(1, available / 4); + + auto const* level0 = items_at_path(path_); + if (level0 == nullptr) { return; } + auto const sel0 = clamp_selection(current_selection(), level0->size()); + + auto path1 = path_; + path1.push_back(sel0); + auto const* level1 = items_at_path(path1); + auto const sel1 = + (level1 && selections_.size() > path_.size() + 1) + ? clamp_selection(selections_[path_.size() + 1], level1->size()) + : 0U; + + auto path2 = path1; + if (level1 && !level1->empty()) { path2.push_back(sel1); } + auto const* level2 = (level1 && !level1->empty()) ? items_at_path(path2) : nullptr; + auto const sel2 = + (level2 && selections_.size() > path_.size() + 2) + ? clamp_selection(selections_[path_.size() + 2], level2->size()) + : 0U; + + draw_column(c, *level0, sel0, left_margin, start_y, column_width, true); + + if (level1 && !level1->empty()) { + auto const x1 = left_margin + column_width + gap; + draw_column(c, *level1, sel1, x1, start_y, column_width, false); + } + + if (level2 && !level2->empty()) { + auto const x2 = left_margin + (column_width + gap) * 2; + draw_column(c, *level2, sel2, x2, start_y, column_width, false); + } + + auto const hint = std::string_view{"Up/Down, Left to go back, Right/Enter to run"}; + put(c, {2, c.size.height - 2}, hint | Trait::Dim); +} diff --git a/package/bhtui/src/menu_app.h b/package/bhtui/src/menu_app.h new file mode 100644 index 0000000..5e22ae9 --- /dev/null +++ b/package/bhtui/src/menu_app.h @@ -0,0 +1,53 @@ +#pragma once + +#include +#include + +#include + +#include "menu_item.h" + +class MenuApp { + public: + MenuApp(std::vector menu, std::string& output); + + ox::EventResponse handle_key_press(ox::Key k); + ox::EventResponse handle_resize(ox::Area); + ox::Terminal::Cursor handle_paint(ox::Canvas c); + + private: + std::vector menu_; + std::string& output_; + + std::vector path_; + std::vector selections_{0}; + + private: + auto current_items() -> std::vector&; + auto current_items() const -> std::vector const&; + + auto current_selection() -> std::size_t&; + auto current_selection() const -> std::size_t; + + void select_next(int delta); + auto enter_selected() -> bool; + void go_back(); + + auto breadcrumb() const -> std::string; + auto selected_print_path() const -> std::string; + + static auto clamp_selection(std::size_t selection, std::size_t size) -> std::size_t; + + auto items_at_path(std::vector const& path) -> std::vector*; + auto items_at_path(std::vector const& path) const + -> std::vector const*; + + void draw_column(ox::Canvas c, + std::vector const& items, + std::size_t selection, + int x, + int y, + int width, + bool active); + void draw_menu(ox::Canvas c); +}; diff --git a/package/bhtui/src/menu_builder.cpp b/package/bhtui/src/menu_builder.cpp new file mode 100644 index 0000000..a9eeb47 --- /dev/null +++ b/package/bhtui/src/menu_builder.cpp @@ -0,0 +1,47 @@ +#include "menu_builder.h" + +#include + +MenuBuilder::MenuBuilder() : current_{&root_} {} + +MenuBuilder& MenuBuilder::menu(std::string display, std::string print) +{ + current_ = &root_; + stack_.clear(); + root_.push_back(MenuItem{std::move(display), std::move(print), {}}); + stack_.push_back(&root_); + current_ = &root_.back().children; + return *this; +} + +MenuBuilder& MenuBuilder::submenu(std::string display, std::string print) +{ + if (current_ == nullptr) { current_ = &root_; } + current_->push_back(MenuItem{std::move(display), std::move(print), {}}); + stack_.push_back(current_); + current_ = ¤t_->back().children; + return *this; +} + +MenuBuilder& MenuBuilder::item(std::string display, std::string print) +{ + if (current_ == nullptr) { current_ = &root_; } + current_->push_back(MenuItem{std::move(display), std::move(print), {}}); + return *this; +} + +MenuBuilder& MenuBuilder::end() +{ + if (stack_.empty()) { + current_ = &root_; + return *this; + } + current_ = stack_.back(); + stack_.pop_back(); + return *this; +} + +auto MenuBuilder::build() -> std::vector +{ + return std::move(root_); +} diff --git a/package/bhtui/src/menu_builder.h b/package/bhtui/src/menu_builder.h new file mode 100644 index 0000000..5495e71 --- /dev/null +++ b/package/bhtui/src/menu_builder.h @@ -0,0 +1,25 @@ +#pragma once + +#include +#include + +#include "menu_item.h" + +class MenuBuilder { + public: + MenuBuilder(); + + MenuBuilder& menu(std::string display, std::string print); + MenuBuilder& submenu(std::string display, std::string print); + MenuBuilder& item(std::string display, std::string print); + MenuBuilder& end(); + + auto build() -> std::vector; + + private: + std::vector root_; + std::vector* current_; + std::vector*> stack_; +}; + +inline auto menu_() -> MenuBuilder { return MenuBuilder{}; } diff --git a/package/bhtui/src/menu_item.cpp b/package/bhtui/src/menu_item.cpp new file mode 100644 index 0000000..4c0e056 --- /dev/null +++ b/package/bhtui/src/menu_item.cpp @@ -0,0 +1 @@ +#include "menu_item.h" diff --git a/package/bhtui/src/menu_item.h b/package/bhtui/src/menu_item.h new file mode 100644 index 0000000..8eead0c --- /dev/null +++ b/package/bhtui/src/menu_item.h @@ -0,0 +1,10 @@ +#pragma once + +#include +#include + +struct MenuItem { + std::string display; + std::string print; + std::vector children; +}; diff --git a/package/bhtui/third-party/TermOx b/package/bhtui/third-party/TermOx new file mode 160000 index 0000000..71deae4 --- /dev/null +++ b/package/bhtui/third-party/TermOx @@ -0,0 +1 @@ +Subproject commit 71deae40e2c27920025b1a1495672f9c08c14b05 diff --git a/package/bjorn/bjorn b/package/bjorn/bjorn index ce28922..e783232 160000 --- a/package/bjorn/bjorn +++ b/package/bjorn/bjorn @@ -1 +1 @@ -Subproject commit ce2892265c3a034ec421fb9b71c1c6980a476160 +Subproject commit e783232e5c807d6ec6ca6709f35188bdb1a1951e diff --git a/package/blackhat/scripts/data_thief.py b/package/blackhat/scripts/data_thief.py index b874a7d..cef6f02 100755 --- a/package/blackhat/scripts/data_thief.py +++ b/package/blackhat/scripts/data_thief.py @@ -18,7 +18,7 @@ def bash(cmd, sudo=False, suppress_output=False): if __name__ == "__main__": TARGET_DISK = "/dev/sda1" # Name of disk we're robbing - LOOT_DISK = "/dev/mmcblk0p3" # Out disk + LOOT_DISK = "/dev/mmcblk0p2" # Out disk LOOT_MOUNT_POINT = "/media/loot" TARGET_MOUNT_POINT = "/media/target" diff --git a/package/blackhat/scripts/start_bjorn.sh b/package/blackhat/scripts/start_bjorn.sh index e36cc0b..809aa27 100755 --- a/package/blackhat/scripts/start_bjorn.sh +++ b/package/blackhat/scripts/start_bjorn.sh @@ -2,6 +2,6 @@ cd /root/bjorn/ chmod +x kill_port_8000.sh -./kill_port_8000.sh +./kill_port_8000.sh 2> /dev/null python Bjorn.py > /dev/null 2>&1 & -echo Bjorn Started! +echo "Bjorn Started! Port: 8000" diff --git a/package/blackhat/scripts/stop_bjorn.sh b/package/blackhat/scripts/stop_bjorn.sh index 189705d..374adf5 100755 --- a/package/blackhat/scripts/stop_bjorn.sh +++ b/package/blackhat/scripts/stop_bjorn.sh @@ -1,3 +1,4 @@ #!/bin/bash kill $(pidof python Bjorn.py) +dd if=/dev/zero of=/dev/fb0 bs=1M 2>/dev/null diff --git a/package/blackhat/src/blackhat.sh b/package/blackhat/src/blackhat.sh index a70d9bd..dd30a10 100755 --- a/package/blackhat/src/blackhat.sh +++ b/package/blackhat/src/blackhat.sh @@ -1,30 +1,41 @@ #!/bin/bash set -m -exec > >(tee /dev/tty1) 2>&1 -export PYTHONUNBUFFERED=1 - -CONFIG_F=blackhat.conf - -if test -f $CONFIG_F; then - CONFIG_F="$PWD/$CONFIG_F" - LOG_F=blackhat.log -elif test -f /mnt/$CONFIG_F; then - CONFIG_F=/mnt/$CONFIG_F - LOG_F=/mnt/blackhat.log -elif test -f /etc/$CONFIG_F; then - CONFIG_F=/etc/$CONFIG_F - LOG_F=/var/log/blackhat.log + +# For Debugging +# set -mxe +# x: print everything +# e: quit when anything fails + +# If we're not connect to the blackpants, echo +# everything back to the screen +USB_HUB=0424:2514 +blackpants=true +if ! lsusb -d "$USB_HUB" >/dev/null 2>&1; then + exec > >(tee /dev/tty1) 2>&1 + export PYTHONUNBUFFERED=1 + blackpants=false +fi + +armbian=false +if grep -qi '^ID=debian' /etc/os-release; then + armbian=true +fi + +config_f="/mnt/blackhat.conf" +if [[ -f "${config_f}" ]]; then + log_f="/mnt/blackhat.log" else echo "Could not load conf file" exit fi -source "$CONFIG_F" -rm $LOG_F 2>/dev/null +source "$config_f" +rm -rf $log_f 2>/dev/null -function print_help() { +print_help() { echo "Commands:" echo "usage: bh wifi connect wlan0" + echo "usage: bh wifi" echo " bh set PASS 'my_wifi_password'" echo " set" echo " SSID Set SSID of WiFi network to connect to" @@ -51,7 +62,42 @@ function print_help() { echo " run