diff --git a/.gitignore b/.gitignore index 393fe2b..1ed1207 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,3 @@ _utils config.laptop.yml .idea tmp -mnt diff --git a/README.md b/README.md index 6936837..7bb826d 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Depending on the status of the unit, several states and states transitions are c If instead you are a boring person, you can disable the AI and have the algorithm run just with the preconfigured default parameters and enjoy a very portable bettercap + webui dedicated hardware. -**NOTE:** The software **requires bettercap compiled from master**. +**NOTE:** The software **requires bettercap v2.25**. ![units](https://i.imgur.com/MStjXZF.png) @@ -42,13 +42,14 @@ For hackers to learn reinforcement learning, WiFi networking and have an excuse #### Automatically create an image -You can use the `create_sibling.sh` script to create an - ready to flash - rasbian image with pwnagotchi. +You can use the `scripts/create_sibling.sh` script to create an - ready to flash - rasbian image with pwnagotchi. ```shell -usage: ./create_sibling.sh [OPTIONS] +usage: ./scripts/create_sibling.sh [OPTIONS] Options: - -n # Name of the pwnagotchi (default: alpha) + -n # Name of the pwnagotchi (default: pwnagotchi) + -i # Provide the path of an already downloaded raspbian image -o # Name of the img-file (default: pwnagotchi.img) -s # Size which should be added to second partition (in Gigabyte) (default: 4) -p # Only run provisioning (assumes the image is already mounted) @@ -56,6 +57,10 @@ usage: ./create_sibling.sh [OPTIONS] -h # Show this help ``` +#### Host Connection Share + +If you connect to the unit via `usb0` (thus using the data port), you might want to use the `scripts/linux_connection_share.sh` script to bring the interface up on your end and share internet connectivity from another interface, so you can update the unit and generally download things from the internet on it. + ### UI The UI is available either via display if installed, or via http://10.0.0.2:8080/ if you connect to the unit via `usb0` and set a static address on the network interface. @@ -76,29 +81,8 @@ The UI is available either via display if installed, or via http://10.0.0.2:8080 - `/var/log/pwnagotchi.log` is your friend. - if connected to a laptop via usb data port, with internet connectivity shared, magic things will happen. - checkout the `ui.video` section of the `config.yml` - if you don't want to use a display, you can connect to it with the browser and a cable. - -Magic scripts that makes it talk to the internet: - -```sh -#!/bin/bash - -# name of the ethernet gadget interface on the host -USB_IFACE=${1:-enp0s20f0u1} -USB_IFACE_IP=10.0.0.1 -USB_IFACE_NET=10.0.0.0/24 -# host interface to use for upstream connection -UPSTREAM_IFACE=enxe4b97aa99867 - -ip addr add $USB_IFACE_IP/24 dev $USB_IFACE -ip link set $USB_IFACE up - -iptables -A FORWARD -o $UPSTREAM_IFACE -i $USB_IFACE -s $USB_IFACE_NET -m conntrack --ctstate NEW -j ACCEPT -iptables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT -iptables -t nat -F POSTROUTING -iptables -t nat -A POSTROUTING -o $UPSTREAM_IFACE -j MASQUERADE - -echo 1 > /proc/sys/net/ipv4/ip_forward -``` +- If you get `[FAILED] Failed to start Remount Root and Kernel File Systems.` while booting pwnagotchi, make sure +the `PARTUUID`s for `rootfs` and `boot` partitions are the same in `/etc/fstab`. Use `sudo blkid` to find those values when you are using `create_sibling.sh`. ## License diff --git a/create_sibling.sh b/scripts/create_sibling.sh similarity index 62% rename from create_sibling.sh rename to scripts/create_sibling.sh index d0e29dd..6b8ea34 100755 --- a/create_sibling.sh +++ b/scripts/create_sibling.sh @@ -2,15 +2,25 @@ # based on: https://wiki.debian.org/RaspberryPi/qemu-user-static ## and https://z4ziggy.wordpress.com/2015/05/04/from-bochs-to-chroot/ -REQUIREMENTS=( wget gunzip git dd e2fsck resize2fs parted losetup qemu-system-x86_64 ) -SCRIPT_DIR="$(dirname "$(realpath "$0")")" +set -eu -PWNI_NAME="alpha" +REQUIREMENTS=( wget gunzip git dd e2fsck resize2fs parted losetup qemu-system-x86_64 ) +REPO_DIR="$(dirname "$(dirname "$(realpath "$0")")")" +TMP_DIR="${REPO_DIR}/tmp" +MNT_DIR="${TMP_DIR}/mnt" + +PWNI_NAME="pwnagotchi" PWNI_OUTPUT="pwnagotchi.img" PWNI_SIZE="4" OPT_PROVISION_ONLY=0 OPT_CHECK_DEPS_ONLY=0 +OPT_IMAGE_PROVIDED=0 + +if [[ "$EUID" -ne 0 ]]; then + echo "Run this script as root!" + exit 1 +fi function check_dependencies() { echo "[+] Checking dependencies" @@ -27,55 +37,63 @@ function check_dependencies() { fi if ! systemctl is-active systemd-binfmt.service >/dev/null 2>&1; then - sudo mkdir -p "/lib/binfmt.d" - sudo sh -c "echo ':qemu-arm:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00:\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfe\xff\xff\xff:/usr/bin/qemu-arm-static:F' >> /lib/binfmt.d/qemu-arm-static.conf" - sudo systemctl restart systemd-binfmt.service + mkdir -p "/lib/binfmt.d" + echo ':qemu-arm:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00:\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfe\xff\xff\xff:/usr/bin/qemu-arm-static:F' > /lib/binfmt.d/qemu-arm-static.conf + systemctl restart systemd-binfmt.service fi } function get_raspbian() { echo "[+] Downloading raspbian.zip" - mkdir -p "${SCRIPT_DIR}/tmp/" - wget -qcN -O "${SCRIPT_DIR}/tmp/rasbian.zip" "https://downloads.raspberrypi.org/raspbian_lite_latest" + mkdir -p "${TMP_DIR}" + wget --show-progress -qcO "${TMP_DIR}/raspbian.zip" "https://downloads.raspberrypi.org/raspbian_lite_latest" echo "[+] Unpacking raspbian.zip to raspbian.img" - gunzip -c "${SCRIPT_DIR}/tmp/rasbian.zip" > "${SCRIPT_DIR}/tmp/raspbian.img" + gunzip -c "${TMP_DIR}/raspbian.zip" > "${TMP_DIR}/raspbian.img" +} + +function provide_raspbian() { + echo "[+] Providing path of raspbian file" + mkdir -p "${TMP_DIR}" + echo "[+] Unpacking raspbian.zip to raspbian.img" + gunzip -c "${PWNI_INPUT}" > "${TMP_DIR}/raspbian.img" } function setup_raspbian(){ echo "[+] Resize image" - dd if=/dev/zero bs=1G count="$PWNI_SIZE" >> "${SCRIPT_DIR}/tmp/raspbian.img" + dd if=/dev/zero bs=1G count="$PWNI_SIZE" >> "${TMP_DIR}/raspbian.img" echo "[+] Setup loop device" - mkdir -p "${SCRIPT_DIR}/mnt" - LOOP_PATH="$(sudo losetup --find --partscan --show "${SCRIPT_DIR}/tmp/raspbian.img")" - PART2_START="$(sudo parted -s "$LOOP_PATH" -- print | awk '$1==2{ print $2 }')" - sudo parted -s "$LOOP_PATH" rm 2 - sudo parted -s "$LOOP_PATH" mkpart primary "$PART2_START" 100% + mkdir -p "${MNT_DIR}" + LOOP_PATH="$(losetup --find --partscan --show "${TMP_DIR}/raspbian.img")" + PART2_START="$(parted -s "$LOOP_PATH" -- print | awk '$1==2{ print $2 }')" + parted -s "$LOOP_PATH" rm 2 + parted -s "$LOOP_PATH" mkpart primary "$PART2_START" 100% echo "[+] Check FS" - sudo e2fsck -f "${LOOP_PATH}p2" + e2fsck -f "${LOOP_PATH}p2" echo "[+] Resize FS" - sudo resize2fs "${LOOP_PATH}p2" + resize2fs "${LOOP_PATH}p2" echo "[+] Device is ${LOOP_PATH}" echo "[+] Unmount if already mounted with other img" - sudo umount -r "${SCRIPT_DIR}/mnt" || true + mountpoint -q "${MNT_DIR}" && umount -R "${MNT_DIR}" echo "[+] Mount /" - sudo mount -o rw "${LOOP_PATH}p2" "${SCRIPT_DIR}/mnt" + mount -o rw "${LOOP_PATH}p2" "${MNT_DIR}" echo "[+] Mount /boot" - sudo mount -o rw "${LOOP_PATH}p1" "${SCRIPT_DIR}/mnt/boot" - sudo mount --bind /dev "${SCRIPT_DIR}/mnt/dev/" - sudo mount --bind /sys "${SCRIPT_DIR}/mnt/sys/" - sudo mount --bind /proc "${SCRIPT_DIR}/mnt/proc/" - sudo mount --bind /dev/pts "${SCRIPT_DIR}/mnt/dev/pts" - sudo mount --bind /etc/ssl/certs "${SCRIPT_DIR}/mnt/etc/ssl/certs" - sudo mount --bind /etc/ca-certificates "${SCRIPT_DIR}/mnt/etc/ca-certificates" - sudo cp /usr/bin/qemu-arm-static "${SCRIPT_DIR}/mnt/usr/bin" + mount -o rw "${LOOP_PATH}p1" "${MNT_DIR}/boot" + mount --bind /dev "${MNT_DIR}/dev/" + mount --bind /sys "${MNT_DIR}/sys/" + mount --bind /proc "${MNT_DIR}/proc/" + mount --bind /dev/pts "${MNT_DIR}/dev/pts" + mount --bind /etc/ssl/certs "${MNT_DIR}/etc/ssl/certs" + mount --bind /etc/ca-certificates "${MNT_DIR}/etc/ca-certificates" + cp /usr/bin/qemu-arm-static "${MNT_DIR}/usr/bin" } function provision_raspbian() { - cd "${SCRIPT_DIR}/mnt/" || exit 1 - sudo sed -i'' 's/^\([^#]\)/#\1/g' etc/ld.so.preload # add comments + cd "${MNT_DIR}" + sed -i'' 's/^\([^#]\)/#\1/g' etc/ld.so.preload # add comments echo "[+] Run chroot commands" - sudo LANG=C chroot . bin/bash -x < /etc/hostname sed -i "s@^127\.0\.0\.1 .*@127.0.0.1 localhost "$PWNI_NAME" "$PWNI_NAME".local@g" /etc/hosts - sed -i "s@alpha@$PWNI_NAME@g" /etc/motd + sed -i "s@pwnagotchi@$PWNI_NAME@g" /etc/motd chmod +x /etc/rc.local @@ -144,11 +162,11 @@ STOP apt update apt install -y kalipi-kernel kalipi-bootloader kalipi-re4son-firmware kalipi-kernel-headers libraspberrypi0 libraspberrypi-dev libraspberrypi-doc libraspberrypi-bin EOF - sudo sed -i'' 's/^#//g' etc/ld.so.preload - cd "${SCRIPT_DIR}" || exit 1 - sudo umount -R "${SCRIPT_DIR}/mnt/" - sudo losetup -D "$(losetup -l | awk '/raspbian\.img/{print $1}')" - mv "${SCRIPT_DIR}/tmp/raspbian.img" "$PWNI_OUTPUT" + sed -i'' 's/^#//g' etc/ld.so.preload + cd "${REPO_DIR}" + umount -R "${MNT_DIR}" + losetup -D "$(losetup -l | awk '/raspbian\.img/{print $1}')" + mv "${TMP_DIR}/raspbian.img" "$PWNI_OUTPUT" } function usage() { @@ -157,11 +175,12 @@ function usage() { usage: $0 [OPTIONS] Options: - -n # Name of the pwnagotchi (default: alpha) + -n # Name of the pwnagotchi (default: pwnagotchi) + -i # Provide the path of an already downloaded raspbian image -o # Name of the img-file (default: pwnagotchi.img) -s # Size which should be added to second partition (in Gigabyte) (default: 4) -p # Only run provisioning (assumes the image is already mounted) - -p # Only run dependencies checks + -d # Only run dependencies checks -h # Show this help EOF @@ -169,11 +188,15 @@ EOF exit 0 } -while getopts ":n:o:s:dph" o; do +while getopts ":n:i:o:s:dph" o; do case "${o}" in n) PWNI_NAME="${OPTARG}" ;; + i) + PWNI_INPUT="${OPTARG}" + OPT_IMAGE_PROVIDED=1 + ;; o) PWNI_OUTPUT="${OPTARG}" ;; @@ -205,7 +228,13 @@ elif [[ "$OPT_CHECK_DEPS_ONLY" -eq 1 ]]; then fi check_dependencies -get_raspbian + +if [[ "$OPT_IMAGE_PROVIDED" -eq 1 ]]; then + provide_raspbian +else + get_raspbian +fi + setup_raspbian provision_raspbian diff --git a/scripts/linux_connection_share.sh b/scripts/linux_connection_share.sh new file mode 100755 index 0000000..57fe718 --- /dev/null +++ b/scripts/linux_connection_share.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +# name of the ethernet gadget interface on the host +USB_IFACE=${1:-enp0s20f0u1} +USB_IFACE_IP=10.0.0.1 +USB_IFACE_NET=10.0.0.0/24 +# host interface to use for upstream connection +UPSTREAM_IFACE=${2:-enxe4b97aa99867} + +ip addr add $USB_IFACE_IP/24 dev $USB_IFACE +ip link set $USB_IFACE up + +iptables -A FORWARD -o $UPSTREAM_IFACE -i $USB_IFACE -s $USB_IFACE_NET -m conntrack --ctstate NEW -j ACCEPT +iptables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT +iptables -t nat -F POSTROUTING +iptables -t nat -A POSTROUTING -o $UPSTREAM_IFACE -j MASQUERADE + +echo 1 > /proc/sys/net/ipv4/ip_forward diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/voice.py b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/voice.py index c92be18..714d315 100644 --- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/voice.py +++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/voice.py @@ -35,7 +35,7 @@ def on_bored(): def on_motivated(reward): - return 'This is best day\nof my life!' + return 'This is the best\nday of my life!' def on_demotivated(reward): diff --git a/sdcard/rootfs/usr/bin/cpuusage b/sdcard/rootfs/usr/bin/cpuusage new file mode 100755 index 0000000..ea9e63a --- /dev/null +++ b/sdcard/rootfs/usr/bin/cpuusage @@ -0,0 +1,51 @@ +#!/usr/bin/gawk -f +#------------------------------------------------------------------------------- +# ~/bin/cpustat : display cpu utilization +# +# usage : normally used as a GNU/screen backtick +# +# notes : 1. Works on the assumption that /proc/stat's first line +# : has the total "jiffies" since boot up used by the +# : different types of tasks in the system. See the +# : filesystems/proc.txt document in kernel source tree +# : +# : 2. Displays a total CPU% (user+system+nice) as well as +# : user CPU% system CPU% and nice CPU% +#------------------------------------------------------------------------------- +BEGIN { + file = "/proc/stat" + while (getline < file) { # read first line + # extract jiffies: + user=$2-user_saved; # . user + nice=$3-nice_saved; # . nice user + syst=$4-syst_saved; # . system + idle=$5-idle_saved; # . idle + wait=$6-wait_saved; # . iowait + irqs=$7-irqs_saved; # . irq + sirq=$8-sirq_saved; # . softirq + + cact=user+syst+nice; # what counts + ctot=user+nice+syst+idle+wait+irqs+sirq; # total activity + + tcpu=cact/ctot*100; # total % cpu utilization + ucpu=user/ctot*100; # user % cpu utilization + scpu=syst/ctot*100; # system % cpu utilization + ncpu=nice/ctot*100; # nice % cpu utilization + + printf "%.1f %%\n",tcpu + + + user_saved=$2; # save the current jiffies + nice_saved=$3; # values for the next loop + syst_saved=$4; + idle_saved=$5; + wait_saved=$6; + irqs_saved=$7; + sirq_saved=$8; + + close(file) # re-read file + + system("sleep 3") + } +} + diff --git a/sdcard/rootfs/usr/bin/memusage b/sdcard/rootfs/usr/bin/memusage new file mode 100755 index 0000000..14efdb1 --- /dev/null +++ b/sdcard/rootfs/usr/bin/memusage @@ -0,0 +1 @@ +free -m | grep Mem | awk {'printf( "%.1f %", $3 / $2 * 100 )'} diff --git a/sdcard/rootfs/usr/bin/monstart b/sdcard/rootfs/usr/bin/monstart new file mode 100755 index 0000000..112c65e --- /dev/null +++ b/sdcard/rootfs/usr/bin/monstart @@ -0,0 +1,2 @@ +#!/bin/bash +iw phy phy0 interface add mon0 type monitor && ifconfig mon0 up diff --git a/sdcard/rootfs/usr/bin/monstop b/sdcard/rootfs/usr/bin/monstop new file mode 100755 index 0000000..8ca7f89 --- /dev/null +++ b/sdcard/rootfs/usr/bin/monstop @@ -0,0 +1,2 @@ +#!/bin/bash +ifconfig mon0 down && iw dev mon0 del