前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >mmap及linux地址空间随机化失效漏洞

mmap及linux地址空间随机化失效漏洞

作者头像
WeaponX
发布于 2018-09-20 02:38:50
发布于 2018-09-20 02:38:50
2.3K00
代码可运行
举报
文章被收录于专栏:BinarySecBinarySec
运行总次数:0
代码可运行

Linux下动态库是通过mmap建立起内存和文件的映射关系。其定义如下void* mmap(void* start,size_t length,int prot,int flags,int fd,off_t offset);,在第一个参数startNULL的时候系统会随机分配一个地址,我们可以通过示例来看mmap映射地址的流程。

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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(NULL1415560PROT_READ | PROT_EXECMAP_PRIVATE | MAP_DENYWRITE3,0= 0xb75b1000
mmap2(0xb7705000,12288PROT_READ | PROT_WRITEMAP_PRIVATE | MAP_FIXED | MAP_DENYWRITE3,0x154= 0xb7705000
mmap2(0xb7708000,10632PROT_READ | PROT_WRITEMAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS-1,0= 0xb7708000
接近(3

在通常情况下通过mmap映射的地址会被内核进行随机化处理,所以每次程序运行加载的动态库基址都不相同。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
〜$ 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看动态库加载的地址是否发生变化
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
〜$ 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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/ *
 *这个功能,在创建新功能的过程中非常早
 *处理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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/ *
 * 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()为真。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/ *
 * mmap区域的顶部(就在进程堆栈下方)。
 *
 *留下至少~128 MB的空洞,可能有堆栈随机化。
 * /
#限定 MIN_GAP128 * 1024 * 1024UL + stack_maxrandom_size())
#限定 MAX_GAPTASK_SIZE / 6 * 5static  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 修复方案分析

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2017-03-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
【linux命令讲解大全】193.Linux命令解析:chroot与clock的用途和实例
chroot 命令用于在指定的根目录下运行指令。chroot 是 change root directory (更改根目录)的缩写。在 Linux 系统中,默认的目录结构是以 / 作为根目录的起点。而使用 chroot 后,系统的目录结构将会以指定的位置作为新的根目录。
全栈若城
2024/03/02
2450
10张图22段代码,万字长文带你搞懂虚拟内存模型和malloc内部原理
摊牌了,不装了,其实我是程序喵辛苦工作一天还要回家编辑公众号到大半夜的老婆,希望各位大哥能踊跃转发,完成我一千阅读量的KPI(梦想),谢谢!
C语言与CPP编程
2020/12/02
2050
10张图22段代码,万字长文带你搞懂虚拟内存模型和malloc内部原理
永远修复不完的Linux本地ASLR漏洞
ASLR,应为全称为Address Space Layout Randomization,即地址空间布局随机化。它是一种概率性安全防御机制,由PaX团队于2001年正式提出,并在2005年开始引入到Linux内核之中。ASLR能够在每次运行可执行文件的时候通过基地址随机映射的方式来为其随机分配地址空间。ASLR存在的目的,就是为了防止那些需要了解内存地址来利用内存崩溃漏洞的攻击行为。
FB客服
2020/03/20
1.5K0
从内核世界透视 mmap 内存映射的本质(源码实现篇)
通过上篇文章 《从内核世界透视 mmap 内存映射的本质(原理篇)》的介绍,我们现在已经非常清楚了 mmap 背后的映射原理以及它的使用方法,其核心就是在进程虚拟内存空间中分配一段虚拟内存出来,然后将这段虚拟内存与磁盘文件映射起来,整个 mmap 系统调用就结束了。
bin的技术小屋
2023/10/30
1K0
从内核世界透视 mmap 内存映射的本质(源码实现篇)
linux编译so库「建议收藏」
以一个例子来说明。 这里有三个so_test.h, test_a.c, test_b.c
全栈程序员站长
2022/09/07
3.5K0
Linux (x86) Exploit 开发系列教程之七 绕过 ASLR -- 第二部分
在这个技巧中,攻击者选择特定的 Libc 基址,并持续攻击程序直到成功。假设你足够幸运,这个技巧是用于绕过 ASLR 的最简单的技巧。
ApacheCN_飞龙
2022/12/01
3630
linux之chroot命令
在经过 chroot 之后,在新根下将访问不到旧系统的根目录结构和文件,这样就增强了系统的安全性。这个一般是在登录 (login) 前使用 chroot,以此达到用户不能访问一些特定的文件。
入门笔记
2021/09/12
1.2K0
进程内存管理初探
随着cpu技术发展,现在大部分移动设备、PC、服务器都已经使用上64bit的CPU,但是关于Linux内核的虚拟内存管理,还停留在历史的用户态与内核态虚拟内存3:1的观念中,导致在解决一些内存问题时存在误解。
刘盼
2020/06/19
2.5K0
进程内存管理初探
Linux pwn入门学习到放弃
PWN是一个黑客语法的俚语词,自”own”这个字引申出来的,意为玩家在整个游戏对战中处在胜利的优势。本文记录菜鸟学习linux pwn入门的一些过程,详细介绍linux上的保护机制,分析一些常见漏洞如栈溢出,堆溢出,use after free等,以及一些常见工具介绍等。
FB客服
2020/09/22
3.9K0
Linux pwn入门学习到放弃
【Linux 内核 内存管理】虚拟地址空间布局架构 ① ( 虚拟地址空间布局架构 | 用户虚拟地址空间划分 )
" ARM64 架构 " 中 , Linux 系统的 " 内核虚拟地址 “ 与 ” 用户虚拟地址 " 是等同的 ;
韩曙亮
2023/03/30
7.4K0
【Linux 内核 内存管理】虚拟地址空间布局架构 ① ( 虚拟地址空间布局架构 | 用户虚拟地址空间划分 )
linux中的ldd命令简介
在linux中, 有些命令是大家通用的, 比如ls, rm, mv, cp等等, 这些我觉得没有必要再细说了。 而有些命令, 只有开发人员才会用到的, 这类命令, 作为程序员的我们, 是有必要了解的, 有的甚至需要熟练使用。
全栈程序员站长
2022/08/10
4.3K1
【Linux 内核 内存管理】虚拟地址空间布局架构 ② ( 用户虚拟地址空间组成 | 内存描述符 mm_struct 结构体源码 )
⑤ 堆内存 : 通过 malloc brk vmalloc 等函数 申请的 动态分配 的内存 ;
韩曙亮
2023/03/30
6980
【Linux 内核 内存管理】虚拟地址空间布局架构 ② ( 用户虚拟地址空间组成 | 内存描述符 mm_struct 结构体源码 )
ret2libc过地址随机化
之前我们运用ret2blic技术时,编译编译一个c文件,开启了栈不可执行关闭地址随机化,那么利用这个溢出时只需找到溢出点的位置,然后将其替换成system等函数和参数的地址来获取权限,这种情况下system与'/bin/sh'的地址并不会改变。而现在,我们在编译c文件时,开启了栈不可执行和地址随机化,system和'/bin/sh'会发生改变,那我们该如何获取system等的位置呢?
FB客服
2020/05/13
9040
栈溢出漏洞的利用和缓解
一直有人说这个时代做渗透太难了, 各个平台都开始重视安全性, 不像十几年前, 随便有个栈溢出就能轻松利用. 现在的环境对于新手而言确实不算友好, 上来就需要 面临着各种边界保护, 堆栈保护, 地址布局
evilpan
2023/02/12
1.3K0
mmap的系统调用
mmap:进程创建匿名的内存映射,把内存的物理页映射到进程的虚拟地址空间。进程把文件映射到进程的虚拟地址空间,可以像访问内存一样访问文件,不需要调用系统调用read()/write()访问文件,从而避免用户模式和内核模式之间的切换,提高读写文件速度。两个进程针对同一个文件创建共享的内存映射,实现共享内存。2.删除内存映射
刘盼
2023/01/05
1.6K0
mmap的系统调用
brk实现
在32位Linux内核中,每个用户进程拥有3GB的虚拟空间。内核如何为用户空间来划分这3GB的虚拟空间呢?用户进程的可执行文件由代码段和数据段组成,数据段包括所有静态分配的数据空间,例如全局变量和静态局部变量等。这些空间在可执行文件装载时,内核就为其分配好这些空间,包括虚拟地址和物理页面,并建立好两者的映射关系。如图2.15所示,用户进程的用户栈从3GB虚拟空间的顶部开始,由顶向下延伸,而brk分配的空间是从数据段的顶部end_data到用户栈的底部。所以动态分配空间是从进程的end_data开始,每次分配一块空间,就把这个边界往上推进一段,同时内核和进程都会记录当前边界的位置。
233333
2020/07/31
8580
brk实现
让你操作更有效率的Linux命令
Linux是最适合开发的操作系统,它是把所有的操作权都交给了用户,有什么操作,就会呈现出什么样的格局。开放、自由、诚实,就是它最大的魅力。
周辰晨
2022/09/20
4980
Android中mmap原理及应用简析
mmap是Linux中常用的系统调用API,用途广泛,Android中也有不少地方用到,比如匿名共享内存,Binder机制等。本文简单记录下Android中mmap调用流程及原理。mmap函数原型如下:
看书的小蜗牛
2019/02/22
1.9K0
Android中mmap原理及应用简析
linux ldd命令源代码,Linux中ldd命令的用法详解[通俗易懂]
Linux中ldd命令主要用于查看程式运行所需的共享库,那么ldd命令具体要如何使用呢?下面小编就给大家介绍下Linux下ldd命令的使用方法,感兴趣的朋友一起来学习下吧。
全栈程序员站长
2022/08/23
3.5K0
linux ldd命令源代码,Linux中ldd命令的用法详解[通俗易懂]
ls 不显示,rm 删不掉,怎么办?
有个叫atest的东西 ls -l atest 查不出来是什么 下面删也删不掉 但是可以用mv改名字,它放在/目录下,用ls /导致不能显示 如果操作,请大侠指点, 顺便问下什么时候会导致ls /   不显示,谢谢! # s
三杯水Plus
2018/11/14
1K0
推荐阅读
相关推荐
【linux命令讲解大全】193.Linux命令解析:chroot与clock的用途和实例
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验