一直以来内核漏洞安全给很多人的印象就是:难,枯燥。但是内核安全是否掌握是衡量一个系统安全工程师水平的标准之一,也是安全从业人员都应该掌握的基本功。本文通过详细的实例带领读者走进内核安全的大门。难度系数:四颗星

原文地址:https://hshrzd.wordpress.com/2017/06/05/starting-with-windows-kernel-exploitation-part-2/

由prison翻译整理,首发i春秋。

本文默认读者已经配置好了基本实验环境,因为环境配置网络上有大量详细资源,在此编者不再单独成文介绍环境。此文章供参考:https://hshrzd.wordpress.com/201 … setting-up-the-lab/

1.本文所使用的环境:

§  环境配置 the previous part

§  HackSys Extreme Vulnerable Driver(HEVD) – prebuild version + the source code

§  OSR Driver Loader

§  DebugView (from SysInternals Suite)

§  Visual Studio 2012 (版本随意)

安装并测试HEVD首先,我将展示如何安装HEVD。我们将会配置Debugee和调试器,以查看调试字符串和HEVD的符号。我们也会用一些专用的漏洞来玩。

油管视频(我也很无奈啊~):

查看调试字符串HEVD和一些专门的行为利用了大量的信息作为调试字符串。我们可以从调试器(使用WinDbg)和被调试程序(使用调试器)来观察它们。

安装HEVD之前,我们将设着一些内容来查看驱动程序初始化期间打印的字符串。


在调试器上:为了获得kd标识,我们需要中断调试器的执行(WinDbg->Debug->Break)。然后,我们可以通过命令打印调试字符串:

ed nt!Kd_Default_Mask 8

之后,我们可以通过执行命令进一步运行调试器:

g
Warning: Enabling this slows down the Debugee. So, whenever possible, try to watch DebugStrings locally (on the Debugee only).

这个警告大概是说这个命令会减慢调试器的速度,所以优先选择在本地仅在被调试程序上观察调试字符。

在被调试程序上:

我们需要以管理员身份运行DebugView。然后我们从菜单中依次选择:

Capture->Capture Kernel

安装驱动程序首先,我们将在被调试方(靶机)上下载预构建包(驱动程序+exploit)安装并且进行测试。我们可以在GitHub上找到HackSysTem,https://github.com/hacksysteam/HackSy**tremeVulnerableDriver/releases

这个包包含两个易受攻击的版本的驱动程序,我们将选一个比较脆皮的进行构建(

32位i386)

我们选择自启动。然后我们点击[RegisterService]成功后点击[StartService]

我们应该可以在调试方的WinDbg和靶机的WbgView上看到打印出的HEVD

添加标识符HEVD的预编译包带有符号(sdb文件),我们还可以将其添加到调试器中。首先,我们通过发送一个中断信号来停止调试器,并查看所有已加载的模块。

我们可以设置一个过滤器来找到HEVD模块

lm m H*

我们可以看到它没有任何标识符,我们可以很容易的将其固定。首先,打开:

!sym_noisy

–用来打印所有和WinDbg引用路径的信息以找到标识符。然后试着重载这些标识符:

.reload

再试着再次提引用。你将看到路径,我们可以复制pdb文件。在将pdb文件移动到调试器机器上的适当位置之后,再次重载标识符。你可以试着打印HEVD的所有功能来进行测试。

x HEVD!*利用测试同一个包中还包含了一组专用的漏洞。我们可以通过执行一个适当的命令来运行它们。我们来尝试进行一些部署,并执行cmd.exe

池溢出利用部署:

如果利用成功,请求的应用程序将会被部署到更高的权限。

通过命令:

whoami

我们可以确定,它的权限升高。

与此同时,我们可以调试机上看到由expolit打印的调试字符串:

所有的攻击,除了双重取回,都应该在一个核心上运行良好。如果我们想要利用这个,则需要在调试器机器上启用两个核心。

警告:有些exp并不是100%可靠的,我们在部署它们之后可能会遇到系统崩溃。别担心,一切不以格盘为目的的崩溃信息都是纸老虎。

与驱动进行一场扎心的交流就像在用户层的情况下一样,在内核方面的开发利用中,从寻找点开始,我们可以为程序提供一个输入。然后,我们需要找到能够破坏执行的输入(与用户层相反——在内核层面上,崩溃将直接导致蓝屏!)最后,我们将尝试以一种控制脆弱程序执行的方式来构造输入。

为了与来自用户模式的驱动程序进行通信,我们将发送一些IOCTL-输入-输出控制。IOCTL允许我们从用户向驱动程序发送一些内容到缓冲区。这是我们可以尝试利用的点。

HEVD包含各种各样的漏洞的演示。每一个都可以使用不同的IOCTL触发,并被所提供的缓冲区所利用。有些(但不是全部)会导致系统在触发时崩溃。

查找设备名称和IOCTL

在我们尝试与设备连接之前,我们需要知道两件事:

驱动程序创建的设备(如果它不创建任何东西,我们将无法进行通信)

驱动程序接受的IOCTL(输入-输出控制)列表

HEVD是开源的,因此我们可以直接从源代码中读取所有必需的数据。在黑盒测试过程中,我们可能要通过逆向驱动程序来读取所需数据。

让我们来看看HEVD创建一个设备的代码片段。

https://github.com/hacksysteam/HackSy**tremeVulnerableDriver/blob/master/Driver/HackSy**tremeVulnerableDriver.c#L79

上面提到了这个设备的名称。

现在,我们通过从IRP数组来找IOCTL列表

连接到IRP_MJ_DEVICE_CONTOL的函数将会分配IOCTL发送给驱动程序。所以,我们需要看一下这个函数。

https://github.com/hacksysteam/HackSy**tremeVulnerableDriver/blob/master/Driver/HackSy**tremeVulnerableDriver.c#L193

这里有一个switch循环,调用一个特定的处理IOCTL的函数,我们可以对这些switch的case进行转换以获取我们所需要的IOCTL列表。常量的值在header中被忽视。

https://github.com/hacksysteam/HackSy**tremeVulnerableDriver/blob/master/Driver/HackSy**tremeVulnerableDriver.h#L57

编写一个客户端应用程序

好的,我们现在已经搞到了所有需要用到的数据,我们可以用我们自己的程序与驱动程序进行通信。我们可以把它们放在头文件中,也就是:hevd_constants.h

#pragma once
#include <windows.h>
 
const char kDevName[] = "\\\\.\\HackSy**tremeVulnerableDriver";
 
#define HACKSYS_EVD_IOCTL_STACK_OVERFLOW                  CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_NEITHER, FILE_ANY_ACCESS)
#define HACKSYS_EVD_IOCTL_STACK_OVERFLOW_GS               CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_NEITHER, FILE_ANY_ACCESS)
#define HACKSYS_EVD_IOCTL_ARBITRARY_OVERWRITE             CTL_CODE(FILE_DEVICE_UNKNOWN, 0x802, METHOD_NEITHER, FILE_ANY_ACCESS)
#define HACKSYS_EVD_IOCTL_POOL_OVERFLOW                   CTL_CODE(FILE_DEVICE_UNKNOWN, 0x803, METHOD_NEITHER, FILE_ANY_ACCESS)
#define HACKSYS_EVD_IOCTL_ALLOCATE_UAF_OBJECT             CTL_CODE(FILE_DEVICE_UNKNOWN, 0x804, METHOD_NEITHER, FILE_ANY_ACCESS)
#define HACKSYS_EVD_IOCTL_USE_UAF_OBJECT                  CTL_CODE(FILE_DEVICE_UNKNOWN, 0x805, METHOD_NEITHER, FILE_ANY_ACCESS)
#define HACKSYS_EVD_IOCTL_FREE_UAF_OBJECT                 CTL_CODE(FILE_DEVICE_UNKNOWN, 0x806, METHOD_NEITHER, FILE_ANY_ACCESS)
#define HACKSYS_EVD_IOCTL_ALLOCATE_FAKE_OBJECT            CTL_CODE(FILE_DEVICE_UNKNOWN, 0x807, METHOD_NEITHER, FILE_ANY_ACCESS)
#define HACKSYS_EVD_IOCTL_TYPE_CONFUSION                  CTL_CODE(FILE_DEVICE_UNKNOWN, 0x808, METHOD_NEITHER, FILE_ANY_ACCESS)
#define HACKSYS_EVD_IOCTL_INTEGER_OVERFLOW                CTL_CODE(FILE_DEVICE_UNKNOWN, 0x809, METHOD_NEITHER, FILE_ANY_ACCESS)
#define HACKSYS_EVD_IOCTL_NULL_POINTER_DEREFERENCE        CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80A, METHOD_NEITHER, FILE_ANY_ACCESS)
#define HACKSYS_EVD_IOCTL_UNINITIALIZED_STACK_VARIABLE    CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80B, METHOD_NEITHER, FILE_ANY_ACCESS)
#define HACKSYS_EVD_IOCTL_UNINITIALIZED_HEAP_VARIABLE     CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80C, METHOD_NEITHER, FILE_ANY_ACCESS)
#define HACKSYS_EVD_IOCTL_DOUBLE_FETCH                    CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80D, METHOD_NEITHER, FILE_ANY_ACCESS)

IOCTL的数目是由一个标准的Windows头文件winioctl.h中定义的宏所创建的。

如果你引用了windows.h文件,上面的宏将被自动添加。现在,我们不需要操心特定常量的含义——我们只需要使用已定义的元素就可以了。

因此,我们准备编写一个简单的用户层应用程序,该应用程序将与驱动程序进行对话。首先,我们使用函数CreateFile打开设备。然后,我们可以使用DeviceIoControl.来发送IOCTL。

下面你可以看到一个小例子。这个应用程序将STACK_OVERFLOWIOCTL 发送给驱动程序: send_ioctl.cpp

#include <stdio.h>
#include <windows.h>
 
#define HACKSYS_EVD_IOCTL_STACK_OVERFLOW    CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_NEITHER, FILE_ANY_ACCESS)
 
const char kDevName[] = "\\\\.\\HackSy**tremeVulnerableDriver";
 
HANDLE open_device(const char* device_name)
{
    HANDLE device = CreateFileA(device_name,
        GENERIC_READ | GENERIC_WRITE,
        NULL,
        NULL,
        OPEN_EXISTING,
        NULL,
        NULL
    );
    return device;
}
 
void close_device(HANDLE device)
{
    CloseHandle(device);
}
 
BOOL send_ioctl(HANDLE device, DWORD ioctl_code)
{
    //prepare input buffer:
    DWORD bufSize = 0x4;
    BYTE* inBuffer = (BYTE*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, bufSize);
 
    //fill the buffer with some content:
    RtlFillMemory(inBuffer, bufSize, 'A');
 
    DWORD size_returned = 0;
    BOOL is_ok = DeviceIoControl(device,
        ioctl_code,
        inBuffer,
        bufSize,
        NULL, //outBuffer -> None
        0, //outBuffer size -> 0
        &size_returned,
        NULL
    );
    //release the input bufffer:
    HeapFree(GetProcessHeap(), 0, (LPVOID)inBuffer);
    return is_ok;
}
 
int main()
{
    HANDLE dev = open_device(kDevName);
    if (dev == INVALID_HANDLE_VALUE) {
        printf("Failed!\n");
        system("pause");
        return -1;
    }
 
    send_ioctl(dev, HACKSYS_EVD_IOCTL_STACK_OVERFLOW);
 
    close_device(dev);
    system("pause");
    return 0;
}

尝试编译这个程序并将其部署到靶机上。启动DebugView观察由驱动程序打印的调试字符串。

你可能看到类似输出:

你懂得~

以下为作者福利:

练习,让我们一起搞波事情~

我在HEVD创建了一个小客户端,你可以在这看到源代码:

https://github.com/hasherezade/wke_exercises/tree/master/task1

编译后的32位二进制文件: here.

试着玩各种不同的IOCTL,直到你成功。因为Debugee在调试器的控制下运行,你不会出现蓝幕——相反,WinDbg会被触发。试着对每一个案例做一个简短的崩溃分析。从打印信息开始:

!analyze -v其他一些有用的命令:

k - stack trace
kb - stack trace with parameters
r - registers
dd [address]- display data as DWORD starting from the address

要了解更多,请参阅“WinDbg”帮助文件:

.hh

在我们的示例应用程序中,用户缓冲区填满了“A”-ASCII 0×41

https://github.com/hasherezade/wke_exercises/blob/master/task1/src/main.cpp#L34

RtlFillMemory(inBuffer, bufSize, 'A');

油管示例:

Example #1

https://www.youtube.com/watch?v=lw7vMrkeTpY

Example #2

https://www.youtube.com/watch?v=YV0IqXEUf5s

请注意,触发相同的漏洞可能会给您带来不同的输出,这取决于崩溃的直接原因,这与溢出的大小、内存的当前布局等有关。

内核漏洞学习—熟悉HEVD的更多相关文章

  1. 【翻译】 Windows 内核漏洞学习—空指针解引用

    Windows Kernel Exploitation – NullPointer Dereference 原文地址:https://osandamalith.com/2017/06/22/windo ...

  2. Windows 内核漏洞学习—空指针解引用

    原标题:Windows Kernel Exploitation – NullPointer Dereference 原文地址:https://osandamalith.com/2017/06/22/w ...

  3. Linux kernel pwn notes(内核漏洞利用学习)

    前言 对这段时间学习的 linux 内核中的一些简单的利用技术做一个记录,如有差错,请见谅. 相关的文件 https://gitee.com/hac425/kernel_ctf 相关引用已在文中进行了 ...

  4. CVE-2014-0038内核漏洞原理与本地提权利用代码实现分析 作者:seteuid0

    关键字:CVE-2014-0038,内核漏洞,POC,利用代码,本地提权,提权,exploit,cve analysis, privilege escalation, cve, kernel vuln ...

  5. 初识linux内核漏洞利用

    0x00 简介 之前只接触过应用层的漏洞利用, 这次第一次接触到内核层次的,小结一下. 0x01 概况 这次接触到的,是吾爱破解挑战赛里的一个题,给了一个有问题的驱动程序,要求在ubuntu 14.0 ...

  6. PWN二进制漏洞学习指南

    目录 PWN二进制漏洞学习指南 前言 前置技能 PWN概念 概述 发音 术语 PWN环境搭建 PWN知识学习途径 常见漏洞 安全机制 PWN技巧 PWN相关资源博客 Pwn菜鸡小分队 PWN二进制漏洞 ...

  7. Linux内核ROP学习

    0x00 前言 1.SMEP(Supervisor Mode Execution Protection):一种减缓内核利用的cpu策略,禁止内核态到用户态内存页的代码执行(32位的addresses ...

  8. XSS漏洞学习笔记

    XSS漏洞学习 简介 xss漏洞,英文名为cross site scripting. xss最大的特点就是能注入恶意的代码到用户浏览器的网页上,从而达到劫持用户会话的目的. 说白了就是想尽办法让你加载 ...

  9. Fibratus:一款功能强大的Windows内核漏洞利用和跟踪工具

    今天给大家介绍的是一款名叫Fibratus的开源工具,广大研究人员可以使用这款功能强大的工具来进行Windows内核漏洞利用.挖掘与跟踪. Fibratus这款工具能够捕捉到绝大多数的Windows内 ...

随机推荐

  1. Codeforces 665A. Buses Between Cities 模拟

    A. Buses Between Cities time limit per test: 1 second memory  limit per test: 256 megabytes input: s ...

  2. CreateThread

    CreateThread(NULL,0,ReportResultThread,this,0,&g_dwThreadId) 2. 参数说明: 第一个参数 lpThreadAttributes 表 ...

  3. Laravel框架中实现supervisor执行异步进程

    问题描述:在使用Laravel框架实现动态网页时,若有些操作计算量较大,为了不影响用户体验,往往需要使用异步方式去处理.这里使用supervisor和laravel自带的queues实现. Super ...

  4. RSA生成、加密、解密、签名。

    首先,要会生成RSA密码对. https://app.alipay.com/market/document.htm?name=saomazhifu#page-23    (事例中的密钥对好像有问题,最 ...

  5. 想到的regular方法果然已经被sklearn实现了就是L1和L2组合rugular

  6. 树结构(三)----平衡二叉树(AVL树)

    将二叉排序树的的缺点优化,继承二叉排序的树的优化 左子树和右子树的高度差的绝对值不超过1

  7. FreeTextBox备忘

    添加对4.0的dll文件引用 吧aspnet_client目录 copy到根目录下 设置文件上传目录属性ImageGalleryPath 设置相册属性到 ftb.imagegallery.aspx位置 ...

  8. 微信小程序底部导航Tabbar

    1,底部导航栏这个功能是非常常见的一个功能,基本上一个完成的app,都会存在一个导航栏,那么微信小程序的导航栏该怎么实现呢?经过无数的踩坑,终于实现了,好了,先看看效果图. 2,对于底部导航栏,小程序 ...

  9. webservice大文件怎么传输

    版权所有 2009-2018荆门泽优软件有限公司 保留所有权利 官方网站:http://www.ncmem.com/ 产品首页:http://www.ncmem.com/webapp/up6.2/in ...

  10. 反爬虫破解系列-汽车之家利用css样式替换文字破解方法

    网站: 汽车之家:http://club.autohome.com.cn/ 以论坛为例 反爬虫措施: 在论坛发布的贴子正文中随机抽取某几个字使用span标签代替,标签内容位空,但css样式显示为所代替 ...