From 4bdca8197a34489886688fbeca41cb963e68bb10 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Thu, 19 Nov 2015 13:45:04 -0600 Subject: [PATCH] FS-8160 Additional vulnerability in json parsing malformed utf encoded chars discovered by Brian Martin - Tenable Security Response CVE-2015-7392 --- libs/esl/src/esl_json.c | 12 +++++++++--- libs/libks/src/ks_json.c | 12 +++++++++--- src/switch_json.c | 12 +++++++++--- 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/libs/esl/src/esl_json.c b/libs/esl/src/esl_json.c index df5a88135d..02270a7f71 100644 --- a/libs/esl/src/esl_json.c +++ b/libs/esl/src/esl_json.c @@ -150,6 +150,13 @@ static char *print_number(cJSON *item) return str; } +#define is_hexdigit(c) ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) +static int scan_unicode(const char *ptr, unsigned int *uc) +{ + if (!is_hexdigit(*(ptr)) || !is_hexdigit(*(ptr+1)) || !is_hexdigit(*(ptr+2)) || !is_hexdigit(*(ptr+3))) return -1; + return sscanf(ptr, "%4x", uc); +} + /* Parse the input text into an unescaped cstring, and populate item. */ static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; static const char *parse_string(cJSON *item,const char *str) @@ -177,8 +184,7 @@ static const char *parse_string(cJSON *item,const char *str) case 'r': *ptr2++='\r'; break; case 't': *ptr2++='\t'; break; case 'u': /* transcode utf16 to utf8. */ - if (sscanf(ptr+1,"%4x",&uc) < 1) break; - + if (scan_unicode(ptr+1, &uc) < 1) break; ptr+=4; /* get the unicode char. */ if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0) break; // check for invalid. @@ -186,7 +192,7 @@ static const char *parse_string(cJSON *item,const char *str) if (uc>=0xD800 && uc<=0xDBFF) // UTF16 surrogate pairs. { if (ptr[1]!='\\' || ptr[2]!='u') break; // missing second-half of surrogate. - if (sscanf(ptr+3,"%4x",&uc2) < 1) break; + if (scan_unicode(ptr+3,&uc2) < 1) break; ptr+=6; if (uc2<0xDC00 || uc2>0xDFFF) break; // invalid second-half of surrogate. uc=0x10000 | ((uc&0x3FF)<<10) | (uc2&0x3FF); diff --git a/libs/libks/src/ks_json.c b/libs/libks/src/ks_json.c index 63529e7b5b..4ee4a84ef6 100644 --- a/libs/libks/src/ks_json.c +++ b/libs/libks/src/ks_json.c @@ -150,6 +150,13 @@ static char *print_number(cJSON *item) return str; } +#define is_hexdigit(c) ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) +static int scan_unicode(const char *ptr, unsigned int *uc) +{ + if (!is_hexdigit(*(ptr)) || !is_hexdigit(*(ptr+1)) || !is_hexdigit(*(ptr+2)) || !is_hexdigit(*(ptr+3))) return -1; + return sscanf(ptr, "%4x", uc); +} + /* Parse the input text into an unescaped cstring, and populate item. */ static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; static const char *parse_string(cJSON *item,const char *str) @@ -177,8 +184,7 @@ static const char *parse_string(cJSON *item,const char *str) case 'r': *ptr2++='\r'; break; case 't': *ptr2++='\t'; break; case 'u': /* transcode utf16 to utf8. */ - if (sscanf(ptr+1,"%4x",&uc) < 1) break; - + if (scan_unicode(ptr+1, &uc) < 1) break; ptr+=4; /* get the unicode char. */ if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0) break; // check for invalid. @@ -186,7 +192,7 @@ static const char *parse_string(cJSON *item,const char *str) if (uc>=0xD800 && uc<=0xDBFF) // UTF16 surrogate pairs. { if (ptr[1]!='\\' || ptr[2]!='u') break; // missing second-half of surrogate. - if (sscanf(ptr+3,"%4x",&uc2) < 1) break; + if (scan_unicode(ptr+3,&uc2) < 1) break; ptr+=6; if (uc2<0xDC00 || uc2>0xDFFF) break; // invalid second-half of surrogate. uc=0x10000 | ((uc&0x3FF)<<10) | (uc2&0x3FF); diff --git a/src/switch_json.c b/src/switch_json.c index c3c25364da..2f52967a0b 100644 --- a/src/switch_json.c +++ b/src/switch_json.c @@ -150,6 +150,13 @@ static char *print_number(cJSON *item) return str; } +#define is_hexdigit(c) ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) +static int scan_unicode(const char *ptr, unsigned int *uc) +{ + if (!is_hexdigit(*(ptr)) || !is_hexdigit(*(ptr+1)) || !is_hexdigit(*(ptr+2)) || !is_hexdigit(*(ptr+3))) return -1; + return sscanf(ptr, "%4x", uc); +} + /* Parse the input text into an unescaped cstring, and populate item. */ static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; static const char *parse_string(cJSON *item,const char *str) @@ -177,8 +184,7 @@ static const char *parse_string(cJSON *item,const char *str) case 'r': *ptr2++='\r'; break; case 't': *ptr2++='\t'; break; case 'u': /* transcode utf16 to utf8. */ - if (sscanf(ptr+1,"%4x",&uc) < 1) break; - + if (scan_unicode(ptr+1, &uc) < 1) break; ptr+=4; /* get the unicode char. */ if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0) break; // check for invalid. @@ -186,7 +192,7 @@ static const char *parse_string(cJSON *item,const char *str) if (uc>=0xD800 && uc<=0xDBFF) // UTF16 surrogate pairs. { if (ptr[1]!='\\' || ptr[2]!='u') break; // missing second-half of surrogate. - if (sscanf(ptr+3,"%4x",&uc2) < 1) break; + if (scan_unicode(ptr+3,&uc2) < 1) break; ptr+=6; if (uc2<0xDC00 || uc2>0xDFFF) break; // invalid second-half of surrogate. uc=0x10000 | ((uc&0x3FF)<<10) | (uc2&0x3FF);