网上流传的永恒之蓝漏洞利用代码中,关于内核shellcode部分,大部分都是利用APC注入的。
最近有个想法,直接利用内核代码执行权限,来写文件,于是就抄起了VS,开始写shellcode,开始以为和R3下面写shellcode一样简单..
新建个驱动的项目,按照下面修改项目的属性,然后动态获取API,再调API完成自己的功能。
项目属性配置好以后,开始写shellcode,计算要使用的内核API的名称hash,为了方便计算,我写了一个简单的MFC程序

刚开始遇到的第一个问题就是如何获取nt的基址,在内核中所有api都是从ntoskrnl.exe中导出的。
参考这个git项目 88aK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6%4L8%4u0S2N6$3W2@1i4K6u0r3e0g2x3I4y4#2)9J5k6o6l9I4x3q4)9J5k6h3N6A6N6q4!0q4c8W2!0n7b7#2)9^5b7#2!0q4z5g2)9^5y4#2)9^5b7#2!0q4z5g2)9&6c8q4!0m8x3W2!0q4y4W2)9&6b7#2)9^5z5g2!0q4y4g2)9^5y4W2)9^5y4g2!0q4y4W2!0m8x3q4!0n7z5s2y4Z5k6h3I4D9j5$3!0V1k6g2!0q4y4#2)9&6b7g2)9^5y4r3q4K6L8g2!0q4y4W2)9&6y4W2)9^5y4#2!0q4y4q4!0n7b7W2!0n7y4W2!0q4c8W2!0n7b7#2)9^5b7#2!0q4y4W2)9&6y4W2)9^5y4#2!0q4y4q4!0n7b7W2!0n7y4W2!0q4y4q4!0n7z5q4!0m8c8q4!0q4y4W2)9&6b7#2)9^5z5g2!0q4z5q4)9^5c8g2!0n7y4#2!0q4y4g2)9^5c8W2)9&6y4X3&6@1i4@1f1#2i4K6W2r3i4@1u0m8i4@1f1#2i4K6W2p5i4K6R3H3i4@1f1%4i4K6W2m8i4K6R3@1i4@1f1&6i4K6R3K6i4@1p5^5i4@1f1#2i4K6R3^5i4K6R3$3i4@1f1K6i4K6R3H3i4K6R3J5
但是这个asm文件是NASM的语法,导致我用vs直接编译不了,还需要弄个nasm的编译环境。
最后我修改为MASM版本,最终得到的获取ntoskrnl.exe基址的MASM汇编如下:
432K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6H3j5i4m8W2M7W2)9J5k6i4y4W2k6h3u0#2k6#2)9J5k6h3!0J5k6#2)9J5c8Y4m8S2M7r3g2J5M7#2)9J5c8Y4y4U0P5W2)9J5c8Y4N6A6L8X3c8G2N6%4y4Q4x3V1j5J5x3o6p5%4x3o6b7I4y4K6p5@1x3e0k6Q4x3X3g2@1P5s2c8Q4x3U0k6F1j5Y4y4H3i4K6y4n7i4@1f1^5i4@1u0r3i4K6V1&6i4@1f1@1i4@1t1^5i4@1q4m8i4@1f1&6i4K6V1K6i4@1u0q4i4@1f1$3i4K6S2q4i4@1p5#2i4@1f1@1i4@1t1^5i4@1q4p5i4@1f1@1i4@1t1&6i4K6W2r3i4@1f1$3i4K6W2o6i4K6R3&6i4@1f1#2i4@1q4r3i4@1t1&6i4@1f1$3i4@1t1H3i4@1t1^5i4@1f1$3i4K6R3I4i4K6V1J5i4@1f1@1i4@1t1&6i4K6S2n7i4@1f1^5i4K6V1K6i4K6W2p5i4@1f1^5i4K6S2q4i4@1t1%4i4@1f1#2i4K6S2r3i4K6V1$3L8Y4c8Q4c8e0g2Q4z5f1k6Q4b7V1q4Q4c8e0g2Q4z5f1c8Q4z5o6m8Q4c8e0N6Q4z5f1q4Q4z5o6c8Q4c8e0g2Q4z5o6S2Q4z5o6k6Q4c8e0k6Q4z5f1g2Q4z5e0m8Q4c8e0y4Q4z5o6m8Q4z5o6t1`.
把以上代码保存为demo.asm,添加到创建的vs驱动项目中,右键该文件,选择属性,修改项类型为: Mircrosoft Macro Assembler

这段汇编代码,导出了一个名为_getNtBase的函数,在vs项目中使用这个函数,需要用extern声明一下才能使用
然后开始编译我的vs项目,在编译时,又遇到第二个问题: vs项目中的指定函数编译顺序的FunctionOrder.txt,对这个asm中的函数不起作用。
无论我怎么调整顺序,这个_getNtBase函数永远排在main.obj中所有函数后面,这意味着,我在提取shellcode时,必须把一些main.obj中无用的函数也提取上。
最后我的解决办法也很粗暴,先用masm编译这个demo.asm, 拿到二进制机器码,再拼后面直接拼接我的shellcode..
这个demo.asm获取nt基址的代码执行完,结果最终放在rax中。
IRQL级别问题,这个也是卡了我时间最久的,我的shellcode思路如下:
以上思路用VS写,直接编译成驱动后,安装并运行,测试功能ok!
然后我用IDA提取shellcode,使用windbg强制改RIP,跳转到我shellcode中执行。 参考一位同事写的一篇笔记《内核调试shellcode》9d7K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6%4N6%4N6Q4x3X3g2U0L8X3u0D9L8$3N6K6i4K6u0W2j5$3!0E0i4K6u0r3k6$3!0S2j5X3!0#2N6o6u0Q4x3V1k6H3i4K6u0r3y4K6R3%4y4e0x3%4x3W2)9J5k6h3S2@1L8h3H3`.
强改RIP后,shellcode前面部分执行ok,但是执行IoCreateFile这个函数的时候,就蓝屏。 一直中断到内核函数内部。

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
最后于 2020-9-18 17:18
被Adventure编辑
,原因: 添加附件