Windows破绽应用技能:滥用用户形式调试器 | 申博官网
登录
  • 欢迎进入申博官网!
  • 如果您觉得申博官网对你有帮助,那么赶紧使用Ctrl+D 收藏申博官网并分享出去吧
  • 这里是申博官方网!
  • 申博官网是菲律宾sunbet官网品牌平台!
  • 申博开户专业品牌平台!

Windows破绽应用技能:滥用用户形式调试器

申博_新闻事件 申博 102次浏览 已收录 0个评论

申博网络安全巴士站

申博-网络安全巴士站是一个专注于网络安全、系统安全、互联网安全、信息安全,全新视界的互联网安全新媒体。

————————————-

 

媒介

近来,我一直在研讨如作甚NtObjectManager增加当地用户形式调试器支撑。每当我增加一个新功能时,我都必需举行一些研讨和逆向工程事情,以更好的明白其详细的事情体式格局。在这类情况下,我愿望晓得调试现有的正在运转的历程需要甚么级别的接见权限。另外,我还注重到用户形式API袒露的内容与内核现实实行的操纵之间存在一些安全性不婚配的题目,这异常值得存眷,浏览这些相干文档也异常主要。在这里,我将形貌的并非一个特定的安全破绽,而是一个通用的破绽应用技能,这一技能关于应用某些种别的破绽来讲异常具有资助,因而我也将其归结在我的“破绽应用技能”系列文章当中。

就本文而言,我们不盘算深入探讨用户形式的调试器是怎样事情的,若是列位读者想要相识更多,可以或许浏览Ionescu在12年前写的3份白皮书申报(1 ,2 ,3),这三份申报是针对Windows XP的,而且从当时最先,Windows体系的内部道理一直没有转变太多。鉴于这一视察效果,当我在Windows 10 1809上测试并纪录行动时,我确信这些手艺适用于初期版本的Windows。

附加到正在运转的历程

要在古代版本的Windows

NT上举行调试,需要基于Debug内核工具,我们可以或许经由过程挪用NtCreateDebugObject体系挪用来建立该工具。该工具将作为分派调试历程的“桥梁”,并守候返回调试事宜。Win32
API将会对用户隐蔽该工具的建立,每一个线程都具有其自身的调试工具,而且存储在其TEB中。

若是要附加到现有历程,可以或许挪用具有原型的Win32
API
DebugActiveProcess:

BOOL DebugActiveProcess(_In_ DWORD dwProcessId);

终究,挪用了当地API,NtDebugActiveProcess,它具有以下原型:

NTSTATUS NtDebugActiveProcess(
   _In_ HANDLE ProcessHandle,
   _In_ HANDLE DebugObjectHandle);

DebugObjectHandle来自TEB,但它需要的是历程句柄,而非PID,这将致使两个API的挪用语义不婚配。这意味着,Win32 API卖力翻开历程的句柄,然后将其通报给当地API。

当我看到如许的代码后,马上想到了一些题目,Win32

API需要甚么接见,随后内核API现实实行了甚么事情?这不仅仅是一个闲暇时的简朴思索,我们晓得,安全破绽往往会涌如今接口层之间不婚配的假定当中。我们有一个很好的例子,就是发明NTFS硬链接在运用CreateHardlink从Win32应用顺序建立时,需要写入接见权限。然则,内核API其实不需要任何接见权限(请参阅我的博客文章中,此处议论的硬链接题目),许可我们硬链接到可以或许为任何接见权限翻开的任何文件。要相识Win32

API和内核API实行的内容,我们需要检察反汇编顺序中的代码,或许检察Alex编写的原始代码,个中包罗代码RE’d。DebugActiveProcess中的代码将挪用一个资助顺序ProcessIdToHandle,以猎取以下所示的历程句柄:

HANDLE ProcessIdToHandle(DWORD dwProcessId) {
 NTSTATUS Status;
 OBJECT_ATTRIBUTES ObjectAttributes;
 CLIENT_ID ClientId;
 HANDLE ProcessHandle;
 DWORD DesiredAccess = PROCESS_CREATE_THREAD |
                       PROCESS_VM_OPERATION |
                       PROCESS_VM_READ |
                       PROCESS_VM_WRITE |
                       PROCESS_QUERY_INFORMATION |
                       PROCESS_SUSPEND_RESUME;
 
 ClientId.UniqueProcess = dwProcessId;
 InitializeObjectAttributes(&ObjectAttributes, NULL, ...)
 
 Status = NtOpenProcess(&ProcessHandle,
                        DesiredAccess,
                        &ObjectAttributes,
                        &ClientId);
 if (NT_SUCCESS(Status))
   return ProcessHandle;
 BaseSetLastNTError(Status);
 return NULL;
}

上面的代码看上去没有太大的题目,其PID运用NtOpenProcess翻开一个历程。代码需要调试器所需要的一切接见权限:

1、建立新线程,这是注入初始断点的体式格局。

2、读取和修正内存的权限,用于写入断点,并搜检历程的运转状况。

3、停息和规复全部历程。

一旦内核取得句柄,它就需要运用ObReferenceObjectByHandle将其转换回历程工具指针。API接纳所需的接见掩码(Access
Mask),该掩码针对翻开的句柄接见掩码举行搜检,而且只要在搜检胜利经由过程时才会返回指针。下面是相干的代码片断:

NTSTATUS NtDebugActiveProcess(HANDLE ProcessHandle,
                             HANDLE DebugObjectHandle) {
 PEPROCESS Process;
 NTSTATUS status = ObReferenceObjectByHandle(
            ProcessHandle,
            PROCESS_SUSPEND_RESUME,
            PsProcessType,
            KeGetCurrentThread()->PreviousMode,
            &Process);
 // ...
}

在这里,涌现了严峻的不婚配题目。用户形式API需要以比内核API要求更高的接见权限来翻开历程。内核仅强制实行挂起和规复目标历程的权限。从内核的角度来看,这是有意义的(正如Raymond

Chen所说,需要透过内核的彩色眼镜来看),因为将历程附加到调试工具的直接影响是停息历程。我们可以或许假定,若是没有其他接见权限(比方:VM读取、VM写入),就不会举行太多调试,但从内核角度来看,这是可有可无的。我们只需要运用内核API,便可停息/规复历程(经由过程NtDebugContinue),并从调试工具中读取事宜。从设想角度来看,我们可以或许会在调试事宜的过程当中猎取没法接见的内存地址,这一现实其实不主要。

那末,详细的题目在那里呢?只要PROCESS_SUSPEND_RESUME接见权限。我们可以或许调试具有有限接见权限的历程,但若是没有其他接见权限,就没法完成这一操纵。然则,若是我们仅仅具有PROCESS_SUSPEND_RESUME接见权限,我们该怎么办?

收集赤军部队建设指南

0x00、Red Team建设目标 在平时听新闻联播,军事解决当中,我们都会听到红蓝军对抗,在信息安全行业与军方的一些相似性,网络世界Red Team就是攻击者的一方。安全能力的提升,在安全威胁没有挖掘出来之前,只能通过攻防对抗的形式体现出

接见调试事宜

要解答这一题目,需要回忆我们在第一次守候调试事宜时收到的CREATE_PROCESS_DEBUG_INFO事宜。需要注重的是,当地构造与示例比拟会略有分歧,但充足完成我们的目标。

每当我们衔接到运动历程时,都邑收到历程建立事宜,它许可调试器经由过程供应一组事宜(比方:建立历程、建立线程、加载模块)来同步其状况。若是我们直接在调试器下启动历程,就会收到这些事宜。现实上,NtDebugActiveProcess挪用DbgkpPostFakeProcessCreateMessages要领,它给出了调试事宜的状况。

关于CREATE_PROCESS_DEBUG_INFO,存在一个值得存眷的处所,我们会注重到HANDLE函数、hFile、hProcess和hThread对应于历程可实行文件的句柄、被调试历程的句柄和末了一个初始线程的句柄。DbgkpPostFakeProcessCreateMessages搜检中,将会捕捉工具,但不会天生句柄。句柄的建立则是在NtWaitForDebugEvent体系挪用内部完成的,特别是在DbgkpOpenHandles中。我们在该函数的以下代码片断中发明了题目标地点:

NTSTATUS DbgkpOpenHandles(PDEBUG_EVENT Event,
                         EPROCESS DebugeeProcess,
                         PETHREAD DebugeeThread) {
 
 // Handle other event types first...
 if (Event->DebugEventCode == CREATE_PROCESS_DEBUG_EVENT) {
   if (ObOpenObjectByPointer(DebugeeThread, 0, NULL,
         THREAD_ALL_ACCESS, PsThreadType,
         KernelMode, &Event->CreateProcess.hThread) < 0) {
     Event->CreateProcess.hThread = NULL;
   }
  
   if (ObOpenObjectByPointer(DebugeeProcess, 0, 0,
         PROCESS_ALL_ACCESS, PsProcessType,
         KernelMode, &Event->CreateProcess.hProcess < 0) {
     Event->CreateProcess.hThread = NULL;
   }
  
   ObDuplicateObject(PsGetCurrentProcess(),
                     Event->CreateProcess.hFile,
                     PsGetCurrentProcess(),
                     &Event->CreateProcess.hFile, 0, 0,
                     DUPLICATE_SAME_ACCESS, KernelMode);
 }
 // ...
}

这段代码运用ObOpenObjectByPointer
API将debugee历程和线程工具转换回句柄,这自身没有题目。但题目在于,挪用API时,接见形式被设置为内核形式,这意味着该挪用不会实行任何接见搜检,这一点上存在一些题目。而且,再加上没有对PROCESS_SUSPEND_RESUME要求分外的权限,配合致使了这一机制存在较大的题目。该代码可以或许有效地将NtWaitForDebugEvent挪用者的一切接见权限授与调试的目标历程。

这类行动的效果将致使一个具有PROCESS_SUSPEND_RESUME的历程句柄,纵然在工具未授与其挪用者接见权限的情况下,也可以或许用来取得对历程和初始线程的完全接见权限。但或许有人会说,纵然将调试器附加到历程中,那末背面能完成甚么样的应用呢?现实上,挪用方需要在衔接调试器之前翻开适宜的历程和线程句柄,并运用它们来接见目标。或许,若是内核必需建立新句柄,最少要对它们举行接见搜检。如许一来,就引出了我们的第一个破绽应用技能。

破绽应用技能(1)

若是存在具有PROCESS_SUSPEND_RESUME接见权限的历程句柄,就可以或许经由过程调试器API将其转换为对历程具有完全接见权限的句柄。

因为PROCESS_SUSPEND_RESUME会被视为是对历程的写接见权限,因而我们可以或许很少会碰到此类破绽。任何会走漏对特权历程接见权限的处所也往往会走漏其他写接见,比方PROCESS_CREATE_THREAD或PROCESS_VM_WRITE,如许游戏就完毕了。为了证实这一破绽应用技能,下面是一个简朴的PowerShell剧本,它将接收历程ID,翻开PROCESS_SUSPEND_RESUME的历程,将其附加到调试器,然后盗取句柄,并返回完全的接见句柄。

param(
   [Parameter(Mandatory)]
   [int]$ProcessId
)
 
# Get a privileged process handle with only PROCESS_SUSPEND_RESUME.
Import-Module NtObjectManager
 
Use-NtObject($dbg = New-NtDebug -ProcessId $ProcessId) {
   Use-NtObject($e = Start-NtDebugWait $dbg -Infinite) {
       $dbg.Detach($ProcessId)
       [NtApiDotNet.NtProcess]::DuplicateFrom($e.Process, -1)
   }
}

那末,CREATE_PROCESS_DEBUG_INFO中的第三个句柄,也就是历程可实行文件的句柄会怎样呢?它具有分歧的行动,而不仅仅是翻开它复制现有句柄的原始指针。若是我们检察代码,会发明它好像与以后挪用者的历程反复,而且再次返回。若是它已在调试器历程中,为何还需要举行复制呢?关键在于末了一个参数,它会再次通报内核形式,这意味着ObDuplicateObject现实上会复制以后历程的内核句柄。附加到历程时,会翻开文件句柄,并运用以下代码:

HANDLE DbgkpSectionToFileHandle(PSECTION Section) {
 HANDLE FileHandle;
 UNICODE_STRING Name;
 OBJECT_ATTRIBUTES ObjectAttributes;
 IO_STATUS_BLOCK IoStatusBlock;
 
 MmGetFileNameForSection(Section, &Name);
 
 InitializeObjectAttributes(&ObjectAttributes,
     &Name,
     OBJ_CASE_INSENSITIVE |
     OBJ_FORCE_ACCESS_CHECK |
     OBJ_KERNEL_HANDLE);
 
 ZwOpenFile(&FileHandle, GENERIC_READ | SYNCHRONIZE,
            &ObjectAttributes, &IoStatusBlock,
            FILE_SHARE_ALL, FILE_SYNCHRONOUS_IO_NONALERT);
 return FileHandle;
}

该代码会警惕肠将OBJ_FORCE_ACCESS_CHECK通报给文件翻开挪用,以确保不会让调试器接见人以文件。而且,会存储文件句柄,以便稍后挪用NtWaitForDebugEvent举行收受接管。由此,我们发明了第二个破绽应用技能。

破绽应用技能(2)

运用恣意内核句柄封闭的破绽,我们可以或许盗取内核句柄。

这类破绽应用技能背地的基本道理在于,一旦捕捉到句柄,就会无限期地存储,最少在历程依然存在时一直会生存。我们可以或许在恣意时候点对句柄举行检索。如许一来,就为我们供应了一个更大的时候窗口来应用句柄封闭破绽。这类破绽的一个例子是我在Novell驱动顺序中找到的Issue

274。在这类情况下,驱动顺序在编写日记条目时,不会搜检ZwOpenFile是不是胜利,因而在挪用ZwClose时会重用存储在栈中的句柄值。如许一来,将会致使人以内核句柄被封闭。要运用调试器来完成Novell破绽的应用,我们需要实行以下操纵:

1、天生日记条目,建立随后封闭的内核句柄,此时栈中的值不会被掩盖。

2、调试历程,以猎取已分派的文件句柄。句柄分派是可以或许展望的,因而很有可以或许将雷同的句柄值重用为与破绽一同运用的句柄值。

3、触发处置惩罚完毕破绽,在这类情况下,它将封闭如今由调试器分派的栈上的现有值,从而发生悬空的(Dangling)句柄值。

4、在内核中,运用代码以再次重新分派如今未运用的句柄值。比方,经由过程NtCreateLowBoxToken挪用的SepSetTokenCachedHandles可以或许会复制其他内核句柄。需要申明的是,因为我申报了Issue

483,以是会对运用的句柄举行相称严厉的搜检。

5、猎取调试器以返回句柄。

只管它们可以或许异常少见,但句柄封闭的破绽确切存在。另外,我们在此过程当中必需要警惕,因为通常情况下,封闭已封闭的内核句柄,可以或许会致使破绽搜检。

总结

用户形式调试器的行动,会对底本的功能设想发生不测的效果。我在本文中形貌的任何内容都不属于安全破绽,但如许的行动异常风趣,而且值得存眷可以或许完成破绽应用的详细情况。

利用GHIDRA逆向Tytera MD380的固件

背景知识介绍 2019年1月,美国国家安全局(NSA)宣布,它将免费向公众开放其逆向工程工具GHIDRA,源码已经于今年3月登陆代码托管平台GitHub 。NSA指出,GHIDRA框架的本质,是一款适用于 Windows、Mac 和 Linux平台的反汇编程序。它能够将


申博|网络安全巴士站声明:该文看法仅代表作者自己,与本平台无关。版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权
转载请注明Windows破绽应用技能:滥用用户形式调试器
喜欢 (0)
[]
分享 (0)
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址