12558网页游戏私服论坛

 找回密码
 立即注册
游戏开服表 申请开服
游戏名称 游戏描述 开服状态 游戏福利 运营商 游戏链接
攻城掠地-仿官 全新玩法,觉醒武将,觉醒技能 每周新区 经典复古版本,长久稳定 进入游戏
巅峰新版攻 攻城掠地公益服 攻城掠地SF 新兵种、新武将(兵种) 进入游戏
攻城掠地公 散人玩家的天堂 新开 进入游戏
改版攻城掠 上线即可国战PK 稳定新区 全新改版,功能强大 进入游戏
少年江山 高福利高爆率 刚开一秒 江湖水落潜蛟龙 进入游戏
太古封魔录 开服送10亿钻石 福利多多 不用充钱也可升级 进入游戏
神魔之道 签到送元宝 稳定开新区 送豪华签到奖励 进入游戏
神奇三国 统帅三军,招揽名将 免费玩新区 激情国战,征战四方 进入游戏
龙符 三日豪礼领到爽 天天开新区 助你征战无双 进入游戏
王者之师 免费领豪华奖励 免费玩新区 6元送6888元宝 进入游戏
查看: 355|回复: 0

【OSG】CVE-2016-6187 Exploiting Linux kernel heap off-by-one 利用堆大

[复制链接]

49

主题

49

帖子

108

积分

实习版主

Rank: 7Rank: 7Rank: 7

积分
108
发表于 2019-8-20 11:11:57 | 显示全部楼层 |阅读模式
【OSG】CVE-2016-6187 Exploiting Linux kernel heap off-by-one 利用堆大小差一错误爆破Linux内核(下)
原文作者:Vitaly Nikolenko 译者:rodster 校对:song
原文链接:https://cyseclabs.com/blog/cve-2016-6187-heap-off-by-one-exploit

Target object
因为目标对象,我使用了struct subprocess_info 结构,正是96字节大小。为了触发这个对象的分配,下面的套接字操作可以使用一个随机的协议家族:[table][tr][td]
1
[/td][td]
socket(22, AF_INET, 0);
套接字族22不存在但是模块自动加载会触发到内核中下面的函数:[table][tr][td]
1

2

3

4

5

6

7

8

9

10

11

12
[/td][td]
int call_usermodehelper(char *path, char **argv, char **envp, int wait)
{
        struct subprocess_info *info;
        gfp_t gfp_mask = (wait == UMH_NO_WAIT) ? GFP_ATOMIC : GFP_KERNEL;
  
        info = call_usermodehelper_setup(path, argv, envp, gfp_mask,    [6]
                                         NULL, NULL, NULL);
        if (info == NULL)
                return -ENOMEM;
  
        return call_usermodehelper_exec(info, wait);                    [7]
}
call_usermodehelper_setup [6] 然后会分配对象和初始化它的字段:[table][tr][td]
1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22
[/td][td]
struct subprocess_info *call_usermodehelper_setup(char *path, char **argv,
                char **envp, gfp_t gfp_mask,
                int (*init)(struct subprocess_info *info, struct cred *new),
                void (*cleanup)(struct subprocess_info *info),
                void *data)
{
        struct subprocess_info *sub_info;
        sub_info = kzalloc(sizeof(struct subprocess_info), gfp_mask);
        if (!sub_info)
                goto out;
  
        INIT_WORK(⊂_info->work, call_usermodehelper_exec_work);
        sub_info->path = path;
        sub_info->argv = argv;
        sub_info->envp = envp;
  
        sub_info->cleanup = cleanup;
        sub_info->init = init;
        sub_info->data = data;
  out:  
        return sub_info;
}
一旦对象被初始化,这将绕过 call_usermodehelper_exec in [7]:[table][tr][td]
1

2

3

4

5

6

7

8

9

10

11
[/td][td]
int call_usermodehelper_exec(struct subprocess_info *sub_info, int wait)
{
        DECLARE_COMPLETION_ONSTACK(done);
        int retval = 0;
  
        if (!sub_info->path) {                                          [8]
                call_usermodehelper_freeinfo(sub_info);
                return -EINVAL;
        }
...
}
如果路径变量为null[8],然后 cleanup 函数被执行并且对象被释放:[table][tr][td]
1

2

3

4

5

6
[/td][td]
static void call_usermodehelper_freeinfo(struct subprocess_info *info)
{
        if (info->cleanup)
                (*info->cleanup)(info);
        kfree(info);
}
如果我们覆盖了 cleanup 函数指针(记住对象现在在用户空间被分配),然后我们随着CPL=0就有了任意代码执行。仅有的一个问题是subprocess_info 对象分配和释放在同样的路径。在 info->cleanup)(info) 被调用并且设置函数指针到我们的权限提升payload之前修改对象函数指针的一个方法是以某种方法停止执行。我本可以找到其他同样大小的因为分配和函数触发的两种“分开”路径,但是我需要一个理由去尝试 userfaultfd()  和这个页面分裂的想法。
Userfaultfd系统调用能够被用来处理用户空间中的页面错误。我们可以在用户空间分配一个页面并且设置一个处理器(当做一个分线程);当这个页面因为读或写被访问,执行会被转移到用户空间处理器去处理页面错误。这里没有新鲜的并且这是被Jann Hornh所提到的。
SLUB分配器在被分配之前访问对象(首8个字节去更新缓存freelist指针)。因此,这个主意就是分离subprocess_info 对象到两个连续的页面以便所有对象字段除了说这最后一个(如 void *data)将会被放在同样的页:



然后我们会设置用户空间页面错误处理器去处理在第二页的PF。当call_usermodehelper_setup 去设定sub_info->data ,代码被转移到用户空间PF处理器(在那里我们可以改变先前设定的sub_info->cleanup 函数指针)。如果目标被kmalloc 所分配,这个方法会起作用。不像kmallockzalloc  在分配之后使用memset(..., 0, size(...)) 归零对象。不想glibc,内核的杂类函数实现是十分简洁直接的(例如设置连续化的单个字节):[table][tr][td]
1

2

3

4

5

6

7

8

9
[/td][td]
void *memset(void *s, int c, size_t count)
{
        char *xs = s;
  
        while (count--)
                *xs++ = c;
        return s;
}
EXPORT_SYMBOL(memset);
这意味着设置在第二页的用户空间PF处理器将不再起作用,因为一个PF将会被杂项函数触发。然而,这仍然有可能被束缚用户空间页面错误所绕过:
1.       分配两个连续页面,分割对象到这两个页面(如之前的)并且为第二个页面设置页面处理器。
2.       当用户空间PF被杂项函数触发,为第一页设置另一个用户空间PF处理器。
3.       当对象变量在 call_usermodehelper_setup 中初始化了,那么接下来的用户空间PF将会触发。这时候设置为第二个页面设置另一个PF
4.       最终,最后一个的用户空间PF处理器可以修改cleanup  函数指针(通过设置它指向我们的权限提升payload或者ROP链)并且设置path  成员为0(因为这些成员在第一页被分配并且已经初始化了)。因为“页面错误”的页面能够通过再次去除内存页映射/映射这些页实现,设置用户空间PF处理器。并且然后传递它们到userfaultfd()4.5.1版本的POC能够在这里被找到。尽管对于内核版本没有什么特殊的(它应该可以工作在所有含有漏洞的内核)。这里没有权限提升payload但是这POC会在用户空间地址0xdeadbeef 执行指令。

Conclusion
这有可能是更容易利用此漏洞的方法,但是我仅仅想我只想让我发现的目标对象随着userfaultfd “工作”。清理机制缺失是因为我们是分配IPC msg对象,这不是非常重要并且有一些简单的方法稳固系统。

Update - 18/10/2016
Qihoo 360反应他们的工作是独立的并且他们从来没有引用过公共资源。我想他们说的应该没错。
来源:http://www.12558.net
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
楼主热帖
回复

使用道具 举报

*滑块验证:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|12558网页游戏私服论坛 |网站地图

GMT+8, 2024-4-29 07:32 , Processed in 0.125000 second(s), 31 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表