做者:huity
出處:http://www.javashuo.com/article/p-gruicjtm-gz.html
版權:本文版權歸做者全部。文章在博客園、看雪、我的博客同時發佈。
轉載:歡迎轉載,但未經做者贊成,必須保留此段聲明;必須在文章中給出原文鏈接;不然必究法律責任。html
#include "stdio.h" #include "string.h" int main() { int i; char buf[8]; unsigned short int size; char overflow[65550]; memset(overflow,65,sizeof(overflow)); printf("Input the num:\n"); scanf("%d",&i); size=i; printf("size:%d\n",size); printf("i:%d\n",i); if(size>8) return -1; memcpy(buf,overflow,i);//棧溢出 return 0; }
上面的demo中,size爲無符號短整數(0-65535),當咱們輸入大於65535是就會形成溢出,例如咱們輸入65536,最終獲得的size爲0,從而繞過邊界檢查,可是在memcpy函數複製數據時,使用的是int類型的i參數,致使棧溢出。git
#include "stdio.h" #include "string.h" #include "Windows.h" int main() { int heap; unsigned short int size; char* v1,*v2; HANDLE HeapHandle; printf("int put size: \n"); scanf("%d",&size); HeapHandle = HeapCreate(HEAP_GENERATE_EXCEPTIONS,0x100,0xfff); if(size <=0x50) { size-=5; printf("size:%d\n",size); v1=(char*)HeapAlloc(HeapHandle,0,size); v2=(char*)HeapAlloc(HeapHandle,0,0x50); } HeapFree(HeapHandle,0,v1); HeapFree(HeapHandle,0,v2); return 0; }
上述demo中size爲unsigned short int,小於5時,例如,當size=2時,size減去5則獲得負數,但size取值範圍致使沒法識別負數,而獲得正數65533,而分配獲得大的堆塊,從而溢出致使覆蓋到後面的堆管理結構。github
__declspec(safebuffers) NTSTATUS TriggerIntegerOverflow( _In_ PVOID UserBuffer, _In_ SIZE_T Size) { ULONG Count = 0; NTSTATUS Status = STATUS_SUCCESS; ULONG BufferTerminator = 0xBAD0B0B0; ULONG KernelBuffer[BUFFER_SIZE] = { 0 };//512*4=2048 SIZE_T TerminatorSize = sizeof(BufferTerminator);//4 PAGED_CODE(); __try { // // UserBuffer 爲Ring3地址 其中前面均用A填充,倒數8字節開始的4字節爲Payload地址 最後四字節爲0xBAD0B0B0 ProbeForRead(UserBuffer, sizeof(KernelBuffer), (ULONG)__alignof(UCHAR)); DbgPrint("[+] UserBuffer: 0x%p\n", UserBuffer); DbgPrint("[+] UserBuffer Size: 0x%X\n", Size); DbgPrint("[+] KernelBuffer: 0x%p\n", &KernelBuffer); DbgPrint("[+] KernelBuffer Size: 0x%X\n", sizeof(KernelBuffer)); #ifdef SECURE // // 安全注意:這是安全的,由於開發人員沒有對用戶提供的值進行任何算術運算。 //相反,開發人員從KernelBuffer的大小減去ULONG的大小,即x86上的4。 所以,不會發生整數溢出,而且此檢查不會失敗 if (Size > (sizeof(KernelBuffer) - TerminatorSize)) { DbgPrint("[-] Invalid UserBuffer Size: 0x%X\n", Size); Status = STATUS_INVALID_BUFFER_SIZE; return Status; } #else DbgPrint("[+] Triggering Integer Overflow (Arithmetic Overflow)\n"); // 注意這裏是有漏洞的版本 if ((Size + TerminatorSize) > sizeof(KernelBuffer))//FFFFFFFF+4 = 00000003 { DbgPrint("[-] Invalid UserBuffer Size: 0x%X\n", Size); Status = STATUS_INVALID_BUFFER_SIZE; return Status; } #endif //實現拷貝操做 while (Count < (Size / sizeof(ULONG))) { if (*(PULONG)UserBuffer != BufferTerminator) { KernelBuffer[Count] = *(PULONG)UserBuffer; UserBuffer = (PULONG)UserBuffer + 1; Count++; } else { break; } } } __except (EXCEPTION_EXECUTE_HANDLER) { Status = GetExceptionCode(); DbgPrint("[-] Exception Code: 0x%X\n", Status); } return Status; }
函數中比較了用戶提交緩衝區長度和內核緩衝區長度,在有漏洞的版本中,這一比較採用了:shell
if ((Size + TerminatorSize) > sizeof(KernelBuffer))
咱們在Windbg中一樣能夠看到這一問題:編程
97c4ba9f 8b450c mov eax,dword ptr [ebp+0Ch] 97c4baa2 0345d4 add eax,dword ptr [ebp-2Ch] 97c4baa5 3d00080000 cmp eax,800h kd> r eax eax=00000003
kd> r eax=00000003 ebx=00000000 ecx=ffffffff edx=0000004d esi=86e61528 edi=860fff80 eip=97c80adb esp=9398f268 ebp=9398fab0 iopl=0 nv up ei ng nz na pe cy cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00000287 HEVD!TriggerIntegerOverflow+0x16b: 97c80adb 8b450c mov eax,dword ptr [ebp+0Ch] ss:0010:9398fabc=ffffffff kd> dd 9398fab0 9398fab0 9398fad4 97c80956 00408028 ffffffff 9398fac0 00000001 c0000001 ffffffff 00000000 9398fad0 00408028 9398fafc 97c800ae 86e6a870 9398fae0 86e6a8e0 00000001 00000000 00222027 9398faf0 00000024 c00000bb 86e6a8e0 9398fb14 9398fb00 83e7f593 86e61528 86e6a870 86e6a870 9398fb10 86e61528 9398fb34 8407399f 860fff80 9398fb20 86e6a870 86e6a8e0 00000094 0498fbac