0%

windows池风水-LFH低碎片堆

windows池风水-LFH低碎片堆

在阅读完Scoop_The_Windows_10_pool这篇文章后,对段堆有了一些认识,纸上得来终觉浅,一定要实践下,这篇文章针对LFH低碎片堆的池风水构造进行研究学习.

漏洞程序选择了HEVD,我编译为了win10 x64平台的版本,以其中的函数MemoryDisclosureNonPagedPoolNxIoctlHandler

作为目标.

1.LFH回顾

LFH低碎片堆后端,是用于分配1b-16383b的小块的后端.它分配的块由标准的_POOL_HEADER结构作为头部.

LFH段堆由_HEAP_LFH_CONTEXT结构进行管理

1
2
3
4
5
6
7
8
9
10
11
12
1: kd> dt _HEAP_LFH_CONTEXT
nt!_HEAP_LFH_CONTEXT
+0x000 BackendCtx : Ptr64 Void
+0x008 Callbacks : _HEAP_SUBALLOCATOR_CALLBACKS
+0x030 AffinityModArray : Ptr64 UChar
+0x038 MaxAffinity : UChar
+0x039 LockType : UChar
+0x03a MemStatsOffset : Int2B
+0x03c Config : _RTL_HP_LFH_CONFIG
+0x040 BucketStats : _HEAP_LFH_SUBSEGMENT_STATS
+0x048 SubsegmentCreationLock : Uint8B
+0x080 Buckets : [129] Ptr64 _HEAP_LFH_BUCKET
1
2
3
4
5
6
7
8
9
10
11
1: kd> dt _HEAP_LFH_BUCKET
nt!_HEAP_LFH_BUCKET
+0x000 State : _HEAP_LFH_SUBSEGMENT_OWNER
+0x038 TotalBlockCount : Uint8B
+0x040 TotalSubsegmentCount : Uint8B
+0x048 ReciprocalBlockSize : Uint4B
+0x04c Shift : UChar
+0x04d ContentionCount : UChar
+0x050 AffinityMappingLock : Uint8B
+0x058 ProcAffinityMapping : Ptr64 UChar
+0x060 AffinitySlots : Ptr64 Ptr64 _HEAP_LFH_AFFINITY_SLOT

在LFH中,使用了大小不同的bucket以避免碎片化,如果要出发LFH,需要对相同大小的桶连续16次请求,共有129个bucket,每个bucket都有着不同的粒度,以1-64的bucket举例.粒度是16字节,代表着从1b-1008b中,1b-16b,17b-31b,32b-48b….的16字节的粒度分配都将在bucket1-bucket64中进行分配.直到最终8177b-16368b的512b粒度.

如果要对1b-16383b中的字节大小的对象进行池喷射,而且它的大小与LFH中的一个bucket的大小相匹配,那么它大部分将会分配在LFH中.

image-20230904140838454

LFH的块连续释放并不会将空闲块进行合并优化,因为LFH使用了预定的bucket管理这些块,即使我们释放,这些空闲块也依然会被保留,不会进行合并.

其实在利用时,最困难的一步是找到一个合适大小的对象,并且让这两个对象相邻,进行溢出,使漏洞块覆盖下一个块,并且池的类型也应相同.