Practical analysis and summary of various binary vulnerability principles

Posted by groundwar on Sun, 26 Dec 2021 22:42:39 +0100

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

0x03 heap debugging skills

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.

Topics: C++ security