This part will make a systematic analysis of common binary vulnerabilities to facilitate the location and identification of what types of vulnerabilities are in the process of vulnerability mining. If you want to do a good job, you must first sharpen its tools.
catalogue
0x01 stack overflow vulnerability principle
0x02 heap overflow vulnerability principle
0x04 integer overflow vulnerability principle
0x05 format string vulnerability principle
0x06 double release vulnerability principle
0x07 re reference vulnerability principle after release
0x08 array out of bounds access vulnerability
0x09 type confusion vulnerability principle
0x10 competitive condition vulnerability principle
0x01 stack overflow vulnerability principle
Stack overflow vulnerability is a kind of buffer vulnerability. Examples are as follows:
#include <stdio.h> #include <string.h> int main() { char *str = "AAAAAAAAAAAAAAAAAAAAAAAA"; vulnfun(str); return; } int vulnfun(char *str) { char stack[10]; strcpy(stack,str); // Overflow here! }
Run with windbg after compilation
It runs directly to the address 0x4141, which is the string AAAA, that is, when the string in the variable str is copied to the stack space through strcpy, there is no limit on the length of the string, resulting in stack overflow and finally overwriting the return address, resulting in program crash.
The stack space layout after overflow is as follows:
Stack overflow schematic
0x02 heap overflow vulnerability principle
Use the following code to demonstrate heap overflow vulnerabilities
#include <windows.h> #include <stdio.h> int main ( ) { HANDLE hHeap; char *heap; char str[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; hHeap = HeapCreate(HEAP_GENERATE_EXCEPTIONS, 0x1000, 0xffff); getchar(); // Used to pause the program for the debugger to load heap = HeapAlloc(hHeap, 0, 0x10); printf("heap addr:0x%08x\n",heap); strcpy(heap,str); // Cause heap overflow HeapFree(hHeap, 0, heap); // Trigger crash HeapDestroy(hHeap); return 0; }
Due to the different structures of the debug heap and the normal heap, the getchar function is added to the demo code to pause the process, which is convenient to attach the process with the debugger after running heapoverflowexe. Each memory structure and allocation process in the actual running process of debug version and release version are also different, so it should be compiled into release version during testing.
Run the program and use windbg to add debugging (be sure to add debugging). After g running, the program crashes
The above ecx has been overwritten by the AAAA string. Finally, it crashes when referring to the address. Through the previous stack backtracking, locate the main function entry and find the lower breakpoint of the function copying the string
At this time, the heap block has been allocated, and the corresponding allocation address is 0x007104a0. 0x007104a0 is the starting address of heap block data, not the starting address of heap header information. For the allocated heap block, there is an 8-byte heap at the beginning_ Entry structure, so heap_ The entry structure is located at 0x007104a0-8=0x710498.
View the information of two heap blocks on windbg. These two heap blocks are currently occupied, with a total space of 0x10
0:000> !heap -p -a 0x710498 address 00710498 found in _HEAP @ 710000 HEAP_ENTRY Size Prev Flags UserPtr UserSize - state 00710498 0005 0000 [00] 007104a0 00010 - (busy)
In windbg, use! Heap view the entire heap block information created by HeapCreate. You can find that there is a free heap block 0x007104c0 after the heap block heap:
0:000> !heap Heap Address NT/Segment Heap 560000 NT Heap 800000 NT Heap 710000 NT Heap 0:000> !heap -a 710000 HEAPEXT: Unable to get address of ntdll!RtlpHeapInvalidBadAddress. Index Address Name Debugging options enabled 3: 00710000 Segment at 00710000 to 00720000 (00001000 bytes committed) Flags: 40001064 ForceFlags: 40000064 Granularity: 8 bytes Segment Reserve: 00100000 Segment Commit: 00002000 DeCommit Block Thres: 00000200 DeCommit Total Thres: 00002000 Total Free Size: 00000164 Max. Allocation Size: 7ffdefff Lock Variable at: 00710248 Next TagIndex: 0000 Maximum TagIndex: 0000 Tag Entries: 00000000 PsuedoTag Entries: 00000000 Virtual Alloc List: 0071009c Uncommitted ranges: 0071008c 00711000: 0000f000 (61440 bytes) FreeList[ 00 ] at 007100c0: 007104c8 . 007104c8 007104c0: 00028 . 00b20 [104] - free Segment00 at 00710000: Flags: 00000000 Base: 00710000 First Entry: 00710498 Last Entry: 00720000 Total Pages: 00000010 Total UnCommit: 0000000f Largest UnCommit:00000000 UnCommitted Ranges: (1) Heap entries for Segment00 in Heap 00710000 address: psize . size flags state (requested size) 00710000: 00000 . 00498 [101] - busy (497) 00710498: 00498 . 00028 [107] - busy (10), tail fill //Heap block occupied by heap 007104c0: 00028 . 00b20 [104] free fill //Free heap block 00710fe0: 00b20 . 00020 [111] - busy (1d) 00711000: 0000f000 - uncommitted bytes.
When copying strings, the heap block with the original size of 0x10 will be overwritten to the lower free heap block 007104c0 when too many strings are filled. Before copying, the heap of 007104c0 free heap block will be overwritten_ FREE_ The entry structure data is as follows:
0:000> dt _HEAP_FREE_ENTRY 0x007104c0 ntdll!_HEAP_FREE_ENTRY +0x000 HeapEntry : _HEAP_ENTRY +0x000 UnpackedEntry : _HEAP_UNPACKED_ENTRY +0x000 Size : 0x6298 +0x002 Flags : 0x16 '' +0x003 SmallTagIndex : 0xac '' +0x000 SubSegmentCode : 0xac166298 +0x004 PreviousSize : 0xcfb9 +0x006 SegmentOffset : 0 '' +0x006 LFHFlags : 0 '' +0x007 UnusedBytes : 0 '' +0x000 ExtendedEntry : _HEAP_EXTENDED_ENTRY +0x000 FunctionIndex : 0x6298 +0x002 ContextValue : 0xac16 +0x000 InterceptorValue : 0xac166298 +0x004 UnusedBytesLength : 0xcfb9 +0x006 EntryOffset : 0 '' +0x007 ExtendedBlockSignature : 0 '' +0x000 Code1 : 0xac166298 +0x004 Code2 : 0xcfb9 +0x006 Code3 : 0 '' +0x007 Code4 : 0 '' +0x004 Code234 : 0xcfb9 +0x000 AgregateCode : 0x0000cfb9`ac166298 +0x008 FreeList : _LIST_ENTRY [ 0x7100c0 - 0x7100c0 ]
0:000> dt _LIST_ENTRY 0x007104c0+8 ntdll!_LIST_ENTRY [ 0x7100c0 - 0x7100c0 ] +0x000 Flink : 0x007100c0 _LIST_ENTRY [ 0x7104c8 - 0x7104c8 ] +0x004 Blink : 0x007100c0 _LIST_ENTRY [ 0x7104c8 - 0x7104c8 ]
Heap of 0x007104c0 free block after overwriting_ FREE_ The entry structure data is as follows:
0:000> g (2c08.234): Access violation - code c0000005 (!!! second chance !!!) eax=007e04a0 ebx=007e0498 ecx=41414141 edx=007e0260 esi=007e04b8 edi=007e0000 eip=7775919d esp=0019fdb0 ebp=0019fea8 iopl=0 nv up ei ng nz na po cy cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010283 ntdll!RtlpFreeHeap+0x5bd: 7775919d 8b11 mov edx,dword ptr [ecx] ds:002b:41414141=???????? 0:000> dt _HEAP_FREE_ENTRY 0x007104c0 ntdll!_HEAP_FREE_ENTRY +0x000 HeapEntry : _HEAP_ENTRY +0x000 UnpackedEntry : _HEAP_UNPACKED_ENTRY +0x000 Size : ?? +0x002 Flags : ?? +0x003 SmallTagIndex : ?? +0x000 SubSegmentCode : ?? +0x004 PreviousSize : ?? +0x006 SegmentOffset : ?? +0x006 LFHFlags : ?? +0x007 UnusedBytes : ?? +0x000 ExtendedEntry : _HEAP_EXTENDED_ENTRY +0x000 FunctionIndex : ?? +0x002 ContextValue : ?? +0x000 InterceptorValue : ?? +0x004 UnusedBytesLength : ?? +0x006 EntryOffset : ?? +0x007 ExtendedBlockSignature : ?? +0x000 Code1 : ?? +0x004 Code2 : ?? +0x006 Code3 : ?? +0x007 Code4 : ?? +0x004 Code234 : ?? +0x000 AgregateCode : ?? +0x008 FreeList : _LIST_ENTRY Memory read error 007104c0
The entire idle heap header information is overwritten, including the forward and backward pointers in the last idle linked list are 0x4141. When HeapFree is called to release the heap block later, buf2 and the subsequent idle heap block 0x007104c0 will be merged. Modifying the forward and backward pointers of the two idle heap blocks will reference 0x4141, resulting in a crash.
If the above operation of releasing the heap block is replaced by allocating the heap block HeapAlloc (), it will also cause a crash, because it will traverse the free linked list pointer when allocating heap blocks, which will cause address reference exceptions. When multiple heap blocks have been allocated in memory, the allocated heap blocks may be overwritten. At this time, the HEAP_ENTRY structure may be overwritten, rather than the HEAP_FREE_ENTRY structure.
Heap overflow schematic
0x03 heap debugging skills
Microsoft provides some debugging options to assist heap debugging. You can use the gflag provided by windbg Exe or! Gflag command to set:
htc: Tail check for overflow hfc: Reactor release check hpc: Reactor parameter check hpa: Enable page heap htg: Heap flag ust: User state stack backtracking
For heapoverflow Exe adds heap tail check and page heap, and removes the heap flag:
gflags.exe -i F:\vulns\Release\heapoverflow +htc +hpa +htg
Tail inspection
It is mainly to add 8 bytes after user data at the end of each heap block, usually 2 consecutive 0xababs. If the data segment is damaged, overflow may occur.
For heapoverflow Exe starts hpc and htc and loads the heapoverflow program with windbg. The additional process cannot add additional flags at the end of the heap. Use the following command to start the end of the heap check and heap parameter check:
0:000> !gflag +htc +hpc Current NtGlobalFlag contents: 0x00000070 htc - Enable heap tail checking hfc - Enable heap free checking hpc - Enable heap parameter checking
0:000:x86> g HEAP[heapoverflow.exe]: Heap block at 001E0498 modified at 001E04B0 past requested size of 10 (13d0.3c9c): WOW64 breakpoint - code 4000001f (first chance) First chance exceptions are reported before any exception handling. This exception may be expected and handled. ntdll_77710000!RtlpBreakPointHeap+0x13: 777f07c7 cc int 3
After executing the command g, press enter and the program will break
0:000:x86> kb # ChildEBP RetAddr Args to Child 00 0019fd18 777dd85b 00000000 001e0000 001e0498 ntdll_77710000!RtlpBreakPointHeap+0x13 01 0019fd30 77793e9c 001e0000 00000000 77786780 ntdll_77710000!RtlpCheckBusyBlockTail+0x1a2 02 0019fd4c 777ef9f1 7772e4dc 9ceeef49 001e0000 ntdll_77710000!RtlpValidateHeapEntry+0x633d9 03 0019fda4 7775991d 001e04a0 9ceeec45 001e0498 ntdll_77710000!RtlDebugFreeHeap+0xbf 04 0019fea8 77758b98 001e0498 001e04a0 001e04c1 ntdll_77710000!RtlpFreeHeap+0xd3d *** WARNING: Unable to verify checksum for F:\vulns\Release\heapoverflow.exe 05 0019fefc 00401094 001e0000 00000000 001e04a0 ntdll_77710000!RtlFreeHeap+0x758 WARNING: Stack unwind information not available. Following frames may be wrong. 06 001e0000 01000709 ffeeffee 00000000 001e00a4 heapoverflow+0x1094 07 001e0004 ffeeffee 00000000 001e00a4 001e00a4 0x1000709 08 001e0008 00000000 001e00a4 001e00a4 001e0000 0xffeeffee
HEAP[heapoverflow.exe]: Heap block at 001E0498 modified at 001E04B0 past requested size of 10
The debugging output information in the above sentence means that the 0x001E04B0 coverage of the heap block 0x001E0498 with the size of 0x10 is damaged. The space with the size of 0x10 plus the 8 bytes of the heap head is 0x18 bytes in total. 0x001E04B0-0x001E0498=0x18, that is, 0x001E04B0 is located on the last byte of the heap block data. Based on the above information, It can be analyzed that the program is mainly due to the heap overflow caused by copying too much data into the heap block of 0x10.
Page heap
When debugging vulnerabilities, it is often necessary to locate the code and functions that lead to vulnerabilities, such as byte copy instruction rep movsz that leads to heap overflow. The previous heap tail inspection method is mainly the scene of heap destruction, which is not conducive to locating the code that leads to vulnerabilities. For this reason. The concept of page heap is introduced. After opening, inaccessible fence pages will be added to the heap block, and overflow will trigger an exception if it covers the fence page.
Open page heap:
gflags.exe -i F:\vulns\Release\heapoverflow +hpa
Load heapoverflow with windbg and run it! The gflag command starts the page heap, and then g after running, press the Enter key in cmd to disconnect
0:000> g (46c.b74): Access violation - code c0000005 (!!! second chance !!!) eax=00000021 ebx=01795ff0 ecx=00000004 edx=77d364f4 esi=0012ff38 edi=01796000 eip=00401084 esp=0012ff10 ebp=01790000 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010202 image00400000+0x1084: 00401084 f3a5 rep movs dword ptr es:[edi],dword ptr [esi] 0:000> dd esi 0012ff38 41414141 41414141 41414141 41414141 0012ff48 00407000 00401327 00000001 01699fb0 0012ff58 0169bf70 00000000 00000000 7ffdd000 0012ff68 c0000005 00000000 0012ff5c 0012fb1c 0012ff78 0012ffc4 00402c50 004060b8 00000000 0012ff88 0012ff94 76281174 7ffdd000 0012ffd4 0012ff98 77d4b3f5 7ffdd000 77cb48a4 00000000 0012ffa8 00000000 7ffdd000 c0000005 76292b35 0:000> dc edi 01796000 ???????? ???????? ???????? ???????? ???????????????? 01796010 ???????? ???????? ???????? ???????? ???????????????? 01796020 ???????? ???????? ???????? ???????? ???????????????? 01796030 ???????? ???????? ???????? ???????? ???????????????? 01796040 ???????? ???????? ???????? ???????? ???????????????? 01796050 ???????? ???????? ???????? ???????? ???????????????? 01796060 ???????? ???????? ???????? ???????? ???????????????? 01796070 ???????? ???????? ???????? ???????? ????????????????
It can be found that the program triggers an exception when copying A string. The program is disconnected when copying to 0x11 bytes. At this time, the exception has not been destroyed to the heap block. Directly locate the copy instruction rep movs that causes overflow
0:000> kb ChildEBP RetAddr Args to Child WARNING: Stack unwind information not available. Following frames may be wrong. 0012ff48 00401327 00000001 01699fb0 0169bf70 image00400000+0x1084 *** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Windows\system32\kernel32.dll - 0012ff88 76281174 7ffdd000 0012ffd4 77d4b3f5 image00400000+0x1327 0012ff94 77d4b3f5 7ffdd000 77cb48a4 00000000 kernel32!BaseThreadInitThunk+0x12 0012ffd4 77d4b3c8 0040b000 7ffdd000 00000000 ntdll!RtlInitializeExceptionChain+0x63 0012ffec 00000000 0040b000 7ffdd000 00000000 ntdll!RtlInitializeExceptionChain+0x36 0:000> ub image00400000+0x1327 image00400000+0x1301: 00401301 e847120000 call image00400000+0x254d (0040254d) 00401306 e8af0e0000 call image00400000+0x21ba (004021ba) 0040130b a150994000 mov eax,dword ptr [image00400000+0x9950 (00409950)] 00401310 a354994000 mov dword ptr [image00400000+0x9954 (00409954)],eax 00401315 50 push eax 00401316 ff3548994000 push dword ptr [image00400000+0x9948 (00409948)] 0040131c ff3544994000 push dword ptr [image00400000+0x9944 (00409944)] 00401322 e8d9fcffff call image00400000+0x1000 (00401000)
According to the stack backtracking, the upper function calling rep movs is located in the previous instruction of image00400000+0x1084, that is, 00401322. Here, 00401000 function is called. It is easy to find that this is the main entry function:
0:000> uf 00401000 image00400000+0x1000: 00401000 83ec24 sub esp,24h 00401003 b908000000 mov ecx,8 00401008 53 push ebx 00401009 55 push ebp 0040100a 56 push esi 0040100b 57 push edi 0040100c be44704000 mov esi,offset image00400000+0x7044 (00407044) 00401011 8d7c2410 lea edi,[esp+10h] 00401015 f3a5 rep movs dword ptr es:[edi],dword ptr [esi] 00401017 68ffff0000 push 0FFFFh 0040101c 6800100000 push 1000h //Block size press in 00401021 6a04 push 4 00401023 a4 movs byte ptr es:[edi],byte ptr [esi] 00401024 ff150c604000 call dword ptr [image00400000+0x600c (0040600c)]//Call HeapCreate to create a heap block 0040102a 8be8 mov ebp,eax 0040102c a16c704000 mov eax,dword ptr [image00400000+0x706c (0040706c)] 00401031 48 dec eax 00401032 a36c704000 mov dword ptr [image00400000+0x706c (0040706c)],eax 00401037 7808 js image00400000+0x1041 (00401041) image00400000+0x1039: 00401039 ff0568704000 inc dword ptr [image00400000+0x7068 (00407068)] 0040103f eb0d jmp image00400000+0x104e (0040104e) image00400000+0x1041: 00401041 6868704000 push offset image00400000+0x7068 (00407068) 00401046 e896000000 call image00400000+0x10e1 (004010e1) 0040104b 83c404 add esp,4 image00400000+0x104e: 0040104e 6a10 push 10h 00401050 6a00 push 0 00401052 55 push ebp 00401053 ff1508604000 call dword ptr [image00400000+0x6008 (00406008)] //Call heaprealloc to allocate the heap block of 0x10 00401059 8bd8 mov ebx,eax //Allocated heap block address 0040105b 53 push ebx 0040105c 6830704000 push offset image00400000+0x7030 (00407030) 00401061 e84a000000 call image00400000+0x10b0 (004010b0) 00401066 8d7c2418 lea edi,[esp+18h] 0040106a 83c9ff or ecx,0FFFFFFFFh 0040106d 33c0 xor eax,eax 0040106f 83c408 add esp,8 00401072 f2ae repne scas byte ptr es:[edi] 00401074 f7d1 not ecx //Get str length 00401076 2bf9 sub edi,ecx 00401078 53 push ebx 00401079 8bc1 mov eax,ecx 0040107b 8bf7 mov esi,edi //str = 0x20 0040107d 8bfb mov edi,ebx //The allocated heap block is only 0x10 0040107f 6a00 push 0 00401081 c1e902 shr ecx,2 00401084 f3a5 rep movs dword ptr es:[edi],dword ptr [esi] 00401086 8bc8 mov ecx,eax 00401088 55 push ebp 00401089 83e103 and ecx,3 0040108c f3a4 rep movs byte ptr es:[edi],byte ptr [esi] //0x20 < 0x10 overflow caused by cyclic replication 0040108e ff1504604000 call dword ptr [image00400000+0x6004 (00406004)] 00401094 55 push ebp 00401095 ff1500604000 call dword ptr [image00400000+0x6000 (00406000)] 0040109b 5f pop edi 0040109c 5e pop esi 0040109d 5d pop ebp 0040109e 33c0 xor eax,eax 004010a0 5b pop ebx 004010a1 83c424 add esp,24h 004010a4 c3 ret
0x04 integer overflow vulnerability principle
Integers are divided into signed and unsigned. The highest bit of signed numbers is used as the sign bit, the highest bit of positive integers is 1, and the highest bit of negative integers is 0. Different types of integers have different value ranges in memory, unsigned int = 4 bytes and int = 4 bytes. Overflow occurs when the stored value exceeds the maximum value of this type of integers.
Integer overflow vulnerabilities are most likely to occur during some signed and unsigned conversions.
Stack based integer overflow
Example of stack based integer overflow:
#include "stdio.h" #include "string.h" int main(int argc, char *argv){ int i; char buf[8]; // Stack buffer unsigned short int size; // Unsigned short integer value range: 0 ~ 65535 char overflow[65550]; memset(overflow,65,sizeof(overflow)); // Fill with "A" character printf("Please enter a value:\n"); scanf("%d",&i); //Input 65540 size = i; printf("size: %d\n",size); // Output the size value recognized by the system 4 printf("i: %d\n",i); // 65540 i data recognized by the output system if (size > 8) //Boundary check return -1; memcpy(buf,overflow,i); // Stack overflow return 0; }
The size variable in the code is an unsigned short integer with a value range of 0 ~ 65535. If the entered value is greater than 65535, overflow will occur. Finally, size 4 will pass the boundary check. However, when memcpy is used to copy data, the parameter i of type int is used. This value is the input 65540, and stack overflow will occur:
Heap based integer overflow
Example of heap based integer overflow:
#include "stdio.h" #include "windows.h" int main(int argc, char * argv) { int* heap; unsigned short int size; // Unsigned short integer value range: 0 ~ 65535 char *pheap1, *pheap2; HANDLE hHeap; printf("input size Value:\n"); scanf("%d",&size); hHeap = HeapCreate(HEAP_GENERATE_EXCEPTIONS, 0x100, 0xfff); //Create a heap block if (size <= 0x50) { size -= 5; //Enter 2, size=-3=65533, printf("size: %d\n",size); pheap1 = HeapAlloc(hHeap, 0, size); // pheap1 will allocate too large heap blocks, resulting in overflow! pheap2 = HeapAlloc(hHeap, 0, 0x50); } HeapFree(hHeap, 0, pheap1); HeapFree(hHeap, 0, pheap2); return 0; }
The size in the code is of unsigned short int type. When the input is less than 5, size minus 5 will get a negative number. However, due to the limitation of the value range of unsigned short int, the negative number cannot be recognized and a positive number 65533 is obtained. Finally, too large heap blocks are allocated, and the overflow covers the following heap management structure:
0x05 format string vulnerability principle
The main reason for the format vulnerability is that the user input content is not filtered. Some input data is passed as parameters to some functions performing format operations, such as printf, fprintf, vprintf and sprintf.
Malicious users can use format characters such as% s and% x to output data from the stack and other memory locations, or use format character% n to write data to any address. Combined with printf() function, they can write formatted bytes to any address, which may lead to arbitrary code execution or read sensitive data.
Take the following code as an example to explain the principle of format string vulnerability:
#include <stdio.h> #include <string.h> int main (int argc, char *argv[]) { char buff[1024]; // Set stack space strncpy(buff,argv[1],sizeof(buff)-1); printf(buff); //Trigger vulnerability return 0; }
It can be found that when the input data contains% s and% x format characters, other data will be output unexpectedly:
To attach a debugger with ollydbg, you need to set the command line parameters before execution. Debug - parameters - command line: test-%x
After running the program, the only parameter passed to printf is test-%x, but he passes another stack data after the input parameter test-%x to the printf function as a parameter, because the basic type of printf is:
printf("Format controller ", variable list);
There is only one parameter passed to printf, but the program passes the next data on the stack as a parameter to the printf function by default, The next data is the target address of strcpy() function, which is the buff variable. Buff just points to the address 0x0019fec4 of test-%x, so the program will output 0x0019fec4. If you add another% x later, the value of src parameter will also be output, so you can traverse the data on the whole stack.
In addition to using% x to read data on the stack, you can also use% n to write data and modify the return address to exploit the vulnerability.
0x06 double release vulnerability principle
The Double Free vulnerability is caused by the secondary release of the same block of memory. Using the vulnerability, arbitrary code can be executed and compiled into release. The example code is as follows:
#include <stdio.h> #include "windows.h" int main (int argc, char *argv[]) { void *p1,*p2,*p3; p1 = malloc(100); printf("Alloc p1: %p\n",p1); p2 = malloc(100); printf("Alloc p2: %p\n",p2); p3 = malloc(100); printf("Alloc p3: %p\n",p3); printf("Free p1\n"); free(p1); printf("Free p3\n"); free(p3); printf("Free p2\n"); free(p2); printf("Double Free p2\n"); //Secondary release free(p2); return 0; }
When p2 is released for the second time, the program will crash, but not every time Double Free occurs, and the crash will occur only when the heap block merging action occurs
#include <stdio.h> #include "windows.h" int main (int argc, char *argv[]) { void *p1,*p2,*p3; p1 = malloc(100); printf("Alloc p1: %p\n",p1); p2 = malloc(100); printf("Alloc p2: %p\n",p2); p3 = malloc(100); printf("Alloc p3: %p\n",p3); printf("Free p2\n"); free(p2); printf("Double Free p2\n"); free(p2); printf("Free p1\n"); free(p1); printf("Free p3\n"); free(p3); return 0; }
Dual release schematic
During the release process, the adjacent released heap blocks have a merge operation, which will change the original heap header information, and then release the address reference, and an access exception will occur.
0x07 re reference vulnerability principle after release
Understand the principle of UAF vulnerability through the following code:
#include <stdio.h> #define size 32 int main(int argc, char **argv) { char *buf1; char *buf2; buf1 = (char *) malloc(size); printf("buf1: 0x%p\n", buf1); free(buf1); // Allocate buf2 to the memory location of "pit" buf1 buf2 = (char *) malloc(size); printf("buf2: 0x%p\n\n", buf2); // Reset buf2 memory memset(buf2, 0, size); printf("buf2: %d\n", *buf2); // The released buf1 pointer is re referenced, but the buf2 value is tampered with printf("==== Use After Free ===\n"); strncpy(buf1, "hack", 5); printf("buf2: %s\n\n", buf2); free(buf2); }
Buf2 "occupies the memory location of buf1. After UAF, buf2 is successfully tampered with
The program allocates the heap block buf2 with the same size as buf1 to occupy the pit. It seems that buf2 is allocated to the released memory location of buf1. However, because the buf1 pointer is still valid and the memory data pointed to is unpredictable, it may be recycled by the heap manager or filled by other data. The buf1 pointer is called the hanging pointer, and the memory is assigned hack with the help of the hanging pointer buf1, As a result, buf2 is also tampered with as hack.
If the original vulnerable program references the data pointed by the hanging pointer to execute instructions, it will lead to arbitrary code execution.
In common browser UAF vulnerabilities, a C + + object is re referenced after it is released. Assuming that there is a UAF vulnerability in the program, there is a hanging pointer pointing to the test object. To realize vulnerability exploitation, overwrite the virtual table pointer of the test object by occupying the pit. The virtual table pointer points to the storage address of the virtual function. Now let it point to the maliciously constructed shellcode, When the program references the test object again, it will cause arbitrary code execution.
Schematic diagram of UAF vulnerability utilization
0x08 array out of bounds access vulnerability
First, distinguish between array cross-border vulnerabilities and overflow vulnerabilities: array cross-border access contains read-write types, and overflow belongs to data writing; The essence of some overflow vulnerabilities is indeed array cross-border vulnerabilities.
Array crossing is like pouring the wrong cup when pouring water. Overflow is like water overflowing from the cup.
The following code analyzes the array cross-border access vulnerability as an example:
#include "stdio.h" int main(){ int index; int array[3] = {0x11, 0x22, 0x33}; printf("Enter array index subscript:"); scanf("%d", &index); printf("Output array elements: array[%d] = 0x%x\n", index, array[index]); //Array out of Bounds Read operation //array[index] = 1 ; // Array out of bounds write operation return 0; }
Execute the generated program, and then input 12345 respectively. The output results are as follows. When the subscripts of the input array are 12 respectively, the normal value will be obtained, but it is beyond the range of the original array from index 3. For example, entering 5 will access the array beyond the range of the array, resulting in reading the value that is not within the control range of the program.
Using ollydbg debugging, it is found that array[5] is the sixth data 0x4012A9 from array. Data outside array has been read. If the cross-border access distance is too large, inaccessible memory space will be accessed, resulting in program crash.
0x09 type confusion vulnerability principle
Type Confusion vulnerability generally resolves the reference of data type A as data type B, which may lead to illegal access to data and execution of arbitrary code, such as converting Unit into String and class object into data structure.
Type confusion vulnerability is the mainstream vulnerability of browser vulnerability mining. This kind of vulnerability is very common in weak typed languages such as java and js.
In the following code, class A is confused with class B, which may cause the private domain to be accessed externally:
class A { private int value; }; class B { public int value; }; B attack = AcastB(var); //Convert type A confusion to type B attack.value = 1; //Causes access to private domains
Take IE/Edge type confusion vulnerability (CVE-2017-0037) as an example. The reason for the vulnerability is that the object type is not strictly checked during function processing, resulting in type confusion.
The PoC is as follows: a table is defined in the PoC, the table id is th1 defined in the label, referenced in boom(), and then the setInterval setting event.
Run PoC, attach and load with Windbg, and crash occurs
From the crash point, we can see that eax, as a pointer, refers to an invalid address, resulting in a crash. The previous instruction is a call. The invalid return value comes from this call. At this call, the breakpoint is set, ecx is used as a parameter, and the stored object is a Layout::FlowItem::`vftable virtual table
Here, the value of + 4 in the virtual table is read. When it is 0, the this pointer is assigned v1, and then returned after v1+16. Therefore, the situation of the pointer of Layout::FlowItem::`vftable is normal, and the function will return normally and enter the subsequent processing logic
If the program continues to run, the function will be called again. At this time, ecx is not a virtual table object, but an int Array object. Here, we can track the creation process of the two objects through conditional breakpoints, focusing on the functions created by the two objects, one is the virtual table object corresponding to FlowItem::`vftable, and the other is the int Array object causing the crash. The return value of these two functions is the pointer to the two created objects stored in the eax register.
Through tracing, we can see that ecx is a normal FlowItem object when the Readable function is called for the first time, and an int Array Object when ecx is called for the second time. The layout:: patchable >:: Readable function is a function that handles virtual table objects, because Th1. 0 is referenced in the boom() function Align causes the Readable function to get the second reference. Because the object property is not checked, the table object is passed in the second call, and finally type confusion crashes.
0x10 competitive condition vulnerability principle
Race Condition is that multiple threads / objects / processes operate on the same resource at the same time, resulting in the system executing behavior contrary to the original logic setting. Such vulnerabilities are very common in linux, kernel, windows and web.
The emergence of mutex is to solve such loopholes and ensure that when an object accesses a specific resource, other objects cannot operate the resource.
The "race condition" occurs when multiple threads access the same shared code, variable, file, etc. at the same time without locking or synchronization—— Wikipedia-computer_science
For example, the following code:
#-*-coding:utf-8-*- import threading COUNT = 0 def Run(threads_name): global COUNT read_value = COUNT print "COUNT in Thread-%s is %d" % (str(threads_name), read_value) COUNT = read_value + 1 def main(): threads = [] for j in range(10): t = threading.Thread(target=Run,args=(j,)) threads.append(t) t.start() for i in range(len(threads)): threads[i].join() print("Finally, The COUNT is %d" % (COUNT,)) if __name__ == '__main__': main()
The results are as follows:
According to our expectation, the results should all be 10, but it is found that there may be unexpected solutions to the results. The reason is that we do not make synchronization constraints on the variable COUNT, which may lead to Thread-7 reading the COUNT and not having time to change the COUNT. Thread-8 grabs resources and reads the COUNT, and modifies the COUNT to its reading result + 1, resulting in unexpected results.