首页
社区
课程
招聘
[原创]windows 内核系列二: cve-2015-0057 ==> DDCTF kernel pwn第二题
发表于: 2018-10-15 09:50 14382

[原创]windows 内核系列二: cve-2015-0057 ==> DDCTF kernel pwn第二题

2018-10-15 09:50
14382

这是UAF系列的第二篇. 三篇的主要内容如下.

首先要说很多感谢, NCC group真的做了很杰出的工作, 受益颇多. 然后是keenjoy98老师, 他在blackhat上提供的PDF给我思路的理解提供了很大的帮助. 还有拖了这么多天. sakura师父没有把我打死. 还有就是小刀师傅这段时间不厌其烦的解惑.

然后是一点小小(大大)的抱歉.

其次是一点小小的说明.

然后是一点啼笑皆非的事. 我实习的时候想去xxx, 然后师傅和我说. 你要是把ddctf的两道kernel pwn的题做出来, 我不认为你去不了. 所以ddctf的pwn题本来是我这个月末的目标来着. 结果在做堆头修复的时候. 查资料才发现这就是第二题... emmmmm. 不过我由于我参考了过多的资料, 所以其实不算做出来.

下面是文章主要涉及的知识点:

我自己浪费的时间比较久的是:

所以我会把这三个部分我犯得错误贴出来. 希望能够帮你避免你能够重复犯错.

代码的实现我实现的NCC group的方法. 由于英文比较差, 出现了点理解误差, 所以我的布局和NCC gruop的有一点点小的不同. keenjoy98老师的方法我觉得我应该大概理解了, 但是我可能想的麻烦了, 所以就不再赘述.

希望这篇文章对你能够有点小小的帮助.

Let's Go

故事的开头是这样的. 有一天你想实现一下内核提权. 于是你写了如下的shellcode.

这部分的shellcode你可以从第一篇当中的到解释从而类推. 或者你可以在这里得到. 代码也有详细的注释. 所以 这一部分. 我主要讲一下如何编译64的汇编. x64不支持_asm内联汇编. 所以我目前知道的有三种选择.

我个人更喜欢第三种. 因为好看. 我的环境是vs 2015. 设置编译选项的动态图如下. shellcode

需要注意的是这两个命令. 原封不动的ctrl+cctrl+v即可

好了. shellcode的编译已经写完了. 我们知道shellcode只能在内核当中执行. 如何在内核当中执行它呢. 在内核当中我们观察到一个有趣的代码段.

ntQueryIntervalPtrofile
函数nt!NtQueryIntervalProfile+0x22调用了nt!KeQueryIntervalProfile, 接着我们观察一下nt!KeQueryIntervalProfile, 发现如下代码段.
KeQueryIntervalProfile

我们发现这个地方调用了一个函数指针(一个指针用来存储函数的地址), 我们存储在nt!HalDispatchTable+0x8处 , 那么它指向哪一个函数呢呢. 运行下面的指令

hal是一个函数指针数组. dqs列出其中的值. 我们看到函数hal!HaliQuerySystemInformation存储在偏移0x8处. 如果. 我是说我们如果能有一个对任意地址写的机会. 我们就有能力修改偏移0x8处的值. 何不试试把它改成shellcode的地址. 那么在KeQueryIntervalProfile中的代码可以替换成call shellcode. 于是我们就可以执行shellcode. 记下我们接下来要实现的目标

那么我们去找一个漏洞吧, 才不要(逃), 作为一个win内核选手我们得记住我们是拥有windbg的男人. windbg具有的功能

所以我们可以采用windbg来模拟任意地址读写. 整个过程的步骤如下.

最后我们采用在代码最后加上system("cmd") 创建cmd, 用来观察提权是否成功.main函数代码如下.

需要注意的shi__debugbreak, 相当于int 3, 方便我们使用windbg, 这是我exp开发过程中用的最多的命令. 动态图如下:
蓝屏
wait, 咋和说好的不一样呢. 蓝屏了.

万恶之源来源于在微软在win8下实现的一个缓解措施. SMEP. 解释如下.

上面的逻辑我们用伪代码表示如下.

我们看到那个地方有一个条件判断. 是否开启SMEP. 所以绕过这个判断. 让我们加入这一个语句绕过smep.

ok, 再次运行. 得到提权. 演示如下.
骗你的smep绕过 !

好了. 提权成功, 那我们这篇文章到这里就结束了(我就皮一下...).

好吧, 还没有. 我们用的调试器. 那么我们得用代码模拟调试器呀. 如何模拟调试器呢. 三个小目标.

我们先讲前两个.

我们前面的蓝屏是一键很难受的事, 所以我们得绕过SMEP.

SMEP是微软在win8先加的缓解措施. 其目的是kernel不可执行user space的代码. 所以假设我们的shellcode放在0x410000处(user mode), 我们控制rip执行shellocde的时候, 就会产生kernel执行user space代码的情况. 于是BSOD发生. 漏洞利用失败.

wait. 某某不可执行, 于是我们想到了我们的老本行, DEP. 数据段不可执行. 那么我们可不可以利用DEP的绕过方式: ROP. 答案是肯定的. 于是我们来看下面这一段代码.

等等, cr4是啥. cr4是决定SMEP的关键寄存器. SMEP将基于cr4寄存器来判断. 先来看一张图.

smep

我们通过smep标志位(第20位, 从0计数)来判断是否要启用SMEP. 我们来查看一下我们的cr4寄存器的运行在我的环境下触发漏洞前后的对比.

我们可以看到关键bit位的更改, 假设我们把haldispatchtable+0x8处改为nt!KiConfigureDynamicProcessor+0x40的时候, rax也刚刚好为0x406f8, 而刚好返回地址也为shellcode的地址, 那么简直完美. 幸运的是, 假设我们把漏洞利用函数改为此.

动态调试你会发现其刚刚好. 不幸的是, 我们查看这个地方的汇编代码, 长这样:

问题出在ecx. 这个地方返回地址我们可控的是32位, 而我们的exp是64位, 也就是shellcode地址是64位的. pwn2town上介绍了一种我完全看不懂的方法(由于这个原因, 我尝试过其他的SMEP bypass). 所以我换了另外一个思路.

在我的源码最后, 我加了这么几句, 来恢复堆栈平衡和修复cr4寄存器(不能瞎改内核的东西, 借完之后借的还回去)

如果你惊讶于30等值是如何检测出来的, 你可以利用你的windbg, 动态调试来修复就可以了. 而0fffff8020074af75h是由于ROP的时候返回地址被破坏了, 我一开始采用虚拟机把它记作一个常量. 后来用获取基地址的计数把它替换掉了, 具体的你可以查看我的源码.

由于windbg的存在, 我们可以假设我们已经拥有了write-what-where的功能. So, 如果是要完成将第二项改为shellcode的地址. 那我们第一件要做的事, 势必是去找到他. 调试器中我们很机智的用dqs就找到了, 但是在代码当中如何来实现呢. 源代码当中我是这样实现的

首先, 我们假设我们经过GetKernelImageBase函数获取到了"ntoskrnl.exe"加载在内存当中的基地址, 并把它赋值给了pKernelBase变量(后面我们会让这个假设成为真实). 上面的代码获取nt!haldispatchTable在内核当中的地址的思路是:

好了, 让我们来获取pKernelBase.

windows加了地址随机化. 所以每次开机重新加载的时候. ntoskrnl.exe在内核当中的基地址都不一样. 这一部分, 其实我的个人建议是, 直接保存一个虚拟机镜像, 这样KASLR就已经被绕过了. 直接拷出每个函数在这个镜像当中的地址, 然后直接使用, 把后面的做完了再来绕过KASLR. anyway, 让我们来看一下如何找到内核当中的ntoskrnl的镜像.

我的学习是在r00k1ts大大的这篇文章找到了答案, 获取基地址的思路如下.

哇, 走到这里, 万事OK, 现在我们所欠缺的, 只是如何构造一个write_what_where而已. 让我们来看看我们的漏洞的代码.

很好, 逆向这一部分的工作, 你可以查看我上传的IDB文件观察细节, ncc gourp里面也给了详细的解释. 这里我先给出另外一个函数.

微软给出这个函数的解释如下:

三个参数与漏洞函数的三个参数关系如下.

So, 前面讲了这么多和我们的漏洞有什么关系呢, 针对一个滚动条控件窗口, 首先由一个tagWND窗口来装载(第一个参数pwndWnd), 期间有一个psbInfo结构体. 如下:

psbInfo存储滚动条的相关信息, 定义如下:

接着, 你可以利用这几个结构体去查看上面的代码, 这里我直接给出结论.

我们看一下过程.
变成0xe

我们得经过上面的这个程序才能实现完整的漏洞触发. 你可以进行逆向看下必须满足什么条件. 这里我给出结论.

于是, 相关的源代码当中, 体现这两个细节的是.

So, 我们来实现控制回调函数.

回调在我看来, 是内核漏洞发生的本源. 因为如果从内核层次回到user mode, 再从user mode回到内核层次, 在用户层次的时候我们拥有着极大的自由. 这样的我们能够做太多事了.

SO: 如何利用回调.

我们假设, 在xxxDrawScrollBar里面会触发某个函数回调, 代码会去执行回调函数A, 如果我们能够HOOK回调函数A. 使其指向我们自己写的回调函数, 我们就能在此期间做一些坏坏的事. 关键的问题是, 这个回调函数A是谁呢?

现在的我看来, 这是一个很简单的问题, 但是当时的我, 花了足够多的时间去解决和思考这个问题.

一开始的时候, 我选用的方法是: 静态阅读xxxDrawScrollBar的代码, 看下他当中有哪些回调函数, 确定哪些函数会被调用. 于是我祭出了我的IDA, 就一步一步的点啊之类的. 在经历了漫长的调试分析之后, 我失败了. 因为到后面的时候我的思绪乱了.

于是夜里三点, 躺在寝室的床上, 我开始思考人生, 真的要这样下去么, 一辈子就看着代码点点点度日子... 突然灵光一闪烁, 我意识到这样下去破日子不能这样子过下去. 于是我开始思考我掌握的和回调相关的知识. 定位到了关键性的几个信息.

首先看一条命令.

此处指向回调函数指针数组, 类似于这样:

接着查看回调函数必然经过这里:

该函数的原型如下:

其中, ApiNumber勾起了我的兴趣

期间, 我在一个win32k的paper上看到如上定义, 也就是说, 我只要能够通过确定rcx的值, 来确定我要hook的回调函数是谁.

首先, 在这两个地方下断点.

此指令用于查看寄存器的值

在地点A和地点B之间会经过nt!KeUserModeCallback处, 我们查看rcx, 即可确定会调用哪些回调函数. 就是这么简单.

hook函数思路演示

最后我选取了NCC group推荐的回调函数, 在确定了需要HOOK函数之后, 代码如下.

OK, 由此我们get到了需要HOOK的函数地址, 所以后面我们只要进行简单的相应的赋值语句就好了.

Hook完毕, 让我们进行下一步. 在我们自己定义的fakeHookFunc之中, 我们能干些啥.

这一步, 我决定先给出相关的代码实现:

首先想说的Hookflag和hookCount, 我们在hook了函数之后, 这个回调函数很有可能被系统的其他部分使用. 但是我们想控制的只是由xxxDrawScrollBar触发的时候, 所以我们得确定一下哪一次才是由xxxDrawScrollBar触发的. 我设置这两个变量就是为了做这件事.

这一部分我们保证了我们从进入触发流程之后再计数, 之后我们在调用xxxDrawScrollBar下断点, 看一下从xxxDrawScrollBar之后进去HOOK是第几次. 是不是有点小小的绕, 让我们来看一下动态的过程.

之后是两处注释, phmValidateHandle函数用于获取hwndVulA的内核地址, 是为了方便我自己调试用的. 至于如何获取的, 你可以查看这里(小刀师傅的博客). 接着.

偏移为b0的地方为其psbInfo. 于是我用了下面的语句来查看信息.

如果rax+b0 地址为 0400: 100, 那么这条命令会打印出100处的内容. 在我整个exp开发的过程中, 我频繁的使用这条语句来进行堆风水布局的验证.

接着是DestoryWindow, 这个函数会销毁窗口的相关内容, 但是其句柄因为不会被销毁, 因为其引用计数不能为0. 但是已经够了, 这样之后, 我们的psbinfo处于free状态, 且指针不为0. 于是我们可以通过堆喷射(堆喷射请参考上一篇)来重新填充内容.

如何来通过堆喷来伪造填充我们的psbInfo呢, 先看一下正常状况下的pbInfo. 我dump下来的数据如下:

接着我调用了下面一个for循环, 实现了堆喷. 覆盖数据如下所示:

为了证明不是我瞎编的, 图如下.

上面那一小节我们证明了我们的看到了我们的win32k!tagSBINFO大小为0x30(加上对齐和_HEAP_ENTRY, 先别在意这两个.), 接着我们来查看一个结构体:

调用SetPropA第一次的时候, 首先会在分配一个堆, 存储一个tagPropLIST结构体. 第二次调用setPropA的时候, 会继续分配一个tagPROP结构体(0x10). 也就刚刚是0x28, 再加上其的-heap-enrty. 刚刚好合适.

接着, 由于刚好是2个, 根据前面的结论. 这个数值会在后面的异或过程中变为0xe. 我们如何来利用0xe呢. 恐怕我们就得说一下tagPropList了.

首先来查看SetPropA函数:

这个函数对于此次漏洞利用的信息有:

这一部分过了之后, 那么我们如何使用这个特性呢. 我们得对前面的结构体加一点点注释.

在漏洞函数执行回win32k!xxxEnableWndSBArrows()函数之后, 通过前面的讨论, 内核结构遭到篡改. 内核会误以为一共有0xe个tagProp, 所以我们可以在后面继续调用setProp覆盖后面的数据. 也就是有了一个越界读写的能力. ==> 能写0xe个tagProp

听起来不错, 我们有了破坏内核结构的能力. wait, 如果你仔细的查看tagProp和setPropA的对应关系. 你会发现写原语残缺. 截图如下.

高亮的部分就是我们可以控制的内容. 非高亮部分是无法控制的. 我们在win32k!的利用当中, 常见的思路是去破坏tagWND结构体的某一个值. 然后实现任意地址读写. 但是, 假设我们后面接的是一个tagWND结构体, 那么我们进行写操作的时候我们必定会对其中的某些重要值照成破坏. 照成利用失败.

于是NCC gruop安排了一个新的布局(这一部分的布局我自己改了一下). 如下.

下面我们来解释为什么要这样布局. 首先看一个函数.

接着查看一下tagWND的一个结构体成员.

当调用NtUserDefSetText函数的时候, 内核当中, 关联的tagWND结构体的strName会有相应的改变. buffer存储一个指针, 指向o4lstr指向的字符串. 而这一步的关键点在于. 这些字符是分配在一个堆中. 堆含有一个堆头. 如下所示:

你可以去查看写原语残缺的时候dump的内存. 你会发现heap entry的内容是可控的. 里面包含当前堆块的大小等信息. 所以, 现在假设一种状况:

基于此, 新的问题就产生了

这是我们后面主要需要讨论的. 所以我们从简单的说起.

我在heap cookie上花了大量的时间, 因为当时找的资料并不多, 大多数都是堆内部管理的资料. 我想找一个泄露cookie的资料, 死活没有找到. 所以最后在通过阅读源码+阅读堆内部管理的理论知识, 解决了这个问题.

首先, 我们假设要伪造的_HEAP_ENTRY所关联的堆大小是0x1b0(后面解释为什么为这个值), 堆是以0x10的为一个单位. 前面我们可以看到前面的_HEAP_ENTRY结构体偏移0x8处即为size, 那么我们直接把这个值改为0x1b(记住以0x10为单位). 那么是不是就ok了呢.

如果这样做的话, 我们就会被安排的明明白白. windows呢, 很久以前就知道有人想弄它的堆. 所以他就实现了一个Cookie. 来保护它的堆. 保护的过程如下.

windows在每次开机的时候, 都会有一个随机的cookie值生成. heapChunk 释放状态的时候.

所以我们的heapChunk不能乱搞, 我们只单单改大小是过不了堆的检测的. 我们如何构建一个能通过检测的堆. 首先, 假设我们已经获取正确的cookie(此时假设为). 我们dump一下还没有被覆盖的heap

算下small tagIndex

OK, 之后:

这里你可能有一个小小的疑惑, 为什么我要dump解密之后再加密. _HEAP_ENTRY 在未与cookie异或之前, 不管你怎么电脑开机, 每次除了smalltagIndex之外, 应该都是一样的(这个地方可能有点问题, 但是这是我调试得出的结论.). 所以你直接dump改变大小, 重新赋值size. 再和cookie进行异或就可以使用了了. 当然, 你也可以选择具体深究_HEAP_ENTRY结构体的每一个成员, 算出他们每一个的值.

这一部分我自己的开发过程中. 根本没有管这个cookie. 反正电脑是虚拟机. 那么保存镜像. 每次都是一样的. 那么我只要用调试器获取一个cookie. 然后就可以用了.

我们来讲一下如何用代码来泄露此cookie(这一部分我其实不是独立开发, 用的别人代码调试理解)

这一部分我是如何理解的呢(这个地方我是通过调试器理解+原理, 所以可能有误, 因为实在没有找到现成的详细解释的资料, 所以实在抱歉). 我注意到上面有几个常量. 刚好可以和_HEAP对应起来.

我dump了几个_HEAP的数据, 发现他们的0x10处都为0xffeeffee, 所以依据此可以判断此内存块存放_HEAP结构.

接着通过下面的这张图:
desktop heap

Desktop heap会有一份堆映射到user space, 也就是我们可以用virtualAlloc可以查询到的, 每一个Desktop heap在kernel中的地址和映射到内核中的地址是固定的, 如果满足user space address + offset = kernel space address. 说明到了Desktop heap对应的_HEAP结构, 接着偏移0x80的地方存放的是我们的cookie值.

我们前面讲过, tagWND里会有一个strName, 与NtUserSetText函数关联, 期间strName是一个nt!_LARGE_UNICODE_STRING结构体.

我们知道我们差的是write_what_where:

这就是我们整体的利用思路, 举个例子, 我们不是要写nt!halDispatchTagble+0x8的值为shellcode么.

ok, 现在我们的剩下的唯一问题就是我们如何把布局变成我们想要的布局.

很多时候名字是一个有意思的事, 比如fengshui布局. 光从一个名字我们能得到什么.

对于这个漏洞利用来说, 什么样的环境是我们需要的呢. 前面我们说过.

所以我们期望的布局图示如下.

feng shui 布局成果

我在风水布局上面花了相当长的一段时间. 因为对两个地方理解有误导致.

如果听不懂就对了. 我们来搞懂他.(这一部分建议看看我的源码, 虽然很丑)

首先. 由前面我们知道.

通过上面的代码片段我们分配了0x1e0大小的桌面堆块, NtUserDefSetText函数是我进行堆喷射的接口. 通过它我们能够的到任意大小的heap.

于是, 为了实现上面的堆分配. 我一开始分配了0x300个0x1e0Desktop heap.
feng shui 布局

之后为了防止堆块合并, 我进行了隔一个进行free.
feng shui 布局

free之后, 我通过两次填充, 布局如下:
feng shui 布局

很好, 我们释放此0x1b0的数据, 接着先填充0x180, 在填充0x30的数据. 在释放0x180之后, 我们申请tagWND, 如下:
feng shui 布局

接着隔一释放我们另外的0x1e0的数据块, 一堆循环重复之后, 我们实现了我们想要的布局.

很抱歉, 这一部分实在讲的不够好. 一个是我实在不会做gif图, 那种彩色图实在是不会做, 如果后面我学会了, 这一部分会重新更新. 另外一部分, 我总感觉绕了很多的弯路, 幸运的是, 他是可靠的.

我依据的原则如下:

在实现了布局之后, 我们的漏洞利用就结束了. 只要构造一个假的tagWND, 改变其strname.buffer值, 就能够实现我们的任意地址读写.

在我学习heap cookie的过程中, 我查阅资料的时候发现, 这是ddctf的第二题... 于是, 我看到出题的keenjoy98师傅说.

那一瞬间觉得整个人都凉了, 因为我的代码, 何止需要打磨, 简直需要回炉重造. 一开始还是有代码组织的, 后来自从heap cookie开始, 每一天想的都是如何实现功能, 根本没有想组织的心情. 所以那是一份相当不堪入目的代码.

另外一个问题是死锁, 如果你观察我的代码, 能看到很多的Sleep函数, 原因来源于, 其实exp的开发很久以前就完工了. 但是有个很奇怪的事, 当我运行在调试某些地方写入__debugbreak的时候, 我在最后运行的时候, 我可以运行cmd, 但是去掉这些__debugbreak(), 在调试器当中我打印出Token已经被替换了. 但是就是没有cmd产生. 于是我dump了一下此时卡住时候的堆栈. 发现是由于windows的消息卡住了. 于是我花费了三四天的时间在研究如何绕过死锁. 最后实在没有找到方法(因为操作系统实在是太菜了). 有一天, 我想, 既然我那么多个__debugbreak()可以抛出cmd, 那么我是不是能够通过模仿__debugbreak的行为来绕过死锁呢. 我一开始选取了for循环, 但是在vs 万恶的优化下, 自动帮我去掉了, 所以我最后选取了Sleep(5000)函数, 成功的帮我绕过了死锁.

首先, 这一部分只算是我自己的想法. 所以不算是教科书般的定义... 所以请把他当作是一种讨论, 不要当作教条.

win32k是一个很大很大的东西, 也就是说, 就算给了你源代码写了详细的注释, 可能你都得花一辈子的时间去理解阅读, 估计是比等名侦探柯南完结更久的时间. 所以, 尽量少去静态逆向win32k的代码. 很多时候, 动态调试能帮你省去很多时间. 我自己做的过程中, 必须需要逆向的代码, 体现在漏洞触发的时候, 我需要理解代码如何才能抵达漏洞触发的那个点的位置. 基于这种情况下. 一般的有用的资料是.

说到底, 我只是想写提权而已. 每一年都有无数个win32k漏洞被爆出来, 每次的漏洞的函数都不一样, 存在很大的可能性, 在你一年之后, 回想一年前的代码你已经忘记的干干净净了. 所以, 纠结于这个函数到底干嘛, 这个结构体到底在干嘛, 我觉得并不一定是合适. 相反, 与我而言. 更重要的是.

拥有能力我觉得是比使用能力更重要的事. 因为如果你有能力, 剩下的过程不过是循环往复, 调试改正. 这样.

可能看了上面的东西你有点小小的难受, SMEP, heap cookie... 这都啥啥啥.... 但是一个好消息. 如果你阅读完全文之后, 你会发现. 其实大多数是依赖于操作系统. 和你此次的利用哪一个漏洞代码其实无关. 也就是说, 这一部分的东西, 你只要学习一次就好. 我觉得这是一个很好的消息. 意味着,如果你是一个懒惰的人, 大可以翻翻有没有开源的库, 别人已经编写好的代码直接用就好了. 类似于这样.


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2018-10-17 23:59 被wjzid编辑 ,原因: 更新一个重要的链接(调试的时候使用最多)
收藏
免费 2
支持
分享
打赏 + 2.00雪花
打赏次数 1 雪花 + 2.00
 
赞赏  junkboy   +2.00 2018/10/15
最新回复 (23)
雪    币: 620
活跃值: (372)
能力值: (RANK:150 )
在线值:
发帖
回帖
粉丝
2
图片应该是上传完了...
最后于 2018-10-15 10:53 被wjzid编辑 ,原因:
2018-10-15 09:51
0
雪    币: 11404
活跃值: (3396)
能力值: (RANK:520 )
在线值:
发帖
回帖
粉丝
3
感谢分享
2018-10-15 11:36
0
雪    币: 620
活跃值: (372)
能力值: (RANK:150 )
在线值:
发帖
回帖
粉丝
4
netwind 感谢分享
谢谢老师
2018-10-15 11:49
0
雪    币: 38
活跃值: (34)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
小妹妹你到底是有多少个师傅。。。
2018-10-15 11:50
0
雪    币: 620
活跃值: (372)
能力值: (RANK:150 )
在线值:
发帖
回帖
粉丝
6
Jeasnc 小妹妹你到底是有多少个师傅。。。
一个... 不对, 我不是小妹妹
最后于 2018-10-15 12:02 被wjzid编辑 ,原因:
2018-10-15 11:59
0
雪    币: 11716
活跃值: (133)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
支持
2018-10-15 12:59
0
雪    币: 190
活跃值: (84)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
赞~~~~~
2018-10-15 13:17
0
雪    币: 283
活跃值: (1018)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
简单看了下开头 我想问下如果一个提权漏洞需要 手动去写某地址或者说需要其他漏洞去任意读写某地址 这还叫漏洞么 有什么价值呢
2018-10-15 15:11
0
雪    币: 283
活跃值: (1018)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
或者说如果 我已经可以任意读写 那这样的漏洞不是可以 造出很多个么
2018-10-15 15:13
0
雪    币: 620
活跃值: (372)
能力值: (RANK:150 )
在线值:
发帖
回帖
粉丝
11
zhangheil 简单看了下开头 我想问下如果一个提权漏洞需要 手动去写某地址或者说需要其他漏洞去任意读写某地址 这还叫漏洞么 有什么价值呢
对不起, 可能是因为我没有讲的太清楚, 大概是这样, 手动写某地址其实可以拆成两步. 定位数据. 写数据. 这两个都是可以通过和具体漏洞关联用代码来实现的. 后面有介绍代码实现. 我做东西喜欢倒推. sorry.
2018-10-15 15:56
0
雪    币: 5676
活跃值: (1303)
能力值: ( LV17,RANK:1185 )
在线值:
发帖
回帖
粉丝
12
小妹妹太强了,膜拜
2018-10-15 19:26
0
雪    币: 23
活跃值: (57)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
13
膜师傅,tql !
2018-10-15 21:58
0
雪    币: 6112
活跃值: (1212)
能力值: (RANK:30 )
在线值:
发帖
回帖
粉丝
14
2018-10-17 13:37
0
雪    币: 23
活跃值: (57)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
15
2333 学习一波
最后于 2018-10-17 21:18 被gd菜鸡编辑 ,原因:
2018-10-17 20:56
0
雪    币: 1604
活跃值: (640)
能力值: ( LV13,RANK:460 )
在线值:
发帖
回帖
粉丝
16
大神您好,看了您的第二篇精彩文章,有些问题我还搞不清楚(懒得自己去研究了),向您请教一下:
1. 你那个内核提权shellcode应该就是通过当前进程的EPROCESS 结构遍历EPROCESS 链,找到 system 进程的EPROCESS 结构,将它的 token 复制到当前进程的 token,实现提权吧?
2.利用 ntdll 导出的 NtQueryIntervalProfile ,调用内核下同名称的 API,传入精心制作的参数,启动提权过程?
3. 禁用 SMEP 需要一次在 Ring3 下对CR4 的初始写操作,但 CR4 应该只能在 Ring0 下可访问,从你给出的代码来看
   nt!KiConfigureDynamicProcessor+0x40:
    fffff802`005f97cc 0f22e0          mov     cr4,rax
    fffff802`005f97cf 4883c428        add     rsp,28h
    fffff802`005f97d3 c3              ret
应该是通过设置 rax 的值禁用 SMEP ;问题在于,KiConfigureDynamicProcessor,是内核私有 API,你没讲清楚,为何 Ring3 下调用 ntdll 导出的 NtQueryIntervalProfile,会最终调用到 KiConfigureDynamicProcessor?至少给个栈回溯或流程图比较清晰吧?
4.给出代码:

void * p = (void*)0x100000;
p = VirtualAlloc(p, 0x1000, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memset(p, 0x41, 0x1000);
CopyMemory((VOID*)0x100300, shellCode, 0x200);

应该是分配一个起始地址 0x100000 ,4KB 的可执行虚拟页,然后把 shellCode 引用的64位地址内容复制到从  0x100300 开始的32位地址处?
5.  如果 nt!HalDispatchTable 受限于64位 Patch Guard 检查,可能在你还原修改前就被检测到,然后蓝屏。必须在修改前禁用 Patch Guard 
6. 整个 demo_time.exe  exploit 运行在用户空间,因此也受限于 ASLR,换言之,每次 demo_time.exe 启动时的加载基地址都不一样,因此没有前面的虚拟页分配,NtQueryIntervalProfile(0x100300, (PULONG)&newcr4); 执行第二次就会蓝屏了吧?
7。 GetProcAddress 一般只能用来获取过程的地址,把它用来获取数据结构 HalDispatchTable 的地址倒还蛮新奇的。你的思路是:在用户空间中模拟 ntoskrnl.exe 的加载、找出 HalDispatchTable 相对前者的偏移;因为无论 ntoskrnl.exe 载入到内核还是用户空间,HalDispatchTable  的偏移量不变;所以这个 offset 加上 ntoskrnl.exe 的内核基地址(通过用户态 API NtQuerySystemInformation 获取),就得到了 HalDispatchTable 的内核基地址。
最后于 2018-10-19 17:22 被shayi编辑 ,原因:
2018-10-19 17:20
0
雪    币: 620
活跃值: (372)
能力值: (RANK:150 )
在线值:
发帖
回帖
粉丝
17
shayi 大神您好,看了您的第二篇精彩文章,有些问题我还搞不清楚(懒得自己去研究了),向您请教一下:1. 你那个内核提权shellcode应该就是通过当前进程的EPROCESS 结构遍历EPROCESS 链,找 ...
师傅, 您好, 很抱歉原来文章有些问题没有说的清楚. 以及, 我不是大神了...
    [+] 第一个问题就是您说的思路: 我们可以根据那个链表去遍历找到system. 我主要参考文章是这两篇.
            ==> https://improsec.com/blog/windows-kernel-shellcode-on-windows-10-part-1
            ==> https://hshrzd.wordpress.com/2017/06/22/starting-with-windows-kernel-exploitation-part-3-stealing-the-access-token/
       第一篇文章是针对64的shellcode来写的. 自己写的过程主要是替换偏移值(如Token等).  第二篇文章对于我自己漏洞开发其实最重要的一篇. 以前在博客上面做过笔记, 但是由于博客出了点问题, 就不见了... 这篇文章帮助我学习了token替换的思路, 以及教会了我最重要的用调试器学习, 然后用代码来模拟的思想. 如果您有时间的话. 可以看一看.

       [+] 第二个问题是如何最终运行shellcode. 大概是, haldispatchtable类似于一个函数指针数组, 如果你能够篡改其中某个项(这个地方你可以看看我的haldispatchtable的截图, 高亮那个就是)的值为shellcode, 那么你就能运行你的shellcode了, 遗憾的是haldispatchtable是内核地址, 我们不能任意对内核地址进行写操作. 所以我们得通过漏洞构造任意读写的机会. 这是最简单的思路, 但是由于win8的smep, 直接去shellcode会失败. 所以们先让他跳到能够禁掉semp的rop链.
       [+] 第三个问题就是第二个问题, 我们把Hook的地址改为kiConfigureDynamicProcessor的地址. 在禁用SMEP之后由于参数的精心构造会跳到我们的shellcode中去.
              ==> 没有流程图, 因为我不会做....
              ==> 没有栈回溯, 因为当时写文章的时候心情太差了, 觉得应该调试可以自己调试出来的, 就没有写.... 本来准备做个调试截图的...
[+] 第四个问题在我的文章当中有些... 如果你直接不做任何预处理, shellcode的地址可能是7FFF FFFF FFFF FFFF. 但是由于传入参数是ecx, 所以只能传入0000 0000 FFFF FFFF... 所以我采取了这种迂回的方式. 在blackhat的2014的另外一篇文章有一个更高深的方法,来解决这个缺陷... 思路大概是清理栈利用伪造参数.. 但是我对那个API不是很熟, 所以我觉得换了个思路. 假设一开始就是 0000 0000 FFFF FFFF, 那么即使是ecx也无所谓了...
[+] 第五个问题. 我不是很清楚这个问题. 因为我也是学习的过程, 所以patch guard我也不太懂. 但是我当时的代码里面, 应该是在执行完shellcode之后再把这个值写回去了(maybe.. ). 利用这个漏洞, 读写都是一件很简单的事..
【+】 第六个问题我觉得应该如你所说, 我自己来实现我的漏洞利用做的是不断的开机重启虚拟机进行检测. 来检验是否可靠. 但是我觉得, 如果我在程序结束之前把原值还回去. 那么这个问题应该是不存在的. 一般来说, HOOK之后不都是要修复的么...  这一部分这几天可能没办法做.. 因为在做另外一个洞的利用. 隔段时间我会尝试组织一下代码结构以及深究一下死锁.
[+] 第七个问题. 算是学习的收获吧. 我一开始也是觉得只能获取函数地址, 后来调试分析发现数据结构地址也能获取. 找它的基地址类似于一种线段相等的感觉. 长度一定, 获取以前就可以算的出.

可能文章会有出错的地方. 因为实力问题. 欢迎您的指正. 如果还有什么其他的疑惑的话. 您可以通过我的QQ(2953427564)联系我, 我会的就一定说...

最后于 2018-10-20 01:02 被wjzid编辑 ,原因:
2018-10-20 01:02
0
雪    币: 2473
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
dbgview出来了?
2018-10-20 04:50
0
雪    币: 3567
活跃值: (467)
能力值: ( LV10,RANK:170 )
在线值:
发帖
回帖
粉丝
19
tql tql
2018-10-20 18:11
0
雪    币: 192
活跃值: (94)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
能否详细概述下女装大佬的学习历史,萌新特好奇,也特需要个方向。
2018-10-20 18:40
0
雪    币: 620
活跃值: (372)
能力值: (RANK:150 )
在线值:
发帖
回帖
粉丝
21
古朴 能否详细概述下女装大佬的学习历史,萌新特好奇,也特需要个方向。
我自己也是瞎学 主要是因为自己做的也不是太好, 所以不敢乱说... ctf的话, 你可以问问上面的holing师傅, 我老大!

女装是不可能女装的, 这辈子都不会女装的.
最后于 2018-10-20 19:30 被wjzid编辑 ,原因:
2018-10-20 19:29
0
雪    币: 620
活跃值: (372)
能力值: (RANK:150 )
在线值:
发帖
回帖
粉丝
22
PYGame dbgview出来了?
enen
2018-10-20 19:30
0
雪    币: 192
活跃值: (94)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
23
严重甩锅。
2018-10-20 21:36
0
雪    币: 292
活跃值: (850)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
24
shayi 大神您好,看了您的第二篇精彩文章,有些问题我还搞不清楚(懒得自己去研究了),向您请教一下:1. 你那个内核提权shellcode应该就是通过当前进程的EPROCESS 结构遍历EPROCESS 链,找 ...
PatchGuard当前主要还是针对SDT,GDT,IDT以及text段部分(代码段部分针对hook),hal!HalDispatchTable所述hal的.data段应该不受patchguard限制,目前微软对修改vtable的限制方法是将很多易利用的dispatchtable放在.rdata段,这样往只读段写入会BSoD
2018-10-22 15:22
0
游客
登录 | 注册 方可回帖
返回
//