漏洞描述

GDM守护进程不能正确的取消导出在D-Bus 接口上已经被销毁的display对象,这造成本地用户可以触发UAF,从而使系统崩溃或造成任意代码执行。

调试环境

gdm版本: 3.14.2(通过git下载3.14版本的gdm)

Linux发型版本: Debain 9.5

内核版本: 4.9.0-7

体系结构: x86_64

工具: d-feet

环境搭建

安装前需要将已经安装的登陆管理器卸载(我环境中的是gdm3)

需要装的库:

build-essential dh-autoreconf intltool libcurl4-openssl-dev pkg-config libgtk-3-dev libmutter-dev libwnck-3-dev libgnome-menu-3-dev libupower-glib-dev gobject-introspection libglib3.0-cil-dev libgtk3.0-cil-dev libaccountsservice-dev libcanberra-gtk3-0 libcanberra-gtk3-dev libpam0g-dev

gdm 安装

# groupadd -g 21 gdm &&
useradd -c "GDM Daemon Owner" -d /var/lib/gdm -u 21 \
        -g gdm -s /bin/false gdm &&
passwd -ql gdm

# ./autogen.sh

# ./configure CFLAGS=-g --prefix=/usr         \
            --sysconfdir=/etc     \
            --localstatedir=/var  \
            --without-plymouth    \
            --disable-static      \
            --enable-gdm-xsession \
            --with-pam-mod-dir=/lib/security &&
make

# make install &&
install -v -m644 data/gdm.service.in /lib/systemd/system/gdm.service

更换/etc/X11/default-display-manager中为刚刚安装好的gdm二进制文件路径

之后运行

# systemctl enable gdm

使gdm守护进程开机启动

重启发现根本无法显示登陆管理器界面,可以使用Ctrl+Alt+F3的方式 切换到字符终端,然后登陆输入startx。其gdm守护进程也是启动的不影响调试。

漏洞分析

使gdm守护进程崩溃的命令如下:

$ display_path=$(dbus-send --system --dest=org.gnome.DisplayManager --type=method_call --print-reply=literal /org/gnome/DisplayManager/LocalDisplayFactory org.gnome.DisplayManager.LocalDisplayFactory.CreateTransientDisplay)

$ sleep 5

$ dbus-send --system --dest=org.gnome.DisplayManager --type=method_call $display_path org.gnome.DisplayManager.Display.GetId

其中D-Bus是针对桌面环境优化的IPC机制,用于进程间的通信或进程与内核的通信。(更加详细的D-Bus介绍可参考资料4、5、6)

第一条命令:调用显示登录管理器下面的LocalDisplayFactory对象的CreateTransientDisplay方法,并将回复的消息正文保存到display_path变量中

第二条命令 : 等待5秒

第三条命令:调用显示登录管理器下面的名称为第一条命令返回的字符串(保存在display_path变量中,类似于字符串“/org/gnome/DisplayManager/Displays/94425659672144”)的GetId方法

第一条命令分析

阅读资料7可以发现,第一条命令会调用daemon/gdm-local-display-factory.c:handle_create_transient_display函数

static gboolean
handle_create_transient_display (GdmDBusLocalDisplayFactory *skeleton,
                                 GDBusMethodInvocation      *invocation,
                                 GdmLocalDisplayFactory     *factory)
{
    ..............................
    created = gdm_local_display_factory_create_transient_display (factory,
                                                                      &id,
                                                                      &error);
    ..............................
    gdm_dbus_local_display_factory_complete_create_transient_display (skeleton, invocation, id);
    ..............................
}

其主要调用的函数为gdm_local_display_factory_create_transient_display.

gboolean
gdm_local_display_factory_create_transient_display (GdmLocalDisplayFactory *factory,
                                                    char                  **id,
                                                    GError                **error)
{
        ..................................................
        store_display (factory, num, display);
        ..................................................
}

其主要完成的任务是:

分配一个数字,然后分配一个与刚刚分配数字相关联的display对象。将display保存到GdmDisplayStore中的hash表中,将数字保存到GdmLocalDisplayFactory中priv的hash表中。

如果继续跟踪的store_display(静态+动态),会发现其调用了on_display_added函数

\\gdm-manager.c
static void
on_display_added (GdmDisplayStore *display_store,
                  const char      *id,
                  GdmManager      *manager)
{
        ............................
        display = gdm_display_store_lookup (display_store, id);
        ..........................
        if (display != NULL) {
                g_dbus_object_manager_server_export (manager->priv->object_manager,
                                                     gdm_display_get_object_skeleton (display));

                g_signal_connect (display, "notify::status",
                                  G_CALLBACK (on_display_status_changed),
                                  manager);
                g_signal_emit (manager, signals[DISPLAY_ADDED], 0, id);
        }
}

该函数完成的功能是:将刚刚创建的对象导出,并且将display对象的状态变换与on_display_status_changed(gdm-local-display-factory.c)函数相关联,如果我们用d-feet工具查看的话,可以看到已经导出。

第二条命令分析

我们分析刚刚创建的display对象的状态变换函数:

\\gdm-local-display-factory.c
static void
on_display_status_changed (GdmDisplay             *display,
                           GParamSpec             *arg1,
                           GdmLocalDisplayFactory *factory)
{
.....................
    case GDM_DISPLAY_FINISHED:
                /* remove the display number from factory->priv->displays
                   so that it may be reused */
                g_hash_table_remove (factory->priv->displays, GUINT_TO_POINTER (num));
                gdm_display_store_remove (store, display);
.....................
}

其会将display对象从hash表中删除(并没有将该内存销毁,销毁是在另一个函数中完成的)

我们查看gdm-display.c中的queue_finish函数,其会调用g_idle_add添加一个让程序在空闲时执行的函数,让其在空闲的时候销毁display对象。跟踪(动态加静态)发现其调用

static void
stored_display_free (StoredDisplay *stored_display)
{
        char *id;

        gdm_display_get_id (stored_display->display, &id, NULL);

        g_signal_emit (G_OBJECT (stored_display->store),
                       signals[DISPLAY_REMOVED],
                       0,
                       id);
        g_free (id);

        g_debug ("GdmDisplayStore: Unreffing display: %p",
                 stored_display->display);
        g_object_unref (stored_display->display);

        g_slice_free (StoredDisplay, stored_display);
}

其在这里完成了display对象的内存销毁,在销毁对象之前,该函数会调用on_display_removed函数

\\gdm-manager.c
static void
on_display_removed (GdmDisplayStore *display_store,
                    const char      *id,
                    GdmManager      *manager)
{
        GdmDisplay *display;

        display = gdm_display_store_lookup (display_store, id);
        if (display != NULL) {
                g_dbus_object_manager_server_unexport (manager->priv->object_manager, id);

                g_signal_handlers_disconnect_by_func (display, G_CALLBACK (on_display_status_changed), manager);

                g_signal_emit (manager, signals[DISPLAY_REMOVED], 0, id);
        }
}

分析可知该函数是将该对象取消导出。

所以可以知道第二条命令完成的是:等待display对象状态变为GDM_DISPLAY_FINISHED,然后将其从hash表中移除。等待空闲时调用stored_display_free函数,其调用on_display_removed,在该函数中因为该display对象已经被移除,gdm_display_store_lookup会返回空,所以取消该对象的导出失败,然后返回stored_display_free函数,将display对象销毁。但是通过d-feet工具查看,该对象仍然存在。

第三条命令分析

然后我们分析第三条命令(要调用的对象是/org/gnome/DisplayManager/Displays/94425659672144的GetId,其中只有数字部分是随机的其他不变)

根据介绍的方法可以定位到调用GetId方法的代码.

\\daemon\gdm-display.c
static gboolean
handle_get_id (GdmDBusDisplay        *skeleton,
               GDBusMethodInvocation *invocation,
               GdmDisplay            *display)
{
        char *id;

        gdm_display_get_id (display, &id, NULL);

        gdm_dbus_display_complete_get_id (skeleton, invocation, id);

        g_free (id);
        return TRUE;
}

其对已经释放的display对象操作,造成UAF。

资料

1.CVE-2018-14424 use-after-free of disposed transient displays

https://gitlab.gnome.org/GNOME/gdm/issues/401

2.GDM源代码

https://github.com/GNOME/gdm

3.GDM安装

http://www.linuxfromscratch.org/blfs/view/systemd/gnome/gdm.html

4.dbus实例讲解(一):初次见面

http://www.fmddlmyy.cn/text49.html

5.dbus实例讲解(二)

http://www.fmddlmyy.cn/text51.html

6.dbus实例讲解(二上):消息和消息总线

http://www.fmddlmyy.cn/text52.html

7.gdbus-codegen

https://manned.org/gdbus-codegen/37c6dcd1

8.GObject对象系统

https://www.ibm.com/developerworks/cn/linux/l-gobject/index.html

CVE-2018-14424 use-after-free of disposed transient displays 分析报告的更多相关文章

  1. 《2018年云上挖矿态势分析报告》发布,非Web类应用安全风险需重点关注

    近日,阿里云安全团队发布了<2018年云上挖矿分析报告>.该报告以阿里云2018年的攻防数据为基础,对恶意挖矿态势进行了分析,并为个人和企业提出了合理的安全防护建议. 报告指出,尽管加密货 ...

  2. 如何利用Smartbi做数据分析:2018内5月热销乘用车分析报告

    在2018年第一季度热销乘用车分析报告中,SUV以总体销量15.4%的同比增长率让人不可小觑,Smartbi刚得到5月分析的数据就迫不及待的来看看是否热度不减,结果在5月这个所谓汽车销售淡季,轿车以9 ...

  3. 2018年1月12日--微信小程序----出错报告(40kb的原因)---并解决方法

    一. 报错的原因是因为,图片的文件太大了,已经超过了40kb...不能超过40kb. 在这里查看图片文件的大小:

  4. 2018.11.20 Struts2中对结果处理方式分析&struts2内置的方式底层源码剖析

    介绍一下struts2内置帮我们封装好的处理结果方式也就是底层源码分析 这是我们的jar包里面找的位置目录 打开往下拉看到result-type节点 name那一列就是我们的type类型取值 上一篇博 ...

  5. 无聊的活动/缘生意转(2018 Nova OJ新年欢乐赛B题)解题报告

    题目2(下面的太抓 我重新写了个背景 其他都一样) 无聊的活动 JLZ老师不情愿的参加了古风社一年一度的活动,他实在不觉得一群学生跳舞有什么好看,更不明白坐在身后的学生为什么这么兴奋(看小姐姐),于是 ...

  6. CVE漏洞分析

    分析cve-2018-9489漏洞和download content provider(CVE-2018-9468, CVE-2018-9493, CVE-2018-9546), 每人至少选择一个漏洞 ...

  7. 2018 Unite大会——《使用UPA工具优化项目》演讲实录

    2018年5月11日至13日,腾讯WeTest与Unity联合打造的移动游戏性能分析工具(Unity Performance Analysis,以下称为UPA)正式亮相2018 Unite大会,为Un ...

  8. 2018 Python开发者大调查:Python和JavaScript最配?

    在2018年秋季,Python软件基金会与JetBrains发起了年度Python开发者调查. 报告的目的是寻找Python领域的新趋势,帮助开发者深入了解2018年Python开发者的现状. 该报告 ...

  9. 云原生生态周报 Vol. 14 | K8s CVE 修复指南

    业界要闻 Mesosphere 公司正式更名为 D2IQ, 关注云原生. Mesosophere 公司日前发布官方声明正式更名为:D2iQ(Day-Two-I-Q),称关注点转向 Kubernetes ...

随机推荐

  1. 【Spring】24、<load-on-startup>0</load-on-startup>配置

    load-on-startup标记容器是否在启动的时候实例化并调用其init()方法的优先级. 它的值表示servlet应该被载入的顺序 当值为0或者大于0时,表示容器在应用启动时就加载并初始化这个s ...

  2. Swagger2限定接口范围

    前面在使用Swagger2时遇到的坑中简单介绍了Swagger的使用. 不过默认情况下,Swagger2会把项目中的所有接口都展示在列表里,特别是你用了Springboot/SpringCloud之后 ...

  3. java——线程

    线程与进程 1.线程:程序中单独顺序的控制流 线程本身是通过程序进行运行 线程是程序中的顺序控制流,只能使用分配给程序的资源与环境 2.进程:执行中的程序 一个进程可以包含一个或多个线程 一个进程至少 ...

  4. 解决vue-cli不能初始化webpack模板的问题(vue init卡住了,解决办法)

    报这个错误 有人说是代理问题.我也不懂,但这个方法有用 1.去github上下载要初始化的模板 https://github.com/vuejs-templates/webpack 或者直接用git去 ...

  5. CSS布局设置

    一 盒模型 盒模型 在CSS中,"box model"这一术语是用来设计和布局时使用,然后在网页中基本上都会显示一些方方正正的盒子.我们称为这种盒子叫盒模型. 盒模型有两种:标准模 ...

  6. ionic3打包不能prod的问题

    在最近的项目中,我ionic3采用了懒加载,来提高性能.但是当我普通打包的时候,正常成功了,但是加上--prod的时候,就报错了. 报错如下: 大概意思就是page是声明的一部分,然后请在更高级声明之 ...

  7. Flutter 布局(九)- Flow、Table、Wrap详解

    本文主要介绍Flutter布局中的Flow.Table.Wrap控件,详细介绍了其布局行为以及使用场景,并对源码进行了分析. 1. Flow A widget that implements the ...

  8. mysql的高级特性-存储过程

    定义: 存储例程是存储在数据库服务器中的一组sql语句,通过在查询中调用一个指定的名称来执行这些sql语句命令. 语法: DELIMITER // 声明语句结束符,用于区分; CEATE PROCED ...

  9. Git 学习一

    刚刚接触git,学习现骨干操作并记录一下过程中的小问题(Windows下) 1.新建git目录 创建一个目录,使用命令 git init 2.添加文件  git add a.txt 3.提交文件  g ...

  10. Tensorflow实现稀疏自动编码(SAE)

    1.概述 人在获取图像时,并不是像计算机逐个像素去读,一般是扫一眼物体,大致能得到需要的信息,如形状,颜色,特征.怎么让机器也有这项能力呢,稀疏编码来了. 定义: 稀疏自编码器(Sparse Auto ...