[2024]复现Storm-0978的"EDR的梦魇"踩的坑 huoji win32k,EDR,setwindowshook,窗口 2024-04-28 333 次浏览 2 次点赞 刚发布那会,这玩意被吹的神乎其神,于是乎进行了一波复现,发现过程非常多的坑.于是记录一下 免责一下,本人没样本,纯靠qax给的信息复现,有些思路可能是错的 **当然,不会给POC和任何代码.只能跟你们说一下思路.** ### 原理 核心原理: https://learn.microsoft.com/en-us/windows/win32/winmsg/about-window-classes?redirectedfrom=MSDN 注意看: ```cpp The SetClassWord and SetClassLong functions copy a value to the extra class memory. To retrieve a value from the extra class memory, use the GetClassWord and GetClassLong functions. The cbClsExtra member of the WNDCLASSEX structure specifies the amount of extra class memory to allocate. An application that does not use extra class memory must initialize the cbClsExtra member to zero. ``` cbClsExtra的内存是共享的,来自内核映射的.所有窗口进程都会共享这块内核地址.这就是一切的根本.这里不再阐述. 有趣的是,虽然微软提到不能超过40bytes,否则会异常,但是实际是可以超过40bytes,并且会覆盖掉其他窗口的标题的buffer导致其他窗口标题乱码 ![](https://key08.com/usr/uploads/2024/04/1095307109.jpg) ### 坑1: 天堂之门不是必须 在qax的威胁情报里面介绍了天堂之门跳到X64执行X64的代码.这一步在复现环节不是必须的,为什么要跳,因为样本自己是WOW64的,他要注入的目标是chrome,chrome应该是x64的,所以找了个X64的noteapad在里面操作.**这一步不是为了规避什么** ![](https://key08.com/usr/uploads/2024/04/2732029771.png) ### 坑2: 还是必须openprocess 虽然文章中提到 > 此次填充的数据仅用于定位内核共享数据块映射到malicious.exe中的具体地址,样本通过查找TEB->Win32ClientInfo->phkCurrent结构下的AllocationBase来确定窗口内存的基址,接着对该区域的内存与之前调用填充的数据进行逐个比较找到共享内存块的地址,找到位置后再次调用NtUserSetClassLong将填充数据清空。 **但这里本人愚钝,不知道有什么其他办法能在不用win32的API的情况下知道notepad的共享内存的虚拟地址** 查找TEB->Win32ClientInfo->phkCurrent[20]只是缩小范围,其实不如直接virtualqueryex遍历,我实在是不知道这里要怎么定位到notepad的地址.如果跟我一样用win32 api **主流edr绝对有痕迹,包括sysmon** ### 坑3: WM_SETTEXT参数写入 文章提到的通过WM_SETTEXT输入参数应该是通过WM_SETTEXT把shellcode塞到笔记本里面,作者参考的技术是: https://github.com/odzhan/injection/blob/08fc7c2e462dc09387cc22046897d67bda0d2b33/eminject/poc.c#L157 **但是这只针对英文系统有效果** 具体参考连接: https://modexp.wordpress.com/2020/07/07/wpi-wm-paste/ ![](https://key08.com/usr/uploads/2024/04/659594937.png) 请看: ```cpp Since the input is stored in Unicode format, it’s not possible to just copy any shellcode to the clipboard and paste into the edit control. On my system, notepad converts the clipboard data to Unicode using the CP_ACP codepage, which is using Windows-1252 (CP-1252) encoding. CP-1252 is a single byte character set used by default in legacy components of Microsoft Windows for languages derived from the Latin alphabet. When notepad receives the WM_PASTE message, it invokes GetClipboardData() with CF_UNICODETEXT as the format. Internally, this invokes GetClipboardCodePage(), which on my system returns CP_ACP, before invoking MultiByteToWideChar() converting the text into Unicode format. For CF_TEXT format, ensure the code you copy to the clipboard doesn’t contain characters in the ranges [0x80, 0x8C], [0x91, 0x9C] or 0x8E, 0x9E and 0x9F. These “bad characters” will be converted to double byte character encodings. For UTF-8, only bytes in range [0x00, 0x7F] can be used. ``` 具体翻译是: > 记事本接收到 WM_PASTE 消息后,会调用格式为 CF_UNICODETEXT 的 GetClipboardData() 函数。在调用 MultiByteToWideChar() 将文本转换为 Unicode 格式之前,会在内部调用 GetClipboardCodePage(),在我的系统上,该函数返回 CP_ACP 因此这对于UTF-8系统是无效的,**因为shellcode会被中间强制带0,除非能故意构造让MultiByteToWideChar反序化为正确的地址东西**,我是偷懒了,直接用API写了,如果有什么好的方法请回复我我试一下: ```cpp // ***这里有个限制 除非我是英文系统 否则会被格式为Utf-8导致不能用** // 我直接writememory让那个地方看起来像是英文系统 auto emh = (PVOID)SendMessage(hwndEdit, EM_GETHANDLE, 0, 0); PVOID embuf; SIZE_T numOfWrite; ReadProcessMemory(pi.hProcess, emh, &embuf, sizeof(ULONG_PTR), &numOfWrite); WriteProcessMemory(pi.hProcess, embuf, &TheNotepadTagClsAddress, 8, &numOfWrite); ``` ### 坑4: Shellcode构造问题 shellcode构造这块如果逆向了API就知道 他是 [[address]]这样读的,先是EM_SETWORDBREAKPROC回调读了一层(其实是来自剪切板) 然后I_RpcFreePipeBuffer读了一层 所以意味着要套两层shellcode,+0x8后才是真payload的rpc_message的结构体地址 ### 坑5: VirtualProtect改哪里? 这个是文章里面没有提出来的一个隐藏的问题,即: ![](https://key08.com/usr/uploads/2024/04/3669017516.png) "PRPC_MESSAGE_A中DispatchTable的地址还是NdrServerCallAll,至此形成套娃,会第二次进入NdrServerCallAll,此时的参数为PRPC_MESSAGE_B,而PRPC_MESSAGE_B的DispatchTable函数为VirtualProtect,将共享内存块中shellcodeB的内存属性改为可读可写可执行。" 这一块是内核的共享地址,内存属性是map,virtualprotect是改不了map的地址的属性的: ![](https://key08.com/usr/uploads/2024/04/601958352.png) **所以shellcode的位置本人大胆猜测压根不在cbClsExtra的内存里面(这一块是改不了的),考虑到最有可能的,应该是在WM_SETTEXT设置的EDIT编辑框里面** ### 来源: 原创or抄袭? **如果按照本人的复现思路实现的POC,有三个点EDR能很好的检测此类注入.具体是啥自己动脑筋了,总之,这绝对不是什么"edr梦魇" 充其量是一种花里胡哨的的allocmemory并且remotecall技术.** 此类窗口技术本人最早关注的时间点是2023年(那会就已经发现一些样本用这个技术了,但是路线不一样): [2023]阻止window hook exploit meme https://key08.com/index.php/2023/12/30/1823.html 在此之前,UC论坛上就已经有人提过了并且提到已经有完整的注入方案并且在售卖(22年左右) ![](https://key08.com/usr/uploads/2024/04/1702129503.png) ![](https://key08.com/usr/uploads/2024/04/486479419.png) ![](https://key08.com/usr/uploads/2024/04/2096883002.png) 此外RPC call部分是来自于另外一个漏洞的CFG bypass实现(因为notepad的CFG保护的): https://hackyboiz.github.io/2023/10/30/pwndorei/newjeans-hyper-v-pt5/ 窗口部分来自: https://modexp.wordpress.com/2020/07/07/wpi-wm-paste/ ### 参考连接 https://mp.weixin.qq.com/s/y-sI1kaWv_5InhJMzNPhJw https://modexp.wordpress.com/2020/07/07/wpi-wm-paste/ https://github.com/odzhan/injection/blob/master/eminject/poc.c#L38 https://www.unknowncheats.me/forum/anti-cheat-bypass/512416-using-setwindowhookex-manipulating-game.html https://hackyboiz.github.io/2023/10/30/pwndorei/newjeans-hyper-v-pt5/ 本文由 huoji 创作,采用 知识共享署名 3.0,可自由转载、引用,但需署名作者且注明文章出处。 点赞 2
还不快抢沙发