diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a78e0d2..2be655f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,6 +1,7 @@ +--- name: CI -on: +"on": push: branches: - master @@ -32,15 +33,33 @@ jobs: run: docker build -t etherjack-ci -f tests/Dockerfile . # -------------------------------------------------------------------------- - # ShellCheck — static analysis on all scripts - # The .shellcheckrc in the repo root suppresses SC1091/SC2154 which are - # false positives caused by inter-script variable sourcing. + # Lint — ShellCheck on all scripts and bats tests, yamllint on workflows, + # shfmt to enforce consistent indentation (catches mixed tabs/spaces). + # .shellcheckrc suppresses SC1091/SC2154 (false positives from sourcing) + # .yamllint.yml holds the shared rule config used locally and here # -------------------------------------------------------------------------- - name: ShellCheck run: | - docker run --rm -v "$PWD:/etherjack" etherjack-ci \ - bash -c 'find /etherjack -name "*.sh" -not -path "/etherjack/.git/*" \ - | xargs shellcheck --severity=error' + docker run --rm -v "$PWD:/etherjack" etherjack-ci bash -c ' + find /etherjack \( -name "*.sh" -o -name "*.bats" \) \ + -not -path "/etherjack/.git/*" \ + | xargs shellcheck --severity=warning + ' + + - name: shfmt + run: | + docker run --rm -v "$PWD:/etherjack" etherjack-ci bash -c ' + find /etherjack \( -name "*.sh" -o -name "*.bats" \) \ + -not -path "/etherjack/.git/*" \ + | xargs shfmt -d -i 4 + ' + + - name: yamllint + run: | + docker run --rm -v "$PWD:/etherjack" etherjack-ci bash -c ' + find /etherjack/.github -name "*.yml" \ + | xargs yamllint -c /etherjack/.yamllint.yml + ' # -------------------------------------------------------------------------- # BATS unit / integration tests diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 4c8eadf..957ba98 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,6 +1,7 @@ +--- name: Release -on: +"on": push: tags: - 'v[0-9]+.[0-9]+.[0-9]+' diff --git a/.yamllint.yml b/.yamllint.yml new file mode 100644 index 0000000..9c5ec51 --- /dev/null +++ b/.yamllint.yml @@ -0,0 +1,5 @@ +--- +extends: default +rules: + line-length: + max: 120 diff --git a/EtherJack.sh b/EtherJack.sh index c40fa66..fbef94f 100755 --- a/EtherJack.sh +++ b/EtherJack.sh @@ -7,33 +7,33 @@ source EtherJack.conf case $EJMODE in - lan|LAN) - mkdir $EJPATH/lan/$ENGAGEMENT - cd $EJPATH/lan/$ENGAGEMENT - cat $EJPATH/files/ejmotd >>$EJLOG - echo "Running EJ in LAN Mode" >>$EJLOG - echo "Setting up Engagement Folder" >>$EJLOG - echo "Starting netfinder.sh" >>$EJLOG - $EJPATH/lan/netfinder.sh - ;; - wifi|WIFI|WiFi) - mkdir $EJPATH/wifi/$ENGAGEMENT - cd $EJPATH/wifi/$ENGAGEMENT - cat $EJPATH/files/ejmotd >>$EJLOG - echo "Running EJ in WiFi Mode" >>$EJLOG - echo "Setting up Engagement Folder" >>$EJLOG - $EJPATH/wifi/wifi.sh - ;; - preset|PRESET) - mkdir $EJPATH/preset/$ENGAGEMENT - cd $EJPATH/preset/$ENGAGEMENT - cat $EJPATH/files/ejmotd >>$EJLOG - echo "Running EJ in preset mode" >>$EJLOG - echo "Setting up Engagement Folder" >>$EJLOG - $EJPATH/preset/preset.sh - ;; - *) - echo "Invalid mode defined. Shutting system down!!" - init 0 - ;; +lan | LAN) + mkdir $EJPATH/lan/$ENGAGEMENT + cd $EJPATH/lan/$ENGAGEMENT || exit + cat $EJPATH/files/ejmotd >>$EJLOG + echo "Running EJ in LAN Mode" >>$EJLOG + echo "Setting up Engagement Folder" >>$EJLOG + echo "Starting netfinder.sh" >>$EJLOG + $EJPATH/lan/netfinder.sh + ;; +wifi | WIFI | WiFi) + mkdir $EJPATH/wifi/$ENGAGEMENT + cd $EJPATH/wifi/$ENGAGEMENT || exit + cat $EJPATH/files/ejmotd >>$EJLOG + echo "Running EJ in WiFi Mode" >>$EJLOG + echo "Setting up Engagement Folder" >>$EJLOG + $EJPATH/wifi/wifi.sh + ;; +preset | PRESET) + mkdir $EJPATH/preset/$ENGAGEMENT + cd $EJPATH/preset/$ENGAGEMENT || exit + cat $EJPATH/files/ejmotd >>$EJLOG + echo "Running EJ in preset mode" >>$EJLOG + echo "Setting up Engagement Folder" >>$EJLOG + $EJPATH/preset/preset.sh + ;; +*) + echo "Invalid mode defined. Shutting system down!!" + init 0 + ;; esac diff --git a/dev/Dockerfile b/dev/Dockerfile new file mode 100644 index 0000000..46e7bb3 --- /dev/null +++ b/dev/Dockerfile @@ -0,0 +1,29 @@ +FROM --platform=linux/arm/v7 kalilinux/kali-rolling + +ARG DEBIAN_FRONTEND=noninteractive + +# All tools EtherJack scripts call at runtime +RUN apt-get update && apt-get install -y --no-install-recommends \ + bash \ + tshark \ + tcpdump \ + nmap \ + macchanger \ + iproute2 \ + net-tools \ + iptables \ + iputils-arping \ + hostapd \ + dnsmasq \ + iw \ + rfkill \ + openssh-server \ + procps \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + +COPY entrypoint.sh /entrypoint.sh +RUN chmod +x /entrypoint.sh + +WORKDIR /usr/local/EtherJack +ENTRYPOINT ["/entrypoint.sh"] diff --git a/dev/README.md b/dev/README.md new file mode 100644 index 0000000..bcce7e2 --- /dev/null +++ b/dev/README.md @@ -0,0 +1,97 @@ +# EtherJack ARM Dev Environment + +Runs EtherJack on an emulated ARMv7 (Raspberry Pi Zero W) environment inside Docker using QEMU user-static. Lets you edit scripts on your host and test them instantly without physical hardware. + +## Requirements + +- Docker +- x86/amd64 host (Linux or Mac with Rosetta) + +QEMU ARM support is registered automatically on first run. + +## Usage + +From the repo root: + +```sh +bash dev/run.sh +``` + +This will: +1. Register QEMU ARM binfmt handlers if not already present +2. Build the `etherjack-dev` Docker image (cached after first build) +3. Drop you into an interactive ARM shell at `/usr/local/EtherJack` + +The repo is bind-mounted, so any edits you make on the host are reflected immediately — no rebuild needed. + +## Inside the container + +``` + ARM dev environment — armv7l + + Interfaces: + eth0@eth0-peer UP ... + eth0-peer@eth0 UP ... + wlan0 UP ... + + Repo mounted at : /usr/local/EtherJack + Current EJMODE : EJMODE=preset +``` + +### Running EtherJack + +```sh +# Edit the mode if needed +nano EtherJack.conf # set EJMODE=lan | wifi | preset + +bash EtherJack.sh +``` + +### Interface layout + +| Interface | Purpose | +|------------|---------| +| `eth0` | EtherJack's interface — what the scripts see | +| `eth0-peer`| The veth peer — available if you want to inject traffic manually | +| `wlan0` | Dummy interface for WIFI mode config and iptables rules | + +On real Pi hardware, `eth0` would have live LAN traffic as soon as the device is plugged in. In this environment that traffic is absent — see known limitations below. + +### Scripted / non-interactive use + +Pass a command as an argument to `run.sh` via Docker directly: + +```sh +docker run --rm --platform linux/arm/v7 --privileged --network=none \ + -v "$PWD:/usr/local/EtherJack" \ + etherjack-dev bash -c 'bash EtherJack.sh' +``` + +## Known limitations + +### tshark / tcpdump — live capture does not work + +QEMU user-static does not fully emulate `AF_PACKET` socket operations required by libpcap. Both `tshark` and `tcpdump` will fail to open a capture session on `eth0`: + +``` +setsockopt (PACKET_ADD_MEMBERSHIP): Protocol not available +``` + +**Impact:** `netfinder.sh` will not collect IP addresses from ARP traffic. +**Workaround:** Use the BATS test suite (`bash dev/run-tests.sh` or CI) to unit-test capture logic with mocked commands. + +### hostapd — will not bind to wlan0 + +`hostapd` requires a real wireless driver with AP mode support. The dummy `wlan0` interface satisfies everything *except* the actual bind. WIFI mode will run through its full setup (IP configuration, iptables rules, dnsmasq) and then print a hostapd error. + +### init is intercepted + +EtherJack calls `init 0` on an unrecognised `EJMODE`. Inside the container this would kill the shell. A stub `init` in `/dev-bin` intercepts the call and prints a message instead, so the container stays alive. + +## Rebuilding the image + +Only needed after changing `dev/Dockerfile` or `dev/entrypoint.sh`: + +```sh +docker build --platform linux/arm/v7 -t etherjack-dev -f dev/Dockerfile dev/ +``` diff --git a/dev/entrypoint.sh b/dev/entrypoint.sh new file mode 100755 index 0000000..dc33a9c --- /dev/null +++ b/dev/entrypoint.sh @@ -0,0 +1,88 @@ +#!/bin/bash + +# --------------------------------------------------------------------------- +# EtherJack dev environment entrypoint +# +# Sets up a virtual eth0 using a veth pair and a dummy wlan0, then drops +# to an interactive bash shell so you can run / edit EtherJack scripts +# without real Pi hardware. +# +# Known limitations (QEMU user-static on x86): +# tshark/tcpdump — AF_PACKET socket operations are not fully emulated; +# live packet capture fails. netfinder.sh will not collect IPs. +# Use the BATS test suite for unit testing capture logic. +# hostapd — needs a real wireless driver; WIFI mode starts but +# hostapd will fail to bind. The rest of wifi.sh runs fine. +# init 0 — intercepted so the container isn't killed on an invalid +# EJMODE value. +# --------------------------------------------------------------------------- + +echo "" +echo " ███████╗████████╗██╗ ██╗███████╗██████╗ ██╗ █████╗ ██████╗██╗ ██╗" +echo " ██╔════╝╚══██╔══╝██║ ██║██╔════╝██╔══██╗ ██║██╔══██╗██╔════╝██║ ██╔╝" +echo " █████╗ ██║ ███████║█████╗ ██████╔╝ ██║███████║██║ █████╔╝ " +echo " ██╔══╝ ██║ ██╔══██║██╔══╝ ██╔══██╗██ ██║██╔══██║██║ ██╔═██╗ " +echo " ███████╗ ██║ ██║ ██║███████╗██║ ██║╚█████╔╝██║ ██║╚██████╗██║ ██╗" +echo " ╚══════╝ ╚═╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝ ╚════╝ ╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝" +echo "" +echo " ARM dev environment — $(uname -m)" +echo "" + +# --------------------------------------------------------------------------- +# Intercept init so invalid/empty EJMODE doesn't kill the container +# --------------------------------------------------------------------------- +mkdir -p /dev-bin +cat >/dev-bin/init <<'EOF' +#!/bin/bash +echo "[dev] init $* called — ignoring shutdown in dev environment" +EOF +chmod +x /dev-bin/init +export PATH="/dev-bin:$PATH" + +# --------------------------------------------------------------------------- +# Virtual eth0 via veth pair +# eth0 — EtherJack's interface (what the scripts see) +# eth0-peer — available if you want to inject traffic manually +# --------------------------------------------------------------------------- +ip link add eth0 type veth peer name eth0-peer 2>/dev/null || true +ip link set eth0 up 2>/dev/null || true +ip link set eth0-peer up 2>/dev/null || true + +# --------------------------------------------------------------------------- +# Dummy wlan0 (enough for wifi.sh to configure IP / iptables rules; +# hostapd will fail to bind — that's a known dev limitation) +# --------------------------------------------------------------------------- +ip link add wlan0 type dummy 2>/dev/null || true +ip link set wlan0 up 2>/dev/null || true + +echo " ##############################################################" +echo " # KNOWN DEV LIMITATIONS #" +echo " ##############################################################" +echo " tshark/tcpdump — live capture fails (QEMU AF_PACKET limitation)." +echo " On real hardware eth0 would have live LAN traffic." +echo " hostapd — needs a real wireless driver; won't bind to wlan0." +echo " ##############################################################" +echo "" +echo " ##############################################################" +echo " # INTERFACES #" +echo " ##############################################################" +ip -brief link 2>/dev/null || true +echo "" +echo " ##############################################################" +echo " # ENVIRONMENT INFO #" +echo " ##############################################################" +echo " Repo mounted at : /usr/local/EtherJack" +echo " Current EJMODE : $(grep '^EJMODE=' /usr/local/EtherJack/EtherJack.conf 2>/dev/null || echo 'not set')" +echo "" +echo " To run EtherJack (on real hardware this starts automatically on boot):" +echo " cd /usr/local/EtherJack && bash EtherJack.sh" +echo "" + +# Pass through any arguments (e.g. bash -c '...' for scripted use); +# default to an interactive shell (not --login; avoids Kali profile scripts +# that can hang or suppress the prompt in the ARM QEMU environment) +if [ $# -gt 0 ]; then + exec "$@" +else + exec bash -i +fi diff --git a/dev/run.sh b/dev/run.sh new file mode 100755 index 0000000..57e0750 --- /dev/null +++ b/dev/run.sh @@ -0,0 +1,40 @@ +#!/bin/bash +set -e + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" + +# --------------------------------------------------------------------------- +# Ensure QEMU ARM binfmt handlers are registered so Docker can run arm/v7 +# images on this x86 host. This is a one-time no-op after first run. +# --------------------------------------------------------------------------- +if ! grep -rq "arm" /proc/sys/fs/binfmt_misc/ 2>/dev/null; then + echo "[run] Registering QEMU ARM binfmt handlers..." + docker run --rm --privileged multiarch/qemu-user-static --reset -p yes +else + echo "[run] QEMU ARM binfmt already registered." +fi + +# --------------------------------------------------------------------------- +# Build the dev image (cached after first build) +# --------------------------------------------------------------------------- +echo "[run] Building ARM dev image..." +docker build \ + --platform linux/arm/v7 \ + -t etherjack-dev \ + -f "$SCRIPT_DIR/Dockerfile" \ + "$SCRIPT_DIR" + +# --------------------------------------------------------------------------- +# Launch the container +# --privileged needed for ip link / iptables inside the container +# -v mount the live repo so edits on the host take effect +# immediately — no rebuild required +# --------------------------------------------------------------------------- +echo "[run] Launching EtherJack ARM dev environment..." +docker run --rm -it \ + --platform linux/arm/v7 \ + --privileged \ + --network=none \ + -v "$REPO_ROOT:/usr/local/EtherJack" \ + etherjack-dev diff --git a/lan/netfinder.sh b/lan/netfinder.sh index c015127..243daf2 100755 --- a/lan/netfinder.sh +++ b/lan/netfinder.sh @@ -22,11 +22,11 @@ echo "nameserver 8.8.8.8" >/etc/resolv.conf # Disable ipv6 on eth0 echo "Ensuring ipv6 is disabled" >>$EJLOG if grep -q "net.ipv6.conf.all.disable_ipv6 = 1" /etc/sysctl.conf; then - echo "IPV6 already disabled" >>$EJLOG + echo "IPV6 already disabled" >>$EJLOG else - echo "Disabling IPV6" >>$EJLOG - echo "net.ipv6.conf.all.disable_ipv6 = 1" >>/etc/sysctl.conf - sysctl -p + echo "Disabling IPV6" >>$EJLOG + echo "net.ipv6.conf.all.disable_ipv6 = 1" >>/etc/sysctl.conf + sysctl -p fi echo "Bringing up eth0" >>$EJLOG ifconfig eth0 up @@ -48,7 +48,10 @@ grep -v -e "tshark" -e "Running" $MAC_ADDR | sort -rn | uniq >$MAC_ADDR_UNIQ awk -F \: '{print $1":"$2":"$3}' $MAC_ADDR_UNIQ | sort -rn | uniq >$MAC_ADDR_OUI_UNIQ echo "Generating a mac address using most common OUI to blend into network" >>$EJLOG MY_OUI=$(head -1 $MAC_ADDR_OUI_UNIQ) -OCT1=$(tr -dc a-f >$EJLOG @@ -60,113 +63,113 @@ ifconfig eth0 up # Finding source networks on LAN echo "Locating source networks within broadcast domain" >>$EJLOG echo "Discovering local RFC1918 private IP addresses" >>$EJLOG -tcpdump -i eth0 -n -c $PKTS arp src net 10 or 172.16/12 or 192.168/16 -w $DUMP > /dev/null 2>&1 -tcpdump -r $DUMP 2>&1 | awk '(NR>1)' | awk '{print $7}' | awk -F \, '{print $1}' | sort -rn | uniq > $IPS -grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}' $IPS > $IPv4 +tcpdump -i eth0 -n -c $PKTS arp src net 10 or 172.16/12 or 192.168/16 -w $DUMP >/dev/null 2>&1 +tcpdump -r $DUMP 2>&1 | awk '(NR>1)' | awk '{print $7}' | awk -F \, '{print $1}' | sort -rn | uniq >$IPS +grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}' $IPS >$IPv4 echo "Identifying uniq RFC1918 network ranges" >>$EJLOG -grep -v -e '^[[:space:]]"$' $IPv4 | grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}' | awk -F \. '{print $1"."$2"."$3}' | sort -rn | uniq > $NET +grep -v -e '^[[:space:]]"$' $IPv4 | grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}' | awk -F \. '{print $1"."$2"."$3}' | sort -rn | uniq >$NET echo "Determine specific target class network" >>$EJLOG -ROW=$(wc -l < $NET) +ROW=$(wc -l <$NET) #echo "row equals $row" if [ "$ROW" -eq 1 ]; then - echo "Class C network" >>$EJLOG - CLASS=$(cat $NET) - echo "Target network is $CLASS" >>$EJLOG - echo "Define our IP Address" >>$EJLOG - DONE=NO - while [ "$DONE" == "NO" ]; do - RANDNUM=$(shuf -i 2-253 -n 1) - MYIP="$CLASS.$RANDNUM" - # Check if $MYIP exists in $IPv4 - if grep -q "$MYIP" $IPv4; then - DONE=NO - else - # Verify $MYIP does not exist on the network already - echo "Verify $MYIP does not exist on the network already" >>$EJLOG - SRC_IP=$(head -1 $IPv4) - arping -I eth0 -c 1 $MYIP -S $SRC_IP | grep -q "0 packets received" && IP_EXISTS="" || IP_EXISTS="YES" - if [ -z "$IP_EXISTS" ]; then - echo "Our IP is $MYIP" >>$EJLOG - echo "Configuring IP address and netmask" >>$EJLOG - ifconfig eth0 $MYIP/24 - echo "$CLASS.0/24" >my_net - echo "$MYIP" >my_ip - DONE=YES - else - echo "The IP exists...start again" >>$EJLOG - DONE=NO - fi - fi - done + echo "Class C network" >>$EJLOG + CLASS=$(cat $NET) + echo "Target network is $CLASS" >>$EJLOG + echo "Define our IP Address" >>$EJLOG + DONE=NO + while [ "$DONE" == "NO" ]; do + RANDNUM=$(shuf -i 2-253 -n 1) + MYIP="$CLASS.$RANDNUM" + # Check if $MYIP exists in $IPv4 + if grep -q "$MYIP" $IPv4; then + DONE=NO + else + # Verify $MYIP does not exist on the network already + echo "Verify $MYIP does not exist on the network already" >>$EJLOG + SRC_IP=$(head -1 $IPv4) + arping -I eth0 -c 1 $MYIP -S $SRC_IP | grep -q "0 packets received" && IP_EXISTS="" || IP_EXISTS="YES" + if [ -z "$IP_EXISTS" ]; then + echo "Our IP is $MYIP" >>$EJLOG + echo "Configuring IP address and netmask" >>$EJLOG + ifconfig eth0 $MYIP/24 + echo "$CLASS.0/24" >my_net + echo "$MYIP" >my_ip + DONE=YES + else + echo "The IP exists...start again" >>$EJLOG + DONE=NO + fi + fi + done else - echo "Not a class C network" >>$EJLOG - awk -F \. '{print $1"."$2}' $NET | uniq > $CLASSB - ROW=$(wc -l < $CLASSB) - if [ "$ROW" -eq 1 ]; then - echo "Class B network" >>$EJLOG - CLASS=$(cat $CLASSB) - echo "Target network is $CLASS" >>$EJLOG - echo "Define our IP Address" >>$EJLOG - DONE=NO - while [ "$DONE" == "NO" ]; do - RANDNUM=$(shuf -i 2-253 -n 1) - RANDNUM2=$(shuf -i 2-253 -n 1) - MYIP="$CLASS.$RANDNUM.$RANDNUM2" - # Check if $MYIP exists in $IPv4 - if grep -q "$MYIP" $IPv4; then - DONE=NO - else - # Verify $MYIP does not exist on the network already - echo "Verify $MYIP does not exist on the network already" >>$EJLOG - SRC_IP=$(head -1 $IPv4) - arping -I eth0 -c 1 $MYIP -S $SRC_IP | grep -q "0 packets received" && IP_EXISTS="" || IP_EXISTS="YES" - if [ -z "$IP_EXISTS" ]; then - echo "Our IP is $MYIP" >>$EJLOG - echo "Configuring IP address and netmask" >>$EJLOG - ifconfig eth0 $MYIP/16 - echo "$CLASS.0.0/16" >my_net - echo "$MYIP" >my_ip - DONE=YES - else - echo "The IP exists...start again" >>$EJLOG - DONE=NO - fi - fi - done - else - echo "Class A network" >>$EJLOG - awk -F \. '{print $1}' $NET | uniq > $CLASSA - CLASS=$(cat $CLASSA) - echo "Target network is $CLASSA" >>$EJLOG - echo "Define our IP Address" $EJLOG - DONE=NO - while [ "$DONE" == "NO" ]; do - RANDNUM=$(shuf -i 2-253 -n 1) - RANDNUM2=$(shuf -i 2-253 -n 1) - RANDNUM3=$(shuf -i 2-253 -n 1) - MYIP="$CLASS.$RANDNUM.$RANDNUM2.$RANDNUM3" - # Check if $MYIP exists in $IPv4 - if grep -q "$MYIP" $IPv4; then - DONE=NO - else - # Verify $MYIP does not exist on the network already - echo "Verify $MYIP does not exist on the network already" >>$EJLOG - SRC_IP=$(head -1 $IPv4) - arping -I eth0 -c 1 $MYIP -S $SRC_IP | grep -q "0 packets received" && IP_EXISTS="" || IP_EXISTS="YES" - if [ -z "$IP_EXISTS" ]; then - echo "Our IP is $MYIP" >>$EJLOG - echo "Configuring IP address and netmask" >>$EJLOG - ifconfig eth0 $MYIP/8 - echo "$CLASS.0.0.0/8" >my_net - echo "$MYIP" >my_ip - DONE=YES - else - echo "The IP exists...start again" >>$EJLOG - DONE=NO - fi - fi - done - fi + echo "Not a class C network" >>$EJLOG + awk -F \. '{print $1"."$2}' $NET | uniq >$CLASSB + ROW=$(wc -l <$CLASSB) + if [ "$ROW" -eq 1 ]; then + echo "Class B network" >>$EJLOG + CLASS=$(cat $CLASSB) + echo "Target network is $CLASS" >>$EJLOG + echo "Define our IP Address" >>$EJLOG + DONE=NO + while [ "$DONE" == "NO" ]; do + RANDNUM=$(shuf -i 2-253 -n 1) + RANDNUM2=$(shuf -i 2-253 -n 1) + MYIP="$CLASS.$RANDNUM.$RANDNUM2" + # Check if $MYIP exists in $IPv4 + if grep -q "$MYIP" $IPv4; then + DONE=NO + else + # Verify $MYIP does not exist on the network already + echo "Verify $MYIP does not exist on the network already" >>$EJLOG + SRC_IP=$(head -1 $IPv4) + arping -I eth0 -c 1 $MYIP -S $SRC_IP | grep -q "0 packets received" && IP_EXISTS="" || IP_EXISTS="YES" + if [ -z "$IP_EXISTS" ]; then + echo "Our IP is $MYIP" >>$EJLOG + echo "Configuring IP address and netmask" >>$EJLOG + ifconfig eth0 $MYIP/16 + echo "$CLASS.0.0/16" >my_net + echo "$MYIP" >my_ip + DONE=YES + else + echo "The IP exists...start again" >>$EJLOG + DONE=NO + fi + fi + done + else + echo "Class A network" >>$EJLOG + awk -F \. '{print $1}' $NET | uniq >$CLASSA + CLASS=$(cat $CLASSA) + echo "Target network is $CLASSA" >>$EJLOG + echo "Define our IP Address" $EJLOG + DONE=NO + while [ "$DONE" == "NO" ]; do + RANDNUM=$(shuf -i 2-253 -n 1) + RANDNUM2=$(shuf -i 2-253 -n 1) + RANDNUM3=$(shuf -i 2-253 -n 1) + MYIP="$CLASS.$RANDNUM.$RANDNUM2.$RANDNUM3" + # Check if $MYIP exists in $IPv4 + if grep -q "$MYIP" $IPv4; then + DONE=NO + else + # Verify $MYIP does not exist on the network already + echo "Verify $MYIP does not exist on the network already" >>$EJLOG + SRC_IP=$(head -1 $IPv4) + arping -I eth0 -c 1 $MYIP -S $SRC_IP | grep -q "0 packets received" && IP_EXISTS="" || IP_EXISTS="YES" + if [ -z "$IP_EXISTS" ]; then + echo "Our IP is $MYIP" >>$EJLOG + echo "Configuring IP address and netmask" >>$EJLOG + ifconfig eth0 $MYIP/8 + echo "$CLASS.0.0.0/8" >my_net + echo "$MYIP" >my_ip + DONE=YES + else + echo "The IP exists...start again" >>$EJLOG + DONE=NO + fi + fi + done + fi fi #Configure IPtables rules diff --git a/lan/routefinder.sh b/lan/routefinder.sh index fe8ec42..e091635 100755 --- a/lan/routefinder.sh +++ b/lan/routefinder.sh @@ -18,25 +18,25 @@ grep -i up nmaparp | awk '{print $2}' | grep -v Nmap | grep -v $MY_IP >$GTWY_IPS DONE=NO echo "ARP scan completed" >>$EJLOG while [ "$DONE" == "NO" ]; do - echo "Attempting to identify the gateway" >>$EJLOG - for GTWY_IP in $(cat $GTWY_IPS); do - echo "Testing $GTWY_IP as the gateway" >>$EJLOG - route add default gw $GTWY_IP - PortCheck="" - PortCheck="$(nmap -n -sT -p $TESTPORT $TESTIP | grep -i open | awk '{print $2}')" - if [ "$PortCheck" != "open" ]; then - echo "Incorrect gateway...try again" >>$EJLOG - ip route flush $GTWY_IP default - DONE=NO - else - echo "Found gateway at $GTWY_IP" >>$EJLOG - echo $GTWY_IP >$MY_GTWY_IP - DONE=YES - # Execute Payload - echo "Network and route setup complete" >>$EJLOG - echo "Calling home" >>$EJLOG - echo "############### END ROUTEFINDER ###############" >>$EJLOG - systemctl start Etherjack-payload - fi - done + echo "Attempting to identify the gateway" >>$EJLOG + for GTWY_IP in $(cat $GTWY_IPS); do + echo "Testing $GTWY_IP as the gateway" >>$EJLOG + route add default gw $GTWY_IP + PortCheck="" + PortCheck="$(nmap -n -sT -p $TESTPORT $TESTIP | grep -i open | awk '{print $2}')" + if [ "$PortCheck" != "open" ]; then + echo "Incorrect gateway...try again" >>$EJLOG + ip route flush $GTWY_IP default + DONE=NO + else + echo "Found gateway at $GTWY_IP" >>$EJLOG + echo $GTWY_IP >$MY_GTWY_IP + DONE=YES + # Execute Payload + echo "Network and route setup complete" >>$EJLOG + echo "Calling home" >>$EJLOG + echo "############### END ROUTEFINDER ###############" >>$EJLOG + systemctl start Etherjack-payload + fi + done done diff --git a/preset/preset.sh b/preset/preset.sh index 3dbd86e..39529d5 100755 --- a/preset/preset.sh +++ b/preset/preset.sh @@ -10,75 +10,75 @@ source ../preset.conf echo "############### PRESET MODE ###############" >>$EJLOG case $CONFIG in - static|STATIC) - echo "Configuring EJ for a static IP configuration" >>$EJLOG - systemctl stop NetworkManager - systemctl disable NetworkManager - ifconfig eth0 down - ifconfig eth0 up - ifconfig eth0 $IPADDR netmask $NETMASK - route add default gw $GATEWAY - echo "nameserver $NAMESERVER" > /etc/resolv.conf - echo "My IP is: $IPADDR" >>$EJLOG - echo "My Netmask is: $NETMASK" >>$EJLOG - echo "My Gateway is: $GATEWAY" >>$EJLOG - echo "My Nameserver is: $NAMESERVER" >>$EJLOG - DONE=NO - while [ $DONE == "NO" ]; do - for TRY in {1..5}; do - echo "Attempting to reach the Internet" >>$EJLOG - PortCheck="$(nmap -n -sT -p $TESTPORT $TESTIP | grep -i open | awk '{print $2}')" - if [ "$PortCheck" != "open" ]; then - echo "Try $TRY of 5. Static configuration didn't work!!" >>$EJLOG - if [ $TRY == 5 ]; then - echo "Number of trys to reach Internet exceeded. Shutting system down." >>$EJLOG - init 0 - else - echo "Trying Internet check again. Sleeping for 5 seconds..." >>$EJLOG - sleep 5 - fi - else - echo "Internet check successfull!!" >>$EJLOG - break - fi - done - echo "Calling home" >>$EJLOG - $CALLHOME - DONE=YES - done - ;; - dhcp|DHCP) - echo "Configuring EJ for a DHCP configuration" >>$EJLOG - systemctl stop NetworkManager - ifconfig eth0 down - ifconfig eth0 up - systemctl start NetworkManager - DONE=NO - while [ $DONE == "NO" ]; do - echo "Attempting to reach the Internet" >>$EJLOG - PortCheck="$(nmap -n -sT -p $TESTPORT $TESTIP | grep -i open | awk '{print $2}')" - if [ "$PortCheck" != "open" ]; then - echo "Still waiting on DHCP. Sleeping for 2 seconds until retry...." >>$EJLOG - sleep 2 - DONE=NO - else - echo "Internet check successfull!!" >>$EJLOG - DHCPIP=$(hostname -I) - DHCPGTW=$(ip route show default) - DHCPMASK=$(ifconfig eth0 | grep -i mask | awk '{print $4}') - DHCPNS=$(cat /etc/resolv.conf | grep nameserver | awk '{print $2}') - echo "My IP is: $DHCPIP" >>$EJLOG - echo "My Netmask is: $DHCPMASK" >>$EJLOG - echo "My Gateway is: $DHCPGTW" >>$EJLOG - echo "My Nameserver is: $DHCPNS" >>$EJLOG - echo "Calling home" >>$EJLOG - systemctl start Etherjack-payload - DONE=YES - fi - done - ;; - *) - echo "Invalid configuration defined. Shutting system down!!" >>$EJLOG - init 0 - ;; +static | STATIC) + echo "Configuring EJ for a static IP configuration" >>$EJLOG + systemctl stop NetworkManager + systemctl disable NetworkManager + ifconfig eth0 down + ifconfig eth0 up + ifconfig eth0 $IPADDR netmask $NETMASK + route add default gw $GATEWAY + echo "nameserver $NAMESERVER" >/etc/resolv.conf + echo "My IP is: $IPADDR" >>$EJLOG + echo "My Netmask is: $NETMASK" >>$EJLOG + echo "My Gateway is: $GATEWAY" >>$EJLOG + echo "My Nameserver is: $NAMESERVER" >>$EJLOG + DONE=NO + while [ $DONE == "NO" ]; do + for TRY in {1..5}; do + echo "Attempting to reach the Internet" >>$EJLOG + PortCheck="$(nmap -n -sT -p $TESTPORT $TESTIP | grep -i open | awk '{print $2}')" + if [ "$PortCheck" != "open" ]; then + echo "Try $TRY of 5. Static configuration didn't work!!" >>$EJLOG + if [ $TRY == 5 ]; then + echo "Number of trys to reach Internet exceeded. Shutting system down." >>$EJLOG + init 0 + else + echo "Trying Internet check again. Sleeping for 5 seconds..." >>$EJLOG + sleep 5 + fi + else + echo "Internet check successfull!!" >>$EJLOG + break + fi + done + echo "Calling home" >>$EJLOG + $CALLHOME + DONE=YES + done + ;; +dhcp | DHCP) + echo "Configuring EJ for a DHCP configuration" >>$EJLOG + systemctl stop NetworkManager + ifconfig eth0 down + ifconfig eth0 up + systemctl start NetworkManager + DONE=NO + while [ $DONE == "NO" ]; do + echo "Attempting to reach the Internet" >>$EJLOG + PortCheck="$(nmap -n -sT -p $TESTPORT $TESTIP | grep -i open | awk '{print $2}')" + if [ "$PortCheck" != "open" ]; then + echo "Still waiting on DHCP. Sleeping for 2 seconds until retry...." >>$EJLOG + sleep 2 + DONE=NO + else + echo "Internet check successfull!!" >>$EJLOG + DHCPIP=$(hostname -I) + DHCPGTW=$(ip route show default) + DHCPMASK=$(ifconfig eth0 | grep -i mask | awk '{print $4}') + DHCPNS=$(cat /etc/resolv.conf | grep nameserver | awk '{print $2}') + echo "My IP is: $DHCPIP" >>$EJLOG + echo "My Netmask is: $DHCPMASK" >>$EJLOG + echo "My Gateway is: $DHCPGTW" >>$EJLOG + echo "My Nameserver is: $DHCPNS" >>$EJLOG + echo "Calling home" >>$EJLOG + systemctl start Etherjack-payload + DONE=YES + fi + done + ;; +*) + echo "Invalid configuration defined. Shutting system down!!" >>$EJLOG + init 0 + ;; esac diff --git a/tests/Dockerfile b/tests/Dockerfile index bddba77..e447efa 100644 --- a/tests/Dockerfile +++ b/tests/Dockerfile @@ -5,11 +5,16 @@ ARG DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get install -y --no-install-recommends \ bash \ shellcheck \ + yamllint \ git \ ca-certificates \ + curl \ && git clone --depth 1 https://github.com/bats-core/bats-core.git /tmp/bats-core \ && /tmp/bats-core/install.sh /usr/local \ && rm -rf /tmp/bats-core \ + && curl -sSL https://github.com/mvdan/sh/releases/download/v3.13.0/shfmt_v3.13.0_linux_amd64 \ + -o /usr/local/bin/shfmt \ + && chmod +x /usr/local/bin/shfmt \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* diff --git a/tests/test_mode_dispatch.bats b/tests/test_mode_dispatch.bats index a0688da..f7b3450 100644 --- a/tests/test_mode_dispatch.bats +++ b/tests/test_mode_dispatch.bats @@ -14,21 +14,21 @@ setup() { mkdir -p "$EJPATH/lan" "$EJPATH/wifi" "$EJPATH/preset" "$EJPATH/files" "$EJPATH/bin" # Provide ejmotd so the cat command in each mode branch doesn't error - cp "$REPO_ROOT/files/ejmotd" "$EJPATH/files/ejmotd" 2>/dev/null \ - || touch "$EJPATH/files/ejmotd" + cp "$REPO_ROOT/files/ejmotd" "$EJPATH/files/ejmotd" 2>/dev/null || + touch "$EJPATH/files/ejmotd" # Lightweight sub-script stubs for entry in "lan/netfinder.sh:netfinder" "wifi/wifi.sh:wifi" "preset/preset.sh:preset"; do local path="${entry%%:*}" local name="${entry##*:}" - printf '#!/bin/bash\necho "%s called"\n' "$name" > "$EJPATH/$path" + printf '#!/bin/bash\necho "%s called"\n' "$name" >"$EJPATH/$path" chmod +x "$EJPATH/$path" done # Mock bin: init must be intercepted before the real /sbin/init runs export MOCK_BIN="$BATS_TEST_TMPDIR/bin" mkdir -p "$MOCK_BIN" - cat > "$MOCK_BIN/init" << 'EOF' + cat >"$MOCK_BIN/init" <<'EOF' #!/bin/bash echo "SHUTDOWN: init $*" exit 0 @@ -37,7 +37,7 @@ EOF export PATH="$MOCK_BIN:$PATH" # Minimal EtherJack.conf — EJMODE left blank; each test fills it via run_ej() - cat > "$EJPATH/EtherJack.conf" << EOF + cat >"$EJPATH/EtherJack.conf" < "$MOCK_BIN/init" << 'EOF' + cat >"$MOCK_BIN/init" <<'EOF' #!/bin/bash echo "SHUTDOWN: init $*" exit 0 @@ -31,14 +31,14 @@ EOF export PATH="$MOCK_BIN:$PATH" # Mock payload (CALLHOME target) - cat > "$EJPATH/bin/payload" << 'EOF' + cat >"$EJPATH/bin/payload" <<'EOF' #!/bin/bash echo "payload executed" EOF chmod +x "$EJPATH/bin/payload" # EtherJack.conf — sourced via ../../EtherJack.conf from the engagement dir - cat > "$EJPATH/EtherJack.conf" << EOF + cat >"$EJPATH/EtherJack.conf" < "$EJPATH/preset/preset.conf" << EOF + cat >"$EJPATH/preset/preset.conf" <>$EJLOG systemctl stop NetworkManager systemctl disable NetworkManager @@ -52,11 +51,11 @@ echo "nameserver 8.8.8.8" >/etc/resolv.conf # Disable ipv6 on eth0 echo "Ensuring ipv6 is disabled" >>$EJLOG if grep -q "net.ipv6.conf.all.disable_ipv6 = 1" /etc/sysctl.conf; then - echo "IPV6 already disabled" >>$EJLOG + echo "IPV6 already disabled" >>$EJLOG else - echo "Disabling IPV6" >>$EJLOG - echo "net.ipv6.conf.all.disable_ipv6 = 1" >>/etc/sysctl.conf - sysctl -p + echo "Disabling IPV6" >>$EJLOG + echo "net.ipv6.conf.all.disable_ipv6 = 1" >>/etc/sysctl.conf + sysctl -p fi echo "Starting dnsmasq" >>$EJLOG