This uses https://github.com/intel/bmap-tools to generate a .bmap file which can be copied around. The bmaptool allows storing sparse files onto for instance an SD card, thus avoiding having to transfer the full disk image every time one burns one. Thus saving lots of time (and SD card cycles). This also adds some instructions for then transfering and copying the sparse file. bmaptool: info: discovered bmap file '/Users/jeroen/berry.img.bmap' bmaptool: info: block map format version 2.0 bmaptool: info: 7324219 blocks of size 4096 (27.9 GiB), mapped 1539940 blocks (5.9 GiB or 21.0%) bmaptool: info: copying image 'berry.img' to file 'rdisk4' using bmap file 'berry.img.bmap' bmaptool: info: 100% copied bmaptool: info: synchronizing '/dev/rdisk4' bmaptool: info: copying time: 6m 49.7s, copying speed 14.7 MiB/sec versus copying the whole 30G which would take forever...
340 lines
11 KiB
Bash
Executable File
340 lines
11 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# based on: https://wiki.debian.org/RaspberryPi/qemu-user-static
|
|
## and https://z4ziggy.wordpress.com/2015/05/04/from-bochs-to-chroot/
|
|
|
|
set -eu
|
|
|
|
REQUIREMENTS=( wget gunzip git dd e2fsck resize2fs parted losetup qemu-system-x86_64 )
|
|
DEBREQUIREMENTS=( wget gzip git parted qemu-system-x86 qemu-user-static parted bmap-tools )
|
|
REPO_DIR="$(dirname "$(dirname "$(realpath "$0")")")"
|
|
TMP_DIR="${REPO_DIR}/tmp"
|
|
MNT_DIR="${TMP_DIR}/mnt"
|
|
THIS_DIR=$(pwd)
|
|
|
|
PWNI_NAME="pwnagotchi"
|
|
PWNI_OUTPUT="pwnagotchi.img"
|
|
PWNI_SIZE="4"
|
|
|
|
OPT_SPARSE=0
|
|
OPT_PROVISION_ONLY=0
|
|
OPT_CHECK_DEPS_ONLY=0
|
|
OPT_IMAGE_PROVIDED=0
|
|
OPT_RASPBIAN_VERSION='latest'
|
|
|
|
SUPPORTED_RASPBIAN_VERSIONS=( 'latest' 'buster' 'stretch' )
|
|
|
|
if [[ "$EUID" -ne 0 ]]; then
|
|
echo "Run this script as root!"
|
|
exit 1
|
|
fi
|
|
|
|
function check_dependencies() {
|
|
if [ -f /etc/debian_version ];
|
|
then
|
|
echo "[+] Checking Debian dependencies"
|
|
|
|
for REQ in "${DEBREQUIREMENTS[@]}"; do
|
|
if ! dpkg -s "$REQ" >/dev/null 2>&1; then
|
|
echo "Dependency check failed for ${REQ}; use 'apt-get install ${REQ}' to install"
|
|
exit 1
|
|
fi
|
|
done
|
|
fi
|
|
|
|
echo "[+] Checking dependencies"
|
|
for REQ in "${REQUIREMENTS[@]}"; do
|
|
if ! type "$REQ" >/dev/null 2>&1; then
|
|
echo "Dependency check failed for ${REQ}"
|
|
exit 1
|
|
fi
|
|
done
|
|
|
|
if ! test -e /usr/bin/qemu-arm-static; then
|
|
echo "[-] You need the package \"qemu-user-static\" for this to work."
|
|
exit 1
|
|
fi
|
|
|
|
if ! systemctl is-active systemd-binfmt.service >/dev/null 2>&1; then
|
|
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() {
|
|
VERSION="$1"
|
|
|
|
case "$VERSION" in
|
|
latest)
|
|
URL="https://downloads.raspberrypi.org/raspbian_lite_latest"
|
|
;;
|
|
buster)
|
|
URL="https://downloads.raspberrypi.org/raspbian/images/raspbian-2019-07-12/2019-07-10-raspbian-buster.zip"
|
|
;;
|
|
stretch)
|
|
URL="https://downloads.raspberrypi.org/raspbian/images/raspbian-2019-04-09/2019-04-08-raspbian-stretch.zip"
|
|
;;
|
|
esac
|
|
|
|
echo "[+] Downloading raspbian.zip"
|
|
mkdir -p "${TMP_DIR}"
|
|
wget --show-progress -qcO "${TMP_DIR}/raspbian.zip" "$URL"
|
|
echo "[+] Unpacking raspbian.zip to 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(){
|
|
# Detect the ability to create sparse files
|
|
if [ "${OPT_SPARSE}" -eq 0 ];
|
|
then
|
|
which bmaptool >/dev/null 2>&1
|
|
if [ $? -eq 0 ];
|
|
then
|
|
echo "[+] Defaulting to sparse image generation as bmaptool is available"
|
|
OPT_SPARSE=1
|
|
else
|
|
echo "[!] bmaptool not available, not creating a sparse image"
|
|
fi
|
|
fi
|
|
|
|
# Note that we 'extend' the raspbian.img
|
|
if [ "${OPT_SPARSE}" -eq 1 ];
|
|
then
|
|
# Resize sparse (so that we can use bmaptool later)
|
|
echo "[+] Resizing sparse image of ${PWNI_SIZE}GB (1000s)"
|
|
truncate -s ${PWNI_SIZE}GB "${TMP_DIR}/raspbian.img"
|
|
else
|
|
echo "[+] Resizing full image to ${PWNI_SIZE}G"
|
|
# Full disk-space using image (appends to raspbian image)
|
|
dd if=/dev/zero bs=1G count="${PWNI_SIZE}" >> "${TMP_DIR}/raspbian.img"
|
|
fi
|
|
|
|
echo "[+] Setup loop device"
|
|
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"
|
|
e2fsck -y -f "${LOOP_PATH}p2"
|
|
echo "[+] Resize FS"
|
|
resize2fs "${LOOP_PATH}p2"
|
|
echo "[+] Device is ${LOOP_PATH}"
|
|
echo "[+] Unmount if already mounted with other img"
|
|
mountpoint -q "${MNT_DIR}" && umount -R "${MNT_DIR}"
|
|
echo "[+] Mount /"
|
|
mount -o rw "${LOOP_PATH}p2" "${MNT_DIR}"
|
|
echo "[+] Mount /boot"
|
|
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"
|
|
cp /usr/bin/qemu-arm-static "${MNT_DIR}/usr/bin"
|
|
cp /etc/resolv.conf "${MNT_DIR}/etc/resolv.conf"
|
|
}
|
|
|
|
function provision_raspbian() {
|
|
cd "${MNT_DIR}"
|
|
sed -i'' 's/^\([^#]\)/#\1/g' etc/ld.so.preload # add comments
|
|
echo "[+] Run chroot commands"
|
|
LANG=C LC_ALL=C LC_CTYPE=C chroot . bin/bash -x <<EOF
|
|
set -eu
|
|
export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
|
|
|
uname -a
|
|
|
|
apt-get -y update
|
|
apt-get -y upgrade
|
|
apt-get -y install git vim screen build-essential golang python3-pip gawk
|
|
apt-get -y install libpcap-dev libusb-1.0-0-dev libnetfilter-queue-dev
|
|
apt-get -y install dphys-swapfile libopenmpi-dev libatlas-base-dev
|
|
apt-get -y install libjasper-dev libqtgui4 libqt4-test libopenjp2-7
|
|
apt-get -y install tcpdump libilmbase23 libopenexr23 libgstreamer1.0-0
|
|
apt-get -y install libavcodec58 libavformat58 libswscale5
|
|
|
|
# setup dphys-swapfile
|
|
echo "CONF_SWAPSIZE=1024" >/etc/dphys-swapfile
|
|
systemctl enable dphys-swapfile.service
|
|
|
|
# install pwnagotchi
|
|
cd /tmp
|
|
git clone https://github.com/evilsocket/pwnagotchi.git
|
|
rsync -aP pwnagotchi/sdcard/boot/* /boot/
|
|
rsync -aP pwnagotchi/sdcard/rootfs/* /
|
|
rm -rf /tmp/pwnagotchi
|
|
|
|
# configure pwnagotchi
|
|
echo -e "$PWNI_NAME" > /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
|
|
|
|
chmod +x /etc/rc.local
|
|
|
|
# need armv6l version of tensorflow and opencv-python, not armv7l
|
|
# PIP_OPTS="--upgrade --only-binary :all: --abi cp37m --platform linux_armv6l --target /usr/lib/python3.7/site-packages/"
|
|
# pip3 install \$PIP_OPTS opencv-python
|
|
# Should work for tensorflow too, but BUG: Hash mismatch; therefore:
|
|
wget -P /root/ -c https://www.piwheels.org/simple/tensorflow/tensorflow-1.13.1-cp37-none-linux_armv6l.whl
|
|
wget -P /root/ -c https://www.piwheels.org/simple/opencv-python/opencv_python-3.4.3.18-cp37-cp37m-linux_armv6l.whl
|
|
# we need to install these on first raspberry start...
|
|
sed -i '/startup\.sh/i pip3 install --no-deps --force-reinstall --upgrade /root/tensorflow-1.13.1-cp37-none-linux_armv6l.whl /root/opencv_python-3.4.3.18-cp37-cp37m-linux_armv6l.whl && rm /root/tensorflow-1.13.1-cp37-none-linux_armv6l.whl /root/opencv_python-3.4.3.18-cp37-cp37m-linux_armv6l.whl && sed -i "/tensorflow/d" /etc/rc.local' /etc/rc.local
|
|
|
|
# newer version is broken
|
|
pip3 install gast==0.2.2
|
|
|
|
</root/pwnagotchi/scripts/requirements.txt xargs -I{} --max-args=1 --max-procs="$(nproc)"\
|
|
pip3 install --progress-bar off {}
|
|
|
|
# waveshare
|
|
pip3 install spidev RPi.GPIO
|
|
|
|
# install bettercap
|
|
export GOPATH=/root/go
|
|
go get -u github.com/bettercap/bettercap
|
|
mv "\$GOPATH/bin/bettercap" /usr/bin/bettercap
|
|
|
|
# install bettercap caplets (cant run bettercap in chroot)
|
|
cd /tmp
|
|
git clone https://github.com/bettercap/caplets.git
|
|
cd caplets
|
|
make install
|
|
rm -rf /tmp/caplets
|
|
cd /root # fixes getcwd error that was bugging me
|
|
|
|
# Re4son-Kernel
|
|
echo "deb http://http.re4son-kernel.com/re4son/ kali-pi main" > /etc/apt/sources.list.d/re4son.list
|
|
wget -O - https://re4son-kernel.com/keys/http/archive-key.asc | apt-key add -
|
|
apt update
|
|
apt install -y kalipi-kernel kalipi-bootloader kalipi-re4son-firmware kalipi-kernel-headers libraspberrypi0 libraspberrypi-dev libraspberrypi-doc libraspberrypi-bin
|
|
|
|
# Fix PARTUUID
|
|
PUUID_ROOT="\$(blkid "\$(df / --output=source | tail -1)" | grep -Po 'PARTUUID="\K[^"]+')"
|
|
PUUID_BOOT="\$(blkid "\$(df /boot --output=source | tail -1)" | grep -Po 'PARTUUID="\K[^"]+')"
|
|
|
|
# sed regex info: search for line containing / followed by whitespace or /boot (second sed)
|
|
# in this line, search for PARTUUID= followed by letters, numbers or "-"
|
|
# replace that match with the new PARTUUID
|
|
sed -i "/\/[ ]\+/s/PARTUUID=[A-Za-z0-9-]\+/PARTUUID=\$PUUID_ROOT/g" /etc/fstab
|
|
sed -i "/\/boot/s/PARTUUID=[A-Za-z0-9-]\+/PARTUUID=\$PUUID_BOOT/g" /etc/fstab
|
|
|
|
sed -i "s/root=[^ ]\+/root=PARTUUID=\${PUUID_ROOT}/g" /boot/cmdline.txt
|
|
|
|
# delete keys
|
|
find /etc/ssh/ -name "ssh_host_*key*" -delete
|
|
|
|
# slows down boot
|
|
systemctl disable apt-daily.timer apt-daily.service apt-daily-upgrade.timer apt-daily-upgrade.service
|
|
|
|
# unecessary services
|
|
systemctl disable triggerhappy bluetooth wpa_supplicant
|
|
|
|
EOF
|
|
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}"
|
|
if [ "${OPT_SPARSE}" -eq 1 ];
|
|
then
|
|
bmaptool create -o "${PWNI_OUTPUT}.bmap" "${PWNI_OUTPUT}"
|
|
fi
|
|
}
|
|
|
|
function usage() {
|
|
cat <<EOF
|
|
|
|
usage: $0 [OPTIONS]
|
|
|
|
Options:
|
|
-n <name> # Name of the pwnagotchi (default: pwnagotchi)
|
|
-i <file> # Provide the path of an already downloaded raspbian image
|
|
-o <file> # Name of the img-file (default: pwnagotchi.img)
|
|
-s <size> # Size which should be added to second partition (in Gigabyte) (default: 4)
|
|
-S # Create a sparse image and generate bmap file (default when bmaptool is available)
|
|
-v <version> # Version of raspbian (Supported: ${SUPPORTED_RASPBIAN_VERSIONS[*]}; default: latest)
|
|
-p # Only run provisioning (assumes the image is already mounted)
|
|
-d # Only run dependencies checks
|
|
-h # Show this help
|
|
|
|
EOF
|
|
|
|
exit 0
|
|
}
|
|
|
|
while getopts ":n:i:o:s:v:dph" o; do
|
|
case "${o}" in
|
|
n)
|
|
PWNI_NAME="${OPTARG}"
|
|
;;
|
|
i)
|
|
PWNI_INPUT="${OPTARG}"
|
|
OPT_IMAGE_PROVIDED=1
|
|
;;
|
|
o)
|
|
PWNI_OUTPUT="${OPTARG}"
|
|
;;
|
|
s)
|
|
PWNI_SIZE="${OPTARG}"
|
|
;;
|
|
p)
|
|
OPT_PROVISION_ONLY=1
|
|
;;
|
|
d)
|
|
OPT_CHECK_DEPS_ONLY=1
|
|
;;
|
|
v)
|
|
if [[ "${SUPPORTED_RASPBIAN_VERSIONS[*]}" =~ ${OPTARG} ]]; then
|
|
OPT_RASPBIAN_VERSION="${OPTARG}"
|
|
else
|
|
usage
|
|
fi
|
|
;;
|
|
h)
|
|
usage
|
|
;;
|
|
*)
|
|
usage
|
|
;;
|
|
esac
|
|
done
|
|
shift $((OPTIND-1))
|
|
|
|
if [[ "$OPT_PROVISION_ONLY" -eq 1 ]]; then
|
|
provision_raspbian
|
|
exit 0
|
|
elif [[ "$OPT_CHECK_DEPS_ONLY" -eq 1 ]]; then
|
|
check_dependencies
|
|
exit 0
|
|
fi
|
|
|
|
check_dependencies
|
|
|
|
if [[ "$OPT_IMAGE_PROVIDED" -eq 1 ]]; then
|
|
provide_raspbian
|
|
else
|
|
get_raspbian "$OPT_RASPBIAN_VERSION"
|
|
fi
|
|
|
|
setup_raspbian
|
|
provision_raspbian
|
|
|
|
echo -e "[+] Congratz, it's a boy (⌐■_■)!"
|
|
echo -e "[+] One more step: dd if=../${PWNI_OUTPUT} of=<PATH_TO_SDCARD> bs=4M status=progress"
|
|
|
|
if [ "${OPT_SPARSE}" -eq 1 ];
|
|
then
|
|
echo -e "[t] To transfer use: rsync -vaS --progress $(whoami)@$(hostname -f):${THIS_DIR}/../${PWNI_OUTPUT} <DEST>"
|
|
echo -e "[t] To burn with bmaptool: bmaptool copy ~/${PWNI_OUTPUT} /dev/<DEVICE>"
|
|
fi
|
|
|
|
# Helpful OSX reminder
|
|
echo -e "[t] Mac: use 'diskutil list' to figure out which device to burn to; 'diskutil unmountDisk' to unmount that disk'; then use /dev/rdiskX (note the 'r') for faster transfer"
|