Merge branch 'master' into master
This commit is contained in:
commit
5b93d1aa24
@ -1,18 +1,22 @@
|
||||
# About the Project
|
||||
|
||||
[Pwnagotchi](https://twitter.com/pwnagotchi) is an "AI" that learns from the WiFi environment and instruments [bettercap](https://www.bettercap.org/) in order to maximize the WPA key material that's being captured either passively or by performing deauthentication and association attakcs. This material is collected as pcap files containing any form of handshake supported by [hashcat](https://hashcat.net/hashcat/), including [PMKIDs](https://www.evilsocket.net/2019/02/13/Pwning-WiFi-networks-with-bettercap-and-the-PMKID-client-less-attack/), full and half WPA handshakes.
|
||||
[Pwnagotchi](https://twitter.com/pwnagotchi) is an [A2C](https://hackernoon.com/intuitive-rl-intro-to-advantage-actor-critic-a2c-4ff545978752)-based "AI" leveraging [bettercap](https://www.bettercap.org/) that learns from its surrounding WiFi environment in order to maximize the WPA key material it captures (either passively, or by performing deauthentication and association attacks). This material is collected as PCAP files containing any form of handshake supported by [hashcat](https://hashcat.net/hashcat/), including [PMKIDs](https://www.evilsocket.net/2019/02/13/Pwning-WiFi-networks-with-bettercap-and-the-PMKID-client-less-attack/),
|
||||
full and half WPA handshakes.
|
||||
|
||||

|
||||
|
||||
Instead of playing [Super Mario or Atari games](https://becominghuman.ai/getting-mario-back-into-the-gym-setting-up-super-mario-bros-in-openais-gym-8e39a96c1e41?gi=c4b66c3d5ced), pwnagotchi will tune over time [its own parameters](https://github.com/evilsocket/pwnagotchi/blob/master/sdcard/rootfs/root/pwnagotchi/config.yml#L54), effectively learning to get better at pwning WiFi things. **Keep in mind:** unlike the usual RL simulations, pwnagotchi learns over time (where a single epoch can last from a few seconds to minutes, depending on how many access points and client stations are visible), do not expect it to perform amazingly well at the beginning, as it'll be exploring several combinations of parameters ... but listen to it when it's bored, bring it with you and have it observe new networks and capture new handshakes and you'll see :)
|
||||
Instead of merely playing [Super Mario or Atari games](https://becominghuman.ai/getting-mario-back-into-the-gym-setting-up-super-mario-bros-in-openais-gym-8e39a96c1e41?gi=c4b66c3d5ced) like most reinforcement learning based "AI" *(yawn)*, Pwnagotchi tunes [its own parameters](https://github.com/evilsocket/pwnagotchi/blob/master/sdcard/rootfs/root/pwnagotchi/config.yml#L54) over time to **get better at pwning WiFi things** in the environments you expose it to.
|
||||
|
||||
Multiple units can talk to each other, advertising their own presence using a parasite protocol I've built on top of the existing dot11 standard, by broadcasting custom information elements. Over time, two or more units learn to cooperate if they detect each other's presence, by dividing the available channels among them.
|
||||
**Keep in mind:** Unlike the usual RL simulations, Pwnagotchi actually learns over time. Time for a Pwnagotchi is measured in epochs; a single epoch can last from a few seconds to minutes, depending on how many access points and client stations are visible. Do not expect your Pwnagotchi to perform amazingly well at the very beginning, as it will be [exploring](https://hackernoon.com/intuitive-rl-intro-to-advantage-actor-critic-a2c-4ff545978752) several combinations of [key parameters](https://github.com/evilsocket/pwnagotchi/blob/master/docs/usage.md#training-the-ai) to determine ideal adjustments for pwning the particular environment you are exposing it to during its beginning epochs ... but **definitely listen to your pwnagotchi when it tells you it's bored!** Bring it into novel WiFi environments with you and have it observe new networks and capture new handshakes—and you'll see. :)
|
||||
|
||||
Multiple units within close physical proximity can "talk" to each other, advertising their own presence to each other by broadcasting custom information elements using a parasite protocol I've built on top of the existing dot11 standard. Over time, two or more units trained together will learn to cooperate upon detecting each other's presence by dividing the available channels among them for optimal pwnage.
|
||||
|
||||

|
||||
|
||||
Depending on the status of the unit, several states and states transitions are configurable and represented on the display as different moods, expressions and sentences.
|
||||
[Depending on the status of the unit](), several states and states transitions are configurable and represented on the display as different moods, expressions and sentences. Pwnagotchi speaks [many languages](https://github.com/evilsocket/pwnagotchi/blob/master/docs/configure.md#configuration), too!
|
||||
|
||||
Of course, it is possible to run your Pwnagotchi with the AI disabled (configurable in `config.yml`). Why might you want to do this? Perhaps you simply want to use your own fixed parameters (instead of letting the AI decide for you), or maybe you want to save battery and CPU cycles, or maybe it's just you have strong concerns about aiding and abetting baby Skynet. Whatever your particular reasons may be: an AI-disabled Pwnagotchi is still a simple and very effective automated deauther, WPA handshake sniffer, and portable [bettercap](https://www.bettercap.org/) + [webui](https://github.com/evilsocket/pwnagotchi/blob/master/docs/usage.md#bettercaps-web-ui) dedicated hardware.
|
||||
|
||||
If instead you just want to use your own parameters and save battery and CPU cycles, you can disable the AI in `config.yml` and enjoy an automated deauther, WPA handshake sniffer and portable bettercap + webui dedicated hardware.
|
||||
|
||||
## License
|
||||
|
||||
|
@ -335,7 +335,13 @@ fi
|
||||
setup_raspbian
|
||||
provision_raspbian
|
||||
|
||||
echo -e "[+] Congratz, it's a boy (⌐■_■)!"
|
||||
#Make a baby with a random gender, maybe do something fun with this later!
|
||||
gender[0]="boy"
|
||||
gender[1]="girl"
|
||||
|
||||
rand=$[ $RANDOM % 2 ]
|
||||
|
||||
echo -e "[+] Congratz, it's a ${arr[$rand]} (⌐■_■)!"
|
||||
echo -e "[+] One more step: dd if=../${PWNI_OUTPUT} of=<PATH_TO_SDCARD> bs=4M status=progress"
|
||||
|
||||
if [ "${OPT_SPARSE}" -eq 1 ];
|
||||
|
@ -3,7 +3,11 @@ main:
|
||||
# currently implemented: en (default), de, nl, it
|
||||
lang: en
|
||||
# custom plugins path, if null only default plugins with be loaded
|
||||
plugins: null
|
||||
custom_plugins:
|
||||
# which plugins to load and enable
|
||||
plugins:
|
||||
- gps
|
||||
- twitter
|
||||
# monitor interface to use
|
||||
iface: mon0
|
||||
# command to run to bring the mon interface up in case it's not up already
|
||||
@ -15,7 +19,9 @@ main:
|
||||
# if true, will not restart the wifi module
|
||||
no_restart: false
|
||||
# access points to ignore
|
||||
whitelist: []
|
||||
whitelist:
|
||||
- EXAMPLE_NETWORK
|
||||
- ANOTHER_EXAMPLE_NETWORK
|
||||
# if not null, filter access points by this regular expression
|
||||
filter: null
|
||||
# cryptographic key for identity
|
||||
|
@ -1,5 +1,4 @@
|
||||
#!/usr/bin/python3
|
||||
import os
|
||||
import argparse
|
||||
import time
|
||||
import logging
|
||||
@ -33,9 +32,9 @@ args = parser.parse_args()
|
||||
config = utils.load_config(args)
|
||||
utils.setup_logging(args, config)
|
||||
|
||||
plugins.load_from_path(plugins.default_path)
|
||||
if 'plugins' in config['main'] and config['main']['plugins'] is not None:
|
||||
plugins.load_from_path(config['main']['plugins'])
|
||||
plugins.load_from_path(plugins.default_path, enabled=config['main']['plugins'])
|
||||
if 'custom_plugins' in config['main'] and config['main']['custom_plugins'] is not None:
|
||||
plugins.load_from_path(config['main']['custom_plugins'], enabled=config['main']['plugins'])
|
||||
|
||||
plugins.on('loaded')
|
||||
|
||||
|
@ -27,14 +27,13 @@ def load_from_file(filename):
|
||||
return plugin_name, instance
|
||||
|
||||
|
||||
def load_from_path(path):
|
||||
def load_from_path(path, enabled=()):
|
||||
global loaded
|
||||
|
||||
for filename in glob.glob(os.path.join(path, "*.py")):
|
||||
name, plugin = load_from_file(filename)
|
||||
if name in loaded:
|
||||
raise Exception("plugin %s already loaded from %s" % (name, plugin.__file__))
|
||||
elif not plugin.__enabled__:
|
||||
elif name not in enabled:
|
||||
# print("plugin %s is not enabled" % name)
|
||||
pass
|
||||
else:
|
||||
|
@ -3,7 +3,6 @@ __version__ = '1.0.0'
|
||||
__name__ = 'hello_world'
|
||||
__license__ = 'GPL3'
|
||||
__description__ = 'An example plugin for pwnagotchi that implements all the available callbacks.'
|
||||
__enabled__ = False # IMPORTANT: set this to True to enable your plugin.
|
||||
|
||||
import logging
|
||||
|
||||
|
@ -3,7 +3,6 @@ __version__ = '1.0.0'
|
||||
__name__ = 'gps'
|
||||
__license__ = 'GPL3'
|
||||
__description__ = 'Save GPS coordinates whenever an handshake is captured.'
|
||||
__enabled__ = True # set to false if you just don't use GPS
|
||||
|
||||
import logging
|
||||
import json
|
||||
|
@ -7,7 +7,6 @@ __version__ = '1.0.0'
|
||||
__name__ = 'memtemp'
|
||||
__license__ = 'GPL3'
|
||||
__description__ = 'A plugin that will add a memory and temperature indicator'
|
||||
__enabled__ = False
|
||||
|
||||
import struct
|
||||
|
||||
|
@ -3,7 +3,6 @@ __version__ = '1.0.0'
|
||||
__name__ = 'twitter'
|
||||
__license__ = 'GPL3'
|
||||
__description__ = 'This plugin creates tweets about the recent activity of pwnagotchi'
|
||||
__enabled__ = True
|
||||
|
||||
import logging
|
||||
from pwnagotchi.voice import Voice
|
||||
|
@ -12,7 +12,6 @@ __version__ = '1.0.0'
|
||||
__name__ = 'ups_lite'
|
||||
__license__ = 'GPL3'
|
||||
__description__ = 'A plugin that will add a voltage indicator for the UPS Lite v1.1'
|
||||
__enabled__ = False
|
||||
|
||||
import struct
|
||||
|
||||
|
@ -0,0 +1,76 @@
|
||||
__author__ = '33197631+dadav@users.noreply.github.com'
|
||||
__version__ = '1.0.0'
|
||||
__name__ = 'wpa_sec'
|
||||
__license__ = 'GPL3'
|
||||
__description__ = 'This plugin automatically uploades handshakes to https://wpa-sec.stanev.org'
|
||||
__enabled__ = False
|
||||
|
||||
import os
|
||||
import logging
|
||||
import subprocess
|
||||
|
||||
READY = False
|
||||
API_KEY = None
|
||||
ALREADY_UPLOADED = None
|
||||
|
||||
# INSTALLATION:
|
||||
## apt-get install libcurl4-openssl-dev
|
||||
## https://github.com/ZerBea/hcxtools.git
|
||||
## cd hcxtools; gcc wlancap2wpasec.c -o wlancap2wpasec -lcurl
|
||||
## mv wlancap2wpasec /usr/bin/
|
||||
|
||||
def on_loaded():
|
||||
global READY
|
||||
global API_KEY
|
||||
global ALREADY_UPLOADED
|
||||
|
||||
if not API_KEY:
|
||||
logging.error("WPA_SEC: API-KEY isn't set. Can't upload to wpa-sec.stanev.org")
|
||||
return
|
||||
|
||||
try:
|
||||
subprocess.call("wlancap2wpasec -h >/dev/null".split(), stdout=open(os.devnull, 'wb'))
|
||||
except OSError:
|
||||
logging.error("WPA_SEC: Can't find wlancap2wpasec. Install hcxtools to use this plugin!")
|
||||
return
|
||||
|
||||
try:
|
||||
with open('/root/.wpa_sec_uploads', 'r') as f:
|
||||
ALREADY_UPLOADED = f.read().splitlines()
|
||||
except OSError:
|
||||
logging.error('WPA_SEC: No upload-file found.')
|
||||
ALREADY_UPLOADED = []
|
||||
|
||||
READY = True
|
||||
|
||||
|
||||
def _upload_to_wpasec(path):
|
||||
try:
|
||||
subprocess.call(f"wlancap2wpasec -k {API_KEY} {path}".split(), stdout=open(os.devnull, 'wb'))
|
||||
except OSError as os_e:
|
||||
logging.error(f"WPA_SEC: Error while uploading {path}")
|
||||
raise os_e
|
||||
|
||||
# called in manual mode when there's internet connectivity
|
||||
def on_internet_available(display, config, log):
|
||||
if READY:
|
||||
|
||||
handshake_dir = config['bettercap']['handshakes']
|
||||
handshake_filenames = os.listdir(handshake_dir)
|
||||
handshake_paths = [os.path.join(handshake_dir, filename) for filename in handshake_filenames]
|
||||
handshake_new = set(handshake_paths) - set(ALREADY_UPLOADED)
|
||||
|
||||
if handhake_new:
|
||||
logging.info("Internet connectivity detected.\
|
||||
Uploading new handshakes to wpa-sec.stanev.org")
|
||||
|
||||
for idx, handshake in enumerate(handshake_new):
|
||||
display.set('status', f"Uploading handshake to wpa-sec.stanev.org ({idx + 1}/{len(handshake_new})")
|
||||
display.update(force=True)
|
||||
try:
|
||||
_upload_to_wpasec(handshake)
|
||||
ALREADY_UPLOADED.append(handshake)
|
||||
with open('/root/.wpa_sec_uploads', 'a') as f:
|
||||
f.write(handshake + "\n")
|
||||
except OSError:
|
||||
pass
|
Loading…
x
Reference in New Issue
Block a user