Null byte termination in hostnames

Inhalt

Summary

fsockopen() doesn't regard hostname as well, hostname is terminated at the null byte. This can cause Server Side Request Forgery in general case.

Details

During fsockopen is being called hostname is passed directly to the low-level C function calls.

/etc/standard/fsock.c:28

static void php_fsockopen_stream(INTERNAL_FUNCTION_PARAMETERS, int persistent)
{
	char *host;
	size_t host_len;
	zend_long port = -1;
	zval *zerrno = NULL, *zerrstr = NULL;
	double timeout;
	bool timeout_is_null = 1;
#ifndef PHP_WIN32
	time_t conv;
#else
	long conv;
#endif
	struct timeval tv;
	char *hashkey = NULL;
	php_stream *stream = NULL;
	int err;
	char *hostname = NULL;
	size_t hostname_len;
	zend_string *errstr = NULL;

	ZEND_PARSE_PARAMETERS_START(1, 5)
		Z_PARAM_STRING(host, host_len)
		Z_PARAM_OPTIONAL
		Z_PARAM_LONG(port)
		Z_PARAM_ZVAL(zerrno)
		Z_PARAM_ZVAL(zerrstr)
		Z_PARAM_DOUBLE_OR_NULL(timeout, timeout_is_null)
	ZEND_PARSE_PARAMETERS_END();

// ...

	stream = php_stream_xport_create(hostname, hostname_len, REPORT_ERRORS,
			STREAM_XPORT_CLIENT | STREAM_XPORT_CONNECT, hashkey, &tv, NULL, &errstr, &err);

When fsockopen() is called, it retrieves hostname from first parameter, into host and host_len. host can contain null bytes in the middle of the string, but host_len can be used to prevent unexpected null termination. These two host and host_len is passed to php_stream_xport_create()

/main/streams/transports.c:_php_stream_xporet_create()

	orig_path = name;
	for (p = name; isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'; p++) {
		n++;
	}

	if ((*p == ':') && (n > 1) && !strncmp("://", p, 3)) {
		protocol = name;
		name = p + 3;
		namelen -= n + 3;
	} else {
		protocol = "tcp";
		n = 3;
	}

After TCP factory is selected, php_network_getaddresses() is called, but still null bytes or any control characters are not processed. This will lead Server Side Request Forgery.

While other url-related functions like parse_url has processing logic using zend_string type and iscntrl() check. This difference can be used to trigger SSRF in general case.

For example, one developer can write following reasonable code.

Verknuepfte CVEs

CVE-ID Severity (CVE.org) CVSS (CVE.org) EPSS EPSS-% Veroeffentlicht (CVE.org)

CVE-2025-1220

- - - -

Quellen-Details

Bezeichnung Name Kategorie Tags Zielgruppe Sprache Feed-URL
PHP Security (php/php-src GHSA)

php_sec

vendor_advisory php, runtime - de https://github.com/php/php-src/security/advisories