Lucene search

K
hackeroneTheflow0H1:2177925
HistorySep 22, 2023 - 7:22 p.m.

PlayStation: Remote vulnerabilities in spp

2023-09-2219:22:45
theflow0
hackerone.com
$12500
17
ps4
ps5
pppoe
remote code execution
heap buffer overwrite
heap buffer overread
integer underflow
kernel context
denial of service
proof of concept
sppp_lcp_rcr
sppp_pap_input

7.8 High

AI Score

Confidence

High

0.066 Low

EPSS

Percentile

93.8%

Summary

A malicious PPPoE server can cause denial-of-service or potentially remote code execution in kernel context on the PS4/PS5.

Heap buffer overwrite and overread in sppp_lcp_RCR and sppp_ipcp_RCR

For some reason, the PS4/PS5 is vulnerable to CVE-2006-4304. By having invalid options, it is possible to cause a heap buffer overwrite and overread.

static int
sppp_ipcp_RCR(struct sppp *sp, struct lcp_header *h, int len)
{
	u_char *buf, *r, *p;
	struct ifnet *ifp = &sp->pp_if;
	int rlen, origlen, debug = ifp->if_flags & IFF_DEBUG;
	u_int32_t hisaddr, desiredaddr;

	len -= 4;
	origlen = len;
	// ...
	buf = r = malloc ((len < 6? 6: len), M_TEMP, M_NOWAIT);
	if (! buf)
		return (0);
	// ...
	p = (void *)(h + 1);
	for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) { // [1]
		if (debug)
			addlog(" %s", sppp_ipcp_opt_name(*p));
		switch (*p) {
        // ...
		default:
			/* Others not supported. */
			if (debug)
				addlog(" [rej]");
			break;
		}
		/* Add the option to rejected list. */
		bcopy (p, r, p[1]); // [2]
		r += p[1];
		rlen += p[1]; // [3]
	}
	if (rlen) {
		if (debug)
			addlog(" send conf-rej\n");
		sppp_cp_send(sp, PPP_IPCP, CONF_REJ, h->ident, rlen, buf); // [4]
		goto end;
	} else if (debug)
		addlog("\n");

	// ...
}

Namely, at [1] the length of p[1] is not validated to be smaller or equal to len. As such, at [2] the call bcopy() will copy with a size potentially larger than both the source and the destination.

Furthermore, at [3] the return length is incremented by the malicious length. Hence, the data that is overread from the mbuf is copied into buf (with overflow) and returned to the malicious PPPoE server with sppp_cp_send().

For example this is some data that got sent back containing pointers:

00000000  54 ab 3a 9a ab ad 00 d9  d1 bc 83 e4 88 64 11 00  |T.:..........d..|
00000010  00 14 00 90 80 21 04 02  00 8e 2a ff 41 41 41 41  |.....!....*.AAAA|
00000020  41 41 41 41 41 41 41 41  41 41 41 41 00 00 00 00  |AAAAAAAAAAAA....|
00000030  00 00 00 00 00 00 00 00  00 00 00 00 38 00 2b c5  |............8.+.|
00000040  72 9a cf 01 03 00 08 00  38 61 07 eb bd ff ff bd  |r.......8a......|
00000050  ff ff bd ff ff d9 d1 bc  83 e4 29 00 00 00 b4 07  |..........).....|
00000060  00 00 03 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000070  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
000000a0  00 00 00 00                                       |....            |
000000a4

Regarding exploitability of the overwrite, note that the allocation size for malloc() can be influenced via the LCP header:

static void
sppp_cp_input(const struct cp *cp, struct sppp *sp, struct mbuf *m)
{
	// ...
	struct lcp_header *h;
	// ...
	h = mtod(m, struct lcp_header *);
	// ...
	if (len > ntohs(h->len))
		len = ntohs(h->len);
	p = (u_char *)(h + 1);
	switch (h->type) {
	case CONF_REQ:
		// ...
		rv = (cp->RCR)(sp, h, len);
		// ...
	}
}

By doing so, it is possible to trigger a copy from a bigger mbuf to a smaller buf, thus allowing to overwrite adjacent allocations with controllable data.

See attachment for a proof-of-concept that leaks data and can eventually panic the device.

Integer underflow in sppp_pap_input leading to heap-buffer overread

void
sppp_pap_input(struct sppp *sp, struct mbuf *m)
{
	// ...
	int len, x;
	// ...
	int name_len, passwd_len;
	// ...
	h = mtod (m, struct lcp_header*);
	if (len > ntohs (h->len))
		len = ntohs (h->len); // [1]
	switch (h->type) {
	/* PAP request is my authproto */
	case PAP_REQ:
		name = 1 + (u_char*)(h+1);
		name_len = name[-1];
		passwd = name + name_len + 1;
		if (name_len > len - 6 || // [2]
		    (passwd_len = passwd[-1]) > len - 6 - name_len) {
			if (debug) {
				log(LOG_DEBUG, SPP_FMT "pap corrupted input "
				    "<%s id=0x%x len=%d",
				    SPP_ARGS(ifp),
				    sppp_auth_type_name(PPP_PAP, h->type),
				    h->ident, ntohs(h->len));
				if (len > 4)
					sppp_print_bytes((u_char*)(h+1), len-4);
				addlog(">\n");
			}
			break;
		}
		// ...
		if (name_len > AUTHMAXLEN ||
		    passwd_len > AUTHMAXLEN ||
		    bcmp(name, sp->hisauth.name, name_len) != 0 ||
		    bcmp(passwd, sp->hisauth.secret, passwd_len) != 0) {
			/* action scn, tld */
			mlen = sizeof(FAILMSG) - 1;
			sppp_auth_send(&pap, sp, PAP_NAK, h->ident,
				       sizeof mlen, (const char *)&mlen,
				       sizeof(FAILMSG) - 1, (u_char *)FAILMSG,
				       0);
			pap.tld(sp);
			break;
		}
		// ...
		if (name_len == sp->hisauth.name_len &&
		    memcmp(name, sp->hisauth.name, name_len) == 0 && // [3]
		    secret_len == sp->hisauth.secret_len &&
		    memcmp(secret, sp->hisauth.secret, secret_len) == 0) {
			sp->scp[IDX_PAP].rcr_type = CP_RCR_ACK;
		} else {
			sp->scp[IDX_PAP].rcr_type = CP_RCR_NAK;
		}
	// ...
	}
}

At [1], it is possible to set len to a length between 0 and 5. Thus, at [2] len - 6 can have a negative length between -6 and -1. As such, the checks for name_len and passwd_len can be bypassed, and it is possible to have lengths up to 255 bytes. As a consequence, at [3] it is possible to read out-of-bounds from the mbuf when comparing the name and password with memcmp(). Since different responses are returned back based on the comparison, an attacker might be able to use this as a an oracle to leak the out-of-bounds data (by setting the name and secret beforehand). This could be used to leak pointers and defeat KASLR remotely.

Note that this vulnerability is still affecting NetBSD and OpenBSD. FreeBSD seemed to have deprecated this whole protocol.

Impact

A malicious PPPoE server can cause denial-of-service or potentially remote code execution in kernel context on the PS4/PS5.

7.8 High

AI Score

Confidence

High

0.066 Low

EPSS

Percentile

93.8%