Security
Headlines
HeadlinesLatestCVEs

Headline

CVE-2021-25112: Changeset 2659751 – WordPress Plugin Repository

The WHMCS Bridge WordPress plugin before 6.4b does not sanitise and escape the error parameter before outputting it back in admin dashboard, leading to a Reflected Cross-Site Scripting

CVE
#windows#linux#js

r2659243 r2659751 11<?php 22class bridgeHttpRequest { 3 var $_fp; // HTTP socket 4 var $_url; // full URL 5 var $_host; // HTTP host 6 var $_protocol; // protocol (HTTP/HTTPS) 7 var $_uri; // request URI 8 var $_port; // port 9 var $_path; 10 var $error=false; 11 var $errno=false; 12 var $post=array(); //post variables, defaults to $_POST 13 var $redirect=false; 14 var $forceWithRedirect=array(); 15 var $errors=array(); 16 var $countRedirects=0; 17 var $sid; 18 var $httpCode; 19 var $repost=false; 20 var $type; //content-type 21 var $follow=true; //whether to follow redirect links or not 22 var $noErrors=false; //whether to trigger an error in case of a curl error 23 var $errorMessage; 24 var $httpHeaders=array(‘Expect:’,’bridgeon: 1’); //avoid 417 errors 25 var $debugFunction; 26 var $time; 27 var $cookieArray=array(); 28 var $cookieCache=’’; 3 public $_fp; // HTTP socket 4 public $_url; // full URL 5 public $_host; // HTTP host 6 public $_protocol; // protocol (HTTP/HTTPS) 7 public $_uri; // request URI 8 public $_port; // port 9 public $_path; 10 public $error=false; 11 public $errno=false; 12 public $post=array(); //post variables, defaults to $_POST 13 public $redirect=false; 14 public $forceWithRedirect=array(); 15 public $errors=array(); 16 public $countRedirects=0; 17 public $sid; 18 public $httpCode; 19 public $repost=false; 20 public $type; //content-type 21 public $follow = true; //whether to follow redirect links or not 22 public $noErrors = false; //whether to trigger an error in case of a curl error 23 public $errorMessage; 24 public $httpHeaders = array(‘Expect:’,’bridgeon: 1’); //avoid 417 errors 25 public $debugFunction; 26 public $time; 27 public $cookieArray = array(); 28 public $cookieCach=’’; 29 public $debugPrefix = '’; 2930 3031 // constructor 31 function __construct($url = "", $sid = "", $repost = false) { 32 public function __construct($url = "", $sid = "", $repost = false) { 3233 if (!$url) return; 3334 $this->sid=$sid; … … 3637 $this->post=$_POST; 3738 $this->repost=$repost; 39 $this->debugPrefix = "[connect “.uniqid().”] "; 3840 } 3941 … … 5759 5860 private function debug($type=0,$msg=’’,$filename="",$linenum=0) { 59 if ($f=$this->debugFunction) $f($type,$msg,$filename,$linenum); 61 if ($f=$this->debugFunction) $f($type,$this->debugPrefix.$msg,$filename,$linenum); 6062 } 6163 … … 6365 if (strtoupper(substr(PHP_OS, 0, 3)) === ‘WIN’) return 'WINDOWS’; 6466 else return 'LINUX’; 65 } 66 67 private function processHeaders($headers) { 68 $this->debug(0, 'Processing headers: '.json_encode($headers)); 69 70 // split headers, one per array element 71 if ( is_string($headers) ) { 72 // tolerate line terminator: CRLF = LF (RFC 2616 19.3) 73 $headers = str_replace("\r\n", "\n", $headers); 74 // unfold folded header fields. LWS = [CRLF] 1*( SP | HT ) <US-ASCII SP, space (32)>, <US-ASCII HT, horizontal-tab (9)> (RFC 2616 2.2) 75 $headers = preg_replace('/\n[ \t]/’, ' ', $headers); 76 // create the headers array 77 $headers = explode("\n", $headers); 78 } 79 80 $response = array(‘code’ => 0, ‘message’ => ‘’); 81 82 // If a redirection has taken place, The headers for each page request may have been passed. 83 // In this case, determine the final HTTP header and parse from there. 84 for ( $i = count($headers)-1; $i >= 0; $i-- ) { 85 if ( !empty($headers[$i]) && false === strpos($headers[$i], ‘:’) ) { 86 $headers = array_splice($headers, $i); 87 break; 88 } 89 } 90 91 $cookies = '’; 92 $newheaders = array(); 93 94 foreach ( $headers as $tempheader ) { 95 if ( empty($tempheader) ) 96 continue; 97 98 if ( false === strpos($tempheader, ‘:’) ) { 99 list( , $response[‘code’], $response[‘message’]) = explode(' ', $tempheader, 3); 100 continue; 101 } 102 103 list($key, $value) = explode(‘:’, $tempheader, 2); 104 105 if ( !empty( $value ) ) { 106 $key = strtolower( $key ); 107 108 if ( isset( $newheaders[$key] ) ) { 109 if ( !is_array($newheaders[$key]) ) 110 $newheaders[$key] = array($newheaders[$key]); 111 $newheaders[$key][] = trim( $value ); 112 } else { 113 $newheaders[$key] = trim( $value ); 114 } 115 if (‘set-cookie’ == $key) { 116 if ($cookies) $cookies.=’ ;’; 117 $cookies .= $value; 118 list($k,$rest)=explode(‘=’,$value,2); 119 $this->cookieArray[trim($k)]=$value; 120 if (stristr($value,’=deleted’)) 121 unset($_SESSION[$this->sid][‘cookie-array’][trim($k)]); 122 else 123 $_SESSION[$this->sid][‘cookie-array’][trim($k)]=$value; 124 } 125 } 126 } 127 return array(‘response’ => $response, ‘headers’ => $newheaders, ‘cookies’ => $cookies); 12867 } 12968 … … 15897 15998 //check if server is live 160 function live() { 99 public function live() { 161100 //return true; 162101 if (ip2long($this->_host)) return true; //in case using an IP instead of a host name … … 169108 170109 //get mime type of uploaded file 171 function mimeType($file) { 110 public function mimeType($file) { 172111 $mime=’’; 173112 if (function_exists(‘finfo_open’)) { … … 182121 183122 //check if wp HTTP API is available 184 function curlInstalled() { 123 public function curlInstalled() { 185124 if (!function_exists(‘wp_remote_request’)) return false; 186125 else return true; … … 188127 189128 //check destination is reachable 190 function checkConnection() { 129 public function checkConnection() { 191130 $this->post[‘checkconnection’]=1; 192131 $output=$this->connect($this->_protocol.’://’.$this->_host.$this->_uri); … … 196135 197136 //error logging 198 function error($msg) { 137 public function error($msg) { 199138 $this->errorMsg=$msg; 200139 $this->error=true; … … 204143 205144 //notification logging 206 function notify($msg) { 145 public function notify($msg) { 207146 $this->errorMsg=$msg; 208147 $this->error=true; … … 212151 213152 // download URL to string 214 function DownloadToString($withHeaders=true,$withCookies=false) { 153 public function DownloadToString($withHeaders=true,$withCookies=false) { 215154 if ($this->_port == 80 || $this->_port == 443) 216155 $html = $this->connect($this->_protocol.’://’.$this->_host.$this->_uri,$withHeaders,$withCookies); … … 221160 } 222161 223 function makeQueryString($params, $prefix = '’, $removeFinalAmp = true) { 162 public function makeQueryString($params, $prefix = '’, $removeFinalAmp = true) { 224163 $queryString = '’; 225164 if (is_array($params)) { … … 246185 } 247186 248 function connect($url, $withHeaders=true, $withCookies=false) { 187 private function generatePostArray() { 188 $apost = []; 189 if (count($this->post) > 0) { 190 $this->debug(0, “HTTP POST 2”); 191 $post = ""; 192 $apost = array(); 193 $this->post = stripslashes_deep($this->post); 194 foreach ($this->post as $k => $v) { 195 if (is_array($v)) { 196 foreach ($v as $k2 => $v2) { 197 if (is_array($v2)) { 198 foreach ($v2 as $k3 => $v3) { 199 if (is_array($v3)) { 200 foreach ($v3 as $k4 => $v4) { 201 $apost[$k . '[' . $k2 . ']' . '[' . $k3 . '][' . $k4 . ']'] = ($v4); 202 } 203 } else { 204 $apost[$k . '[' . $k2 . ']' . '[' . $k3 . ']'] = ($v3); 205 } 206 } 207 } else { 208 $apost[$k . '[' . $k2 . ']'] = ($v2); 209 } 210 } 211 212 } else { 213 $apost[$k] = ($v); 214 } 215 } 216 } 217 return $apost; 218 } 219 220 public function connect($url, $withHeaders=true, $withCookies=false) { 249221 $this->time(‘reset’); 250222 global $wordpressPageName; … … 281253 $http_args = array(); 282254 283 $this->debug(0, 'HTTP Call: ' . $url . (is_array($this->post) ? ' with ' . print_r($this->post, true) : ‘’)); 255 $this->debug(0, 'HTTP Call: ' . $url . (is_array($this->post) ? ' with ' . json_encode($this->post) : ‘’)); 284256 285257 if (get_option(“cc_whmcs_bridge_affiliate_id”) && is_numeric(get_option(“cc_whmcs_bridge_affiliate_id”)) && get_option(“cc_whmcs_bridge_affiliate_id”) > 0) { … … 293265 294266 $http_args[‘headers’] = $this->httpHeaders; 295 296 // curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // return into a variable 297 // curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER[‘HTTP_USER_AGENT’]); 298 299 //cloudflare debug 300 // curl_setopt($ch, CURLOPT_FORBID_REUSE, 1); 301 // curl_setopt($ch, CURLOPT_FRESH_CONNECT, 1); 302 303 //CURLOPT_REFERER - The contents of the "Referer: " header to be used in a HTTP request. 304 //CURLOPT_INTERFACE - The name of the outgoing network interface to use. This can be an interface name, an IP address or a host name. 305 306 // curl_setopt($ch, CURLOPT_TIMEOUT, 120); // times out after 120s 307267 $http_args[‘timeout’] = 60; 308268 309269 if ($this->_protocol == “https”) { 310270 $http_args[‘sslverify’] = false; 311 // curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); 312 // curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); 313 // curl_setopt($ch, CURLOPT_CAINFO, NULL); 314 // curl_setopt($ch, CURLOPT_CAPATH, NULL); 315 //curl_setopt($ch, CURLOPT_SSLVERSION, 3); 316 } 317 // gzip 318 // $this->debug(0, 'Server Software: '.$_SERVER[‘SERVER_SOFTWARE’]); 319 // if (stristr($_SERVER[‘SERVER_SOFTWARE’], ‘litespeed’) !== false) { 320 // curl_setopt($ch, CURLOPT_ENCODING, “”); 321 // } 322 // quicker lookup 323 //curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); 324 325 $cookies = ""; 326 // $cookies = apply_filters('bridgeHttpRequest_pre’, $cookies); 327 328 if (isset($_SESSION[$this->sid][‘cookie-array’]) && count($_SESSION[$this->sid][‘cookie-array’]) > 0) { 329 foreach ($_SESSION[$this->sid][‘cookie-array’] as $n => $v) { 330 // CloudFlare 331 if (stristr($n, ‘__cfduid’) !== false) continue; 332 if (stristr($n, ‘_cflb’) !== false) continue; 333 if (stristr($n, ‘_cf_bm’) !== false) continue; 334 335 if ($cookies) $cookies .= ';’; 336 $cookies .= $v; 337 } 338 } 339 340 if ($cookies) { 341 $this->debug(0, ‘Cookie before:’ . json_encode(explode("\r\n", $cookies))); 342 if (stristr($cookies, ‘__cfduid’) !== false) { 343 $cookies = 'WHMCS’.substr($cookies, strpos($cookies, “WHMCS”) + 1); 344 } 345 //curl_setopt($ch, CURLOPT_COOKIE, $cookies); 346 $http_args[‘cookies’] = explode(";", $cookies); 347 } 348 349 $_SESSION[‘cookieCache’] = $cookies; 271 } 272 273 $cookies = []; 274 275 if (isset($_SESSION[$this->sid][‘cookieArr’]) && count($_SESSION[$this->sid][‘cookieArr’]) > 0) { 276 $cookies = $_SESSION[$this->sid][‘cookieArr’]; 277 } 278 279 if (!empty($cookies)) { 280 $this->debug(0, ‘Cookie before:’ . json_encode($cookies)); 281 $http_args[‘cookies’] = $cookies; 282 } 283 284 $_SESSION[‘cookieCach’] = $cookies; 350285 351286 /*if (count($_FILES) > 0) { … … 388323 389324 $rawPost = file_get_contents(‘php://input’); 390 cc_whmcs_log(0, "RAW data: ".$rawPost); 391 $apost = array(); 392 393 if (count($this->post) > 0) { 394 cc_whmcs_log(0, “HTTP Method POST 2”); 395 //curl_setopt($ch, CURLOPT_POST, 1); // set POST method 396 $post = ""; 397 $apost = array(); 398 $this->post = stripslashes_deep($this->post); 399 foreach ($this->post as $k => $v) { 400 if (is_array($v)) { 401 foreach ($v as $k2 => $v2) { 402 if (is_array($v2)) { 403 foreach ($v2 as $k3 => $v3) { 404 if (is_array($v3)) { 405 foreach ($v3 as $k4 => $v4) { 406 $apost[$k . '[' . $k2 . ']' . '[' . $k3 . '][' . $k4 . ']'] = ($v4); 407 } 408 } else { 409 $apost[$k . '[' . $k2 . ']' . '[' . $k3 . ']'] = ($v3); 410 } 411 } 412 } else { 413 $apost[$k . '[' . $k2 . ']'] = ($v2); 414 } 415 } 416 417 } else { 418 $apost[$k] = ($v); 419 } 420 } 421 } else if (stristr($url, ‘two-factor’) !== false && stristr($url, ‘totp’) === false) { 422 curl_setopt($ch, CURLOPT_CUSTOMREQUEST, “POST”); // set POST method 423 cc_whmcs_log(0, “HTTP customrequest Method POST 1”); 424 } 425 426 if (count($apost) > 0) { 325 if (!empty($rawPost)) 326 $this->debug(0, "RAW data: ".$rawPost); 327 328 $apost = $this->generatePostArray(); 329 330 if (!empty($apost)) { 427331 $http_args[‘method’] = 'POST’; 428332 429333 if (stristr($url, ‘clientarea.php?action=details’) !== false && !isset($apost[‘save’]) && isset($apost[‘firstname’], $apost[‘lastname’], $apost[‘companyname’], $apost[‘address1’])) { 430334 $apost[‘save’] = 'Save Changes’; 431 cc_whmcs_log(0, ‘Safari patch for updating personal details’); 335 $this->debug(0, ‘Safari patch for updating personal details’); 432336 } 433337 434338 if (count($newfiles) > 0) { 435 // curl_setopt($ch, CURLOPT_POSTFIELDS, $apost); 436 cc_whmcs_log(0, 'Posting as [0]: ' . print_r($apost, true)); 339 $this->debug(0, 'Posting as [0]: ' . json_encode($apost)); 437340 438341 $http_args[‘body’] = $apost; 439342 } else { 440343 $pfields = $this->makeQueryString($apost); 441 // curl_setopt($ch, CURLOPT_POSTFIELDS, $pfields); 442 cc_whmcs_log(0, 'Posting as [1]: ' . print_r($pfields, true)); 344 $this->debug(0, 'Posting as [1]: ' . json_encode($pfields)); 443345 444346 $http_args[‘body’] = $pfields; … … 448350 $http_args[‘method’] = 'POST’; 449351 450 if (in_array(substr($rawPost, 0, 1), ['[', '{’, ‘"’])) { 451 // curl_setopt($ch, CURLOPT_CUSTOMREQUEST, “POST”); // set POST method 452 } else { 352 if (!in_array(substr($rawPost, 0, 1), ['[', '{’, ‘"’])) { 453353 parse_str($rawPost, $rawPost); 454354 } 455 // curl_setopt($ch, CURLOPT_POSTFIELDS, $rawPost); 456355 457356 $http_args[‘body’] = $rawPost; 458357 459 cc_whmcs_log(0, "Posting RAW: ".$rawPost); 460 // cc_whmcs_log(0, “HTTP customrequest Method POST 2”); 358 $this->debug(0, "Posting RAW: ".$rawPost); 461359 } else if (strtolower($_SERVER[‘REQUEST_METHOD’]) == “post” && strstr($url, ‘viewinvoice.php’) === false) { 462360 $http_args[‘method’] = 'POST’; 463 //curl_setopt($ch, CURLOPT_POST, 1); // set POST method 464 cc_whmcs_log(0, “HTTP Method POST 1”); 465 } 466 467 // $data = curl_exec($ch); // run the whole process 468 361 362 $this->debug(0, “HTTP Method POST 1”); 363 } 469364 470365 // Fix legacy headers … … 482377 } 483378 484 cc_whmcs_log(0, "Posting to {$url} with: ".json_encode($http_args)); 379 $this->debug(0, "Posting to {$url} with: ".json_encode($http_args)); 485380 486381 $data = wp_remote_request($url, $http_args); 487382 488 // if (curl_errno($ch)) { 489 // $this->errno = curl_errno($ch); 490 // $this->error = curl_error($ch); 491 // $error_msg = ‘An error has occurred: ' . $this->error; 492 // $this->error($this->errno . ‘/’ . $error_msg.’ (‘.$url.’)'); 493 // cc_whmcs_log(0, 'HTTP Error: ‘.$this->errno . ‘/’ . $error_msg.’ (‘.$url.’)'); 494 // return '<body>’.$error_msg.’<br>Please try again later.</body>’; 495 // } 496 // 497 // $info = curl_getinfo($ch); 383 if (is_wp_error($data)) { 384 $this->errno = $data->get_error_code(); 385 $this->error = $data->get_error_message($this->errno); 386 $error_msg = ‘An error has occurred: ' . $this->error; 387 $this->error($this->errno . ‘/’ . $error_msg.’ (‘.$url.’)'); 388 $this->debug(0, 'HTTP Error: ‘.$this->errno . ‘/’ . $error_msg.’ (‘.$url.’)'); 389 return '<body>’.$error_msg.’<br>Please try again later.</body>’; 390 } 498391 499392 if (!empty($data)) { 500 // $headerLength = curl_getinfo($ch, CURLINFO_HEADER_SIZE); 501 // $head = trim(substr($data, 0, $headerLength)); 502 // if (strlen($data) > $headerLength) $body = substr($data, $headerLength); 503 // else $body = '’; 504 // if (false !== strpos($head, “\r\n\r\n”)) { 505 // $headerParts = explode("\r\n\r\n", $head); 506 // $head = $headerParts[count($headerParts) - 1]; 507 // } 508 // 509 // cc_whmcs_log(0, "Head: ".json_encode($head)); 510 // 511 // $head = $this->processHeaders($head); 512 // $headers = $head[‘headers’]; 513 // $cookies = $head[‘cookies’]; 514 // 515 // if (empty($cookies)) 516 // $cookies = $_SESSION[‘cookieCache’]; 517 518393 $headers = $data[‘headers’]->getAll(); 519394 520 cc_whmcs_log(0, 'Headers: '.print_r($headers, true)); 521 522 $cookies = $headers[‘set-cookie’]; 523 524 list($k, $rest) = explode(‘=’, $cookies,2); 525 526 $this->cookieArray[trim($k)] = $cookies; 527 528 if (stristr($cookies,’=deleted’)) 529 unset($_SESSION[$this->sid][‘cookie-array’][trim($k)]); 530 else 531 $_SESSION[$this->sid][‘cookie-array’][trim($k)] = $cookies; 395 $this->debug(0, 'Headers: '.json_encode($headers)); 396 397 $cookies = wp_remote_retrieve_cookies($data); 398 if (!empty($cookies) && !is_wp_error($cookies)) { 399 $_SESSION[$this->sid][‘cookieArr’] = $cookies; 400 } else { 401 $cookies = $_SESSION[‘cookieCach’]; 402 } 532403 533404 $body = $data[‘body’]; 534405 } else { 535406 $headers = array(); 536 $cookies = '’; 537 $body = '’; 538 $this->error(‘An undefined error occured’); 539 return '<body>An undefined error occured</body>’; 540 } 541 542 if (isset($this->cookieArray[‘PHPSESSID’]) && $this->cookieArray[‘PHPSESSID’]) { 543 $_SESSION[$this->sid][‘sessid’] = $this->cookieArray[‘PHPSESSID’]; 544 } 545 546 if ($cookies) { 407 $cookies = []; 408 $body = ""; 409 410 $this->error(“An undefined error occurred”); 411 412 return '<body>An undefined error occurred</body>’; 413 } 414 415 416 $foundSessId = false; 417 foreach ($cookies as $ck) { 418 if ($ck->name == ‘PHPSESSID’) { 419 $foundSessId = true; 420 $_SESSION[$this->sid][‘sessid’] = $ck->value; 421 } 422 } 423 424 if (!empty($cookies)) { 547425 $this->debug(0, ‘Cookie after:’ . json_encode($cookies)); 548426 549 if (!isset($_SESSION[$this->sid])) $_SESSION[$this->sid] = array(); 427 if (!isset($_SESSION[$this->sid])) 428 $_SESSION[$this->sid] = array(); 429 550430 if (isset($_SESSION[$this->sid][‘sessid’])) { 551 if (!strstr($cookies, ‘PHPSESSID’) && $cookies) $cookies .= ‘;’ . $_SESSION[$this->sid][‘sessid’]; 552 elseif (!strstr($cookies, ‘PHPSESSID’)) $cookies = $_SESSION[$this->sid][‘sessid’]; 553 } 431 if (!$foundSessId) 432 $cookies[] = new WP_Http_Cookie([‘name’ => 'PHPSESSID’, ‘value’ => $_SESSION[$this->sid][‘sessid’]]); 433 } 434 554435 $_SESSION[$this->sid][‘cookies’] = $cookies; 555436 } 556 if (is_array($cookies)) $this->debug(0, ‘Cookie after:’ . json_encode($cookies)); 557 558 //curl_close($ch); 559 560 //remove temporary upload files 437 438 if (is_array($cookies)) 439 $this->debug(0, ‘Cookie after:’ . json_encode($cookies)); 440 441 // remove temporary upload files 561442 if (count($newfiles) > 0) { 562 foreach ($newfiles as $file) { 563 @unlink($file); 443 foreach ($newfiles as $nF) { 444 @unlink($nF); 564445 } 565446 } 566447 567448 $this->headers = $headers; 568 //$this->data = $data; 569449 $this->data = $data[‘raw’]; 570450 $this->cookies = $cookies; … … 574454 $this->type = $headers[‘content-type’]; 575455 } 576 577 //$this->cookies = apply_filters('bridgeHttpRequest_post’, $this->cookies); 578456 579457 $this->debug(0, ‘Call process completed in ' . $this->time(‘delta’) . ' microseconds’); … … 776654 $this->countRedirects++; 777655 if ($this->countRedirects < 10) { 778 //if ($redir != $url) { 779656 return $this->connect($redir, $withHeaders, $withCookies); 780 //} 781657 } else { 782658 $error_msg = 'ERROR: Too many redirects ' . $url . ' > ' . $headers[‘location’];

CVE: Latest News

CVE-2023-50976: Transactions API Authorization by oleiman · Pull Request #14969 · redpanda-data/redpanda
CVE-2023-6905
CVE-2023-6903
CVE-2023-6904
CVE-2023-3907