Headline
CVE-2022-25306: Changeset 2679983 for wp-statistics – WordPress Plugin Repository
The WP Statistics WordPress plugin is vulnerable to Cross-Site Scripting due to insufficient escaping and sanitization of the browser parameter found in the ~/includes/class-wp-statistics-visitor.php file which allows attackers to inject arbitrary web scripts onto several pages that execute when site administrators view a sites statistics, in versions up to and including 13.1.5.
wp-statistics/trunk/includes/admin/class-wp-statistics-admin-template.php
r2587105
r2679983
242
242
243
243
// Push To list
244
$list\[$number\_days\] = array('title' => $title, 'link' => $link, 'active' => $active);
244
$list\[$number\_days\] = array('title' => $title, 'link' => sanitize\_url($link), 'active' => $active);
245
245
}
246
246
wp-statistics/trunk/includes/admin/meta-box/wp-statistics-meta-box-platforms.php
r2428043
r2679983
85
85
86
86
// Sanitize Version name
87
$lists\_name\[\] = $l\['platform'\];
87
$lists\_name\[\] = sanitize\_text\_field($l\['platform'\]);
88
88
89
89
// Get List Count
wp-statistics/trunk/includes/admin/templates/optimization/purging.php
r2626597
r2679983
219
219
220
220
<p class="description"><?php \_e('All data table will be lost.', 'wp-statistics'); ?></p>
221
<input id="empty-table-submit" class="button button-primary" type="submit" value="<?php \_e('Clear now!',
222
'wp-statistics'); ?>" name="empty-table-submit" Onclick="return false;"/>
221
<input id="empty-table-submit" class="button button-primary" type="submit" value="<?php \_e('Clear now!', 'wp-statistics'); ?>" name="empty-table-submit" Onclick="return false;"/>
223
222
<span id="empty-status"></span>
224
223
<div id="empty-result"></div>
…
…
235
234
<label for="purge-data"><?php \_e('Days', 'wp-statistics'); ?></label>
236
235
237
<p class="description"><?php echo \_\_('Delete user statistics data older than the selected number of days.',
238
'wp-statistics') . ' ' . \_\_('Minimum value is 30 days.', 'wp-statistics'); ?></p>
239
<input id="purge-data-submit" class="button button-primary" type="submit" value="<?php \_e('Purge now!',
240
'wp-statistics'); ?>" name="purge-data-submit" Onclick="return false;"/>
236
<p class="description"><?php echo \_\_('Delete user statistics data older than the selected number of days.', 'wp-statistics') . ' ' . \_\_('Minimum value is 30 days.', 'wp-statistics'); ?></p>
237
<input id="purge-data-submit" class="button button-primary" type="submit" value="<?php \_e('Purge now!', 'wp-statistics'); ?>" name="purge-data-submit" Onclick="return false;"/>
241
238
<span id="purge-data-status"></span>
242
239
<div id="purge-data-result"></div>
…
…
254
251
<label for="purge-visitor-hits"><?php \_e('Hits', 'wp-statistics'); ?></label>
255
252
256
<p class="description"><?php echo \_\_('Delete user statistics data where the user has more than the defined number of hits in a day.',
257
'wp-statistics') . ' ' . \_\_('This can be useful to clear up old data when your site has been hit by a bot.',
258
'wp-statistics') . ' ' . \_\_('This will remove the visitor and their hits to the site, however it will not remove individual page hits as that data is not recorded on a per use basis.',
259
'wp-statistics') . ' ' . \_\_('Minimum value is 10 hits.', 'wp-statistics'); ?></p>
260
<input id="purge-visitor-hits-submit" class="button button-primary" type="submit" value="<?php \_e('Purge now!',
261
'wp-statistics'); ?>" name="purge-visitor-hits-submit" Onclick="return false;"/>
253
<p class="description"><?php echo \_\_('Delete user statistics data where the user has more than the defined number of hits in a day.', 'wp-statistics') . ' ' . \_\_('This can be useful to clear up old data when your site has been hit by a bot.', 'wp-statistics') . ' ' . \_\_('This will remove the visitor and their hits to the site, however it will not remove individual page hits as that data is not recorded on a per use basis.', 'wp-statistics') . ' ' . \_\_('Minimum value is 10 hits.', 'wp-statistics'); ?></p>
254
<input id="purge-visitor-hits-submit" class="button button-primary" type="submit" value="<?php \_e('Purge now!', 'wp-statistics'); ?>" name="purge-visitor-hits-submit" Onclick="return false;"/>
262
255
<span id="purge-visitor-hits-status"></span>
263
256
<div id="purge-visitor-hits-result"></div>
…
…
291
284
</select>
292
285
293
<p class="description"><?php \_e('All visitor data will be lost for this agent type.',
294
'wp-statistics'); ?></p>
295
<input id="delete-agents-submit" class="button button-primary" type="submit" value="<?php \_e('Delete now!',
296
'wp-statistics'); ?>" name="delete-agents-submit" Onclick="return false;">
286
<p class="description"><?php \_e('All visitor data will be lost for this agent type.', 'wp-statistics'); ?></p>
287
<input id="delete-agents-submit" class="button button-primary" type="submit" value="<?php \_e('Delete now!', 'wp-statistics'); ?>" name="delete-agents-submit" Onclick="return false;">
297
288
<span id="delete-agents-status"></span>
298
289
<div id="delete-agents-result"></div>
…
…
319
310
</select>
320
311
321
<p class="description"><?php \_e('All visitor data will be lost for this platform type.',
322
'wp-statistics'); ?></p>
323
<input id="delete-platforms-submit" class="button button-primary" type="submit" value="<?php \_e('Delete now!',
324
'wp-statistics'); ?>" name="delete-platforms-submit" Onclick="return false;">
312
<p class="description"><?php \_e('All visitor data will be lost for this platform type.', 'wp-statistics'); ?></p>
313
<input id="delete-platforms-submit" class="button button-primary" type="submit" value="<?php \_e('Delete now!', 'wp-statistics'); ?>" name="delete-platforms-submit" Onclick="return false;">
325
314
<span id="delete-platforms-status"></span>
326
315
<div id="delete-platforms-result"></div>
…
…
336
325
<input dir="ltr" id="delete-ip" type="text" name="delete-ip"/>
337
326
338
<p class="description"><?php \_e('All visitor data will be lost for this IP.',
339
'wp-statistics'); ?></p>
340
<input id="delete-ip-submit" class="button button-primary" type="submit" value="<?php \_e('Delete now!',
341
'wp-statistics'); ?>" name="delete-ip-submit" Onclick="return false;">
327
<p class="description"><?php \_e('All visitor data will be lost for this IP.', 'wp-statistics'); ?></p>
328
<input id="delete-ip-submit" class="button button-primary" type="submit" value="<?php \_e('Delete now!', 'wp-statistics'); ?>" name="delete-ip-submit" Onclick="return false;">
342
329
<span id="delete-ip-status"></span>
343
330
<div id="delete-ip-result"></div>
wp-statistics/trunk/includes/admin/templates/pages/refer.url.php
r2587105
r2679983
5
5
|
6
6
<li>
7
<a class="current" href="<?php echo add\_query\_arg(array('referrer' => $args\['domain'\])); ?>">
7
<a class="current" href="<?php echo esc\_url(add\_query\_arg(array('referrer' => $args\['domain'\]))); ?>">
8
8
<?php echo $args\['domain'\]; ?>
9
9
<span class="count">(<?php echo number\_format\_i18n($total); ?>)</span>
wp-statistics/trunk/includes/admin/templates/pages/visitors.php
r2587105
r2679983
31
31
<?php } ?>
32
32
<td>
33
<a href="<?php echo add\_query\_arg('order', ((isset($\_GET\['order'\]) and $\_GET\['order'\] == "asc") ? 'desc' : 'asc')); ?>">
33
<a href="<?php echo esc\_url( add\_query\_arg('order', ((isset($\_GET\['order'\]) and $\_GET\['order'\] == "asc") ? 'desc' : 'asc'))); ?>">
34
34
<?php \_e('Date', 'wp-statistics'); ?>
35
35
<span class="dashicons dashicons-arrow-<?php echo((isset($\_GET\['order'\]) and $\_GET\['order'\] == "asc") ? 'up' : 'down'); ?>"></span>
wp-statistics/trunk/includes/api/v2/class-wp-statistics-api-hit.php
r2626597
r2679983
36
36
{
37
37
return array(
38
'browser',
39
'platform',
40
'version',
41
'ip',
42
'track\_all',
43
'timestamp',
44
'page\_uri',
45
'user\_id',
38
'browser' => array('required' => true, 'type' => 'string'),
39
'platform' => array('required' => true, 'type' => 'string'),
40
'version' => array('required' => true, 'type' => 'string'),
41
'ip' => array('required' => true, 'type' => 'string', 'format' => 'ip'),
42
'track\_all' => array('required' => true, 'type' => 'integer'),
43
'timestamp' => array('required' => true, 'type' => 'integer'),
44
'page\_uri' => array('required' => true, 'type' => 'string'),
45
'user\_id' => array('required' => true, 'type' => 'integer'),
46
'\_wpnonce' => array('required' => true, 'type' => 'string')
46
47
);
47
48
}
…
…
54
55
public function register\_routes()
55
56
{
56
57
// Create Require Params
58
$params = array();
59
foreach (self::require\_params\_hit() as $p) {
60
$params\[$p\] = array('required' => true);
61
}
62
63
// Add X-WP-Nonce
64
$params\['\_wpnonce'\] = array('required' => true);
65
66
57
// Record WP-Statistics when Cache is enable
67
58
register\_rest\_route(self::$namespace, '/' . self::$endpoint, array(
…
…
69
60
'methods' => \\WP\_REST\_Server::READABLE,
70
61
'callback' => array($this, 'hit\_callback'),
71
'args' => $params,
62
'args' => self::require\_params\_hit(),
72
63
'permission\_callback' => function (\\WP\_REST\_Request $request) {
73
64
return true;
wp-statistics/trunk/includes/class-wp-statistics-hits.php
r2671297
r2679983
67
67
if (isset($this->rest\_hits->browser) and isset($this->rest\_hits->platform) and isset($this->rest\_hits->version)) {
68
68
return array(
69
'browser' => $this->rest\_hits->browser,
70
'platform' => $this->rest\_hits->platform,
71
'version' => $this->rest\_hits->version,
69
'browser' => esc\_sql(sanitize\_text\_field($this->rest\_hits->browser)),
70
'platform' => esc\_sql(sanitize\_text\_field($this->rest\_hits->platform)),
71
'version' => esc\_sql(sanitize\_text\_field($this->rest\_hits->version)),
72
72
);
73
73
}
…
…
95
95
public function set\_user\_ip($ip)
96
96
{
97
return isset($this->rest\_hits->ip) ? $this->rest\_hits->ip : $ip;
97
return isset($this->rest\_hits->ip) ? esc\_sql($this->rest\_hits->ip) : esc\_sql($ip);
98
98
}
99
99
…
…
181
181
if (isset($this->rest\_hits->current\_page\_type) and isset($this->rest\_hits->current\_page\_id)) {
182
182
return array(
183
'type' => $this->rest\_hits->current\_page\_type,
184
'id' => $this->rest\_hits->current\_page\_id,
183
'type' => esc\_sql($this->rest\_hits->current\_page\_type),
184
'id' => esc\_sql($this->rest\_hits->current\_page\_id),
185
185
'search\_query' => isset($this->rest\_hits->search\_query) ? $this->rest\_hits->search\_query : ''
186
186
);
wp-statistics/trunk/includes/class-wp-statistics-ip.php
r2428043
r2679983
80
80
}
81
81
82
return apply\_filters('wp\_statistics\_user\_ip', $ip);
82
return apply\_filters('wp\_statistics\_user\_ip', sanitize\_text\_field($ip));
83
83
}
84
84
…
…
130
130
}
131
131
132
return $user\_ip;
132
return sanitize\_text\_field($user\_ip);
133
133
}
134
134
wp-statistics/trunk/includes/class-wp-statistics-pages.php
r2626597
r2679983
52
52
}
53
53
54
//Single Post Fro All Post Type
54
//Single Post From All Post Type
55
55
if (is\_singular()) {
56
56
$current\_page\['type'\] = "post";
…
…
223
223
224
224
// Check if we have already been to this page today.
225
$exist = $wpdb->get\_row("SELECT \`page\_id\` FROM \`" . DB::table('pages') . "\` WHERE \`date\` = '" . TimeZone::getCurrentDate('Y-m-d') . "' " . (array\_key\_exists("search\_query", $current\_page) === true ? "AND \`uri\` = '" . esc\_sql($page\_uri) . "'" : "") . "AND \`type\` = '{$current\_page\['type'\]}' AND \`id\` = {$current\_page\['id'\]}", ARRAY\_A);
225
$exist = $wpdb->get\_row("SELECT \`page\_id\` FROM \`" . DB::table('pages') . "\` WHERE \`date\` = '" . TimeZone::getCurrentDate('Y-m-d') . "' " . (array\_key\_exists("search\_query", $current\_page) === true ? "AND \`uri\` = '" . esc\_sql($page\_uri) . "'" : "") . "AND \`type\` = '{$current\_page\['type'\]}' AND \`id\` = '{$current\_page\['id'\]}'", ARRAY\_A);
226
226
227
227
// Update Exist Page
wp-statistics/trunk/includes/class-wp-statistics-user-online.php
r2428952
r2679983
264
264
foreach ($result as $items) {
265
265
266
$ip = esc\_html($items->ip);
267
$agent = esc\_html($items->agent);
268
$platform = esc\_html($items->platform);
269
266
270
$item = array(
267
271
'referred' => Referred::get\_referrer\_link($items->referred),
268
'agent' => $items->agent,
269
'platform' => $items->platform,
272
'agent' => $agent,
273
'platform' => $platform,
270
274
'version' => $items->version,
271
275
);
…
…
287
291
// Push Browser
288
292
$item\['browser'\] = array(
289
'name' => $items->agent,
290
'logo' => UserAgent::getBrowserLogo($items->agent),
291
'link' => Menus::admin\_url('overview', array('agent' => $items->agent))
293
'name' => $agent,
294
'logo' => UserAgent::getBrowserLogo($agent),
295
'link' => Menus::admin\_url('overview', array('agent' => $agent))
292
296
);
293
297
294
298
// Push IP
295
if (IP::IsHashIP($items->ip)) {
299
if (IP::IsHashIP($ip)) {
296
300
$item\['hash\_ip'\] = IP::$hash\_ip\_prefix;
297
301
} else {
298
$item\['ip'\] = array('value' => $items->ip, 'link' => Menus::admin\_url('visitors', array('ip' => $items->ip)));
299
$item\['map'\] = GeoIP::geoIPTools($items->ip);
302
$item\['ip'\] = array('value' => $ip, 'link' => Menus::admin\_url('visitors', array('ip' => $ip)));
303
$item\['map'\] = GeoIP::geoIPTools($ip);
300
304
}
301
305
…
…
307
311
// Push City
308
312
if (GeoIP::active('city')) {
309
$item\['city'\] = GeoIP::getCity($items->ip);
313
$item\['city'\] = GeoIP::getCity($ip);
310
314
}
311
315
wp-statistics/trunk/includes/class-wp-statistics-visitor.php
r2428952
r2679983
273
273
foreach ($result as $items) {
274
274
275
$ip = esc\_html($items->ip);
276
$agent = esc\_html($items->agent);
277
$platform = esc\_html($items->platform);
278
275
279
$item = array(
276
280
'hits' => (int)$items->hits,
…
…
278
282
'refer' => $items->referred,
279
283
'date' => date\_i18n(get\_option('date\_format'), strtotime($items->last\_counter)),
280
'agent' => $items->agent,
281
'platform' => $items->platform,
282
'version' => $items->version
284
'agent' => $agent,
285
'platform' => $platform,
286
'version' => esc\_html($items->version)
283
287
);
284
288
…
…
294
298
// Push Browser
295
299
$item\['browser'\] = array(
296
'name' => $items->agent,
297
'logo' => UserAgent::getBrowserLogo($items->agent),
298
'link' => Menus::admin\_url('overview', array('agent' => $items->agent))
300
'name' => $agent,
301
'logo' => UserAgent::getBrowserLogo($agent),
302
'link' => Menus::admin\_url('overview', array('agent' => $agent))
299
303
);
300
304
301
305
// Push IP
302
if (IP::IsHashIP($items->ip)) {
306
if (IP::IsHashIP($ip)) {
303
307
$item\['hash\_ip'\] = IP::$hash\_ip\_prefix;
304
308
} else {
305
$item\['ip'\] = array('value' => $items->ip, 'link' => Menus::admin\_url('visitors', array('ip' => $items->ip)));
306
$item\['map'\] = GeoIP::geoIPTools($items->ip);
309
$item\['ip'\] = array('value' => $ip, 'link' => Menus::admin\_url('visitors', array('ip' => $ip)));
310
$item\['map'\] = GeoIP::geoIPTools($ip);
307
311
}
308
312
…
…
314
318
// Push City
315
319
if (GeoIP::active('city')) {
316
$item\['city'\] = GeoIP::getCity($items->ip);
320
$item\['city'\] = GeoIP::getCity($ip);
317
321
}
318
322
wp-statistics/trunk/includes/template-functions.php
r2626597
r2679983
606
606
//Check Browser is defined in wp-statistics
607
607
if (array\_key\_exists(strtolower($out\[0\]), $default\_browser)) {
608
$Browsers\[\] = $out\[0\];
608
$Browsers\[\] = esc\_html($out\[0\]);
609
609
}
610
610
}
…
…
657
657
$Platforms = array();
658
658
foreach ($result as $out) {
659
$Platforms\[\] = $out\[0\];
659
$Platforms\[\] = esc\_html($out\[0\]);
660
660
}
661
661
wp-statistics/trunk/readme.txt
r2671297
r2679983
5
5
Requires at least: 3.0
6
6
Tested up to: 5.9
7
Stable tag: 13.1.5
7
Stable tag: 13.1.6
8
8
Requires PHP: 5.6
9
9
License: GPLv3
…
…
125
125
126
126
\== Changelog ==
127
\= v13.1.6 - 16.02.2022 =
128
\* Bugfix: Hardened plugin security. (Special thanks to Muhammad Zeeshan (Xib3rR4dAr) & WPScan for reporting the issues)
129
127
130
\= v13.1.5 - 02.02.2022 =
128
131
\* Enhancement: Tested up to v5.9
129
132
\* Enhancement: Disable showing the notices with hidden class in the admin settings page
130
133
\* Bugfix: A security issue to accepting the correct \`exclusion\_reason\` through request
131
\* Bugfix: The 403 Forbidden Error issue
134
\* Bugfix: The 403 Forbidden Error issue in REST request
132
135
133
136
\= v13.1.4 - 14.01.2022 =
wp-statistics/trunk/wp-statistics.php
r2671297
r2679983
4
4
\* Plugin URI: https://wp-statistics.com/
5
5
\* Description: This plugin gives you the complete information on your website's visitors.
6
\* Version: 13.1.5
6
\* Version: 13.1.6
7
7
\* Author: VeronaLabs
8
8
\* Author URI: https://veronalabs.com/