这是UAF系列的第一篇. 三篇的主要内容如下.
关于第三篇的内容我还没有决定好, 最近在研究CVE-2018-8410, 如果分析的出来的话. 第三篇的内容我会给出CVE-2018-8410的分析报告. 如果失败的话, 我会挑选一下windows 10下的X64的UAF进行分析. 由于win10加了很多缓解措施, 所以那会是一个相当有趣的过程.
博客的内容我是倒着推的, 因为我喜欢有目的性的工作. 所以决定在最后再进行漏洞原理的分析。而原理的探讨主要是通过对补丁的探讨而完成.
在学习的过程中, 我给出了实验相应步骤的动态图. 希望能对您有所帮助.
由于是系列的第一节, 所以讲一下环境的搭建, 在经过漫长的犹豫之后, 我决定把环境的搭建制作成为一个gif图, 因为觉得动态的过程更容易理解一些.
下面是对环境搭建步骤详解.
[+] 配置支持
把virtualKD解压到宿主调试机C:\SoftWare, 将宿主机C:/software/target目录复制到target机子C:\下. 最终结果如下:
打开target机器下的C:\target\vminstall.exe 点击yes. 电脑重启
设置Vmcommon的调试器路径
开始调试.
在我自己的学习过程中, 我喜欢把自己学的东西切成几大块, 假设为ABCD四个大块, 在B无法理解的情况下, 我能够去弄明白ACD就好.这样即使无法完成此次学习, 我也能保证能在此次的学习过程中得到有用的技能.
让我们来假设一下作为一个对UAF不理解的小白我们会把漏洞的利用过程切为那几个部分.
在进行上面的分析之后, 我们可以先做一些比较轻松的部分.
我相信有部分开始做内核的朋友可能会比较好奇为什么最后运行cmd, 输入whoami之后, 就能证明自己提权成功了, 很不幸的, 这是一段漫长的故事. 其实也还是很简单的. 原理如下.
这一部分的代码感谢小刀师傅, 来源于他的博客和github. 在他的博客和github上面我学习到了很多的有用的东西.
很多时候, 我觉得有些细节其实是可以不用太在意的. 你可以帮他当作拖油瓶, 只是附带的产物, 比如上面的si的赋值之类的. 让我们关注一下重点函数.
CreateProcessW创建一个子进程, 在MSDN上面你可以的到详细的解释. 我们列出重要参数的详细解释.
我们在main函数当中进行调用. main函数现在的代码如下.
运行的结果如下图.
我们发现我们现在的提权没有成功, 这是肯定的. 因为我们并没有进行漏洞的利用.
作为一个有灵魂的内核选手, 这个地方的shellcode我们当然采用汇编编写. 编写之前, 我们继续对我们所学的东西进行分块.
okok, 作为一个内核选手, 我们深知调试器永远不会骗人. 所以我们可以通过调试器来帮助我们验证一下我们的思路是否正确.
运行如下命令:
我们能得到关于system如下的结果.
解释:
接着我们运行如下的命令, 查看system进程的Token.
与找到TokenSys的方法类似, 在虚拟机里面运行一个cmd. 我们可以通过相同的方式找到TokenCmd
这一部分, 我们采用调试器辅助完成. Token存放在进程偏移f8处, 我们可以把TokenCmd按照如下的命令重新赋值.
此时我们再对cmd的Token进行解析. 发现Token的值已经和Sytem的Token出奇一致.
此时我们运行cmd的whoami, 进行验证. 这个实验过程动态图如下.
汇编实现的整体代码如下. 关键点我会给出注释, 如果你需要更详细的解释, 你可以在这里找到答案. (Tips: 汇编代码只是对我们上面手工做的过程的一次模仿. 别畏惧它)
一点小Tips:
调试器无所不能(但是不能帮我找到女朋友...), 我们想要运行shellcode, 如何运行???.
在阅读了源码之后, 我们发现了一个幸福的代码片段.
g_UseAfterFreeObject是一个全局变量, 他的定义如下.
有趣, 如果我们能够篡改他的函数指针指向ShellCode地址. 那么我们就能在内核当中调用我们的shellcode. 接下来做一个小小的演示
Tips:
在未篡改之前, g_UseAfterFreeObject的结构长这样.
在进行了一堆骚操作之后(我们后面的主要内容就是为了讲解这个地方的骚操作).
g_UseAfterFreeObject的结构长这样.
这样的话, 我们就能够运行shellcode了, 提权成功如图.
我们前面说过, 后面的内容主要是一堆骚操作. 来执行替换g_UseAfterFree函数指针的功能.
USE AFTER FREE, 从这个名字来看是指在FREE状态后依然能够被使用. 有趣有趣. 那我们来关注一下FREE状态之后如何使用.
在我们从小到大的过程中. 我们知道POOL是动态分配的, 就像你永远不知道明天的巧克力是什么味道一样(当然作为一个单身狗, 明天也是没有巧克力的, 太凄凉了). 你永远也不知道下一块分配的POOL在那个位置.
Wait, 我们真的不知道吗??? 如果你有兴趣你可以在此处的paper找到相应的POOL分配和释放算法的相关解释. 在这里我直接给出结论.
我们来看一下我们的UAF(假设已经成功)POOL的大小. 我们申请一个和他一模一样的POOL. 是不是有一定的概率使我们分配后的POOL的刚好是这个地方呢. 答案是肯定的. 但是有一个问题. 一定的概率. 我们希望我们的利用代码能够更加的稳定. 假设此时操作一共有X个大小的空闲区域. 我们的概率是1/X, 分配两个是2/X, 不断增加.
最终我们的代码如下.
我们到这里其实利用就已经做完了, 但是永远别忘记一件事, 这只是一个练习. 与真正的漏洞分析差的远. 所以我们学的应该不是教程, 而是这一段在实践当中可以帮助我们做些什么.
漏洞成因的分析在我实践的过程中. 有两种手段.
这个地方我们来模拟补丁比对. 实战当中你可以使用bindiff, 为了让接下来的过程更加的简单. 我们采用源码分析.
在这个地方, 安全与不安全的主要理由是g_UseAfterFreeObject最后是否为NULL.
这个地方有一个小小的问题, 在下一节我们给出我们的套路.
我们来对安全的版本进行一点小小的讨论.
随着思路的推理, 我们的嘴角逐渐浮现出笑容. windows 7 下, 我们可以对申请0地址, 并且填充相应的内容. 假设shellcode地址为0x00410000. 我们通过对0地址进行填充内容.
我们也能顺利执行我们的shellcode. ==> 此处引发了一个空指针解引用漏洞.
OK, 我们验证了这是一个不安全的补丁. 更安全的补丁应该类似于这样
很遗憾的, 当我发现这个的时候, 发现创作者已经做了这样一个检测,,,,,
在进行这次学习之后, 我有一个小小的猜测. 是否存在可能性, 安全人员在进行uaf漏洞补丁的时候. 忽视了空指针解引用呢.
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
最后于 2018-9-29 18:56
被wjzid编辑
,原因: