首页
社区
课程
招聘
第一次发帖,驱动Fuzz程序[持续开发完善中]
发表于: 2013-3-5 22:11 17163

第一次发帖,驱动Fuzz程序[持续开发完善中]

2013-3-5 22:11
17163
看雪的号注册了将近4年,不过从来没在这里发过帖子,实在是遗憾。因为个人技术成长路线的选择,当初没有选择直接杀入安全领域,但是业余一直都在做这方面的事情。开发出身,当年的想法是先走开发,因为觉得开发是作为一个计算机从业者的必备的基本能力,等开发的功底积累的差不多了再转型专攻安全领域应该是比较不错的发展路线,而周围几乎清一色的好朋友都是直接踏上了安全的不归路。走到现在,觉得该转型了,这两天就做了一些尝试,想在公司内部转岗去做安全,可是却被公司的一些硬性规定阻拦了,有点失落。

但是终归说不是因为能力的原因,我也只能静静的等待了,等到我的个人条件达到了我还是要勇敢的朝着安全的道路前进的。

第一篇帖子不知道该发什么内容好,发一些奇技淫巧的小技术在这里也只能让各位大牛觉得陈芝麻烂谷子了,所以就把最近在做的一个小的项目拿出来跟大家分享一下。

看过张东辉写的各种0Day挖掘的文章资料,其中有讲Fuzzer工具的开发,于是就整理了一下资料里所介绍的Fuzz工具的原理,决定自己实现一个Fuzz工具,但是真正实现起来的时候发现文中所讲的MITM中间人Fuzz工具的逻辑实现有点问题,比如说MITM Fuzz中主要以Process Name或者PID,DeviceName或者DriverName,IoControlCode三个因素作为一个Fuzz条目,但是如果有两个Fuzz条目都具有一个相同要素(比如PID),而其他两个要素不同,那在做Fuzz的时候到底要以哪个Fuzz条目为准来进行Fuzz呢?思考了很久,最初决定配个优先级,后来觉得这个问题属于同质化的工作,个人觉得MITM原理是否可以再简化一下呢?所以直接导致我的Fuzz工具走向了Driver Fuzz的分支。

TsFuzzer的设计思路:
驱动层TsFuzzerk.sys
1.InlineHook NtDeviceIoControlFile函数(必须的...)
2.用一个单链表维护所有的Fuzz Item
3.通过IoControlCode对应用层提供Fuzz Item链表的管理维护,以及Fuzz功能的开关
其中Fuzz Item根据Device Name作为索引,
可以进行的Fuzz的参数包括InputBuffer的内容和InputBuffer的长度,
Fuzz的方式有随机,固定值,保持不变三种。

应用层TsFuzzer
用WTL框架实现一个GUI的管理控制界面,与TsFuzzerk.sys进行通信。

目前的大致思路就是这样的,开发进度是TsFuzzerk的基本框架已经搭建完毕,并且实现了一个Console的应用层测试程序。

在这里贴出Fuzz处理函数的实现:
/********************************************************************
  created:  2013/02/26
  created:  25:2:2013   20:29
  filename:   h:\TsFuzzerk\TsFuzzerk\TsFuzzerkFuzzHandler.cpp
  file path:  h:\TsFuzzerk\TsFuzzerk
  file base:  TsFuzzerkFuzzHandler
  file ext:  cpp
  author:    tishion@163.com
  
  purpose:  The implementation of fuzz handler
*********************************************************************/
#include "TsFuzzerk.h"
#include "SysTypedef.h"
#include "TsFuzzerkFuzzItemList.h"

extern PVOID
g_pNtDeviceIoControlFile;

extern CTsFuzzerkFuzzItemList* 
g_pFuzzItemList;

/*
 * A stub to jmp to the original NtDeviceIoControlFile function after we
 * made it into our fake function.
 */
NTSTATUS __declspec(naked) NtDeviceIoControlFile_Stub(
  IN HANDLE  FileHandle,
  IN HANDLE  Event,
  IN PIO_APC_ROUTINE  ApcRoutine,
  IN PVOID  ApcContext,
  OUT PIO_STATUS_BLOCK  IoStatusBlock,
  IN ULONG  IoControlCode,
  IN PVOID  InputBuffer,
  IN ULONG  InputBufferLength,
  OUT PVOID  OutputBuffer,
  IN ULONG  OutputBufferLength)
{
  _asm
  {
    mov    edi, edi
    push  ebp
    mov    ebp, esp
    mov    eax, g_pNtDeviceIoControlFile
    add    eax, 5
    jmp    eax 
  }
}


#define _MAX_NAME_STRING 1024/sizeof(WCHAR)  
typedef struct _NAME_STRING {  
  UNICODE_STRING Name;  
  WCHAR     Buffer[_MAX_NAME_STRING];  
} NAME_STRING, *PNAME_STRING;   


//PsGetProcessPeb 取得指定EPROCESS的Peb地址
typedef PPEB (__stdcall *FUNP_PSGETPROCESSPEB)(PEPROCESS pEProcess);
PPEB PsGetProcessPebWrapper(PEPROCESS pEProcess)
{
  UNICODE_STRING ustrFunName;
  FUNP_PSGETPROCESSPEB fpPsGetProcessPeb = NULL;

  RtlInitUnicodeString(&ustrFunName, (PWCHAR)L"PsGetProcessPeb");
  fpPsGetProcessPeb = (FUNP_PSGETPROCESSPEB)MmGetSystemRoutineAddress(&ustrFunName);
  if (fpPsGetProcessPeb == NULL) 
  {
    return NULL;
  }

  return fpPsGetProcessPeb(pEProcess);
}

#define STRING_POOL_BUFFER_LEN  512*1024
CHAR g_Format[] = {
  "[=======================================TsFuzzer=======================================]\n" \
  "\tProcess:%wZ PID:0x%08X\n" \
  "\tDevice:%wZ Driver:%wZ\n" \
  "\tIOCTL Code:0x%08X Method:%s\n" \
  "\t++++++Parameters Before Fuzz+++++\n" \
  "\tIBuffer:0x%08X Length:0x%08X\n" \
  "\tOBuffer:0x%08X Length:0x%08X\n" \
  "\tInput Data:"
};

CHAR g_Format_after[] = {
  "\t------Parameters After Fuzz------\n" \
  "\tIBuffer:0x%08X Length:0x%08X\n" \
  "\tOBuffer:0x%08X Length:0x%08X\n" \
  "\tInput Data:"
};

PCHAR g_IoMethod[] = {
  "METHOD_BUFFERED",         // 0
  "METHOD_IN_DIRECT",              // 1
  "METHOD_OUT_DIRECT",             // 2
  "METHOD_NEITHER",                // 3
};

NTSTATUS Fake_NtDeviceIoControlFile(
                  IN HANDLE  FileHandle,
                  IN HANDLE  Event,
                  IN PIO_APC_ROUTINE  ApcRoutine,
                  IN PVOID  ApcContext,
                  OUT PIO_STATUS_BLOCK  IoStatusBlock,
                  IN ULONG  IoControlCode,
                  IN PVOID  InputBuffer,
                  IN ULONG  InputBufferLength,
                  OUT PVOID  OutputBuffer,
                  IN ULONG  OutputBufferLength)
{
  NTSTATUS status = STATUS_SUCCESS;
  //KdPrint(("[TsFuzzerk]:++++Fake_NtDeviceIoControlFile()\n"));

  ULONG ulControlCode = 0;
  ULONG ulPid = 0;

  NAME_STRING ImageName;
  ImageName.Name.Buffer = ImageName.Buffer;  
  ImageName.Name.Length = 0;  
  ImageName.Name.MaximumLength = sizeof(ImageName.Buffer);  

  NAME_STRING devName;
  devName.Name.Buffer = devName.Buffer;  
  devName.Name.Length = 0;  
  devName.Name.MaximumLength = sizeof(devName.Buffer);  

  NAME_STRING drvPath;
  drvPath.Name.Buffer = drvPath.Buffer;  
  drvPath.Name.Length = 0;  
  drvPath.Name.MaximumLength = sizeof(drvPath.Buffer);  

  // 获取DeviceName DriverName DriverPath
  PFILE_OBJECT pFileObject = NULL;

  ULONG ulReturnedLength = 0;

  status = ObReferenceObjectByHandle(
    FileHandle, 
    STANDARD_RIGHTS_ALL, 
    *IoFileObjectType, 
    KernelMode, 
    (PVOID*)&pFileObject, 
    NULL);

  if (NT_SUCCESS(status))
  {
    status = ObQueryNameString(
      pFileObject->DeviceObject, 
      (POBJECT_NAME_INFORMATION)&devName, 
      devName.Name.MaximumLength, 
      &ulReturnedLength);

    if (!NT_SUCCESS(status))
    {
      RtlStringCchPrintfW(devName.Buffer, _MAX_NAME_STRING, L"Unknown");
      RtlInitUnicodeString(&(devName.Name), devName.Buffer);
    }

    PLDR_DATA_TABLE_ENTRY pLdr = (PLDR_DATA_TABLE_ENTRY)
      (pFileObject->DeviceObject->DriverObject->DriverSection);
    if (NULL != pLdr && NULL != pLdr->FullDllName.Buffer && 0 != pLdr->FullDllName.Length)
    {
      RtlCopyUnicodeString(&(drvPath.Name), &(pLdr->FullDllName));
    }
    else
    {
      RtlStringCchPrintfW(drvPath.Buffer, _MAX_NAME_STRING, L"Unknown");
      RtlInitUnicodeString(&(drvPath.Name), drvPath.Buffer);
    }

    ObDereferenceObject(pFileObject);
  }

  PFUZZ_ITEM pFuzzListItem = g_pFuzzItemList->GetItemByDeviceName(&(devName.Name));

  if (NULL != pFuzzListItem)
  {
    // 获取IoControlCode
    ulControlCode = IoControlCode;

    if ((0 == pFuzzListItem->IoControlCode) || (ulControlCode == pFuzzListItem->IoControlCode))
    {
      // 获取进程镜像文件路径和PID
      ulPid = (ULONG)PsGetCurrentProcessId();

      PPEB pPeb = NULL;
      PEPROCESS pEprocess = NULL;
      pEprocess = PsGetCurrentProcess();
      if (NULL != pEprocess)
      {
        pPeb = PsGetProcessPebWrapper(pEprocess);
        if (NULL != pPeb)
        {
          RtlCopyUnicodeString(&(ImageName.Name), &(pPeb->ProcessParameters->ImagePathName));
        }
        else
        {
          RtlStringCchPrintfW(ImageName.Buffer, _MAX_NAME_STRING, L"Unknown");
          RtlInitUnicodeString(&(ImageName.Name), ImageName.Buffer);
        }
      }

      PCHAR pszStringBuffer = (PCHAR)ExAllocatePoolWithTag(
        NonPagedPool, STRING_POOL_BUFFER_LEN, 'FUBS');

      if (NULL != pszStringBuffer)
      {
        RtlStringCchPrintfA(pszStringBuffer, STRING_POOL_BUFFER_LEN, g_Format,
          &(ImageName.Name), ulPid, 
          &(devName.Name), &(drvPath.Name), 
          ulControlCode, g_IoMethod[METHOD_FROM_CTL_CODE(ulControlCode)],
          InputBuffer, InputBufferLength,
          OutputBuffer, OutputBufferLength);
      }

      ULONG ulDataStringLength = (InputBufferLength * 4);
      ulDataStringLength = ulDataStringLength + (((InputBufferLength / 0x10) + 1) * 0x10);

      PCHAR pszDataBuffer = (PCHAR)ExAllocatePoolWithTag(
        NonPagedPool, ulDataStringLength, 'FUBD');

      if (pszDataBuffer != NULL)
      {
        pszDataBuffer[0] = '\0';

        CHAR ByteData[] = {"00  "};
        CHAR AddressData[] = {"00000000  "};

        PUCHAR pInputBuffer = (PUCHAR)InputBuffer;

        for (ULONG i = 0; i < InputBufferLength; i++)
        {
          if (0 == i % 0x10)
          {
            RtlStringCchCatA(pszDataBuffer, ulDataStringLength, "\n\t");
            RtlStringCchPrintfA(AddressData, sizeof(AddressData), "%08x  ", (ULONG)InputBuffer + i);
            RtlStringCchCatA(pszDataBuffer, ulDataStringLength, AddressData);
          }

          RtlStringCchPrintfA(ByteData, sizeof(ByteData), "%02X ", pInputBuffer[i]);
          RtlStringCchCatA(pszDataBuffer, ulDataStringLength, ByteData);
        }

        RtlStringCchCatA(pszDataBuffer, ulDataStringLength, "\n");
      }

      DbgPrint(pszStringBuffer);
      DbgPrint(pszDataBuffer);


      // 在此处进行参数Fuzz
      if (FuzzMethod_FillWithRandomData == pFuzzListItem->fmInputBuffer)
      {
        LARGE_INTEGER liSystemTime;
        KeQuerySystemTime(&liSystemTime);
        for (ULONG i = 0; i < InputBufferLength / sizeof(ULONG); i++)
        {
          ((PULONG)InputBuffer)[i] = RtlRandomEx(&(liSystemTime.LowPart));
        }
      }
      else if (FuzzMethod_FillWithFixedDWord == pFuzzListItem->fmInputBuffer)
      {
        for (ULONG i = 0; i < InputBufferLength / sizeof(ULONG); i++)
        {
          ((PULONG)InputBuffer)[i] = pFuzzListItem->FixedDWord;
        }
      }

      if (pszDataBuffer != NULL)
      {
        pszDataBuffer[0] = '\0';

        CHAR ByteData[] = {"00  "};
        CHAR AddressData[] = {"00000000  "};

        PUCHAR pInputBuffer = (PUCHAR)InputBuffer;

        for (ULONG i = 0; i < InputBufferLength; i++)
        {
          if (0 == i % 0x10)
          {
            RtlStringCchCatA(pszDataBuffer, ulDataStringLength, "\n\t");
            RtlStringCchPrintfA(AddressData, sizeof(AddressData), "%08x  ", (ULONG)InputBuffer + i);
            RtlStringCchCatA(pszDataBuffer, ulDataStringLength, AddressData);
          }

          RtlStringCchPrintfA(ByteData, sizeof(ByteData), "%02X ", pInputBuffer[i]);
          RtlStringCchCatA(pszDataBuffer, ulDataStringLength, ByteData);
        }

        RtlStringCchCatA(pszDataBuffer, ulDataStringLength, "\n");
      }

      if (FuzzMethod_ReplaceByRandomLength == pFuzzListItem->fmInputLength)
      {
        LARGE_INTEGER liSystemTime;
        KeQuerySystemTime(&liSystemTime);
        InputBufferLength = RtlRandomEx(&(liSystemTime.LowPart));
      }
      else if (FuzzMethod_ReplaceByFixedLength == pFuzzListItem->fmInputLength)
      {
        InputBufferLength = pFuzzListItem->FixedLength;
      }

      if (NULL != pszStringBuffer)
      {
        RtlStringCchPrintfA(pszStringBuffer, STRING_POOL_BUFFER_LEN, g_Format_after,
          InputBuffer, InputBufferLength,
          OutputBuffer, OutputBufferLength);
      }

      DbgPrint(pszStringBuffer);
      DbgPrint(pszDataBuffer);

      if (NULL != pszStringBuffer)
      {
        ExFreePoolWithTag(pszStringBuffer, 'FUBS');
      }

      if (NULL != pszDataBuffer)
      {
        ExFreePoolWithTag(pszDataBuffer, 'FUBD');
      }
    }
  }

  status = NtDeviceIoControlFile_Stub(
    FileHandle,
    Event,
    ApcRoutine,
    ApcContext,
    IoStatusBlock,
    IoControlCode,
    InputBuffer,
    InputBufferLength,
    OutputBuffer,
    OutputBufferLength);

  //KdPrint(("[TsFuzzerk]:----Fake_NtDeviceIoControlFile()\n"));

  return status;
}


程序还有很多可以挑剔的地方,不足之处只能慢慢来弥补,在开发到现在的进度之后我拿出了IOCTL_Fuzzer的源码来对比参考,看完之后瞬间觉得自己的代码写的太无脑了,没有考虑到的问题太多了!!!就拿上述代码中的Fake_NtDeviceIoControlFile中没有考虑KerneMode和UserMode变换,再比如在Hook的时候没有考虑到去从原始Image文件获取目标函数地址等等。看来自己在驱动开发的道路上还有很大的学习空间,只能加油了。不过作为一个开发出身的人,在代码风格和文件模块划分上自认为还是比较规范的。



================工程文件==========

TsFuzzerk.zip

TsFuzzerTest.zip

可能下一次发篇文章介绍visual studio 2008 + WDK搭建驱动开发环境,敬请期待。

[课程]Linux pwn 探索篇!

上传的附件:
收藏
免费 6
支持
分享
最新回复 (21)
雪    币: 1015
活跃值: (235)
能力值: ( LV12,RANK:440 )
在线值:
发帖
回帖
粉丝
2
沙发,坐等加精!
2013-3-5 22:14
0
雪    币: 71
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
vkl
3
感谢楼主分享
期待下一篇文章早点完成
2013-3-5 22:16
0
雪    币: 496
活跃值: (286)
能力值: ( LV13,RANK:400 )
在线值:
发帖
回帖
粉丝
4
loong哥。。这个怕精不了的,因为内容很普通的。
2013-3-5 22:18
0
雪    币: 496
活跃值: (286)
能力值: ( LV13,RANK:400 )
在线值:
发帖
回帖
粉丝
5
好的,最迟这周发出!
2013-3-5 22:28
0
雪    币: 967
活跃值: (1138)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
6
没有仔细看!貌似是截取应用程序和驱动通信的数据吧

为什么不在应用程序实现啊 !为什么要用驱动啊
HOOK CreateFileA/CreateFileW DeviceIoControl 等函数不好使吗? 并且应用层传入的数据 一半要dump出来啊 而不是打印就ok的
2013-3-5 22:42
0
雪    币: 967
活跃值: (1138)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
7
说句是在乎!要开发一个稳定的东西是不容易的!特别是驱动,要在各种环境中跑,2000,xp,2003,vista,win7 并且还要测试杀毒软件
所以 个人认为能不用驱动,就尽量不用,起码给用户的风险降到最低
2013-3-5 22:48
0
雪    币: 496
活跃值: (286)
能力值: ( LV13,RANK:400 )
在线值:
发帖
回帖
粉丝
8
这个确实是不完善的地方,不过你所说的dump是指在发生异常导致系统Crash的时候转储dump么?还是说数据要按照一定的格式显示到指定的地方?如果是前者的话,现在是没有做的,现在的使用方法是依赖Windbg来捕获异常,然后后分析。
如果是后者的话,dump数据我现在只是将数值打印出来了,并没有做其他的复杂呈现。我这个代码从功能上来说自我评价是一坨屎一样的代码。。



这个是对的,驱动最重要一点的就是稳定性,因为关乎整个系统的稳定,所以我在做一些驱动的时候都是极力的避免去使用一些undocumented的函数或者数据类型等。

如果Fuzz程序在应用层实现的话,那就只能针对特定进程来进行Fuzz了,特定的驱动可能只会跟一种程序打交道,还有一些驱动要跟很多不同种类的进程打交道,而Fuzz程序的本来就相当于对目标驱动进行灰盒测试,测试的数据大多都是测试者所不明的,所以为了尽可能的截获所有数据并对其进行畸形化,个人觉得还是在内核层实现比较好,这样可以提高数据来源的数量,从而提高找到漏洞的几率。
2013-3-5 23:14
0
雪    币: 2177
活跃值: (2045)
能力值: (RANK:400 )
在线值:
发帖
回帖
粉丝
9
图片挂了,帮楼主补上了,希望后期能继续完善。
2013-3-6 11:49
0
雪    币: 106
活跃值: (40)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
10
感谢LZ分享。建议LZ可以区分一下METHOD_BUFFER和METHOD_NEITHER,针对这两种进行不同的策略,可以避免一些无用功。
2013-3-6 12:07
0
雪    币: 12
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
牛人,mark一下,留下学习
2013-3-6 14:29
0
雪    币: 190
活跃值: (40)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
12
牛人啊,还没搞过驱动呢
2013-3-6 17:08
0
雪    币: 341
活跃值: (138)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
13
期待下一篇。。期待新手教学。。。
2013-3-6 22:12
0
雪    币: 297
活跃值: (120)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
14
现在很多东西,不到驱动层根本实现不了,不是我们非要用驱动,是被杀软逼的非到驱动不可!
2013-3-7 00:31
0
雪    币: 29
活跃值: (131)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
期待楼主的更新,也希望楼主可以把这个项目变成一个开源的项目,如果有兴趣的兄弟们可以一起来完成!
2013-3-7 09:22
0
雪    币: 320
活跃值: (183)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
16
mark 支持一下
2013-3-7 18:08
0
雪    币: 494
活跃值: (15)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
牛人么,进这个群,

学习群
190441605  安全技术学习交流 漏洞分析与发掘。

来教我们呀。
2013-3-8 10:31
0
雪    币: 494
活跃值: (15)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
楼主资料放出呀,我们也学习下,
资料好难找呀。
我就有一本王清的0day安全里面有一点介绍漏洞挖掘,其他地方都没见到,都是分析...
2013-3-8 10:35
0
雪    币: 93908
活跃值: (200199)
能力值: (RANK:10 )
在线值:
发帖
回帖
粉丝
19
Thanks for share.
2013-3-10 14:16
0
雪    币: 334
活跃值: (92)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
20
我也正在堆代码写一个类似的工具,楼主的东西可以参考一下。
2013-9-10 13:39
0
雪    币: 43
活跃值: (35)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21
更新了吗?
2014-4-10 10:56
0
雪    币: 71
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
22
好文章啊!期待楼主更多东西!
2014-4-10 11:00
0
游客
登录 | 注册 方可回帖
返回
//