TOR-024 — Tor client – Missing sanity checks in pem_decode
The pem_decode function passes incorrect boundaries to the underlying standard C library function memmem when parsing a PEM file.
- Vulnerability type: CWE-119: Improper Restriction of Operations within the Bounds of a Memory Buffer
- Threat level: Low
Technical description:
Attackers can craft a payload invoking the tor_memstr (memem) function with invalid borders by crafting a haystack smaller than the needle. However, there is a sanity check in the underlying lib, which prevents any form of out-of-bounds. The memmem() function finds the start of the first occurrence of the substring needle of length needlelen in the memory area haystack of length haystacklen. The memmem() function returns a pointer to the beginning of the substring, or NULL if the substring is not found.
Proof of Concept
int poc(){
static const char payload[] = "-----BEGIN WOMBAT QUOTE-----\nA";
unsigned char buf[4096];
int n = pem_decode(buf, sizeof(buf),payload, strlen(payload),"WOMBAT QUOTE");
return n;
}
In src/lib/encoding/pem.c:
int
pem_decode(uint8_t *dest, size_t destlen, const char *src, size_t srclen, const char *objtype)
{
const char *eos = src + srclen;
src = eat_whitespace_eos(src, eos);
char *tag = NULL;
tor_asprintf(&tag, "-----BEGIN %s-----", objtype);
if ((size_t)(eos-src) < strlen(tag) || fast_memneq(src, tag, strlen(tag))) {
tor_free(tag);
return -1;
}
src += strlen(tag);
tor_free(tag);
/* At this point we insist on spaces (including CR), then an LF. */
src = eat_whitespace_eos_no_nl(src, eos);
if (src == eos || *src != '\n') {
/* Extra junk at end of line: this isn't valid. */
return -1;
}
// NOTE lack of trailing \n. We do not enforce its presence.
tor_asprintf(&tag, "\n-----END %s-----", objtype);
const char *end_of_base64 = tor_memstr(src, eos-src, tag);
tor_free(tag);
if (end_of_base64 == NULL)
return -1;
[...]
}
Impact:
This vulnerability could lead to out-of-bounds read/write and other vulnerabilities, including remote code execution. However, demonstrating a critical impact was impossible as the underlying library checked the bounds of the parameters. Nevertheless, this could change, e.g., by using a vulnerable library.
Recommendations:
- Do not rely on sanity checks within the underlying libraries.
- A valid patch could ensure the haystack length is >= needle length before invoking tor_memstr. Or even better, implement this check within tor_memmem.