Headline
CVE-2021-4074: Changeset 2653041 for whmcs-bridge – WordPress Plugin Repository
The WHMCS Bridge WordPress plugin is vulnerable to Stored Cross-Site Scripting via the cc_whmcs_bridge_url parameter found in the ~/whmcs-bridge/bridge_cp.php file which allows attackers to inject arbitrary web scripts, in versions up to and including 6.1. Due to missing authorization checks on the cc_whmcs_bridge_add_admin function, low-level authenticated users such as subscribers can exploit this vulnerability.
whmcs-bridge/trunk/bridge.init.php
r2535021
r2653041
4
4
if (!defined(‘WHMCS_BRIDGE_PAGE’)) define(‘WHMCS_BRIDGE_PAGE’,’WHMCS’);
5
5
6
define(“CC_WHMCS_BRIDGE_VERSION","6.1”);
6
define(“CC_WHMCS_BRIDGE_VERSION","6.3”);
7
7
8
8
if (!defined(‘PHP_VERSION_ID’)) {
…
…
180
180
181
181
function cc_whmcs_bridge_checks() {
182
if (!wp\_verify\_nonce($\_POST\['nonce'\], 'whmcs\_bridge\_check\_bridge') ){
183
die('Permission Denied.');
184
}
185
182
186
$whmcs\_url = get\_option('cc\_whmcs\_bridge\_url');
183
187
…
…
494
498
cc\_whmcs\_log(0, '\[URL '.$ref.'\] '.$http);
495
499
500
if (stristr($http, 'viewinvoice.php') !== false && stristr($http, 'ccce=viewinvoice') !== false) {
501
$http = str\_replace("&ccce=viewinvoice", "", $http);
502
cc\_whmcs\_log(0, '\[URL '.$ref.'\] '.$http);
503
}
504
496
505
if (strstr($http, '?a=checkout') !== false && isset($\_REQUEST\['action'\]) && $\_REQUEST\['action'\] == 'doPayment') {
497
506
$http = str\_replace('?a=checkout', '?a=complete', $http);
…
…
544
553
stristr($\_REQUEST\['js'\], '.png') !== false ||
545
554
stristr($\_REQUEST\['js'\], '.jpeg') !== false ||
546
stristr($\_REQUEST\['js'\], '.gif') !== false
555
stristr($\_REQUEST\['js'\], '.gif') !== false ||
556
stristr($\_REQUEST\['js'\], '.svg') !== false
547
557
))
548
558
) {
…
…
580
590
case "jpeg":
581
591
case "jpg": $ctype="image/jpeg"; break;
592
case "svg": $ctype="image/svg+xml"; break;
582
593
default: $ctype="image"; break;
583
594
}
whmcs-bridge/trunk/bridge.php
r2535021
r2653041
5
5
Description: WHMCS Bridge is a plugin that integrates the powerful WHMCS support and billing software with WordPress.
6
6
Author: globalprogramming
7
Version: 6.1
7
Version: 6.3
8
8
Author URI: http://i-plugins.com/
9
9
*/
whmcs-bridge/trunk/bridge_cp.php
r2216981
r2653041
101
101
function cc_whmcs_bridge_add_admin() {
102
102
103
global $cc\_whmcs\_bridge\_shortname;
104
105
$cc\_whmcs\_bridge\_options = cc\_whmcs\_bridge\_options();
106
107
if (isset($\_GET\['page'\]) && ($\_GET\['page'\] == "cc-ce-bridge-cp")) {
108
if (isset($\_REQUEST\['action'\]) && 'install' == $\_REQUEST\['action'\]) {
109
delete\_option('cc\_whmcs\_bridge\_log');
110
delete\_option('cc\_whmcs\_bridge\_sso\_local\_key');
111
112
foreach ($cc\_whmcs\_bridge\_options as $value) {
113
if (isset($value\['id'\]) && !empty($\_REQUEST\[$value\['id'\]\])) {
114
$post\_value = $\_REQUEST\[$value\['id'\]\];
115
if ($value\['type'\] == 'password' && function\_exists('whmcs\_bridge\_sso\_password\_scrambler')) {
116
$post\_value = whmcs\_bridge\_sso\_password\_scrambler($post\_value, false);
103
global $cc\_whmcs\_bridge\_shortname,$current\_user;
104
105
if (in\_array('administrator', $current\_user->roles)) {
106
$cc\_whmcs\_bridge\_options = cc\_whmcs\_bridge\_options();
107
108
if (isset($\_GET\['page'\]) && ($\_GET\['page'\] == "cc-ce-bridge-cp")) {
109
if (isset($\_REQUEST\['action'\]) && 'install' == $\_REQUEST\['action'\]) {
110
check\_admin\_referer('cc\_bridge\_update\_settings\_submit');
111
112
delete\_option('cc\_whmcs\_bridge\_log');
113
delete\_option('cc\_whmcs\_bridge\_sso\_local\_key');
114
115
foreach ($cc\_whmcs\_bridge\_options as $value) {
116
if (isset($value\['id'\]) && !empty($\_REQUEST\[$value\['id'\]\])) {
117
$post\_value = $\_REQUEST\[$value\['id'\]\];
118
if ($value\['type'\] == 'password' && function\_exists('whmcs\_bridge\_sso\_password\_scrambler')) {
119
$post\_value = whmcs\_bridge\_sso\_password\_scrambler($post\_value, false);
120
}
121
update\_option($value\['id'\], $post\_value);
122
} else if (isset($value\['id'\]) && empty($\_REQUEST\[$value\['id'\]\])) {
123
delete\_option($value\['id'\]);
117
124
}
118
update\_option($value\['id'\], $post\_value);
119
} else if (isset($value\['id'\]) && empty($\_REQUEST\[$value\['id'\]\])) {
120
delete\_option($value\['id'\]);
121
125
}
126
127
if (isset($\_REQUEST\['cc\_whmcs\_bridge\_sso\_cache'\])) {
128
foreach (glob(dirname(\_\_FILE\_\_) . '/cache/\*') as $file) {
129
@unlink($file);
130
}
131
$xtrarg = '&whmcs\_clear=true';
132
} else {
133
$xtrarg = '';
134
}
135
136
cc\_whmcs\_bridge\_install();
137
if (function\_exists('cc\_whmcs\_bridge\_sso\_update'))
138
cc\_whmcs\_bridge\_sso\_update();
139
140
header("Location: " . get\_admin\_url() . "options-general.php?page=cc-ce-bridge-cp&installed=true" . $xtrarg);
141
die;
122
142
}
123
124
if (isset($\_REQUEST\['cc\_whmcs\_bridge\_sso\_cache'\])) {
125
foreach (glob(dirname(\_\_FILE\_\_).'/cache/\*') as $file) {
126
@unlink($file);
127
}
128
$xtrarg = '&whmcs\_clear=true';
129
} else {
130
$xtrarg = '';
143
}
144
145
add\_options\_page(WHMCS\_BRIDGE, WHMCS\_BRIDGE, 'administrator', 'cc-ce-bridge-cp', 'cc\_whmcs\_bridge\_admin');
146
}
147
}
148
149
function cc_whmcs_bridge_admin() {
150
151
global $cc\_whmcs\_bridge\_shortname, $current\_user;
152
153
if (in\_array('administrator', $current\_user->roles)) {
154
$controlpanelOptions = cc\_whmcs\_bridge\_options();
155
156
if (isset($\_REQUEST\['installed'\]))
157
echo '<div id="message" class="updated fade"><p><strong>' . WHMCS\_BRIDGE . ' installed.</strong></p></div>';
158
if (isset($\_REQUEST\['error'\])) {
159
echo '<div id="message" class="updated fade"><p>The following error occured: <strong>' . $\_REQUEST\['error'\] . '</strong></p></div>';
160
if (strstr($\_REQUEST\['error'\], 'parsing')) {
161
echo '<div id="message" class="updated fade"><p>Parse errors occur when the bridge is unable to connect to your WHMCS API, for more information please <a href="http://i-plugins.com/whmcs/knowledgebase/1082/I-am-getting-intermittent-DOMDocument-or-loadXML-errors-showing-up-on-the-bridge.html" target="\_blank"><strong>click here</strong></a></p></div>';
162
131
163
}
132
133
cc\_whmcs\_bridge\_install();
134
if (function\_exists('cc\_whmcs\_bridge\_sso\_update'))
135
cc\_whmcs\_bridge\_sso\_update();
136
137
header("Location: ".get\_admin\_url()."options-general.php?page=cc-ce-bridge-cp&installed=true".$xtrarg);
138
die;
139
164
}
140
}
141
142
add\_options\_page(WHMCS\_BRIDGE, WHMCS\_BRIDGE, 'administrator', 'cc-ce-bridge-cp','cc\_whmcs\_bridge\_admin');
165
166
?>
167
<script>
168
jQuery(function () {
169
jQuery("#bridgetabs").tabs();
170
});
171
</script>
172
173
<div class="wrap">
174
<h2><b><?php echo WHMCS\_BRIDGE; ?></b></h2>
175
<div id="bridgetabs" style="width:68%;float:left;">
176
177
<ul>
178
<li><a href="#bridgetabs-1"><i class="fa fa-cog"></i> Settings</a></li>
179
<li><a href="#bridgetabs-2"><i class="fa fa-bug"></i> Log</a></li>
180
<li><a href="#bridgetabs-3"><i class="fa fa-refresh"></i> Sync</a></li>
181
<li><a href="#bridgetabs-4"><i class="fa fa-info"></i> Help</a></li>
182
</ul>
183
184
<div id="bridgetabs-1">
185
<?php require(dirname(\_\_FILE\_\_) . '/pages/settings.php'); ?>
186
</div>
187
<div id="bridgetabs-2">
188
<?php require(dirname(\_\_FILE\_\_) . '/pages/log.php'); ?>
189
</div>
190
<div id="bridgetabs-3">
191
<?php require(dirname(\_\_FILE\_\_) . '/pages/sync.php'); ?>
192
</div>
193
<div id="bridgetabs-4">
194
<?php require(dirname(\_\_FILE\_\_) . '/pages/help.php'); ?>
195
</div>
196
197
</div> <!-- end bridgetabs -->
198
<div style="width:30%;float:right;">
199
<?php
200
require(dirname(\_\_FILE\_\_) . '/support-us.inc.php');
201
zing\_support\_us('whmcs-bridge', 'whmcs-bridge', 'cc-ce-bridge-cp', CC\_WHMCS\_BRIDGE\_VERSION);
202
?>
203
</div>
204
</div> <!-- end wrap -->
205
<?php
206
}
143
207
}
144
208
145
function cc_whmcs_bridge_admin() {
146
147
global $cc\_whmcs\_bridge\_shortname;
148
149
$controlpanelOptions=cc\_whmcs\_bridge\_options();
150
151
if (isset($\_REQUEST\['installed'\])) echo '<div id="message" class="updated fade"><p><strong>'.WHMCS\_BRIDGE.' installed.</strong></p></div>';
152
if (isset($\_REQUEST\['error'\])) {
153
echo '<div id="message" class="updated fade"><p>The following error occured: <strong>'.$\_REQUEST\['error'\].'</strong></p></div>';
154
if (strstr($\_REQUEST\['error'\], 'parsing')) {
155
echo '<div id="message" class="updated fade"><p>Parse errors occur when the bridge is unable to connect to your WHMCS API, for more information please <a href="http://i-plugins.com/whmcs/knowledgebase/1082/I-am-getting-intermittent-DOMDocument-or-loadXML-errors-showing-up-on-the-bridge.html" target="\_blank"><strong>click here</strong></a></p></div>';
156
157
}
158
}
159
160
?>
161
<script>
162
jQuery(function() {
163
jQuery("#bridgetabs").tabs();
164
});
165
</script>
166
167
<div class="wrap">
168
<h2><b><?php echo WHMCS\_BRIDGE; ?></b></h2>
169
<div id="bridgetabs" style="width:68%;float:left;">
170
171
<ul>
172
<li><a href="#bridgetabs-1"><i class="fa fa-cog"></i> Settings</a></li>
173
<li><a href="#bridgetabs-2"><i class="fa fa-bug"></i> Log</a></li>
174
<li><a href="#bridgetabs-3"><i class="fa fa-refresh"></i> Sync</a></li>
175
<li><a href="#bridgetabs-4"><i class="fa fa-info"></i> Help</a></li>
176
</ul>
177
178
<div id="bridgetabs-1">
179
<?php require(dirname(\_\_FILE\_\_).'/pages/settings.php');?>
180
</div>
181
<div id="bridgetabs-2">
182
<?php require(dirname(\_\_FILE\_\_).'/pages/log.php');?>
183
</div>
184
<div id="bridgetabs-3">
185
<?php require(dirname(\_\_FILE\_\_).'/pages/sync.php');?>
186
</div>
187
<div id="bridgetabs-4">
188
<?php require(dirname(\_\_FILE\_\_).'/pages/help.php');?>
189
</div>
190
191
</div> <!-- end bridgetabs -->
192
<div style="width:30%;float:right;">
193
<?php
194
require(dirname(\_\_FILE\_\_).'/support-us.inc.php');
195
zing\_support\_us('whmcs-bridge','whmcs-bridge','cc-ce-bridge-cp',CC\_WHMCS\_BRIDGE\_VERSION);
196
?>
197
</div>
198
</div> <!-- end wrap -->
199
<?php
200
}
201
202
209
add_action('admin_menu’, ‘cc_whmcs_bridge_add_admin’); ?>
whmcs-bridge/trunk/includes/cpedit.inc.php
r2083858
r2653041
11
11
if (function\_exists('whmcs\_bridge\_sso\_password\_scrambler') && $value\['type'\] == 'password') {
12
12
$text\_value = whmcs\_bridge\_sso\_password\_scrambler($text\_value, true);
13
} else if ($value\['type'\] != 'password') {
14
$text\_value = htmlentities(stripslashes($text\_value));
13
15
}
14
16
?>
whmcs-bridge/trunk/includes/http.class.php
r2535021
r2653041
417
417
418
418
if (count($this->post) > 0) {
419
cc\_whmcs\_log(0, "HTTP Method POST 2");
419
420
curl\_setopt($ch, CURLOPT\_POST, 1); // set POST method
420
421
$post = "";
…
…
445
446
} else if (stristr($url, 'two-factor') !== false && stristr($url, 'totp') === false) {
446
447
curl\_setopt($ch, CURLOPT\_CUSTOMREQUEST, "POST"); // set POST method
448
cc\_whmcs\_log(0, "HTTP customrequest Method POST 1");
447
449
}
448
450
…
…
461
463
cc\_whmcs\_log(0, 'Posting as \[1\]: '.json\_encode($pfields));
462
464
}
465
463
466
} else if (!empty($rawPost)) {
464
467
if (in\_array(substr($rawPost, 0, 1), \['\[', '{', '"'\])) {
…
…
470
473
471
474
cc\_whmcs\_log(0, "Posting RAW: ".$rawPost);
472
} else if (strtolower($\_SERVER\['REQUEST\_METHOD'\]) == "post") {
475
cc\_whmcs\_log(0, "HTTP customrequest Method POST 2");
476
} else if (strtolower($\_SERVER\['REQUEST\_METHOD'\]) == "post" && strstr($url, 'viewinvoice.php') === false) {
473
477
curl\_setopt($ch, CURLOPT\_POST, 1); // set POST method
478
cc\_whmcs\_log(0, "HTTP Method POST 1");
474
479
}
475
480
…
…
629
634
if (empty($rawPost))
630
635
$bounce = true;
631
$redir = $this->\_protocol . '://' .$this->\_host .$this->\_path. $redir;
636
if (stristr($this->\_path, '/user/accounts') !== false)
637
$redir = $this->\_protocol . '://' .$this->\_host .'/'. $redir;
638
else
639
$redir = $this->\_protocol . '://' .$this->\_host .$this->\_path. $redir;
632
640
$this->debug(0, 'S4.1: '.$redir);
633
641
} else {
whmcs-bridge/trunk/includes/parser.inc.php
r2535021
r2653041
278
278
$buffer = str\_replace('url: \\'modules/', 'url: \\''.$bridge\_url.'/modules/', $buffer);
279
279
280
280
281
// Twitter feed
281
282
$buffer = str\_replace('?ccce=index&ajax=1?rp=', '?ccce=index&ajax=1&rp=', $buffer);
…
…
314
315
// whmcsBaseUrl
315
316
$buffer = str\_replace("whmcsBaseUrl+\\"/index.php?rp=\\"", "whmcsBaseUrl+\\"{$home}?ccce=index&rp=\\"", $buffer);
317
//whmcsBaseUrl+"/cart"
316
318
317
319
// Payment Gateways
…
…
328
330
\], $buffer);
329
331
332
$buffer = str\_replace('whmcsBaseUrl+"/cart"', 'whmcsBaseUrl+"'.$home.'?ccce=cart"', $buffer);
330
333
331
334
if (is\_numeric($cache\_setting) && $cache\_setting > 0 && (
…
…
999
1002
1000
1003
// whmcsBaseUrl
1001
$buffer = str\_replace("whmcsBaseUrl = ", "whmcsBaseUrl = \\"\\"; //", $buffer);
1004
$buffer = str\_replace("whmcsBaseUrl = ", "whmcsBaseUrl = \\"{$home}\\"; //", $buffer);
1002
1005
1003
1006
// SolusVM
whmcs-bridge/trunk/pages/help.php
r1890489
r2653041
22
22
<h2>Check my installation</h2>
23
23
<p>
24
<button class="button-positive" onclick="jQuery('#whmcs-check-results').html(''); jQuery('#whmcs-check').show(); jQuery.post(ajaxurl, { action: 'check\_bridge' }, function(data) { jQuery('#whmcs-check-results').html(data); jQuery('#whmcs-check').hide(); }); return false;">
24
<button class="button-positive" onclick="jQuery('#whmcs-check-results').html('');
25
jQuery('#whmcs-check').show();
26
jQuery.post(ajaxurl, { action: 'check\_bridge', nonce: '<?= wp\_create\_nonce('whmcs\_bridge\_check\_bridge') ?>' }, function(data) { jQuery('#whmcs-check-results').html(data); jQuery('#whmcs-check').hide(); }); return false;">
25
27
Check for problems with my setup
26
28
</button>
whmcs-bridge/trunk/pages/settings.php
r1440324
r2653041
4
4
?>
5
5
<form method="post">
6
<?php wp\_nonce\_field( 'cc\_bridge\_update\_settings\_submit' ); ?>
7
6
8
<div class="alert success">
7
9
<span class="closebtn" onclick="this.parentElement.style.display='none';">×</span>
whmcs-bridge/trunk/readme.txt
r2535021
r2653041
4
4
Tags: WHMCS, hosting, support, billing, integration
5
5
Requires at least: 5.0
6
Tested up to: 5.7.2
7
Stable tag: 6.1
6
Tested up to: 5.8.2
7
Stable tag: 6.3
8
8
License: GPLv3
9
9
…
…
77
77
78
78
== Changelog ==
79
80
= 6.3 =
81
* Fixed checkout redirect issue
82
* Security upgrades for admin panel
83
84
= 6.2 =
85
* Fixed issue with svg images not rendering due to incorrect headers
86
* Fixed 400 Bad Request issue on Invoice view
79
87
80
88
= 6.1 =