Issues (30)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

src/PhpConsole/EvalProvider.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace PhpConsole;
4
5
/**
6
 * Execute PHP code with some security & accessibility tweaks
7
 *
8
 * @package PhpConsole
9
 * @version 3.1
10
 * @link http://consle.com
11
 * @author Sergey Barbushin http://linkedin.com/in/barbushin
12
 * @copyright © Sergey Barbushin, 2011-2013. All rights reserved.
13
 * @license http://www.opensource.org/licenses/BSD-3-Clause "The BSD 3-Clause License"
14
 */
15
class EvalProvider {
16
17
	protected $sharedVars = array();
18
	protected $openBaseDirs = array();
19
	protected $codeCallbackHandlers = array();
20
	protected $globalsBackup;
21
22
	/**
23
	 * Execute PHP code handling execution time, output & exception
24
	 * @param string $code
25
	 * @return EvalResult
26
	 */
27 22
	public function evaluate($code) {
28 22
		$code = $this->applyHandlersToCode($code);
29 22
		$code = $this->adaptCodeToEval($code);
30
31 22
		$this->backupGlobals();
32 22
		$this->applyOpenBaseDirSetting();
33
34 22
		$startTime = microtime(true);
35 22
		static::executeCode('', $this->sharedVars);
36 22
		$selfTime = microtime(true) - $startTime;
37
38 22
		ob_start();
39 22
		$result = new EvalResult();
40 22
		$startTime = microtime(true);
41
		try {
42 22
			$result->return = static::executeCode($code, $this->sharedVars);
43
		}
44 3
		catch(\Throwable $exception) {
45 3
			$result->exception = $exception;
46
		}
47
		catch(\Exception $exception) {
48
			$result->exception = $exception;
49
		}
50 22
		$result->time = abs(microtime(true) - $startTime - $selfTime);
51 22
		$result->output = ob_get_clean();
52
53 22
		$this->restoreGlobals();
54
55 22
		return $result;
56
	}
57
58
	/**
59
	 * Add callback that will be called with &$code var reference before code execution
60
	 * @param $callback
61
	 * @throws \Exception
62
	 */
63 2
	public function addCodeHandler($callback) {
64 2
		if(!is_callable($callback)) {
65 1
			throw new \Exception('Argument is not callable');
66
		}
67 1
		$this->codeCallbackHandlers[] = $callback;
68 1
	}
69
70
	/**
71
	 * Call added code handlers
72
	 * @param $code
73
	 * @return mixed
74
	 */
75 22
	protected function applyHandlersToCode($code) {
76 22
		foreach($this->codeCallbackHandlers as $callback) {
77 1
			call_user_func_array($callback, array(&$code));
78
		}
79 22
		return $code;
80
	}
81
82
	/**
83
	 * Store global vars data in backup var
84
	 */
85 22
	protected function backupGlobals() {
86 22
		$this->globalsBackup = array();
87 22
		foreach($GLOBALS as $key => $value) {
88 22
			if($key != 'GLOBALS') {
89 22
				$this->globalsBackup[$key] = $value;
90
			}
91
		}
92 22
	}
93
94
	/**
95
	 * Restore global vars data from backup var
96
	 */
97 22
	protected function restoreGlobals() {
98 22
		foreach($this->globalsBackup as $key => $value) {
99 22
			$GLOBALS[$key] = $value;
100
		}
101 22
		foreach(array_diff(array_keys($GLOBALS), array_keys($this->globalsBackup)) as $newKey) {
102 22
			if($newKey != 'GLOBALS') {
103 22
				unset($GLOBALS[$newKey]);
104
			}
105
		}
106 22
	}
107
108
	/**
109
	 * Execute code with shared vars
110
	 * @param $_code
111
	 * @param array $_sharedVars
112
	 * @return mixed
113
	 */
114 22
	protected static function executeCode($_code, array $_sharedVars) {
115 22
		foreach($_sharedVars as $var => $value) {
116 3
			if(isset($GLOBALS[$var]) && $var[0] == '_') { // extract($this->sharedVars, EXTR_OVERWRITE) and $$var = $value do not overwrites global vars
117 1
				$GLOBALS[$var] = $value;
118
			}
119 2
			elseif(!isset($$var)) {
120 3
				$$var = $value;
121
			}
122
		}
123
124 22
		return eval($_code);
125
	}
126
127
	/**
128
	 * Prepare code PHP tags be correctly passed to eval() function
129
	 * @param string $code
130
	 * @return string
131
	 */
132 22
	protected function trimPhpTags($code) {
133
		$replace = array(
134 22
			'~^(\s*)<\?=~s' => '\1echo ',
135
			'~^(\s*)<\?(php)?~is' => '\1',
136
			'~\?>\s*$~s' => '',
137
			'~<\?(php)?[\s;]*$~is' => '',
138
		);
139 22
		return preg_replace(array_keys($replace), $replace, $code);
140
	}
141
142
	/**
143
	 * Add semicolon to the end of code if it's required
144
	 * @param string $code
145
	 * @return string
146
	 */
147 22
	protected function forceEndingSemicolon($code) {
148 22
		$code = rtrim($code, "; \r\n");
149 22
		return $code[strlen($code) - 1] != '}' ? $code . ';' : $code;
150
	}
151
152
	/**
153
	 * Apply some default code handlers
154
	 * @param string $code
155
	 * @return string
156
	 */
157 22
	protected function adaptCodeToEval($code) {
158 22
		$code = $this->trimPhpTags($code);
159 22
		$code = $this->forceEndingSemicolon($code);
160 22
		return $code;
161
	}
162
163
	/**
164
	 * Protect response code access only to specified directories using http://www.php.net/manual/en/ini.core.php#ini.open-basedir
165
	 * IMPORTANT: classes autoload methods will work only for specified directories
166
	 * @param array $openBaseDirs
167
	 * @codeCoverageIgnore
168
	 */
169
	public function setOpenBaseDirs(array $openBaseDirs) {
170
		$this->openBaseDirs = $openBaseDirs;
171
	}
172
173
	/**
174
	 * Autoload all PHP Console classes
175
	 * @codeCoverageIgnore
176
	 */
177
	protected function forcePhpConsoleClassesAutoLoad() {
178
		foreach(new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator(__DIR__), \RecursiveIteratorIterator::LEAVES_ONLY) as $path) {
179
			/** @var $path \SplFileInfo */
180
			if($path->isFile() && $path->getExtension() == 'php' && $path->getFilename() !== 'PsrLogger.php') {
181
				require_once($path->getPathname());
182
			}
183
		}
184
	}
185
186
	/**
187
	 * Set actual "open_basedir" PHP ini option
188
	 * @throws \Exception
189
	 * @codeCoverageIgnore
190
	 */
191
	protected function applyOpenBaseDirSetting() {
192
		if($this->openBaseDirs) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->openBaseDirs of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
193
			$value = implode(PATH_SEPARATOR, $this->openBaseDirs);
194
			if(ini_get('open_basedir') != $value) {
195
				$this->forcePhpConsoleClassesAutoLoad();
196
				if(ini_set('open_basedir', $value) === false) {
197
					throw new \Exception('Unable to set "open_basedir" php.ini setting');
198
				}
199
			}
200
		}
201
	}
202
203
	/**
204
	 * Protect response code from reading/writing/including any files using http://www.php.net/manual/en/ini.core.php#ini.open-basedir
205
	 * IMPORTANT: It does not protects from system(), exec(), passthru(), popen() & etc OS commands execution functions
206
	 * IMPORTANT: Classes autoload methods will not work, so all required classes must be loaded before code evaluation
207
	 * @codeCoverageIgnore
208
	 */
209
	public function disableFileAccessByOpenBaseDir() {
210
		$this->setOpenBaseDirs(array(__DIR__ . '/not_existed_dir' . mt_rand()));
211
	}
212
213
	/**
214
	 * Add var that will be implemented in PHP code executed from PHP Console debug panel (will be implemented in PHP Console > v3.0)
215
	 * @param $name
216
	 * @param $var
217
	 * @throws \Exception
218
	 */
219 4
	public function addSharedVar($name, $var) {
220 4
		$this->addSharedVarReference($name, $var);
221 4
	}
222
223
	/**
224
	 * Add var that will be implemented in PHP code executed from PHP Console debug panel (will be implemented in PHP Console > v3.0)
225
	 * @param $name
226
	 * @param $var
227
	 * @throws \Exception
228
	 */
229 5
	public function addSharedVarReference($name, &$var) {
230 5
		if(isset($this->sharedVars[$name])) {
231 2
			throw new \Exception('Var with name "' . $name . '" already added');
232
		}
233 5
		$this->sharedVars[$name] =& $var;
234 5
	}
235
}
236
237
class EvalResult {
238
239
	public $return;
240
	public $output;
241
	public $time;
242
	/** @var  \Exception|null */
243
	public $exception;
244
}
245