mirror of
https://github.com/jayofelony/pwnagotchi.git
synced 2025-07-01 18:37:27 -04:00
Added couple of plugins, and some other stuff to work on more than 1 raspberry
Signed-off-by: Jeroen Oudshoorn <oudshoorn.jeroen@gmail.com> Signed-off-by: Jeroen Oudshoorn <oudshoorn.jeroen@gmail.com>
This commit is contained in:
8
Makefile
8
Makefile
@ -20,11 +20,11 @@ install:
|
|||||||
|
|
||||||
image:
|
image:
|
||||||
cd builder && sudo /usr/bin/packer build -var "pwn_hostname=$(PWN_HOSTNAME)" -var "pwn_version=$(PWN_VERSION)" pwnagotchi.json
|
cd builder && sudo /usr/bin/packer build -var "pwn_hostname=$(PWN_HOSTNAME)" -var "pwn_version=$(PWN_VERSION)" pwnagotchi.json
|
||||||
sudo mv builder/output-pwnagotchi/image pwnagotchi-raspberrypi-os-lite-$(PWN_VERSION).img
|
sudo mv builder/output-pwnagotchi/image pwnagotchi-rpi-os-lite-$(PWN_VERSION).img
|
||||||
sudo sha256sum pwnagotchi-raspberrypi-os-lite-$(PWN_VERSION).img > pwnagotchi-raspberrypi-os-lite-$(PWN_VERSION).sha256
|
sudo sha256sum pwnagotchi-rpi-os-lite-$(PWN_VERSION).img > pwnagotchi-rpi-os-lite-$(PWN_VERSION).sha256
|
||||||
sudo zip pwnagotchi-raspberrypi-os-lite-$(PWN_VERSION).zip pwnagotchi-raspberrypi-os-lite-$(PWN_VERSION).sha256 pwnagotchi-raspberrypi-os-lite-$(PWN_VERSION).img
|
sudo zip pwnagotchi-rpi-os-lite-$(PWN_VERSION).zip pwnagotchi-rpi-os-lite-$(PWN_VERSION).sha256 pwnagotchi-rpi-os-lite-$(PWN_VERSION).img
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf /tmp/packer-builder-arm-image
|
rm -rf /tmp/packer-builder-arm-image
|
||||||
rm -f pwnagotchi-raspberrypi-os-lite-*.zip pwnagotchi-raspberrypi-os-lite-*.img pwnagotchi-raspberrypi-os-lite-*.sha256
|
rm -f pwnagotchi-rpi-os-lite-*.zip pwnagotchi-rpi-os-lite-*.img pwnagotchi-rpi-os-lite-*.sha256
|
||||||
rm -rf builder/output-pwnagotchi builder/packer_cache
|
rm -rf builder/output-pwnagotchi builder/packer_cache
|
||||||
|
@ -11,86 +11,24 @@
|
|||||||
{
|
{
|
||||||
"type": "shell",
|
"type": "shell",
|
||||||
"inline": [
|
"inline": [
|
||||||
"sed -i 's/^\\([^#]\\)/#\\1/g' /etc/ld.so.preload",
|
"mv /etc/ld.so.preload /etc/ld.so.preload.DISABLED",
|
||||||
|
"uname -a",
|
||||||
"dpkg-architecture",
|
"dpkg-architecture",
|
||||||
"apt-get -y update",
|
"mkdir -p /usr/local/src/pwnagotchi"
|
||||||
"apt-get install -y ansible"
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "file",
|
"type": "file",
|
||||||
"source": "data/usr/bin/pwnlib",
|
"sources": [
|
||||||
"destination": "/usr/bin/pwnlib"
|
"../dist/pwnagotchi-{{user `pwn_version`}}.tar.gz"
|
||||||
},
|
],
|
||||||
{
|
"destination": "/usr/local/src/pwnagotchi/"
|
||||||
"type": "file",
|
|
||||||
"source": "data/usr/bin/bettercap-launcher",
|
|
||||||
"destination": "/usr/bin/bettercap-launcher"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "file",
|
|
||||||
"source": "data/usr/bin/pwnagotchi-launcher",
|
|
||||||
"destination": "/usr/bin/pwnagotchi-launcher"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "file",
|
|
||||||
"source": "data/usr/bin/monstop",
|
|
||||||
"destination": "/usr/bin/monstop"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "file",
|
|
||||||
"source": "data/usr/bin/monstart",
|
|
||||||
"destination": "/usr/bin/monstart"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "file",
|
|
||||||
"source": "data/usr/bin/hdmion",
|
|
||||||
"destination": "/usr/bin/hdmion"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "file",
|
|
||||||
"source": "data/usr/bin/hdmioff",
|
|
||||||
"destination": "/usr/bin/hdmioff"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "file",
|
|
||||||
"source": "data/etc/network/interfaces.d/lo-cfg",
|
|
||||||
"destination": "/etc/network/interfaces.d/lo-cfg"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "file",
|
|
||||||
"source": "data/etc/network/interfaces.d/wlan0-cfg",
|
|
||||||
"destination": "/etc/network/interfaces.d/wlan0-cfg"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "file",
|
|
||||||
"source": "data/etc/network/interfaces.d/usb0-cfg",
|
|
||||||
"destination": "/etc/network/interfaces.d/usb0-cfg"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "file",
|
|
||||||
"source": "data/etc/network/interfaces.d/eth0-cfg",
|
|
||||||
"destination": "/etc/network/interfaces.d/eth0-cfg"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "file",
|
|
||||||
"source": "data/etc/systemd/system/pwngrid-peer.service",
|
|
||||||
"destination": "/etc/systemd/system/pwngrid-peer.service"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "file",
|
|
||||||
"source": "data/etc/systemd/system/pwnagotchi.service",
|
|
||||||
"destination": "/etc/systemd/system/pwnagotchi.service"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "file",
|
|
||||||
"source": "data/etc/systemd/system/bettercap.service",
|
|
||||||
"destination": "/etc/systemd/system/bettercap.service"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "shell",
|
"type": "shell",
|
||||||
"inline": [
|
"inline": [
|
||||||
"chmod +x /usr/bin/*"
|
"apt-get -y --allow-releaseinfo-change update",
|
||||||
|
"apt-get install -y --no-install-recommends ansible"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -102,7 +40,7 @@
|
|||||||
{
|
{
|
||||||
"type": "shell",
|
"type": "shell",
|
||||||
"inline": [
|
"inline": [
|
||||||
"sed -i 's/^#\\(.+\\)/\\1/g' /etc/ld.so.preload"
|
"mv /etc/ld.so.preload.DISABLED /etc/ld.so.preload"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -36,17 +36,16 @@
|
|||||||
- dnsmasq.service
|
- dnsmasq.service
|
||||||
packages:
|
packages:
|
||||||
bettercap:
|
bettercap:
|
||||||
url: "https://github.com/bettercap/bettercap/releases/download/v2.31.1/bettercap_linux_aarch64_v2.31.1.zip"
|
# We will install bettercap from source
|
||||||
|
# url: "https://github.com/jayofelony/bettercap/releases/download/2.32.1/bettercap-2.32.1.zip"
|
||||||
ui: "https://github.com/bettercap/ui/releases/download/v1.3.0/ui.zip"
|
ui: "https://github.com/bettercap/ui/releases/download/v1.3.0/ui.zip"
|
||||||
pwngrid:
|
pwngrid:
|
||||||
url: "https://github.com/evilsocket/pwngrid/releases/download/v1.10.3/pwngrid_linux_aarch64_v1.10.3.zip"
|
url: "https://github.com/evilsocket/pwngrid/releases/download/v1.10.3/pwngrid_linux_aarch64_v1.10.3.zip"
|
||||||
apt:
|
apt:
|
||||||
hold:
|
hold:
|
||||||
- firmware-atheros
|
- libpcap-dev
|
||||||
- firmware-brcm80211
|
- libpcap0.8
|
||||||
- firmware-libertas
|
- libpcap0.8-dev
|
||||||
- firmware-misc-nonfree
|
|
||||||
- firmware-realtek
|
|
||||||
remove:
|
remove:
|
||||||
- raspberrypi-net-mods
|
- raspberrypi-net-mods
|
||||||
- dhcpcd5
|
- dhcpcd5
|
||||||
@ -58,59 +57,96 @@
|
|||||||
- libraspberrypi-doc
|
- libraspberrypi-doc
|
||||||
- libraspberrypi-bin
|
- libraspberrypi-bin
|
||||||
install:
|
install:
|
||||||
|
- bluez
|
||||||
|
- raspberrypi-kernel-headers
|
||||||
|
- git
|
||||||
|
- libgmp3-dev
|
||||||
|
- gawk
|
||||||
|
- qpdf
|
||||||
|
- bison
|
||||||
|
- flex
|
||||||
|
- make
|
||||||
|
- autoconf
|
||||||
|
- libtool
|
||||||
|
- texinfo
|
||||||
|
- gcc-arm-none-eabi
|
||||||
|
- wl
|
||||||
|
- libfl-dev
|
||||||
|
- g++
|
||||||
|
- xxd
|
||||||
|
- aircrack-ng
|
||||||
|
- time
|
||||||
- rsync
|
- rsync
|
||||||
- vim
|
- vim
|
||||||
|
- wget
|
||||||
- screen
|
- screen
|
||||||
- golang
|
|
||||||
- git
|
|
||||||
- build-essential
|
- build-essential
|
||||||
|
- dkms
|
||||||
- python3-pip
|
- python3-pip
|
||||||
- python3-mpi4py
|
|
||||||
- python3-smbus
|
- python3-smbus
|
||||||
- unzip
|
- unzip
|
||||||
- gawk
|
|
||||||
- libopenmpi-dev
|
- libopenmpi-dev
|
||||||
- libatlas-base-dev
|
- libatlas-base-dev
|
||||||
- libjasper-dev
|
- libelf-dev
|
||||||
- libqtgui4
|
|
||||||
- libqt4-test
|
|
||||||
- libopenjp2-7
|
- libopenjp2-7
|
||||||
- libtiff5
|
- libtiff5
|
||||||
- tcpdump
|
- tcpdump
|
||||||
- lsof
|
- lsof
|
||||||
- libilmbase23
|
|
||||||
- libopenexr23
|
|
||||||
- libgstreamer1.0-0
|
- libgstreamer1.0-0
|
||||||
- libavcodec58
|
- libavcodec58
|
||||||
- libavformat58
|
- libavformat58
|
||||||
- libswscale5
|
- libswscale5
|
||||||
- libpcap-dev
|
|
||||||
- libusb-1.0-0-dev
|
- libusb-1.0-0-dev
|
||||||
- libnetfilter-queue-dev
|
- libnetfilter-queue-dev
|
||||||
- libopenmpi3
|
- libopenmpi3
|
||||||
- dphys-swapfile
|
- dphys-swapfile
|
||||||
- kalipi-kernel
|
- libdbus-1-dev
|
||||||
- kalipi-bootloader
|
- libdbus-glib-1-dev
|
||||||
- kalipi-re4son-firmware
|
- liblapack-dev
|
||||||
- kalipi-kernel-headers
|
- libhdf5-dev
|
||||||
- libraspberrypi0
|
- libc-ares-dev
|
||||||
- libraspberrypi-dev
|
- libeigen3-dev
|
||||||
- libraspberrypi-doc
|
|
||||||
- libraspberrypi-bin
|
|
||||||
- fonts-dejavu
|
- fonts-dejavu
|
||||||
- fonts-dejavu-core
|
- fonts-dejavu-core
|
||||||
- fonts-dejavu-extra
|
- fonts-dejavu-extra
|
||||||
- python3-pil
|
- python3-pil
|
||||||
- python3-smbus
|
- python3-smbus
|
||||||
- libfuse-dev
|
- libfuse-dev
|
||||||
|
- libatlas-base-dev
|
||||||
|
- libopenblas-dev
|
||||||
|
- libblas-dev
|
||||||
- bc
|
- bc
|
||||||
|
- libgl1-mesa-glx
|
||||||
|
- libncursesw5-dev
|
||||||
|
- libssl-dev
|
||||||
|
- libsqlite3-dev
|
||||||
|
- tk-dev
|
||||||
|
- libgdbm-dev
|
||||||
|
- libc6-dev
|
||||||
|
- libbz2-dev
|
||||||
|
- libffi-dev
|
||||||
|
- zlib1g-dev
|
||||||
- fonts-freefont-ttf
|
- fonts-freefont-ttf
|
||||||
- fbi
|
- fbi
|
||||||
- fonts-ipaexfont-gothic
|
- python3-flask
|
||||||
- cryptsetup
|
- python3-flask-cors
|
||||||
- dnsmasq
|
- python3-flaskext.wtf
|
||||||
|
- build-essential
|
||||||
|
- libpcap-dev
|
||||||
|
- libusb-1.0-0-dev
|
||||||
|
- libnetfilter-queue-dev
|
||||||
|
|
||||||
tasks:
|
tasks:
|
||||||
|
- name: download old libpcap packages
|
||||||
|
shell: "wget http://ports.ubuntu.com/pool/main/libp/libpcap/libpcap0.8_1.9.1-3_arm64.deb && wget http://ports.ubuntu.com/pool/main/libp/libpcap/libpcap0.8-dev_1.9.1-3_arm64.deb && wget http://ports.ubuntu.com/pool/main/libp/libpcap/libpcap-dev_1.9.1-3_arm64.deb"
|
||||||
|
dest: /usr/local/src/
|
||||||
|
|
||||||
|
- name: install old libpcap packages
|
||||||
|
shell: dpkg -i /usr/local/src/libpcap*
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
register: libpcap
|
||||||
|
|
||||||
- name: change hostname
|
- name: change hostname
|
||||||
hostname:
|
hostname:
|
||||||
name: "{{pwnagotchi.hostname}}"
|
name: "{{pwnagotchi.hostname}}"
|
||||||
@ -132,37 +168,18 @@
|
|||||||
line: 'ExecStart=/usr/lib/bluetooth/bluetoothd --noplugin=sap'
|
line: 'ExecStart=/usr/lib/bluetooth/bluetoothd --noplugin=sap'
|
||||||
state: present
|
state: present
|
||||||
|
|
||||||
- name: Add re4son-kernel repo key
|
|
||||||
apt_key:
|
|
||||||
url: https://re4son-kernel.com/keys/http/archive-key.asc
|
|
||||||
state: present
|
|
||||||
|
|
||||||
- name: Add re4son-kernel repository
|
|
||||||
apt_repository:
|
|
||||||
repo: deb http://http.re4son-kernel.com/re4son/ kali-pi main
|
|
||||||
state: present
|
|
||||||
|
|
||||||
- name: create /etc/apt/preferences.d/kali.pref
|
|
||||||
copy:
|
|
||||||
dest: /etc/apt/preferences.d/kali.pref
|
|
||||||
force: yes
|
|
||||||
content: |
|
|
||||||
# ensure kali packages that are installed take precedence
|
|
||||||
Package: *
|
|
||||||
Pin: release n=kali-pi
|
|
||||||
Pin-Priority: 999
|
|
||||||
|
|
||||||
- name: add firmware packages to hold
|
- name: add firmware packages to hold
|
||||||
dpkg_selections:
|
dpkg_selections:
|
||||||
name: "{{ item }}"
|
name: "{{ item }}"
|
||||||
selection: hold
|
selection: hold
|
||||||
with_items: "{{ packages.apt.hold }}"
|
with_items: "{{ packages.apt.hold }}"
|
||||||
|
when: libpcap.changed
|
||||||
|
|
||||||
- name: update apt package cache
|
- name: update apt package cache
|
||||||
apt:
|
apt:
|
||||||
update_cache: yes
|
update_cache: yes
|
||||||
|
|
||||||
- name: remove unecessary apt packages
|
- name: remove unnecessary apt packages
|
||||||
apt:
|
apt:
|
||||||
name: "{{ packages.apt.remove }}"
|
name: "{{ packages.apt.remove }}"
|
||||||
state: absent
|
state: absent
|
||||||
@ -180,7 +197,7 @@
|
|||||||
- name: configure dphys-swapfile
|
- name: configure dphys-swapfile
|
||||||
file:
|
file:
|
||||||
path: /etc/dphys-swapfile
|
path: /etc/dphys-swapfile
|
||||||
content: "CONF_SWAPSIZE=1024"
|
content: "CONF_SWAPSIZE=2048"
|
||||||
|
|
||||||
- name: clone papirus repository
|
- name: clone papirus repository
|
||||||
git:
|
git:
|
||||||
@ -206,6 +223,12 @@
|
|||||||
PANEL_VERSION: 'V231_G2'
|
PANEL_VERSION: 'V231_G2'
|
||||||
when: gratisgit.changed
|
when: gratisgit.changed
|
||||||
|
|
||||||
|
- name: Creates custom plugin directory
|
||||||
|
file:
|
||||||
|
path: /usr/local/share/pwnagotchi/custom-plugins/
|
||||||
|
state: directory
|
||||||
|
when: gratisgit.changed
|
||||||
|
|
||||||
- name: configure papirus display size
|
- name: configure papirus display size
|
||||||
lineinfile:
|
lineinfile:
|
||||||
dest: /etc/default/epd-fuse
|
dest: /etc/default/epd-fuse
|
||||||
@ -228,7 +251,7 @@
|
|||||||
|
|
||||||
- name: clone pwnagotchi repository
|
- name: clone pwnagotchi repository
|
||||||
git:
|
git:
|
||||||
repo: https://github.com/evilsocket/pwnagotchi.git
|
repo: https://github.com/jayofelony/pwnagotchi.git
|
||||||
dest: /usr/local/src/pwnagotchi
|
dest: /usr/local/src/pwnagotchi
|
||||||
register: pwnagotchigit
|
register: pwnagotchigit
|
||||||
|
|
||||||
@ -256,18 +279,6 @@
|
|||||||
chdir: /usr/local/src/pwnagotchi
|
chdir: /usr/local/src/pwnagotchi
|
||||||
when: (pwnagotchigit.changed) or (pip_packages['pwnagotchi'] is undefined) or (pip_packages['pwnagotchi'] != pwnagotchi_version)
|
when: (pwnagotchigit.changed) or (pip_packages['pwnagotchi'] is undefined) or (pip_packages['pwnagotchi'] != pwnagotchi_version)
|
||||||
|
|
||||||
- name: install opencv-python
|
|
||||||
pip:
|
|
||||||
name: "https://www.piwheels.org/simple/opencv-python/opencv_python-3.4.3.18-cp37-cp37m-linux_armv6l.whl"
|
|
||||||
extra_args: "--no-deps --no-cache-dir --platform=linux_armv6l --only-binary=:all: --target={{ pip_target.stdout }}"
|
|
||||||
when: (pip_packages['opencv-python'] is undefined) or (pip_packages['opencv-python'] != '3.4.3.18')
|
|
||||||
|
|
||||||
- name: install tensorflow
|
|
||||||
pip:
|
|
||||||
name: "https://www.piwheels.org/simple/tensorflow/tensorflow-1.13.1-cp37-none-linux_armv6l.whl"
|
|
||||||
extra_args: "--no-deps --no-cache-dir --platform=linux_armv6l --only-binary=:all: --target={{ pip_target.stdout }}"
|
|
||||||
when: (pip_packages['tensorflow'] is undefined) or (pip_packages['tensorflow'] != '1.13.1')
|
|
||||||
|
|
||||||
- name: install pwnagotchi wheel and dependencies
|
- name: install pwnagotchi wheel and dependencies
|
||||||
pip:
|
pip:
|
||||||
name: "{{ lookup('fileglob', '/usr/local/src/pwnagotchi/dist/pwnagotchi*.whl') }}"
|
name: "{{ lookup('fileglob', '/usr/local/src/pwnagotchi/dist/pwnagotchi*.whl') }}"
|
||||||
@ -281,6 +292,34 @@
|
|||||||
remote_src: yes
|
remote_src: yes
|
||||||
mode: 0755
|
mode: 0755
|
||||||
|
|
||||||
|
# Install go-1.20.6
|
||||||
|
- name: Install go-1.21
|
||||||
|
unarchive:
|
||||||
|
src: https://go.dev/dl/go1.21.0.linux-arm64.tar.gz
|
||||||
|
dest: /usr/local
|
||||||
|
remote_src: yes
|
||||||
|
register: golang
|
||||||
|
|
||||||
|
- name: Update .bashrc for go-1.21
|
||||||
|
blockinfile:
|
||||||
|
dest: /home/pi/.bashrc
|
||||||
|
state: present
|
||||||
|
block: |
|
||||||
|
export GOPATH=$HOME/go
|
||||||
|
export PATH=/usr/local/go/bin:$PATH:$GOPATH/bin
|
||||||
|
insertafter: EOF
|
||||||
|
when: golang.changed
|
||||||
|
|
||||||
|
- name: Install bettercap v2.32.1
|
||||||
|
shell: "export GOPATH=$HOME/go && export PATH=/usr/local/go/bin:$PATH:$GOPATH/bin && go env -w GO111MODULE=off && go get github.com/jayofelony/bettercap && cd $GOPATH/src/github.com/jayofelony/bettercap && make build && make install"
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
register: bettercap
|
||||||
|
|
||||||
|
- name: Link bettercap v2.32.1
|
||||||
|
command: ln -s /usr/local/bin/bettercap /usr/bin/bettercap
|
||||||
|
when: bettercap.changed
|
||||||
|
|
||||||
- name: download and install bettercap
|
- name: download and install bettercap
|
||||||
unarchive:
|
unarchive:
|
||||||
src: "{{ packages.bettercap.url }}"
|
src: "{{ packages.bettercap.url }}"
|
||||||
@ -297,6 +336,99 @@
|
|||||||
dest: /tmp/caplets
|
dest: /tmp/caplets
|
||||||
register: capletsgit
|
register: capletsgit
|
||||||
|
|
||||||
|
# Install nexmon to fix wireless scanning (takes 2.5G of space)
|
||||||
|
- name: clone nexmon repository
|
||||||
|
git:
|
||||||
|
repo: https://github.com/jayofelony/nexmon.git
|
||||||
|
dest: /usr/local/src/nexmon
|
||||||
|
register: nexmongit
|
||||||
|
|
||||||
|
- name: make firmware
|
||||||
|
shell: "source ./setup_env.sh && make"
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
chdir: /usr/local/src/nexmon/
|
||||||
|
|
||||||
|
# Raspberry Pi Zero 2w (chipset 43436b0)
|
||||||
|
|
||||||
|
- name: make firmware patch (bcm43436b0)
|
||||||
|
shell: "source ./setup_env.sh && cd /usr/local/src/nexmon/patches/bcm43436b0/9_88_4_65/nexmon/ && make"
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
chdir: /usr/local/src/nexmon/
|
||||||
|
|
||||||
|
- name: backup original firmware
|
||||||
|
shell: "source ./setup_env.sh && cd /usr/local/src/nexmon/patches/bcm43436b0/9_88_4_65/nexmon/ && make backup-firmware"
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
chdir: /usr/local/src/nexmon/
|
||||||
|
|
||||||
|
- name: install new firmware
|
||||||
|
shell: "source ./setup_env.sh && cd /usr/local/src/nexmon/patches/bcm43436b0/9_88_4_65/nexmon/ && make install-firmware"
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
chdir: /usr/local/src/nexmon/
|
||||||
|
|
||||||
|
# Raspberry Pi zero 2w (chipset 43430a1)
|
||||||
|
|
||||||
|
- name: make firmware patch (bcm43430a1)
|
||||||
|
shell: "source ./setup_env.sh && cd /usr/local/src/nexmon/patches/bcm43430a1/7_45_41_46/nexmon/ && make"
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
chdir: /usr/local/src/nexmon/
|
||||||
|
|
||||||
|
- name: backup original firmware
|
||||||
|
shell: "source ./setup_env.sh && cd /usr/local/src/nexmon/patches/bcm43430a1/7_45_41_46/nexmon/ && make backup-firmware"
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
chdir: /usr/local/src/nexmon/
|
||||||
|
|
||||||
|
- name: install new firmware
|
||||||
|
shell: "source ./setup_env.sh && cd /usr/local/src/nexmon/patches/bcm43430a1/7_45_41_46/nexmon/ && make install-firmware"
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
chdir: /usr/local/src/nexmon/
|
||||||
|
|
||||||
|
# Raspberry Pi 4
|
||||||
|
|
||||||
|
- name: make firmware patch (bcm43455c0)
|
||||||
|
shell: "source ./setup_env.sh && cd /usr/local/src/nexmon/patches/bcm43455c0/7_45_206/nexmon/ && make"
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
chdir: /usr/local/src/nexmon/
|
||||||
|
|
||||||
|
- name: backup original firmware
|
||||||
|
shell: "source ./setup_env.sh && cd /usr/local/src/nexmon/patches/bcm43455c0/7_45_206/nexmon/ && make backup-firmware"
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
chdir: /usr/local/src/nexmon/
|
||||||
|
|
||||||
|
- name: install new firmware
|
||||||
|
shell: "source ./setup_env.sh && cd /usr/local/src/nexmon/patches/bcm43455c0/7_45_206/nexmon/ && make install-firmware"
|
||||||
|
args:
|
||||||
|
executable: /bin/bash
|
||||||
|
chdir: /usr/local/src/nexmon/
|
||||||
|
|
||||||
|
- name: choose kernel
|
||||||
|
shell: uname -r
|
||||||
|
register: kernel
|
||||||
|
|
||||||
|
- name: copy modified driver
|
||||||
|
copy:
|
||||||
|
src: /usr/local/src/nexmon/patches/driver/brcmfmac_6.1.y-nexmon/brcmfmac.ko
|
||||||
|
dest: "/lib/modules/{{ kernel.stdout }}/kernel/drivers/net/wireless/broadcom/brcm80211/brcmfmac/brcmfmac.ko"
|
||||||
|
|
||||||
|
- name: ensure depmod runs on reboot to load modified driver (brcmfmac)
|
||||||
|
lineinfile:
|
||||||
|
dest: /etc/rc.local
|
||||||
|
line: "/sbin/depmod -a"
|
||||||
|
|
||||||
|
# To shrink the final image, remove the nexmon directory (takes 2.5G of space) post build and installation
|
||||||
|
- name: Delete nexmon content & directory
|
||||||
|
file:
|
||||||
|
state: absent
|
||||||
|
path: /usr/local/src/nexmon/
|
||||||
|
|
||||||
- name: install bettercap caplets
|
- name: install bettercap caplets
|
||||||
make:
|
make:
|
||||||
chdir: /tmp/caplets
|
chdir: /tmp/caplets
|
||||||
|
@ -1 +1 @@
|
|||||||
__version__ = '2.0'
|
__version__ = '2.1'
|
||||||
|
@ -5,6 +5,10 @@ main.custom_plugins = ""
|
|||||||
main.custom_plugin_repos = [
|
main.custom_plugin_repos = [
|
||||||
"https://github.com/evilsocket/pwnagotchi-plugins-contrib/archive/master.zip"
|
"https://github.com/evilsocket/pwnagotchi-plugins-contrib/archive/master.zip"
|
||||||
]
|
]
|
||||||
|
main.custom_plugins = "/usr/local/share/pwnagotchi/custom-plugins/"
|
||||||
|
|
||||||
|
main.fix_brcmf_plugin.enabled = true
|
||||||
|
|
||||||
main.iface = "wlan0mon"
|
main.iface = "wlan0mon"
|
||||||
main.mon_start_cmd = "/usr/bin/monstart"
|
main.mon_start_cmd = "/usr/bin/monstart"
|
||||||
main.mon_stop_cmd = "/usr/bin/monstop"
|
main.mon_stop_cmd = "/usr/bin/monstop"
|
||||||
@ -35,6 +39,20 @@ main.plugins.gps.enabled = false
|
|||||||
main.plugins.gps.speed = 19200
|
main.plugins.gps.speed = 19200
|
||||||
main.plugins.gps.device = "/dev/ttyUSB0"
|
main.plugins.gps.device = "/dev/ttyUSB0"
|
||||||
|
|
||||||
|
main.plugins.exp.enabled = true
|
||||||
|
main.plugins.exp.lvl_x_coord = 0
|
||||||
|
main.plugins.exp.lvl_y_coord = 81
|
||||||
|
main.plugins.exp.exp_x_coord = 38
|
||||||
|
main.plugins.exp.exp_y_coord = 81
|
||||||
|
main.plugins.exp.bar_symbols_count = 12
|
||||||
|
|
||||||
|
main.plugins.bluetoothsniffer.enabled = false
|
||||||
|
main.plugins.bluetoothsniffer.timer = 45 # On how may seconds to scan for bluetooth devices
|
||||||
|
main.plugins.bluetoothsniffer.devices_file = "/root/handshakes/bluetooth_devices.json" # Path to the JSON file with bluetooth devices
|
||||||
|
main.plugins.bluetoothsniffer.count_interval = 86400 # On how may seconds to update count bluetooth devices
|
||||||
|
main.plugins.bluetoothsniffer.bt_x_coord = 160
|
||||||
|
main.plugins.bluetoothsniffer.bt_y_coord = 66
|
||||||
|
|
||||||
main.plugins.webgpsmap.enabled = false
|
main.plugins.webgpsmap.enabled = false
|
||||||
|
|
||||||
main.plugins.onlinehashcrack.enabled = false
|
main.plugins.onlinehashcrack.enabled = false
|
||||||
|
@ -183,9 +183,9 @@ class AutoUpdate(plugins.Plugin):
|
|||||||
|
|
||||||
to_install = []
|
to_install = []
|
||||||
to_check = [
|
to_check = [
|
||||||
('bettercap/bettercap', parse_version('bettercap -version'), True, 'bettercap'),
|
('jayofelony/bettercap', parse_version('bettercap -version'), True, 'bettercap'),
|
||||||
('evilsocket/pwngrid', parse_version('pwngrid -version'), True, 'pwngrid-peer'),
|
('evilsocket/pwngrid', parse_version('pwngrid -version'), True, 'pwngrid-peer'),
|
||||||
('evilsocket/pwnagotchi', pwnagotchi.__version__, False, 'pwnagotchi')
|
('jayofelony/pwnagotchi', pwnagotchi.__version__, False, 'pwnagotchi')
|
||||||
]
|
]
|
||||||
|
|
||||||
for repo, local_version, is_native, svc_name in to_check:
|
for repo, local_version, is_native, svc_name in to_check:
|
||||||
|
182
pwnagotchi/plugins/default/bluetoothsniffer.py
Normal file
182
pwnagotchi/plugins/default/bluetoothsniffer.py
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
import time
|
||||||
|
|
||||||
|
import pwnagotchi
|
||||||
|
import pwnagotchi.agent
|
||||||
|
import pwnagotchi.plugins as plugins
|
||||||
|
import pwnagotchi.ui.fonts as fonts
|
||||||
|
from pwnagotchi.ui.components import LabeledValue
|
||||||
|
from pwnagotchi.ui.view import BLACK
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
class BluetoothSniffer(plugins.Plugin):
|
||||||
|
__author__ = 'diytechtinker'
|
||||||
|
__version__ = '0.1.3'
|
||||||
|
__license__ = 'GPL3'
|
||||||
|
__description__ = 'A plugin that sniffs Bluetooth devices and saves their MAC addresses, name and counts to a JSON file'
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
# Defining the instance variables
|
||||||
|
self.options = {
|
||||||
|
'timer': 45,
|
||||||
|
'devices_file': '/root/handshakes/bluetooth_devices.json',
|
||||||
|
'count_interval': 86400,
|
||||||
|
'bt_x_coord': 160,
|
||||||
|
'bt_y_coord': 66
|
||||||
|
}
|
||||||
|
self.data = {}
|
||||||
|
self.last_scan_time = 0
|
||||||
|
|
||||||
|
|
||||||
|
def on_loaded(self):
|
||||||
|
logging.info("[BtS] bluetoothsniffer plugin loaded.")
|
||||||
|
logging.info("[BtS] Bluetooth devices file location: %s", self.options['devices_file'])
|
||||||
|
# Creating the device file path if it does not exist
|
||||||
|
if not os.path.exists(os.path.dirname(self.options['devices_file'])):
|
||||||
|
os.makedirs(os.path.dirname(self.options['devices_file']))
|
||||||
|
|
||||||
|
# Creating the device file if it does not exist
|
||||||
|
if not os.path.exists(self.options['devices_file']):
|
||||||
|
with open(self.options['devices_file'], 'w') as f:
|
||||||
|
json.dump({}, f)
|
||||||
|
|
||||||
|
# Loading the data from the device file
|
||||||
|
with open(self.options['devices_file'], 'r') as f:
|
||||||
|
self.data = json.load(f)
|
||||||
|
|
||||||
|
|
||||||
|
def on_ui_setup(self, ui):
|
||||||
|
ui.add_element('BtS', LabeledValue(color=BLACK,
|
||||||
|
label='BT SNFD',
|
||||||
|
value=" ",
|
||||||
|
position=(int(self.options["bt_x_coord"]),
|
||||||
|
int(self.options["bt_y_coord"])),
|
||||||
|
label_font=fonts.Small,
|
||||||
|
text_font=fonts.Small))
|
||||||
|
|
||||||
|
def on_unload(self, ui):
|
||||||
|
with ui._lock:
|
||||||
|
ui.remove_element('BtS')
|
||||||
|
|
||||||
|
|
||||||
|
def on_ui_update(self, ui):
|
||||||
|
current_time = time.time()
|
||||||
|
# Checking the time elapsed since last scan
|
||||||
|
if current_time - self.last_scan_time >= self.options['timer']:
|
||||||
|
self.last_scan_time = current_time
|
||||||
|
#logging.info("[BtS] Bluetooth sniffed: %s", str(self.bt_sniff_info()))
|
||||||
|
ui.set('BtS', str(self.bt_sniff_info()))
|
||||||
|
self.scan()
|
||||||
|
|
||||||
|
|
||||||
|
# Method for scanning the nearby bluetooth devices
|
||||||
|
def scan(self):
|
||||||
|
logging.info("[BtS] Scanning for bluetooths...")
|
||||||
|
current_time = time.time()
|
||||||
|
changed = False
|
||||||
|
|
||||||
|
# Running the system command hcitool to scan nearby bluetooth devices
|
||||||
|
cmd_inq = "hcitool inq --flush"
|
||||||
|
try:
|
||||||
|
inq_output = subprocess.check_output(cmd_inq.split())
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
logging.error("[BtS] Error running command: %s", e)
|
||||||
|
|
||||||
|
for line in inq_output.splitlines()[1:]:
|
||||||
|
fields = line.split()
|
||||||
|
mac_address = fields[0].decode()
|
||||||
|
for i in range(len(fields)):
|
||||||
|
if fields[i].decode() == "class:" and i+1 < len(fields):
|
||||||
|
device_class = fields[i+1].decode()
|
||||||
|
logging.info("[BtS] Found bluetooth %s", mac_address)
|
||||||
|
|
||||||
|
# Update the count, first_seen, and last_seen time of the device
|
||||||
|
if mac_address in self.data and len(self.data) > 0:
|
||||||
|
if 'Unknown' == self.data[mac_address]['name']:
|
||||||
|
name = self.get_device_name(mac_address)
|
||||||
|
self.data[mac_address]['name'] = name
|
||||||
|
self.data[mac_address]['new_info'] = 2
|
||||||
|
logging.info("[BtS] Updated bluetooth name: %s", name)
|
||||||
|
changed = True
|
||||||
|
|
||||||
|
if 'Unknown' == self.data[mac_address]['manufacturer']:
|
||||||
|
manufacturer = self.get_device_manufacturer(mac_address)
|
||||||
|
self.data[mac_address]['manufacturer'] = manufacturer
|
||||||
|
self.data[mac_address]['new_info'] = 2
|
||||||
|
logging.info("[BtS] Updated bluetooth manufacturer: %s", manufacturer)
|
||||||
|
changed = True
|
||||||
|
|
||||||
|
if device_class != self.data[mac_address]['class']:
|
||||||
|
self.data[mac_address]['class'] = device_class
|
||||||
|
self.data[mac_address]['new_info'] = 2
|
||||||
|
logging.info("[BtS] Updated bluetooth class: %s", device_class)
|
||||||
|
changed = True
|
||||||
|
|
||||||
|
last_seen_time = int(datetime.strptime(self.data[mac_address]['last_seen'], '%H:%M:%S %d-%m-%Y').timestamp())
|
||||||
|
if current_time - last_seen_time >= self.options['count_interval']:
|
||||||
|
self.data[mac_address]['count'] += 1
|
||||||
|
self.data[mac_address]['last_seen'] = time.strftime('%H:%M:%S %d-%m-%Y', time.localtime(current_time))
|
||||||
|
self.data[mac_address]['new_info'] = 2
|
||||||
|
logging.info("[BtS] Updated bluetooth count.")
|
||||||
|
changed = True
|
||||||
|
else:
|
||||||
|
name = self.get_device_name(mac_address)
|
||||||
|
manufacturer = self.get_device_manufacturer(mac_address)
|
||||||
|
self.data[mac_address] = {'name': name, 'count': 1, 'class': device_class, 'manufacturer': manufacturer, 'first_seen': time.strftime('%H:%M:%S %d-%m-%Y', time.localtime(current_time)), 'last_seen': time.strftime('%H:%M:%S %d-%m-%Y', time.localtime(current_time)), 'new_info': True}
|
||||||
|
logging.info("[BtS] Added new bluetooth device %s with MAC: %s", name, mac_address)
|
||||||
|
changed = True
|
||||||
|
|
||||||
|
# Save the updated devices to the JSON file
|
||||||
|
if changed:
|
||||||
|
with open(self.options['devices_file'], 'w') as f:
|
||||||
|
logging.info("[BtS] Saving bluetooths %s into json.", name)
|
||||||
|
json.dump(self.data, f)
|
||||||
|
display.set('status', 'Bluetooth sniffed and stored!')
|
||||||
|
display.update(force=True)
|
||||||
|
|
||||||
|
# Method to get the device name
|
||||||
|
def get_device_name(self, mac_address):
|
||||||
|
logging.info("[BtS] Trying to get name for %s", mac_address)
|
||||||
|
name = 'Unknown'
|
||||||
|
hcitool_process = subprocess.Popen(["hcitool", "name", mac_address], stdout=subprocess.PIPE)
|
||||||
|
output, error = hcitool_process.communicate()
|
||||||
|
if output.decode().strip() != '':
|
||||||
|
name = output.decode().strip()
|
||||||
|
logging.info("[BtS] Got name %s for %s", name, mac_address)
|
||||||
|
return name
|
||||||
|
|
||||||
|
# Method to get the device manufacturer
|
||||||
|
def get_device_manufacturer(self, mac_address):
|
||||||
|
manufacturer = 'Unknown'
|
||||||
|
cmd_info = f"hcitool info {mac_address} | grep 'Manufacturer:' | cut -d ' ' -f 2-"
|
||||||
|
try:
|
||||||
|
logging.info("[BtS] Trying to get manufacturer for %s", mac_address)
|
||||||
|
start_time = time.time()
|
||||||
|
process = subprocess.Popen(cmd_info, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
|
||||||
|
while process.poll() is None:
|
||||||
|
time.sleep(0.1)
|
||||||
|
if time.time() - start_time > 7:
|
||||||
|
logging.info("[BtS] Timeout while trying to get manufacturer for %s", mac_address)
|
||||||
|
process.kill()
|
||||||
|
return manufacturer
|
||||||
|
output, error = process.communicate(timeout=1)
|
||||||
|
if output.decode().strip() != '':
|
||||||
|
manufacturer = output.decode().strip()
|
||||||
|
logging.info("[BtS] Got manufacturer %s for %s", manufacturer, mac_address)
|
||||||
|
except Exception as e:
|
||||||
|
logging.info("[BtS] Error while trying to get manufacturer for %s: %s", mac_address, str(e))
|
||||||
|
return manufacturer
|
||||||
|
|
||||||
|
def bt_sniff_info(self):
|
||||||
|
num_devices = len(self.data)
|
||||||
|
if num_devices > 0:
|
||||||
|
num_unknown = sum(1 for device in self.data.values() if device['name'] == 'Unknown' or device['manufacturer'] == 'Unknown')
|
||||||
|
num_known = num_devices - num_unknown
|
||||||
|
return_text = "%s|%s" % (num_devices, num_known)
|
||||||
|
else:
|
||||||
|
return_text = "0|0"
|
||||||
|
return return_text
|
336
pwnagotchi/plugins/default/exp.py
Normal file
336
pwnagotchi/plugins/default/exp.py
Normal file
@ -0,0 +1,336 @@
|
|||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import random
|
||||||
|
import json
|
||||||
|
|
||||||
|
import pwnagotchi
|
||||||
|
import pwnagotchi.agent
|
||||||
|
import pwnagotchi.plugins as plugins
|
||||||
|
import pwnagotchi.ui.fonts as fonts
|
||||||
|
from pwnagotchi.ui.components import LabeledValue
|
||||||
|
from pwnagotchi.ui.view import BLACK
|
||||||
|
|
||||||
|
# Static Variables
|
||||||
|
MULTIPLIER_ASSOCIATION = 1
|
||||||
|
MULTIPLIER_DEAUTH = 2
|
||||||
|
MULTIPLIER_HANDSHAKE = 3
|
||||||
|
MULTIPLIER_AI_BEST_REWARD = 5
|
||||||
|
TAG = "[EXP Plugin]"
|
||||||
|
FACE_LEVELUP = '(≧◡◡≦)'
|
||||||
|
BAR_ERROR = "| error |"
|
||||||
|
FILE_SAVE = "exp_stats"
|
||||||
|
FILE_SAVE_LEGACY = "exp"
|
||||||
|
JSON_KEY_LEVEL = "level"
|
||||||
|
JSON_KEY_EXP = "exp"
|
||||||
|
JSON_KEY_EXP_TOT = "exp_tot"
|
||||||
|
|
||||||
|
|
||||||
|
class EXP(plugins.Plugin):
|
||||||
|
__author__ = 'GaelicThunder'
|
||||||
|
__version__ = '1.0.5'
|
||||||
|
__license__ = 'GPL3'
|
||||||
|
__description__ = 'Get exp every time a handshake get captured.'
|
||||||
|
|
||||||
|
# Attention number masking
|
||||||
|
def LogInfo(self, text):
|
||||||
|
logging.info(TAG + " " + text)
|
||||||
|
|
||||||
|
# Attention number masking
|
||||||
|
def LogDebug(self, text):
|
||||||
|
logging.debug(TAG + " " + text)
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.percent = 0
|
||||||
|
self.calculateInitialXP = False
|
||||||
|
self.exp = 0
|
||||||
|
self.lv = 1
|
||||||
|
self.exp_tot = 0
|
||||||
|
# Sets the file type I recommend json
|
||||||
|
self.save_file_mode = self.save_file_modes("json")
|
||||||
|
self.save_file = self.getSaveFileName(self.save_file_mode)
|
||||||
|
# Migrate from old save system
|
||||||
|
self.migrateLegacySave()
|
||||||
|
|
||||||
|
# Create save file
|
||||||
|
if not os.path.exists(self.save_file):
|
||||||
|
self.Save(self.save_file, self.save_file_mode)
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
# Try loading
|
||||||
|
self.Load(self.save_file, self.save_file_mode)
|
||||||
|
except:
|
||||||
|
# Likely throws an exception if json file is corrupted, so we need to calculate from scratch
|
||||||
|
self.calculateInitialXP = True
|
||||||
|
|
||||||
|
# No previous data, try get it
|
||||||
|
if self.lv == 1 and self.exp == 0:
|
||||||
|
self.calculateInitialXP = True
|
||||||
|
if self.exp_tot == 0:
|
||||||
|
self.LogInfo("Need to calculate Total Exp")
|
||||||
|
self.exp_tot = self.calcActualSum(self.lv, self.exp)
|
||||||
|
self.Save(self.save_file, self.save_file_mode)
|
||||||
|
|
||||||
|
self.expneeded = self.calcExpNeeded(self.lv)
|
||||||
|
|
||||||
|
def on_loaded(self):
|
||||||
|
# logging.info("Exp plugin loaded for %s" % self.options['device'])
|
||||||
|
self.LogInfo("Plugin Loaded")
|
||||||
|
|
||||||
|
def save_file_modes(self, argument):
|
||||||
|
switcher = {
|
||||||
|
"txt": 0,
|
||||||
|
"json": 1,
|
||||||
|
}
|
||||||
|
return switcher.get(argument, 0)
|
||||||
|
|
||||||
|
def Save(self, file, save_file_mode):
|
||||||
|
self.LogDebug('Saving Exp')
|
||||||
|
if save_file_mode == 0:
|
||||||
|
self.saveToTxtFile(file)
|
||||||
|
if save_file_mode == 1:
|
||||||
|
self.saveToJsonFile(file)
|
||||||
|
|
||||||
|
def saveToTxtFile(self, file):
|
||||||
|
outfile = open(file, 'w')
|
||||||
|
print(self.exp, file=outfile)
|
||||||
|
print(self.lv, file=outfile)
|
||||||
|
print(self.exp_tot, file=outfile)
|
||||||
|
outfile.close()
|
||||||
|
|
||||||
|
def loadFromTxtFile(self, file):
|
||||||
|
if os.path.exists(file):
|
||||||
|
outfile = open(file, 'r+')
|
||||||
|
lines = outfile.readlines()
|
||||||
|
linecounter = 1
|
||||||
|
for line in lines:
|
||||||
|
if linecounter == 1:
|
||||||
|
self.exp = int(line)
|
||||||
|
elif linecounter == 2:
|
||||||
|
self.lv == int(line)
|
||||||
|
elif linecounter == 3:
|
||||||
|
self.exp_tot == int(line)
|
||||||
|
linecounter += 1
|
||||||
|
outfile.close()
|
||||||
|
|
||||||
|
def saveToJsonFile(self, file):
|
||||||
|
data = {
|
||||||
|
JSON_KEY_LEVEL: self.lv,
|
||||||
|
JSON_KEY_EXP: self.exp,
|
||||||
|
JSON_KEY_EXP_TOT: self.exp_tot
|
||||||
|
}
|
||||||
|
|
||||||
|
with open(file, 'w') as f:
|
||||||
|
f.write(json.dumps(data, sort_keys=True, indent=4, separators=(',', ': ')))
|
||||||
|
|
||||||
|
def loadFromJsonFile(self, file):
|
||||||
|
# Tot exp is introduced with json, no check needed
|
||||||
|
data = {}
|
||||||
|
with open(file, 'r') as f:
|
||||||
|
data = json.loads(f.read())
|
||||||
|
|
||||||
|
if bool(data):
|
||||||
|
self.lv = data[JSON_KEY_LEVEL]
|
||||||
|
self.exp = data[JSON_KEY_EXP]
|
||||||
|
self.exp_tot = data[JSON_KEY_EXP_TOT]
|
||||||
|
else:
|
||||||
|
self.LogInfo("Empty json")
|
||||||
|
|
||||||
|
# TODO: one day change save file mode to file date
|
||||||
|
def Load(self, file, save_file_mode):
|
||||||
|
self.LogDebug('Loading Exp')
|
||||||
|
if save_file_mode == 0:
|
||||||
|
self.loadFromTxtFile(file)
|
||||||
|
if save_file_mode == 1:
|
||||||
|
self.loadFromJsonFile(file)
|
||||||
|
|
||||||
|
def getSaveFileName(self, save_file_mode):
|
||||||
|
file = os.path.dirname(os.path.realpath(__file__))
|
||||||
|
file = file + "/" + FILE_SAVE
|
||||||
|
if save_file_mode == 0:
|
||||||
|
file = file + ".txt"
|
||||||
|
elif save_file_mode == 1:
|
||||||
|
file = file + ".json"
|
||||||
|
else:
|
||||||
|
# See switcher
|
||||||
|
file = file + ".txt"
|
||||||
|
return file
|
||||||
|
|
||||||
|
def migrateLegacySave(self):
|
||||||
|
legacyFile = os.path.dirname(os.path.realpath(__file__))
|
||||||
|
legacyFile = legacyFile + "/" + FILE_SAVE_LEGACY + ".txt"
|
||||||
|
if os.path.exists(legacyFile):
|
||||||
|
self.loadFromTxtFile(legacyFile)
|
||||||
|
self.LogInfo("Migrating Legacy Save...")
|
||||||
|
self.Save(self.save_file, self.save_file_mode)
|
||||||
|
os.remove(legacyFile)
|
||||||
|
|
||||||
|
def barString(self, symbols_count, p):
|
||||||
|
if p > 100:
|
||||||
|
return BAR_ERROR
|
||||||
|
length = symbols_count - 2
|
||||||
|
bar_char = '▥'
|
||||||
|
blank_char = ' '
|
||||||
|
bar_length = int(round((length / 100) * p))
|
||||||
|
blank_length = length - bar_length
|
||||||
|
res = '|' + bar_char * bar_length + blank_char * blank_length + '|'
|
||||||
|
return res
|
||||||
|
|
||||||
|
def on_ui_setup(self, ui):
|
||||||
|
ui.add_element('Lv', LabeledValue(color=BLACK, label='Lv', value=0,
|
||||||
|
position=(int(self.options["lvl_x_coord"]),
|
||||||
|
int(self.options["lvl_y_coord"])),
|
||||||
|
label_font=fonts.Bold, text_font=fonts.Medium))
|
||||||
|
ui.add_element('Exp', LabeledValue(color=BLACK, label='Exp', value=0,
|
||||||
|
position=(int(self.options["exp_x_coord"]),
|
||||||
|
int(self.options["exp_y_coord"])),
|
||||||
|
label_font=fonts.Bold, text_font=fonts.Medium))
|
||||||
|
|
||||||
|
def on_ui_update(self, ui):
|
||||||
|
self.expneeded = self.calcExpNeeded(self.lv)
|
||||||
|
self.percent = int((self.exp / self.expneeded) * 100)
|
||||||
|
symbols_count = int(self.options["bar_symbols_count"])
|
||||||
|
bar = self.barString(symbols_count, self.percent)
|
||||||
|
ui.set('Lv', "%d" % self.lv)
|
||||||
|
ui.set('Exp', "%s" % bar)
|
||||||
|
|
||||||
|
def calcExpNeeded(self, level):
|
||||||
|
# If the pwnagotchi is lvl <1 it causes the keys to be deleted
|
||||||
|
if level == 1:
|
||||||
|
return 5
|
||||||
|
return int((level ** 3) / 2)
|
||||||
|
|
||||||
|
def exp_check(self, agent):
|
||||||
|
self.LogDebug("EXP CHECK")
|
||||||
|
if self.exp >= self.expneeded:
|
||||||
|
self.exp = 1
|
||||||
|
self.lv = self.lv + 1
|
||||||
|
self.expneeded = self.calcExpNeeded(self.lv)
|
||||||
|
self.displayLevelUp(agent)
|
||||||
|
|
||||||
|
def parseSessionStats(self):
|
||||||
|
sum = 0
|
||||||
|
dir = pwnagotchi.config['main']['plugins']['session-stats']['save_directory']
|
||||||
|
# TODO: remove
|
||||||
|
self.LogInfo("Session-Stats dir: " + dir)
|
||||||
|
for filename in os.listdir(dir):
|
||||||
|
self.LogInfo("Parsing " + filename + "...")
|
||||||
|
if filename.endswith(".json") & filename.startswith("stats"):
|
||||||
|
try:
|
||||||
|
sum += self.parseSessionStatsFile(os.path.join(dir, filename))
|
||||||
|
except:
|
||||||
|
self.LogInfo("ERROR parsing File: " + filename)
|
||||||
|
|
||||||
|
return sum
|
||||||
|
|
||||||
|
def parseSessionStatsFile(self, path):
|
||||||
|
sum = 0
|
||||||
|
deauths = 0
|
||||||
|
handshakes = 0
|
||||||
|
associations = 0
|
||||||
|
with open(path) as json_file:
|
||||||
|
data = json.load(json_file)
|
||||||
|
for entry in data["data"]:
|
||||||
|
deauths += data["data"][entry]["num_deauths"]
|
||||||
|
handshakes += data["data"][entry]["num_handshakes"]
|
||||||
|
associations += data["data"][entry]["num_associations"]
|
||||||
|
|
||||||
|
sum += deauths * MULTIPLIER_DEAUTH
|
||||||
|
sum += handshakes * MULTIPLIER_HANDSHAKE
|
||||||
|
sum += associations * MULTIPLIER_ASSOCIATION
|
||||||
|
|
||||||
|
return sum
|
||||||
|
|
||||||
|
# If initial sum is 0, we try to parse it
|
||||||
|
def calculateInitialSum(self, agent):
|
||||||
|
sessionStatsActive = False
|
||||||
|
sum = 0
|
||||||
|
# Check if session stats is loaded
|
||||||
|
for plugin in pwnagotchi.plugins.loaded:
|
||||||
|
if plugin == "session-stats":
|
||||||
|
sessionStatsActive = True
|
||||||
|
break
|
||||||
|
|
||||||
|
if sessionStatsActive:
|
||||||
|
try:
|
||||||
|
self.LogInfo("parsing session-stats")
|
||||||
|
sum = self.parseSessionStats()
|
||||||
|
except:
|
||||||
|
self.LogInfo("Error parsing session-stats")
|
||||||
|
|
||||||
|
|
||||||
|
else:
|
||||||
|
self.LogInfo("parsing last session")
|
||||||
|
sum = self.lastSessionPoints(agent)
|
||||||
|
|
||||||
|
self.LogInfo(str(sum) + " Points calculated")
|
||||||
|
return sum
|
||||||
|
|
||||||
|
# Get Last Sessions Points
|
||||||
|
def lastSessionPoints(self, agent):
|
||||||
|
summary = 0
|
||||||
|
summary += agent.LastSession.handshakes * MULTIPLIER_HANDSHAKE
|
||||||
|
summary += agent.LastSession.associated * MULTIPLIER_ASSOCIATION
|
||||||
|
summary += agent.LastSession.deauthed * MULTIPLIER_DEAUTH
|
||||||
|
return summary
|
||||||
|
|
||||||
|
# Helper function to calculate multiple Levels from a sum of EXPs
|
||||||
|
def calcLevelFromSum(self, sum, agent):
|
||||||
|
sum1 = sum
|
||||||
|
level = 1
|
||||||
|
while sum1 > self.calcExpNeeded(level):
|
||||||
|
sum1 -= self.calcExpNeeded(level)
|
||||||
|
level += 1
|
||||||
|
self.lv = level
|
||||||
|
self.exp = sum1
|
||||||
|
self.expneeded = self.calcExpNeeded(level) - sum1
|
||||||
|
if level > 1:
|
||||||
|
# get Excited ;-)
|
||||||
|
self.displayLevelUp(agent)
|
||||||
|
|
||||||
|
def calcActualSum(self, level, exp):
|
||||||
|
lvlCounter = 1
|
||||||
|
sum = exp
|
||||||
|
# I know it wouldn't work if you change the lvl algorithm
|
||||||
|
while lvlCounter < level:
|
||||||
|
sum += self.calcExpNeeded(lvlCounter)
|
||||||
|
lvlCounter += 1
|
||||||
|
return sum
|
||||||
|
|
||||||
|
def displayLevelUp(self, agent):
|
||||||
|
view = agent.view()
|
||||||
|
view.set('face', FACE_LEVELUP)
|
||||||
|
view.set('status', "Level Up!")
|
||||||
|
view.update(force=True)
|
||||||
|
|
||||||
|
# Event Handling
|
||||||
|
def on_association(self, agent, access_point):
|
||||||
|
self.exp += MULTIPLIER_ASSOCIATION
|
||||||
|
self.exp_tot += MULTIPLIER_ASSOCIATION
|
||||||
|
self.exp_check(agent)
|
||||||
|
self.Save(self.save_file, self.save_file_mode)
|
||||||
|
|
||||||
|
def on_deauthentication(self, agent, access_point, client_station):
|
||||||
|
self.exp += MULTIPLIER_DEAUTH
|
||||||
|
self.exp_tot += MULTIPLIER_DEAUTH
|
||||||
|
self.exp_check(agent)
|
||||||
|
self.Save(self.save_file, self.save_file_mode)
|
||||||
|
|
||||||
|
def on_handshake(self, agent, filename, access_point, client_station):
|
||||||
|
self.exp += MULTIPLIER_HANDSHAKE
|
||||||
|
self.exp_tot += MULTIPLIER_HANDSHAKE
|
||||||
|
self.exp_check(agent)
|
||||||
|
self.Save(self.save_file, self.save_file_mode)
|
||||||
|
|
||||||
|
def on_ai_best_reward(self, agent, reward):
|
||||||
|
self.exp += MULTIPLIER_AI_BEST_REWARD
|
||||||
|
self.exp_tot += MULTIPLIER_AI_BEST_REWARD
|
||||||
|
self.exp_check(agent)
|
||||||
|
self.Save(self.save_file, self.save_file_mode)
|
||||||
|
|
||||||
|
def on_ready(self, agent):
|
||||||
|
if self.calculateInitialXP:
|
||||||
|
self.LogInfo("Initial point calculation")
|
||||||
|
sum = self.calculateInitialSum(agent)
|
||||||
|
self.exp_tot = sum
|
||||||
|
self.calcLevelFromSum(sum, agent)
|
||||||
|
self.Save(self.save_file, self.save_file_mode)
|
384
pwnagotchi/plugins/default/fix_brcmf_plugin.py
Normal file
384
pwnagotchi/plugins/default/fix_brcmf_plugin.py
Normal file
@ -0,0 +1,384 @@
|
|||||||
|
import logging
|
||||||
|
import re
|
||||||
|
import subprocess
|
||||||
|
import time
|
||||||
|
import random
|
||||||
|
from io import TextIOWrapper
|
||||||
|
from pwnagotchi import plugins
|
||||||
|
|
||||||
|
import pwnagotchi.ui.faces as faces
|
||||||
|
from pwnagotchi.bettercap import Client
|
||||||
|
|
||||||
|
from pwnagotchi.ui.components import Text, LabeledValue
|
||||||
|
from pwnagotchi.ui.view import BLACK
|
||||||
|
import pwnagotchi.ui.fonts as fonts
|
||||||
|
|
||||||
|
|
||||||
|
class Fix_BRCMF(plugins.Plugin):
|
||||||
|
__author__ = 'xBits'
|
||||||
|
__version__ = '0.1.1'
|
||||||
|
__license__ = 'GPL3'
|
||||||
|
__description__ = 'Reload brcmfmac module when blindbug is detected, instead of rebooting. Adapted from WATCHDOG.'
|
||||||
|
__name__ = 'Fix_BRCMF'
|
||||||
|
__help__ = """
|
||||||
|
Reload brcmfmac module when blindbug is detected, instead of rebooting. Adapted from WATCHDOG.
|
||||||
|
"""
|
||||||
|
__dependencies__ = {
|
||||||
|
'pip': ['scapy']
|
||||||
|
}
|
||||||
|
__defaults__ = {
|
||||||
|
'enabled': False,
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.options = dict()
|
||||||
|
self.pattern = re.compile(r'brcmf_cfg80211_nexmon_set_channel.*?Set Channel failed')
|
||||||
|
self.pattern2 = re.compile(r'wifi error while hopping to channel')
|
||||||
|
self.isReloadingMon = False
|
||||||
|
self.connection = None
|
||||||
|
self.LASTTRY = 0
|
||||||
|
self._status = "--"
|
||||||
|
self._count = 0
|
||||||
|
|
||||||
|
def on_loaded(self):
|
||||||
|
"""
|
||||||
|
Gets called when the plugin gets loaded
|
||||||
|
"""
|
||||||
|
self.pattern = re.compile(r'brcmf_cfg80211_nexmon_set_channel.*?Set Channel failed')
|
||||||
|
self._status = "ld"
|
||||||
|
logging.info("[FixBRCMF] plugin loaded.")
|
||||||
|
|
||||||
|
def on_ready(self, agent):
|
||||||
|
try:
|
||||||
|
cmd_output = subprocess.check_output("ip link show wlan0mon", shell=True)
|
||||||
|
logging.info("[FixBRCMF ip link show wlan0mon]: %s" % repr(cmd_output))
|
||||||
|
if ",UP," in str(cmd_output):
|
||||||
|
logging.info("wlan0mon is up.")
|
||||||
|
self._status = "up"
|
||||||
|
last_lines = ''.join(list(TextIOWrapper(subprocess.Popen(['journalctl', '-n10', '-k'],
|
||||||
|
stdout=subprocess.PIPE).stdout))[-10:])
|
||||||
|
if len(self.pattern.findall(last_lines)) >= 3:
|
||||||
|
self._status = "XX"
|
||||||
|
if hasattr(agent, 'view'):
|
||||||
|
display = agent.view()
|
||||||
|
display.set('status', 'Blind-Bug detected. Restarting.')
|
||||||
|
display.update(force=True)
|
||||||
|
logging.info('[FixBRCMF] Blind-Bug detected. Restarting.\n%s' % repr(last_lines))
|
||||||
|
try:
|
||||||
|
self._tryTurningItOffAndOnAgain(agent)
|
||||||
|
except Exception as err:
|
||||||
|
logging.warning("[FixBRCMF turnOffAndfOn] %s" % repr(err))
|
||||||
|
else:
|
||||||
|
logging.info("[FixBRCMF] Logs look good, too:\n%s" % last_lines)
|
||||||
|
self._status = ""
|
||||||
|
|
||||||
|
except Exception as err:
|
||||||
|
logging.error("[FixBRCMF ip link show wlan0mon]: %s" % repr(err))
|
||||||
|
try:
|
||||||
|
self._status = "xx"
|
||||||
|
self._tryTurningItOffAndOnAgain(agent)
|
||||||
|
except Exception as err:
|
||||||
|
logging.error("[FixBRCMF OffNOn]: %s" % repr(err))
|
||||||
|
|
||||||
|
# bettercap sys_log event
|
||||||
|
# search syslog events for the brcmf channel fail, and reset when it shows up
|
||||||
|
# apparently this only gets messages from bettercap going to syslog, not from syslog
|
||||||
|
def on_bcap_sys_log(self, agent, event):
|
||||||
|
if re.search('wifi error while hopping to channel', event['data']['Message']):
|
||||||
|
logging.info("[FixBRCMF]SYSLOG MATCH: %s" % event['data']['Message'])
|
||||||
|
logging.info("[FixBRCMF]**** restarting wifi.recon")
|
||||||
|
try:
|
||||||
|
result = agent.run("wifi.recon off; wifi.recon on")
|
||||||
|
if result["success"]:
|
||||||
|
logging.info("[FixBRCMF] wifi.recon flip: success!")
|
||||||
|
if hasattr(agent, 'view'):
|
||||||
|
display = agent.view()
|
||||||
|
if display: display.update(force=True, new_data={"status": "Wifi recon flipped!",
|
||||||
|
"face": faces.COOL})
|
||||||
|
else:
|
||||||
|
print("Wifi recon flipped")
|
||||||
|
else:
|
||||||
|
logging.warning("[FixBRCMF] wifi.recon flip: FAILED: %s" % repr(result))
|
||||||
|
except Exception as err:
|
||||||
|
logging.error("[FixBRCMF]SYSLOG wifi.recon flip fail: %s" % err)
|
||||||
|
|
||||||
|
def on_epoch(self, agent, epoch, epoch_data):
|
||||||
|
# don't check if we ran a reset recently
|
||||||
|
logging.debug("[FixBRCMF]**** epoch")
|
||||||
|
if time.time() - self.LASTTRY > 180:
|
||||||
|
# get last 10 lines
|
||||||
|
display = None
|
||||||
|
last_lines = ''.join(list(TextIOWrapper(subprocess.Popen(['journalctl', '-n10', '-k'],
|
||||||
|
stdout=subprocess.PIPE).stdout))[-10:])
|
||||||
|
other_last_lines = ''.join(list(TextIOWrapper(subprocess.Popen(['journalctl', '-n10'],
|
||||||
|
stdout=subprocess.PIPE).stdout))[-10:])
|
||||||
|
logging.debug("[FixBRCMF]**** checking")
|
||||||
|
if len(self.pattern.findall(last_lines)) >= 3:
|
||||||
|
logging.info("[FixBRCMF]**** Should trigger a reload of the wlan0mon device:\n%s" % last_lines)
|
||||||
|
if hasattr(agent, 'view'):
|
||||||
|
display = agent.view()
|
||||||
|
display.set('status', 'Blind-Bug detected. Restarting.')
|
||||||
|
display.update(force=True)
|
||||||
|
logging.info('[FixBRCMF] Blind-Bug detected. Restarting.')
|
||||||
|
try:
|
||||||
|
self._tryTurningItOffAndOnAgain(agent)
|
||||||
|
except Exception as err:
|
||||||
|
logging.warning("[FixBRCMF] TTOAOA: %s" % repr(err))
|
||||||
|
elif len(self.pattern2.findall(other_last_lines)) >= 5:
|
||||||
|
if hasattr(agent, 'view'):
|
||||||
|
display = agent.view()
|
||||||
|
display.set('status', 'Wifi channel stuck. Restarting recon.')
|
||||||
|
display.update(force=True)
|
||||||
|
logging.info('[FixBRCMF] Wifi channel stuck. Restarting recon.')
|
||||||
|
|
||||||
|
try:
|
||||||
|
result = agent.run("wifi.recon off; wifi.recon on")
|
||||||
|
if result["success"]:
|
||||||
|
logging.info("[FixBRCMF] wifi.recon flip: success!")
|
||||||
|
if display:
|
||||||
|
display.update(force=True, new_data={"status": "Wifi recon flipped!",
|
||||||
|
"brcmfmac_status": self._status,
|
||||||
|
"face": faces.COOL})
|
||||||
|
else:
|
||||||
|
print("Wifi recon flipped\nthat was easy!")
|
||||||
|
else:
|
||||||
|
logging.warning("[FixBRCMF] wifi.recon flip: FAILED: %s" % repr(result))
|
||||||
|
|
||||||
|
except Exception as err:
|
||||||
|
logging.error("[FixBRCMF wifi.recon flip] %s" % repr(err))
|
||||||
|
|
||||||
|
else:
|
||||||
|
print("logs look good")
|
||||||
|
|
||||||
|
def logPrintView(self, level, message, ui=None, displayData=None, force=True):
|
||||||
|
try:
|
||||||
|
if level is "error":
|
||||||
|
logging.error(message)
|
||||||
|
elif level is "warning":
|
||||||
|
logging.warning(message)
|
||||||
|
elif level is "debug":
|
||||||
|
logging.debug(message)
|
||||||
|
else:
|
||||||
|
logging.info(message)
|
||||||
|
|
||||||
|
if ui:
|
||||||
|
ui.update(force=force, new_data=displayData)
|
||||||
|
elif displayData and "status" in displayData:
|
||||||
|
print(displayData["status"])
|
||||||
|
else:
|
||||||
|
print("[%s] %s" % (level, message))
|
||||||
|
except Exception as err:
|
||||||
|
logging.error("[logPrintView] ERROR %s" % repr(err))
|
||||||
|
|
||||||
|
def _tryTurningItOffAndOnAgain(self, connection):
|
||||||
|
# avoid overlapping restarts, but allow it if it's been a while
|
||||||
|
# (in case the last attempt failed before resetting "isReloadingMon")
|
||||||
|
if self.isReloadingMon and (time.time() - self.LASTTRY) < 180:
|
||||||
|
logging.info("[FixBRCMF] Duplicate attempt ignored")
|
||||||
|
else:
|
||||||
|
self.isReloadingMon = True
|
||||||
|
self.LASTTRY = time.time()
|
||||||
|
|
||||||
|
self._status = "BL"
|
||||||
|
if hasattr(connection, 'view'):
|
||||||
|
display = connection.view()
|
||||||
|
if display: display.update(force=True, new_data={"status": "I'm blind! Try turning it off and on again",
|
||||||
|
"brcmfmac_status": self._status,
|
||||||
|
"face": faces.BORED})
|
||||||
|
else:
|
||||||
|
display = None
|
||||||
|
|
||||||
|
# main divergence from WATCHDOG starts here
|
||||||
|
#
|
||||||
|
# instead of rebooting, and losing all that energy loading up the AI
|
||||||
|
# pause wifi.recon, close wlan0mon, reload the brcmfmac kernel module
|
||||||
|
# then recreate wlan0mon, ..., and restart wifi.recon
|
||||||
|
|
||||||
|
# Turn it off
|
||||||
|
|
||||||
|
# attempt a sanity check. does wlan0mon exist?
|
||||||
|
# is it up?
|
||||||
|
try:
|
||||||
|
cmd_output = subprocess.check_output("ip link show wlan0mon", shell=True)
|
||||||
|
logging.info("[FixBRCMF ip link show wlan0mon]: %s" % repr(cmd_output))
|
||||||
|
if ",UP," in str(cmd_output):
|
||||||
|
logging.info("wlan0mon is up. Skip reset?")
|
||||||
|
# not reliable, so don't skip just yet
|
||||||
|
# print("wlan0mon is up. Skipping reset.")
|
||||||
|
# self.isReloadingMon = False
|
||||||
|
# return
|
||||||
|
except Exception as err:
|
||||||
|
logging.error("[FixBRCMF ip link show wlan0mon]: %s" % repr(err))
|
||||||
|
|
||||||
|
try:
|
||||||
|
result = connection.run("wifi.recon off")
|
||||||
|
if "success" in result:
|
||||||
|
self.logPrintView("info", "[FixBRCMF] wifi.recon off: %s!" % repr(result),
|
||||||
|
display, {"status": "Wifi recon paused!", "face": faces.COOL})
|
||||||
|
time.sleep(2)
|
||||||
|
else:
|
||||||
|
self.logPrintView("warning", "[FixBRCMF] wifi.recon off: FAILED: %s" % repr(result),
|
||||||
|
display, {"status": "Recon was busted (probably)",
|
||||||
|
"face": random.choice((faces.BROKEN, faces.DEBUG))})
|
||||||
|
except Exception as err:
|
||||||
|
logging.error("[FixBRCMF wifi.recon off] error %s" % (repr(err)))
|
||||||
|
|
||||||
|
logging.info("[FixBRCMF] recon paused. Now trying wlan0mon reload")
|
||||||
|
|
||||||
|
try:
|
||||||
|
cmd_output = subprocess.check_output("sudo ifconfig wlan0mon down && sudo iw dev wlan0mon del", shell=True)
|
||||||
|
self._status = "dn"
|
||||||
|
self.logPrintView("info", "[FixBRCMF] wlan0mon down and deleted: %s" % cmd_output,
|
||||||
|
display, {"status": "wlan0mon d-d-d-down!", "face": faces.BORED})
|
||||||
|
except Exception as nope:
|
||||||
|
logging.error("[FixBRCMF delete wlan0mon] %s" % nope)
|
||||||
|
pass
|
||||||
|
|
||||||
|
logging.debug("[FixBRCMF] Now trying modprobe -r")
|
||||||
|
|
||||||
|
# Try this sequence 3 times until it is reloaded
|
||||||
|
#
|
||||||
|
# Future: while "not fixed yet": blah blah blah. if "max_attemts", then reboot like the old days
|
||||||
|
#
|
||||||
|
tries = 0
|
||||||
|
while tries < 3:
|
||||||
|
try:
|
||||||
|
# unload the module
|
||||||
|
cmd_output = subprocess.check_output("sudo modprobe -r brcmfmac", shell=True)
|
||||||
|
self.logPrintView("info", "[FixBRCMF] unloaded brcmfmac", display,
|
||||||
|
{"status": "Turning it off #%d" % tries, "face": faces.SMART})
|
||||||
|
self._status = "ul"
|
||||||
|
time.sleep(1 + tries)
|
||||||
|
|
||||||
|
# reload the module
|
||||||
|
try:
|
||||||
|
# reload the brcmfmac kernel module
|
||||||
|
cmd_output = subprocess.check_output("sudo modprobe brcmfmac", shell=True)
|
||||||
|
|
||||||
|
self.logPrintView("info", "[FixBRCMF] reloaded brcmfmac")
|
||||||
|
self._status = "rl"
|
||||||
|
time.sleep(10 + 4 * tries) # give it some time for wlan device to stabilize, or whatever
|
||||||
|
|
||||||
|
# success! now make the mon0
|
||||||
|
try:
|
||||||
|
cmd_output = subprocess.check_output(
|
||||||
|
"sudo iw phy \"$(iw phy | head -1 | cut -d' ' -f2)\" interface add mon0 type monitor && sudo ifconfig mon0 up",
|
||||||
|
shell=True)
|
||||||
|
self.logPrintView("info",
|
||||||
|
"[FixBRCMF interface add mon0] worked #%d: %s" % (tries, cmd_output))
|
||||||
|
self._status = "up"
|
||||||
|
time.sleep(tries + 5)
|
||||||
|
try:
|
||||||
|
# try accessing mon0 in bettercap
|
||||||
|
result = connection.run("set wifi.interface mon0")
|
||||||
|
if "success" in result:
|
||||||
|
logging.info("[FixBRCMF set wifi.interface mon0] worked: %s" % repr(result))
|
||||||
|
self._status = ""
|
||||||
|
self._count = self._count + 1
|
||||||
|
time.sleep(1)
|
||||||
|
# stop looping and get back to recon
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
logging.info("[FixBRCMF set wifi.interfaceface mon0] failed? %s" % repr(result))
|
||||||
|
except Exception as err:
|
||||||
|
logging.info(
|
||||||
|
"[FixBRCMF set wifi.interface mon0] except: %s" % (repr(result), repr(err)))
|
||||||
|
except Exception as cerr: #
|
||||||
|
if not display: print("failed loading mon0 attempt #%d: %s" % (tries, repr(cerr)))
|
||||||
|
except Exception as err: # from modprobe
|
||||||
|
if not display: print("Failed reloading brcmfmac")
|
||||||
|
logging.error("[FixBRCMF] Failed reloading brcmfmac %s" % repr(err))
|
||||||
|
|
||||||
|
except Exception as nope: # from modprobe -r
|
||||||
|
# fails if already unloaded, so probably fine
|
||||||
|
logging.error("[FixBRCMF #%d modprobe -r] %s" % (tries, repr(nope)))
|
||||||
|
if not display: print("[FixBRCMF #%d modprobe -r] %s" % (tries, repr(nope)))
|
||||||
|
pass
|
||||||
|
|
||||||
|
tries = tries + 1
|
||||||
|
if tries < 3:
|
||||||
|
logging.info("[FixBRCMF] wlan0mon didn't make it. trying again")
|
||||||
|
if not display: print(" wlan0mon didn't make it. trying again")
|
||||||
|
|
||||||
|
# exited the loop, so hopefully it loaded
|
||||||
|
if tries < 3:
|
||||||
|
if display:
|
||||||
|
display.update(force=True, new_data={"status": "And back on again...",
|
||||||
|
"brcmfmac_status": self._status,
|
||||||
|
"face": faces.INTENSE})
|
||||||
|
else:
|
||||||
|
print("And back on again...")
|
||||||
|
logging.info("[FixBRCMF] mon0 back up")
|
||||||
|
else:
|
||||||
|
self.LASTTRY = time.time()
|
||||||
|
|
||||||
|
time.sleep(8 + tries * 2) # give it a bit before restarting recon in bettercap
|
||||||
|
self.isReloadingMon = False
|
||||||
|
|
||||||
|
logging.info("[FixBRCMF] re-enable recon")
|
||||||
|
try:
|
||||||
|
result = connection.run("wifi.clear; wifi.recon on")
|
||||||
|
|
||||||
|
if "success" in result: # and result["success"] is True:
|
||||||
|
self._status = ""
|
||||||
|
if display:
|
||||||
|
display.update(force=True, new_data={"status": "I can see again! (probably): %s" % repr(result),
|
||||||
|
"brcmfmac_status": self._status,
|
||||||
|
"face": faces.HAPPY})
|
||||||
|
else:
|
||||||
|
print("I can see again")
|
||||||
|
logging.info("[FixBRCMF] wifi.recon on %s" % repr(result))
|
||||||
|
self.LASTTRY = time.time() + 120 # 2-minute pause until next time.
|
||||||
|
else:
|
||||||
|
logging.error("[FixBRCMF] wifi.recon did not start up: %s" % repr(result))
|
||||||
|
self.LASTTRY = time.time() - 300 # failed, so try again ASAP
|
||||||
|
self.isReloadingMon = False
|
||||||
|
|
||||||
|
except Exception as err:
|
||||||
|
logging.error("[FixBRCMF wifi.recon on] %s" % repr(err))
|
||||||
|
|
||||||
|
# called to setup the ui elements
|
||||||
|
def on_ui_setup(self, ui):
|
||||||
|
# add custom UI elements
|
||||||
|
if "position" in self.options:
|
||||||
|
pos = self.options['position'].split(',')
|
||||||
|
pos = [int(x.strip()) for x in pos]
|
||||||
|
else:
|
||||||
|
pos = (ui.width() / 2 + 35, ui.height() - 11)
|
||||||
|
|
||||||
|
logging.info("Got here")
|
||||||
|
ui.add_element('brcmfmac_status', Text(color=BLACK, value='--', position=pos, font=fonts.Small))
|
||||||
|
|
||||||
|
# called when the ui is updated
|
||||||
|
|
||||||
|
def on_ui_update(self, ui):
|
||||||
|
# update those elements
|
||||||
|
if self._status:
|
||||||
|
ui.set('brcmfmac_status', "wlan0mon %s" % self._status)
|
||||||
|
else:
|
||||||
|
ui.set('brcmfmac_status', "rst#%s" % self._count)
|
||||||
|
|
||||||
|
def on_unload(self, ui):
|
||||||
|
try:
|
||||||
|
ui.remove_element('brcmfmac_status')
|
||||||
|
logging.info("[FixBRCMF] unloaded")
|
||||||
|
except Exception as err:
|
||||||
|
logging.info("[FixBRCMF] unload err %s " % repr(err))
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
# run from command line to brute force a reload
|
||||||
|
if __name__ == "__main__":
|
||||||
|
print("Performing brcmfmac reload and restart mon0 in 5 seconds...")
|
||||||
|
fb = Fix_BRCMF()
|
||||||
|
|
||||||
|
data = {'Message': "kernel: brcmfmac: brcmf_cfg80211_nexmon_set_channel: Set Channel failed: chspec=1234"}
|
||||||
|
event = {'data': data}
|
||||||
|
|
||||||
|
agent = Client('localhost', port=8081, username="pwnagotchi", password="pwnagotchi");
|
||||||
|
|
||||||
|
time.sleep(2)
|
||||||
|
print("3 seconds")
|
||||||
|
time.sleep(3)
|
||||||
|
# fb.on_epoch(agent, event, None)
|
||||||
|
fb._tryTurningItOffAndOnAgain(agent)
|
Reference in New Issue
Block a user