mmap及linux地址空間隨機化失效漏洞

Linux下動態庫是通過mmap建立起內存和文件的映射關係。其定義如下void* mmap(void* start,size_t length,int prot,int flags,int fd,off_t offset);,在第一個參數startNULL的時候系統會隨機分配一個地址,我們可以通過示例來看mmap映射地址的流程。

分析一下程序加載libc.so的流程

open(“/ lib / libc.so.6 ”,O_RDONLY)= 3
讀取(3,“\ 177ELF \ 1 \ 1 \ 1 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 3 \ 0 \ 3 \ 0 \ 1 \ 0 \ 0 \ 0 n \ 1 \ 0004 \ 0 \ 0 \ 0“ ...,512)= 512
fstat64(3,{st_mode = S_IFREG | 0755,st_size = 1409436,...})= 0
mmap2(NULL,1415560,PROT_READ | PROT_EXEC,MAP_PRIVATE | MAP_DENYWRITE,3,0)= 0xb75b1000
mmap2(0xb7705000,12288,PROT_READ | PROT_WRITE,MAP_PRIVATE | MAP_FIXED | MAP_DENYWRITE,3,0x154)= 0xb7705000
mmap2(0xb7708000,10632,PROT_READ | PROT_WRITE,MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS,-1,0)= 0xb7708000
接近(3)

在通常情況下通過mmap映射的地址會被內核進行隨機化處理,所以每次程序運行加載的動態庫基址都不相同。

〜$ ldd mmap
    linux-gate.so.1 =>(0xb77d9000)
    libc.so.6 => /lib/libc.so.6(0xb7654000)
    /lib/ld-linux.so.2(0xb77bd000)
〜$ ldd mmap
    linux-gate.so.1 =>(0xb7738000)
    libc.so.6 => /lib/libc.so.6(0xb75b3000)
    /lib/ld-linux.so.2(0xb771c000

0x01 CVE-2016-3672

Linux kernel 4.5.2之前版本,arch/x86/mm/mmap.c內函數arch_pick_mmap_layout未正確隨機化遺留基址。本地用戶禁用棧資源消耗限制後,可破壞ADDR_NO_RANDOMIZE標記的限制,繞過setuid或setgid程序的ASLR保護機制。

這個漏洞在32位操作系統或者在64位操作系統運行32位程序時,將棧空間設置爲不限制,會導致mmap的ASLR失效,導致動態庫加載的地址固定。

驗證方法:

  1. 設置棧空間爲不限制大小ulimit -s unlimited
  2. 使用ldd看動態庫加載的地址是否發生變化
〜$ ldd mmap
   linux-gate.so.1 =>(0xb77d9000)
   libc.so.6 => /lib/libc.so.6(0xb7654000)
   /lib/ld-linux.so.2(0xb77bd000)
〜$ ldd mmap
   linux-gate.so.1 =>(0xb7738000)
   libc.so.6 => /lib/libc.so.6(0xb75b3000)
   /lib/ld-linux.so.2(0xb771c000)
〜$ ulimit  -s無限制
〜$ ldd mmap
   linux-gate.so.1 =>(0x4001c000)
   libc.so.6 => /lib/libc.so.6(0x4002e000)
   /lib/ld-linux.so.2(0x40000000)
〜$ ldd mmap
   linux-gate.so.1 =>(0x4001c000)
   libc.so.6 => /lib/libc.so.6(0x4002e000)
   /lib/ld-linux.so.2(0x40000000)

可見,設置了棧空間不限制大小後,動態庫的基址就固定了。

0x02 漏洞分析

漏洞所在函數爲arch_pick_mmap_layout

/ *
 *這個功能,在創建新功能的過程中非常早
 *處理VM映像,設置要使用的VM佈局功能:
 * /
void  arch_pick_mmap_layout (struct mm_struct * mm)
{
    mm-> mmap_legacy_base = mmap_legacy_base();
    mm-> mmap_base = mmap_base();
    if(mmap_is_legacy()){
        mm-> mmap_base = mm-> mmap_legacy_base;
        mm-> get_unmapped_area = arch_get_unmapped_area;
    } else {
        mm-> get_unmapped_area = arch_get_unmapped_area_topdown;
    }
}

如果讓ASLR失效則需要讓mm->mmap_base爲固定值。看看mmap_legacy_base

/ *
 * X86_32上的自下而上(傳統)佈局不支持隨機化,X86_64
 *但是在模擬X86_32時沒有
 * /
static  unsigned  long  mmap_legacy_base (void)
{
    if(mmap_is_ia32())
        返回 TASK_UNMAPPED_BASE;
    其他
        返回 TASK_UNMAPPED_BASE + mmap_rnd();
}

可以看到mmap_is_ia32()爲真時,返回的地址爲固定值。註釋更表明了影響32位機器和在64位機器上運行的32位程序。此時,只需要mmap_is_legacy()爲真。

/ *
 * mmap區域的頂部(就在進程堆棧下方)。
 *
 *留下至少~128 MB的空洞,可能有堆棧隨機化。
 * /
#限定 MIN_GAP(128 * 1024 * 1024UL + stack_maxrandom_size())
#限定 MAX_GAP(TASK_SIZE / 6 * 5)
static  int  mmap_is_legacy (void)
{
    if(current-> personality&ADDR_COMPAT_LAYOUT)
        返回 1 ;
    if(rlimit(RLIMIT_STACK)== RLIM_INFINITY)
        返回 1 ;
    return sysctl_legacy_va_layout;
}

注意到rlimit(RLIMIT_STACK) == RLIM_INFINITY則返回真,這就是ulimit -s unlimited的原因。

0x03 修復方案分析

diff --git a / arch / x86 / mm / mmap.cb / arch / x86 / mm / mmap.c
index 96bd1e2..389939f 100644
--- a / arch / x86 / mm / mmap.c
+++ b / arch / x86 / mm / mmap.c
@@ -94,18 +94,6 @@ static unsigned long mmap_base(unsigned long rnd)
 }
 / *
-  * X86_32上的自下而上(傳統)佈局不支持隨機化,X86_64
-  *確實如此,但在模擬X86_32時卻沒有
-  * /
-static unsigned long mmap_legacy_base(unsigned long rnd)
-  {
-  if(mmap_is_ia32())
- 返回TASK_UNMAPPED_BASE;
- 否則
- 返回TASK_UNMAPPED_BASE + rnd;
- }
- 
-  / *
  *這個功能,在創建新功能的過程中非常早
  *處理VM映像,設置要使用的VM佈局功能:
  * /
@@ -116,7 +104,7 @@ void arch_pick_mmap_layout(struct mm_struct * mm)
    if(current-> flags&PF_RANDOMIZE)
        random_factor = arch_mmap_rnd();
-  mm-> mmap_legacy_base = mmap_legacy_base(random_factor);
+ mm-> mmap_legacy_base = TASK_UNMAPPED_BASE + random_factor;
    if(mmap_is_legacy()){
        mm-> mmap_base = mm-> mmap_legacy_base;

很簡單,不管是以lagacy模式運行還是真正的32位程序,mmap的基址mmap_base均加入隨即因子進行隨機化

0x04 題外

在64位機器上發現也存在ASLR失效的問題,不過vDSO還是有隨機化保護的。留個坑有時間在看看。

0x05 Refer

http://rk700.github.io/2016/11/22/mmap-aslr/ http://lists.alioth.debian.org/pipermail/kernel-svn-changes/2016-April/023114.html http://hmarco.org/bugs/CVE-2016-3672-Unlimiting-the-stack-not-longer-disables-ASLR.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章