1
|
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/TYPO3/phar-stream-wrapper/badges/quality-score.png?b=v2)](https://scrutinizer-ci.com/g/TYPO3/phar-stream-wrapper/?branch=v2)
|
2
|
[![Travis CI Build Status](https://travis-ci.org/TYPO3/phar-stream-wrapper.svg?branch=v2)](https://travis-ci.org/TYPO3/phar-stream-wrapper)
|
3
|
|
4
|
# PHP Phar Stream Wrapper
|
5
|
|
6
|
## Abstract & History
|
7
|
|
8
|
Based on Sam Thomas' findings concerning
|
9
|
[insecure deserialization in combination with obfuscation strategies](https://blog.secarma.co.uk/labs/near-phar-dangerous-unserialization-wherever-you-are)
|
10
|
allowing to hide Phar files inside valid image resources, the TYPO3 project
|
11
|
decided back then to introduce a `PharStreamWrapper` to intercept invocations
|
12
|
of the `phar://` stream in PHP and only allow usage for defined locations in
|
13
|
the file system.
|
14
|
|
15
|
Since the TYPO3 mission statement is **inspiring people to share**, we thought
|
16
|
it would be helpful for others to release our `PharStreamWrapper` as standalone
|
17
|
package to the PHP community.
|
18
|
|
19
|
The mentioned security issue was reported to TYPO3 on 10th June 2018 by Sam Thomas
|
20
|
and has been addressed concerning the specific attack vector and for this generic
|
21
|
`PharStreamWrapper` in TYPO3 versions 7.6.30 LTS, 8.7.17 LTS and 9.3.1 on 12th
|
22
|
July 2018.
|
23
|
|
24
|
* https://typo3.org/security/advisory/typo3-core-sa-2018-002/
|
25
|
* https://blog.secarma.co.uk/labs/near-phar-dangerous-unserialization-wherever-you-are
|
26
|
* https://youtu.be/GePBmsNJw6Y
|
27
|
|
28
|
## License
|
29
|
|
30
|
In general the TYPO3 core is released under the GNU General Public License version
|
31
|
2 or any later version (`GPL-2.0-or-later`). In order to avoid licensing issues and
|
32
|
incompatibilities this `PharStreamWrapper` is licenced under the MIT License. In case
|
33
|
you duplicate or modify source code, credits are not required but really appreciated.
|
34
|
|
35
|
## Credits
|
36
|
|
37
|
Thanks to [Alex Pott](https://github.com/alexpott), Drupal for creating
|
38
|
back-ports of all sources in order to provide compatibility with PHP v5.3.
|
39
|
|
40
|
## Installation
|
41
|
|
42
|
The `PharStreamWrapper` is provided as composer package `typo3/phar-stream-wrapper`
|
43
|
and has minimum requirements of PHP v5.3 ([`v2`](https://github.com/TYPO3/phar-stream-wrapper/tree/v2) branch) and PHP v7.0 ([`master`](https://github.com/TYPO3/phar-stream-wrapper) branch).
|
44
|
|
45
|
### Installation for PHP v7.0
|
46
|
|
47
|
```
|
48
|
composer require typo3/phar-stream-wrapper ^3.0
|
49
|
```
|
50
|
|
51
|
### Installation for PHP v5.3
|
52
|
|
53
|
```
|
54
|
composer require typo3/phar-stream-wrapper ^2.0
|
55
|
```
|
56
|
|
57
|
## Example
|
58
|
|
59
|
The following example is bundled within this package, the shown
|
60
|
`PharExtensionInterceptor` denies all stream wrapper invocations files
|
61
|
not having the `.phar` suffix. Interceptor logic has to be individual and
|
62
|
adjusted to according requirements.
|
63
|
|
64
|
```
|
65
|
$behavior = new \TYPO3\PharStreamWrapper\Behavior();
|
66
|
Manager::initialize(
|
67
|
$behavior->withAssertion(new PharExtensionInterceptor())
|
68
|
);
|
69
|
|
70
|
if (in_array('phar', stream_get_wrappers())) {
|
71
|
stream_wrapper_unregister('phar');
|
72
|
stream_wrapper_register('phar', 'TYPO3\\PharStreamWrapper\\PharStreamWrapper');
|
73
|
}
|
74
|
```
|
75
|
|
76
|
* `PharStreamWrapper` defined as class reference will be instantiated each time
|
77
|
`phar://` streams shall be processed.
|
78
|
* `Manager` as singleton pattern being called by `PharStreamWrapper` instances
|
79
|
in order to retrieve individual behavior and settings.
|
80
|
* `Behavior` holds reference to interceptor(s) that shall assert correct/allowed
|
81
|
invocation of a given `$path` for a given `$command`. Interceptors implement
|
82
|
the interface `Assertable`. Interceptors can act individually on following
|
83
|
commands or handle all of them in case not defined specifically:
|
84
|
+ `COMMAND_DIR_OPENDIR`
|
85
|
+ `COMMAND_MKDIR`
|
86
|
+ `COMMAND_RENAME`
|
87
|
+ `COMMAND_RMDIR`
|
88
|
+ `COMMAND_STEAM_METADATA`
|
89
|
+ `COMMAND_STREAM_OPEN`
|
90
|
+ `COMMAND_UNLINK`
|
91
|
+ `COMMAND_URL_STAT`
|
92
|
|
93
|
## Interceptor
|
94
|
|
95
|
The following interceptor is shipped with the package and ready to use in order
|
96
|
to block any Phar invocation of files not having a `.phar` suffix. Besides that
|
97
|
individual interceptors are possible of course.
|
98
|
|
99
|
```
|
100
|
class PharExtensionInterceptor implements Assertable
|
101
|
{
|
102
|
/**
|
103
|
* Determines whether the base file name has a ".phar" suffix.
|
104
|
*
|
105
|
* @param string $path
|
106
|
* @param string $command
|
107
|
* @return bool
|
108
|
* @throws Exception
|
109
|
*/
|
110
|
public function assert($path, $command)
|
111
|
{
|
112
|
if ($this->baseFileContainsPharExtension($path)) {
|
113
|
return true;
|
114
|
}
|
115
|
throw new Exception(
|
116
|
sprintf(
|
117
|
'Unexpected file extension in "%s"',
|
118
|
$path
|
119
|
),
|
120
|
1535198703
|
121
|
);
|
122
|
}
|
123
|
|
124
|
/**
|
125
|
* @param string $path
|
126
|
* @return bool
|
127
|
*/
|
128
|
private function baseFileContainsPharExtension($path)
|
129
|
{
|
130
|
$baseFile = Helper::determineBaseFile($path);
|
131
|
if ($baseFile === null) {
|
132
|
return false;
|
133
|
}
|
134
|
$fileExtension = pathinfo($baseFile, PATHINFO_EXTENSION);
|
135
|
return strtolower($fileExtension) === 'phar';
|
136
|
}
|
137
|
}
|
138
|
```
|
139
|
|
140
|
## Helper
|
141
|
|
142
|
* `Helper::determineBaseFile(string $path)`: Determines base file that can be
|
143
|
accessed using the regular file system. For instance the following path
|
144
|
`phar:///home/user/bundle.phar/content.txt` would be resolved to
|
145
|
`/home/user/bundle.phar`.
|
146
|
* `Helper::resetOpCache()`: Resets PHP's OPcache if enabled as work-around for
|
147
|
issues in `include()` or `require()` calls and OPcache delivering wrong
|
148
|
results. More details can be found in PHP's bug tracker, for instance like
|
149
|
https://bugs.php.net/bug.php?id=66569
|
150
|
|
151
|
## Security Contact
|
152
|
|
153
|
In case of finding additional security issues in the TYPO3 project or in this
|
154
|
`PharStreamWrapper` package in particular, please get in touch with the
|
155
|
[TYPO3 Security Team](mailto:security@typo3.org).
|