Security
Headlines
HeadlinesLatestCVEs

Headline

CVE-2022-23556: Merge pull request from GHSA-ghw3-5qvm-3mqc · codeigniter4/CodeIgniter4@5ca8c99

CodeIgniter is a PHP full-stack web framework. This vulnerability may allow attackers to spoof their IP address when the server is behind a reverse proxy. This issue has been patched, please upgrade to version 4.2.11 or later, and configure Config\App::$proxyIPs. As a workaround, do not use $request->getIPAddress().

CVE
#vulnerability#web#php

@@ -11,6 +11,7 @@
namespace CodeIgniter\HTTP;
use CodeIgniter\Exceptions\ConfigException; use CodeIgniter\Validation\FormatRules;
/** @@ -43,7 +44,9 @@ trait RequestTrait /** * Gets the user’s IP address. * * @return string IP address * @return string IP address if it can be detected, or empty string. * If the IP address is not a valid IP address, * then will return '0.0.0.0’. */ public function getIPAddress(): string { @@ -59,93 +62,86 @@ public function getIPAddress(): string /** * @deprecated $this->proxyIPs property will be removed in the future */ // @phpstan-ignore-next-line $proxyIPs = $this->proxyIPs ?? config(‘App’)->proxyIPs; if (! empty($proxyIPs) && ! is_array($proxyIPs)) { $proxyIPs = explode(',’, str_replace(' ', '’, $proxyIPs)); if (! empty($proxyIPs)) { // @phpstan-ignore-next-line if (! is_array($proxyIPs) || is_int(array_key_first($proxyIPs))) { throw new ConfigException( ‘You must set an array with Proxy IP address key and HTTP header name value in Config\App::$proxyIPs.’ ); } }
$this->ipAddress = $this->getServer(‘REMOTE_ADDR’);
if ($proxyIPs) { foreach (['x-forwarded-for’, 'client-ip’, 'x-client-ip’, ‘x-cluster-client-ip’] as $header) { $spoof = null; $headerObj = $this->header($header);
if ($headerObj !== null) { $spoof = $headerObj->getValue();
// Some proxies typically list the whole chain of IP // addresses through which the client has reached us. // e.g. client_ip, proxy_ip1, proxy_ip2, etc. sscanf($spoof, '%[^,]', $spoof);
if (! $ipValidator($spoof)) { $spoof = null; } else { break; } } }
if ($spoof) { foreach ($proxyIPs as $proxyIP) { // Check if we have an IP address or a subnet if (strpos($proxyIP, ‘/’) === false) { // An IP address (and not a subnet) is specified. // We can compare right away. if ($proxyIP === $this->ipAddress) { // @TODO Extract all this IP address logic to another class. foreach ($proxyIPs as $proxyIP => $header) { // Check if we have an IP address or a subnet if (strpos($proxyIP, ‘/’) === false) { // An IP address (and not a subnet) is specified. // We can compare right away. if ($proxyIP === $this->ipAddress) { $spoof = $this->getClientIP($header);
if ($spoof !== null) { $this->ipAddress = $spoof; break; }
continue; }
// We have a subnet … now the heavy lifting begins if (! isset($separator)) { $separator = $ipValidator($this->ipAddress, ‘ipv6’) ? ‘:’ : '.’; } continue; }
// If the proxy entry doesn’t match the IP protocol - skip it if (strpos($proxyIP, $separator) === false) { continue; } // We have a subnet … now the heavy lifting begins if (! isset($separator)) { $separator = $ipValidator($this->ipAddress, ‘ipv6’) ? ‘:’ : '.’; }
// Convert the REMOTE_ADDR IP address to binary, if needed if (! isset($ip, $sprintf)) { if ($separator === ‘:’) { // Make sure we’re have the “full” IPv6 format $ip = explode(':’, str_replace('::’, str_repeat(':’, 9 - substr_count($this->ipAddress, ‘:’)), $this->ipAddress)); // If the proxy entry doesn’t match the IP protocol - skip it if (strpos($proxyIP, $separator) === false) { continue; }
for ($j = 0; $j < 8; $j++) { $ip[$j] = intval($ip[$j], 16); } // Convert the REMOTE_ADDR IP address to binary, if needed if (! isset($ip, $sprintf)) { if ($separator === ‘:’) { // Make sure we’re having the “full” IPv6 format $ip = explode(':’, str_replace('::’, str_repeat(':’, 9 - substr_count($this->ipAddress, ‘:’)), $this->ipAddress));
$sprintf = '%016b%016b%016b%016b%016b%016b%016b%016b’; } else { $ip = explode('.’, $this->ipAddress); $sprintf = '%08b%08b%08b%08b’; for ($j = 0; $j < 8; $j++) { $ip[$j] = intval($ip[$j], 16); }
$ip = vsprintf($sprintf, $ip); $sprintf = '%016b%016b%016b%016b%016b%016b%016b%016b’; } else { $ip = explode('.’, $this->ipAddress); $sprintf = '%08b%08b%08b%08b’; }
// Split the netmask length off the network address sscanf($proxyIP, '%[^/]/%d’, $netaddr, $masklen); $ip = vsprintf($sprintf, $ip); }
// Again, an IPv6 address is most likely in a compressed form if ($separator === ‘:’) { $netaddr = explode(':’, str_replace('::’, str_repeat(':’, 9 - substr_count($netaddr, ‘:’)), $netaddr)); // Split the netmask length off the network address sscanf($proxyIP, '%[^/]/%d’, $netaddr, $masklen);
for ($i = 0; $i < 8; $i++) { $netaddr[$i] = intval($netaddr[$i], 16); } } else { $netaddr = explode('.’, $netaddr); // Again, an IPv6 address is most likely in a compressed form if ($separator === ‘:’) { $netaddr = explode(':’, str_replace('::’, str_repeat(':’, 9 - substr_count($netaddr, ‘:’)), $netaddr));
for ($i = 0; $i < 8; $i++) { $netaddr[$i] = intval($netaddr[$i], 16); } } else { $netaddr = explode('.’, $netaddr); }
// Convert to binary and finally compare if (strncmp($ip, vsprintf($sprintf, $netaddr), $masklen) === 0) { $spoof = $this->getClientIP($header);
// Convert to binary and finally compare if (strncmp($ip, vsprintf($sprintf, $netaddr), $masklen) === 0) { if ($spoof !== null) { $this->ipAddress = $spoof; break; } @@ -160,6 +156,34 @@ public function getIPAddress(): string return empty($this->ipAddress) ? ‘’ : $this->ipAddress; }
/** * Gets the client IP address from the HTTP header. */ private function getClientIP(string $header): ?string { $ipValidator = [ new FormatRules(), 'valid_ip’, ]; $spoof = null; $headerObj = $this->header($header);
if ($headerObj !== null) { $spoof = $headerObj->getValue();
// Some proxies typically list the whole chain of IP // addresses through which the client has reached us. // e.g. client_ip, proxy_ip1, proxy_ip2, etc. sscanf($spoof, '%[^,]', $spoof);
if (! $ipValidator($spoof)) { $spoof = null; } }
return $spoof; }
/** * Fetch an item from the $_SERVER array. *

Related news

GHSA-ghw3-5qvm-3mqc: CodeIgniter4 allows spoofing of IP address when using proxy

### Impact This vulnerability may allow attackers to spoof their IP address when your server is behind a reverse proxy. ### Patches Upgrade to v4.2.11 or later, and configure `Config\App::$proxyIPs`. ### Workarounds Do not use `$request->getIPAddress()`. ### References - https://codeigniter4.github.io/userguide/incoming/request.html#CodeIgniter\HTTP\Request::getIPAddress ### For more information If you have any questions or comments about this advisory: * Open an issue in [codeigniter4/CodeIgniter4](https://github.com/codeigniter4/CodeIgniter4/issues) * Email us at [SECURITY.md](https://github.com/codeigniter4/CodeIgniter4/blob/develop/SECURITY.md)

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