cups-filters 1.0.52 execute arbitrary commands

2014.06.23
Credit: Anonym
Risk: High
Local: No
Remote: Yes
CWE: N/A

The generate_local_queue function in utils/cups-browsed.c in cups-browsed in cups-filters before 1.0.53 allows remote IPP printers to execute arbitrary commands via shell metacharacters in the host name. NOTE: this vulnerability exists because of an incomplete fix for CVE-2014-2707. === modified file 'NEWS' --- NEWS 2014-04-07 19:57:41 +0000 +++ NEWS 2014-04-24 19:40:58 +0000 @@ -1,6 +1,13 @@ NEWS - OpenPrinting CUPS Filters v1.0.52 - 2014-04-07 ----------------------------------------------------- +CHANGES IN V1.0.53 + + - cups-browsed: SECURITY FIX: Further improvement on the fix + in 1.0.51 as it was insufficient. In addition, some fixes + against OOB access are done. Thanks to Sebastian Krahmer for + the patch (SUSE/Novell bug #871327). + CHANGES IN V1.0.52 - texttopdf: Make sure that margin changes for prettyprint === modified file 'utils/cups-browsed.c' --- utils/cups-browsed.c 2014-04-02 00:17:15 +0000 +++ utils/cups-browsed.c 2014-04-24 19:40:58 +0000 @@ -420,7 +420,7 @@ p->name, p->uri); goto fail; } - + #if 0 uri_status = httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme), @@ -584,7 +584,7 @@ /* * Remove all illegal characters and replace each group of such characters - * by a single dash + * by a single dash, return a free()-able string. * * mode = 0: Only allow letters, numbers, and dashes, for turning make/model * info into a valid print queue name or inro a string which can @@ -613,6 +613,11 @@ return NULL; str = strdup(str_orig); + + /* for later str[strlen(str)-1] access */ + if (strlen(str) < 1) + return str; + for (i = 0, j = 0; i < strlen(str); i++, j++) { if (((str[i] >= 'A') && (str[i] <= 'Z')) || ((str[i] >= 'a') && (str[i] <= 'z')) || @@ -636,11 +641,14 @@ /* Cut off trailing dashes */ while (str[strlen(str)-1] == '-') str[strlen(str)-1] = '\0'; + /* Cut off leading dashes */ - while (str[0] == '-') - str ++; + i = 0; + while (str[i] == '-') + ++i; - return str; + /* keep a free()-able string. +1 for trailing \0 */ + return memmove(str, str + i, strlen(str) - i + 1); } gboolean handle_cups_queues(gpointer unused) { @@ -737,7 +745,7 @@ } if (default_printer_name) break; - } + } } if (default_printer_name && !strcasecmp(default_printer_name, p->name)) { @@ -955,43 +963,52 @@ void *txt) { char uri[HTTP_MAX_URI]; - char *remote_queue, *remote_host, *pdl = NULL; + char *remote_queue = NULL, *remote_host = NULL, *pdl = NULL; #ifdef HAVE_AVAHI char *fields[] = { "product", "usb_MDL", "ty", NULL }, **f; - AvahiStringList *entry; - char *key, *value; + AvahiStringList *entry = NULL; + char *key = NULL, *value = NULL; #endif /* HAVE_AVAHI */ remote_printer_t *p; - char *backup_queue_name, *local_queue_name = NULL; - cups_dest_t *dests, *dest; + char *backup_queue_name = NULL, *local_queue_name = NULL; + cups_dest_t *dests = NULL, *dest = NULL; int i, num_dests, is_cups_queue; - const char *val; + size_t hl = 0; + const char *val = NULL; is_cups_queue = 0; + memset(uri, 0, sizeof(uri)); + /* Determine the device URI of the remote printer */ - httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), + httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri) - 1, (strcasestr(type, "_ipps") ? "ipps" : "ipp"), NULL, host, port, "/%s", resource); - /* Find the remote host name */ - remote_host = strdup(host); - if (!strcmp(remote_host + strlen(remote_host) - 6, ".local")) - remote_host[strlen(remote_host) - 6] = '\0'; - if (!strcmp(remote_host + strlen(remote_host) - 7, ".local.")) - remote_host[strlen(remote_host) - 7] = '\0'; + /* Find the remote host name. + * Used in constructing backup_queue_name, so need to sanitize. + * strdup() is called inside remove_bad_chars() and result is free()-able. + */ + remote_host = remove_bad_chars(host, 1); + hl = strlen(remote_host); + if (hl > 6 && !strcmp(remote_host + hl - 6, ".local")) + remote_host[hl - 6] = '\0'; + if (hl > 7 && !strcmp(remote_host + hl - 7, ".local.")) + remote_host[hl - 7] = '\0'; /* Check by the resource whether the discovered printer is a CUPS queue */ if (!strncmp(resource, "printers/", 9)) { /* This is a remote CUPS queue, use the remote queue name for the local queue */ is_cups_queue = 1; - remote_queue = resource + 9; + /* Not directly used in script generation input later, but taken from packet, + * so better safe than sorry. (consider second loop with backup_queue_name) */ + remote_queue = remove_bad_chars(resource + 9, 0); debug_printf("cups-browsed: Found CUPS queue: %s on host %s.\n", remote_queue, remote_host); } else { /* This is an IPP-based network printer */ is_cups_queue = 0; /* Determine the queue name by the model */ - remote_queue = "printer"; + remote_queue = strdup("printer"); #ifdef HAVE_AVAHI if (txt) { for (f = fields; *f; f ++) { @@ -1018,7 +1035,7 @@ /* Check if there exists already a CUPS queue with the requested name Try name@host in such a case and if this is also taken, ignore the printer */ - if ((backup_queue_name = malloc((strlen(remote_queue) + + if ((backup_queue_name = malloc((strlen(remote_queue) + strlen(remote_host) + 2) * sizeof(char))) == NULL) { debug_printf("cups-browsed: ERROR: Unable to allocate memory.\n"); @@ -1045,6 +1062,8 @@ uri); free (remote_host); free (backup_queue_name); + free (pdl); + free (remote_queue); cupsFreeDests(num_dests, dests); return; } @@ -1082,6 +1101,8 @@ local_queue_name); free (backup_queue_name); free (remote_host); + free (pdl); + free (remote_queue); cupsFreeDests(num_dests, dests); return; } @@ -1157,6 +1178,8 @@ free (backup_queue_name); free (remote_host); + free (pdl); + free (remote_queue); if (p) debug_printf("cups-browsed: Bonjour IDs: Service name: \"%s\", " @@ -1228,7 +1251,7 @@ } /* Clean up */ - + avahi_free(rp_key); avahi_free(rp_value); avahi_free(adminurl_key); @@ -1422,7 +1445,7 @@ avahi_client_free(client); client = NULL; } - if (glib_poll) { + if (glib_poll) { avahi_glib_poll_free(glib_poll); glib_poll = NULL; } @@ -1551,12 +1574,18 @@ char local_resource[HTTP_MAX_URI]; char *c; + memset(scheme, 0, sizeof(scheme)); + memset(username, 0, sizeof(username)); + memset(host, 0, sizeof(host)); + memset(resource, 0, sizeof(resource)); + memset(local_resource, 0, sizeof(local_resource)); + httpSeparateURI (HTTP_URI_CODING_ALL, uri, - scheme, sizeof(scheme), - username, sizeof(username), - host, sizeof(host), + scheme, sizeof(scheme) - 1, + username, sizeof(username) - 1, + host, sizeof(host) - 1, &port, - resource, sizeof(resource)); + resource, sizeof(resource)- 1); /* Check this isn't one of our own broadcasts */ for (iface = cupsArrayFirst (netifs); @@ -1665,7 +1694,12 @@ char remote_host[256]; char uri[1024]; char info[1024]; - char *c; + char *c = NULL, *end = NULL; + + memset(packet, 0, sizeof(packet)); + memset(remote_host, 0, sizeof(remote_host)); + memset(uri, 0, sizeof(uri)); + memset(info, 0, sizeof(info)); srclen = sizeof (srcaddr); got = recvfrom (browsesocket, packet, sizeof (packet) - 1, 0, @@ -1678,7 +1712,7 @@ } packet[got] = '\0'; - httpAddrString (&srcaddr, remote_host, sizeof (remote_host)); + httpAddrString (&srcaddr, remote_host, sizeof (remote_host) - 1); /* Check this packet is allowed */ if (!allowed ((struct sockaddr *) &srcaddr)) { @@ -1696,28 +1730,42 @@ } info[0] = '\0'; + + /* do not read OOB */ + end = packet + sizeof(packet); c = strchr (packet, '\"'); + if (c >= end) + return TRUE; + if (c) { /* Skip location field */ - for (c++; *c != '\"'; c++) + for (c++; c < end && *c != '\"'; c++) ; + if (c >= end) + return TRUE; + if (*c == '\"') { - for (c++; isspace(*c); c++) + for (c++; c < end && isspace(*c); c++) ; } + if (c >= end) + return TRUE; + /* Is there an info field? */ if (*c == '\"') { int i; c++; for (i = 0; - i < sizeof (info) - 1 && *c != '\"'; + i < sizeof (info) - 1 && *c != '\"' && c < end; i++, c++) info[i] = *c; info[i] = '\0'; } } + if (c >= end) + return TRUE; found_cups_printer (remote_host, uri, info); recheck_timer (); @@ -1926,7 +1974,7 @@ while (attr && ippGetGroupTag(attr) == IPP_TAG_PRINTER) { const char *attrname = ippGetName(attr); int value_tag = ippGetValueTag(attr); - + if (!strcmp(attrname, "printer-type") && value_tag == IPP_TAG_ENUM) { type = ippGetInteger(attr, 0);

References:

http://bzr.linuxfoundation.org/loggerhead/openprinting/cups-filters/revision/7194


Vote for this issue:
50%
50%


 

Thanks for you vote!


 

Thanks for you comment!
Your message is in quarantine 48 hours.

Comment it here.


(*) - required fields.  
{{ x.nick }} | Date: {{ x.ux * 1000 | date:'yyyy-MM-dd' }} {{ x.ux * 1000 | date:'HH:mm' }} CET+1
{{ x.comment }}

Copyright 2019, cxsecurity.com

 

Back to Top