|
1
|
|
|
<?php |
|
2
|
|
|
/** |
|
3
|
|
|
* @author Gaetano Giunta |
|
4
|
|
|
* @copyright (C) 2005-2025 G. Giunta |
|
5
|
|
|
* @license code licensed under the BSD License: see file license.txt |
|
6
|
|
|
* |
|
7
|
|
|
* Parses GET/POST variables |
|
8
|
|
|
* |
|
9
|
|
|
* @todo switch params for http compression from 0,1,2 to values to be used directly |
|
10
|
|
|
* @todo do some more sanitization of received parameters |
|
11
|
|
|
* @todo move parameters away from global namespace |
|
12
|
|
|
*/ |
|
13
|
|
|
|
|
14
|
|
|
// handle class autoloading: |
|
15
|
|
|
if (file_exists(__DIR__.'/../vendor/autoload.php')) { |
|
16
|
|
|
// if the debugger's package is installed as top-level project, and dependencies via Composer, allow finding classes |
|
17
|
|
|
// from dependencies |
|
18
|
|
|
include_once(__DIR__.'/../vendor/autoload.php'); |
|
19
|
|
|
} else { |
|
20
|
|
|
// assume this is either a standalone install, or installed as Composer dependency |
|
21
|
|
|
/// @todo if the latter is true, should we just not skip using the custom Autoloader, and let a top-level |
|
22
|
|
|
/// debugger include this one, taking care of autoloading? |
|
23
|
|
|
include_once __DIR__ . "/../src/Autoloader.php"; |
|
24
|
|
|
PhpXmlRpc\Autoloader::register(); |
|
25
|
|
|
} |
|
26
|
|
|
|
|
27
|
|
|
// work around register globals - @see https://www.php.net/manual/en/faq.misc.php#faq.misc.registerglobals |
|
28
|
|
|
if (ini_get('register_globals')) { |
|
29
|
|
|
function unregister_globals() |
|
30
|
|
|
{ |
|
31
|
|
|
// Might want to change this perhaps to a nicer error |
|
32
|
|
|
if (isset($_REQUEST['GLOBALS']) || isset($_FILES['GLOBALS'])) { |
|
33
|
|
|
die('GLOBALS overwrite attempt detected'); |
|
|
|
|
|
|
34
|
|
|
} |
|
35
|
|
|
|
|
36
|
|
|
// Variables that shouldn't be unset |
|
37
|
|
|
$noUnset = array('GLOBALS', '_GET', '_POST', '_COOKIE', '_REQUEST', '_SERVER', '_ENV', '_FILES'); |
|
38
|
|
|
|
|
39
|
|
|
$input = array_merge($_GET, $_POST, $_COOKIE, $_SERVER, $_ENV, $_FILES, |
|
40
|
|
|
isset($_SESSION) && is_array($_SESSION) ? $_SESSION : array() |
|
41
|
|
|
); |
|
42
|
|
|
|
|
43
|
|
|
foreach ($input as $k => $v) { |
|
44
|
|
|
if (!in_array($k, $noUnset) && isset($GLOBALS[$k])) { |
|
45
|
|
|
unset($GLOBALS[$k]); |
|
46
|
|
|
} |
|
47
|
|
|
} |
|
48
|
|
|
} |
|
49
|
|
|
unregister_globals(); |
|
50
|
|
|
} |
|
51
|
|
|
|
|
52
|
|
|
// work around magic quotes |
|
53
|
|
|
if (function_exists('get_magic_quotes_gpc') && @get_magic_quotes_gpc()) { |
|
54
|
|
|
function stripslashes_deep($value) |
|
55
|
|
|
{ |
|
56
|
|
|
$value = is_array($value) ? array_map('stripslashes_deep', $value) : stripslashes($value); |
|
57
|
|
|
|
|
58
|
|
|
return $value; |
|
59
|
|
|
} |
|
60
|
|
|
|
|
61
|
|
|
$_GET = array_map('stripslashes_deep', $_GET); |
|
62
|
|
|
} |
|
63
|
|
|
|
|
64
|
|
|
if (function_exists('mb_detect_encoding')) { |
|
65
|
|
|
$preferredEncodings = 'UTF-8, ASCII, ISO-8859-1, UTF-7, EUC-JP, SJIS, eucJP-win, SJIS-win, JIS, ISO-2022-JP'; |
|
66
|
|
|
if (isset($_GET['usepost']) && $_GET['usepost'] === 'true') { |
|
67
|
|
|
$_GET = $_POST; |
|
68
|
|
|
$inputcharset = mb_detect_encoding(implode('', $_GET), $preferredEncodings); |
|
69
|
|
|
} else { |
|
70
|
|
|
$inputcharset = mb_detect_encoding(urldecode($_SERVER['REQUEST_URI']), $preferredEncodings); |
|
71
|
|
|
} |
|
72
|
|
|
} else { |
|
73
|
|
|
/// @todo do is there a better strategy? At least for the POST case, there is probably an http header to look at... |
|
74
|
|
|
$inputcharset = 'UTF8'; |
|
75
|
|
|
} |
|
76
|
|
|
|
|
77
|
|
|
/// @todo if $inputcharset is not UTF8, we should probably re-encode $_GET to make it UTF-8 |
|
78
|
|
|
|
|
79
|
|
|
// recover input parameters |
|
80
|
|
|
/// @todo instead of using globals, move them to an array. Also: use a class for this parsing... |
|
81
|
|
|
$debug = 0; |
|
82
|
|
|
$protocol = 0; |
|
83
|
|
|
$run = false; |
|
84
|
|
|
$hasjsonrpcclient = class_exists('\PhpXmlRpc\JsonRpc\Client'); |
|
85
|
|
|
$hasjsonrpc2 = $hasjsonrpcclient && method_exists('\PhpXmlRpc\JsonRpc\Client', 'setJsonRpcVersion'); |
|
86
|
|
|
$wstype = defined('DEFAULT_WSTYPE') ? DEFAULT_WSTYPE : 0; |
|
|
|
|
|
|
87
|
|
|
$id = ''; |
|
88
|
|
|
if (isset($_GET['action'])) { |
|
89
|
|
|
if (isset($_GET['wstype']) && ($_GET['wstype'] == '2' || $_GET['wstype'] == '1' || $_GET['wstype'] == '0')) { |
|
90
|
|
|
$wstype = (int)$_GET['wstype']; |
|
91
|
|
|
if ($wstype === 1 || $wstype === 2) { |
|
92
|
|
|
if (!$hasjsonrpcclient) { |
|
93
|
|
|
$wstype = 0; |
|
94
|
|
|
} else if (!$hasjsonrpc2) { |
|
95
|
|
|
$wstype = 1; |
|
96
|
|
|
} |
|
97
|
|
|
} |
|
98
|
|
|
if (($wstype === 1 || $wstype === 2) && isset($_GET['id'])) { |
|
99
|
|
|
$id = $_GET['id']; |
|
100
|
|
|
} |
|
101
|
|
|
} |
|
102
|
|
|
$host = isset($_GET['host']) ? $_GET['host'] : 'localhost'; // using '' will trigger an xml-rpc error... |
|
103
|
|
|
if (isset($_GET['protocol']) && ($_GET['protocol'] == '1' || $_GET['protocol'] == '2' || $_GET['protocol'] == '3' |
|
104
|
|
|
|| $_GET['protocol'] == '4')) { |
|
105
|
|
|
$protocol = (int)$_GET['protocol']; |
|
106
|
|
|
} |
|
107
|
|
|
if (strpos($host, 'http://') === 0) { |
|
108
|
|
|
// NB: if protocol is https or h2, it will override http:// |
|
109
|
|
|
$host = substr($host, 7); |
|
110
|
|
|
} elseif (strpos($host, 'https://') === 0) { |
|
111
|
|
|
$host = substr($host, 8); |
|
112
|
|
|
// NB: otoh if protocol is http1.0 or http1.1, it will be overridden by https:// |
|
113
|
|
|
if ($protocol == 0 || $protocol = 1) { |
|
114
|
|
|
$protocol = 2; |
|
115
|
|
|
} |
|
116
|
|
|
} |
|
117
|
|
|
$port = isset($_GET['port']) ? (int)$_GET['port'] : ''; |
|
118
|
|
|
if ($port === 0) { |
|
119
|
|
|
$port = ''; |
|
120
|
|
|
} |
|
121
|
|
|
$path = isset($_GET['path']) ? $_GET['path'] : ''; |
|
122
|
|
|
// in case user forgot initial '/' in xml-rpc server path, add it back |
|
123
|
|
|
if ($path && ($path[0]) != '/') { |
|
124
|
|
|
$path = '/' . $path; |
|
125
|
|
|
} |
|
126
|
|
|
|
|
127
|
|
|
if (isset($_GET['debug']) && ($_GET['debug'] == '1' || $_GET['debug'] == '2')) { |
|
128
|
|
|
$debug = (int)$_GET['debug']; |
|
129
|
|
|
} |
|
130
|
|
|
|
|
131
|
|
|
$verifyhost = (isset($_GET['verifyhost']) && ($_GET['verifyhost'] == '1' || $_GET['verifyhost'] == '2')) ? $_GET['verifyhost'] : 0; |
|
132
|
|
|
if (isset($_GET['verifypeer']) && $_GET['verifypeer'] == '1') { |
|
133
|
|
|
$verifypeer = true; |
|
134
|
|
|
} else { |
|
135
|
|
|
$verifypeer = false; |
|
136
|
|
|
} |
|
137
|
|
|
$cainfo = isset($_GET['cainfo']) ? $_GET['cainfo'] : ''; |
|
138
|
|
|
$proxy = isset($_GET['proxy']) ? $_GET['proxy'] : 0; |
|
139
|
|
|
if (strpos($proxy, 'http://') === 0) { |
|
140
|
|
|
$proxy = substr($proxy, 7); |
|
141
|
|
|
} |
|
142
|
|
|
/// @todo what about an https proxy? |
|
143
|
|
|
$proxyuser = isset($_GET['proxyuser']) ? $_GET['proxyuser'] : ''; |
|
144
|
|
|
$proxypwd = isset($_GET['proxypwd']) ? $_GET['proxypwd'] : ''; |
|
145
|
|
|
$timeout = isset($_GET['timeout']) ? (int)$_GET['timeout'] : 0; |
|
146
|
|
|
$action = $_GET['action']; |
|
147
|
|
|
|
|
148
|
|
|
$method = isset($_GET['method']) ? $_GET['method'] : ''; |
|
149
|
|
|
$methodsig = isset($_GET['methodsig']) ? $_GET['methodsig'] : 0; |
|
150
|
|
|
$payload = isset($_GET['methodpayload']) ? $_GET['methodpayload'] : ''; |
|
151
|
|
|
$alt_payload = isset($_GET['altmethodpayload']) ? $_GET['altmethodpayload'] : ''; |
|
152
|
|
|
|
|
153
|
|
|
if (isset($_GET['run']) && $_GET['run'] == 'now') { |
|
154
|
|
|
$run = true; |
|
155
|
|
|
} |
|
156
|
|
|
|
|
157
|
|
|
$username = isset($_GET['username']) ? $_GET['username'] : ''; |
|
158
|
|
|
$password = isset($_GET['password']) ? $_GET['password'] : ''; |
|
159
|
|
|
|
|
160
|
|
|
$authtype = (isset($_GET['authtype']) && ($_GET['authtype'] == '2' || $_GET['authtype'] == '8')) ? (int)$_GET['authtype'] : 1; |
|
161
|
|
|
|
|
162
|
|
|
if (isset($_GET['requestcompression']) && ($_GET['requestcompression'] == '1' || $_GET['requestcompression'] == '2')) { |
|
163
|
|
|
(int)$requestcompression = $_GET['requestcompression']; |
|
164
|
|
|
} else { |
|
165
|
|
|
$requestcompression = 0; |
|
166
|
|
|
} |
|
167
|
|
|
if (isset($_GET['responsecompression']) && ($_GET['responsecompression'] == '1' || $_GET['responsecompression'] == '2' || $_GET['responsecompression'] == '3')) { |
|
168
|
|
|
$responsecompression = (int)$_GET['responsecompression']; |
|
169
|
|
|
} else { |
|
170
|
|
|
$responsecompression = 0; |
|
171
|
|
|
} |
|
172
|
|
|
|
|
173
|
|
|
$clientcookies = isset($_GET['clientcookies']) ? $_GET['clientcookies'] : ''; |
|
174
|
|
|
} else { |
|
175
|
|
|
$host = ''; |
|
176
|
|
|
$port = ''; |
|
177
|
|
|
$path = ''; |
|
178
|
|
|
$action = ''; |
|
179
|
|
|
$method = ''; |
|
180
|
|
|
$methodsig = 0; |
|
181
|
|
|
$payload = ''; |
|
182
|
|
|
$alt_payload = ''; |
|
183
|
|
|
$username = ''; |
|
184
|
|
|
$password = ''; |
|
185
|
|
|
$authtype = 1; |
|
186
|
|
|
$verifyhost = 0; |
|
187
|
|
|
$verifypeer = false; |
|
188
|
|
|
$cainfo = ''; |
|
189
|
|
|
$proxy = ''; |
|
190
|
|
|
$proxyuser = ''; |
|
191
|
|
|
$proxypwd = ''; |
|
192
|
|
|
$timeout = 0; |
|
193
|
|
|
$requestcompression = 0; |
|
194
|
|
|
$responsecompression = 0; |
|
195
|
|
|
$clientcookies = ''; |
|
196
|
|
|
} |
|
197
|
|
|
|
|
198
|
|
|
// check input for known attacks against this or other libs |
|
199
|
|
|
function payload_is_safe($input) |
|
|
|
|
|
|
200
|
|
|
{ |
|
201
|
|
|
return true; |
|
202
|
|
|
} |
|
203
|
|
|
|
In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.