How “Russian hackers” tried to learn about new sanctions against Russia: we study CVE-2015-1701

    This zero-day vulnerability in Windows became known on April 20, when FireEye and Bloomberg reported an unsuccessful cyber attack on a government agency in a foreign country that was discussing a US sanctions policy against Russia. The “Russian hackers” from the APT28 group were accused of involvement in the deed, as well as in attempts to hack the NATO special services, state bodies of Georgia, Poland, Hungary and FireEye.

    The attack was implemented using previously unknown vulnerabilities CVE-2015-3043 in Adobe Flash and CVE-2015-1701 in Windows. The user was sent via a link to an infected site, where a JavaScript script using the Flash vulnerability downloaded an executable file to the computer, which, through the hole CVE-2015-1701 in Windows, increased privileges and stole encryption keys.

    Adobe eliminated the vulnerability in Flash within hours, but Microsoft took the time and released the patch only the day before. In this article we will talk about the main features of this bug.

    Valuable gSharedInfo


    First, some structures and mechanisms used to exploit the CVE-2015-1701 vulnerability should be described. This time, it was not without the notoriouswin32k.sys one, so the first thing we will focus on is the structure win32k!tagSHAREDINFOto which the symbol corresponds win32k!gSharedInfo, as well as the data type HWND, which is very closely connected with it. Ours stores pointers to various structures associated with windows and, what is most remarkable, many of these structures are mapped to user space (mapped to a user mode, in our opinion), and the corresponding symbol has been used for some time now (either from whist or from seven) became exported. We are interested in two fields here:



    gSharedInfouser32!gSharedInfo





    • aheList- points to an array of type elements win32k!_HANDLEENTRY;
    • HeEntrySize- contains the size of the element win32k!_HANDLEENTRY.

    So, the lower 16 bits of the window handle HWNDare actually the index in the array gSharedInfo->aheList. For example, if our variable windowcontains a HWNDdescriptor:



    the same thing in the kernel:



    The wUniqstructure field win32k!_HANDLEENTRYcontains the top 16 bits of the descriptor HWNDand, apparently, serves the simple purpose of separating objects that occupy the same address in a given array at different time intervals. Thus, if the object is freed and later its place will be taken, for example, by a new window with wUniq = 0x12, then the old descriptor 0x0011024cwill no longer be able to access it.

    The fields bFlagsand bTypecontain various flags and the type of object addressed by the phead field, respectively. You can look at the possible values ​​that they accept.The ReactOS .

    Here we are only interested in one possible value bType:

    TYPE_WINDOW = 1

    meaning that the object is a window, and the field pheadaddresses the structure win32k!tagWND.



    Here you can pay attention that the user user32!gSharedInfo->aheList[…].pheadstores the address belonging to the kernel. However, if you wish, you can get the address of its user display, but this is a different story, so for details I refer you to the window handle that receives the input HWNDand the return tagWND*procedure user32!ValidateHWND, or rather, to the one that it calls user32!HMValidateHandle.

    The last field of pOwnerstructure not considered earlier win32k!_HANDLEENTRYcontains a pointer to the win32k!_W32THREADstream to which the object belongs. Each thread stores this pointer in win32k!_KTHREAD->Win32Thread(why not in_ETHREAD), and also, which in our case is much more important, c TEB!Win32ThreadInfo.



    Using all this information, we can search for windows that belong to the flow of our process and restore their descriptors. To do this, find an element user32!gSharedInfo->aheList[…]in which:

    • bType == TYPE_WINDOW;
    • pOwner == TEB!Win32ThreadInfo.

    The index of such a structure will be equal to the low 16 bits of the descriptor, and the high 16 bits will be contained in the field wUniq.

    Why not just take advantage user32!FindWindow? At that moment, when we need it, the name and class will not be filled by the window yet.

    KernelCallbackTable


    Another concept that should be explained is closely related to the field PEB!KernelCallbackTable.



    As you can see, various callbacks are contained here, but of course they didn’t kernel, but got their name because their client is usually win32k.syscontacting them when they need to perform an operation in user space. The call takes place in a mannerntdll!KiUserCallbackDispatcher similar to dispatching .

    In the kernel, the callback mechanism of these callbacks is implemented in a function nt!KeUserModeCallback. The call occurs at the callback index. Address resolution by index is already in ntdll!KiUserCallbackDispatcher.

    SetWindowLongPtr


    Next in line user32!SetWindowLongPtr, but in fact - its execution in the form win32k!xxxSetWindowData. We restrict ourselves to only one case that interests us - with the parameter GWLP_WNDPROC.

    win32k!xxxSetWindowDataperforms various checks first. For example, whether the window belongs to the process whose thread it is trying to install WndProc, and whether this window is already destroyed ( FNID_DELETED_BITbit).

    Then comes the very important optimization for us.



    On the passed parameter WndProc( value_in the screenshot) is called MapClientToServerPfn. This simple and at the same time extremely useful function maps functions from win32k!gpsi->apfnClientWand win32k!gpsi->apfnClientAto their corresponding functions from win32k!gpsi-> aStoCidPfn:







    If such a mapping is for a transmittedWndProcperhaps the procedure call can be optimized by referring directly to the implementation of the function in the kernel, for example, win32k!xxxDefWindowProcwithout wasting time switching to user mode to call the wrapper, for example, ntdll!NtdllDefWindowProc_Awhich user32!DefWindowProcAis a pass-through export.

    As can be seen from the screenshot, if the display is successful, then a flag is raised at the window WFSERVERSIDEPROC, after which the displayed value is entered in its field win32k!tagWND->lpfnWndProc.

    Thus, if you user32!SetWindowLongPtrinstall one of the standard procedures, then, in fact, the corresponding procedure from win32k.syskernel mode will be executed .

    xxxCreateWindowEx


    Now consider creating a window. Roughly speaking, the procedure is entirely responsible for this win32k!xxxCreateWindowEx. First, the win32k!HMAllocObjectobject is allocated by calling tagWNDand information about it is entered into the table gSharedInfo->aheList:



    Then the attributes of the window are filled. The whole procedure even hex-raystakes a couple of thousand lines, so there is no sense or opportunity to dwell on all the actions performed.

    Operation option


    The question arises: what will happen if you call SetWindowLongPtr(hwnd, GWLP_WNDPROC, DefWindowProc)the window at the moment when it is already created, but it still has a filled field lpfnWndProc. After all, this field is populated from the class field, in which it is probably already stored displayed by MapClientToServerPfn, if such a mapping is possible.

    And indeed, there is a possibility of calling the SetWindowLongPtrflag WFSERVERSIDEPROCbefore the address WndProcis filled with the value from the class field. At the same time, this flag does not drop when the field is set WndProc, since the developers did not expect the possibility that it could be set. Only the logic for setting the flag for the window is present if the corresponding class flag is raised.



    However, the probability of setting a flag from a neighboring thread by a call SetWindowLongPtrat runtimeCreateWindowExinsignificant, because you must first find the HWNDwindows in the array user32!gSharedInfo->aheList, after which the chain of calls user32!SetWindowLongPtr -> … -> win32k!xxxSetWindowDatashould work out faster than the initialization of the fields tagWNDin win32k!xxxCreateWindowEx. You can, of course, play with the processor affinitythread priorities. However, for Windows 7 and earlier there is a simple way.

    Option for Windows 7


    Despite the enormous size of the function win32k!xxxCreateWindowEx, all the information we are interested in fits into several hex-rays lines:



    If, during the registration of a window class, it specified a picture for a regular icon hIcon, but was not specified for a small icon hIconSm, then win32k!xxxCreateWindowExwhen creating a window for the first time, this class copies , or rather - scales, the icon to fill the field win32k!tagCLS->spicnSm. This action is performed by a function win32k!xxxCreateClassSmIconthat delegates the task to one of the user so-called so-called kernel callbacks:



    Under the 0x36th number in the table goes user32!_ClientCopyImage. He performs the task.



    After copying the icon, the windows from the class are win32k!xxxCreateWindowEximmediately filled . Then, as seen, if the flagWndProcWndProcWFSERVERSIDEPROC erected in the classroom, it is erected for the window.

    results


    As a result, we obtain the following. First, you need to register the class with the usual icon, but without specifying a small one:





    You also need a hook to user32!_ClientCopyImage:



    It will call SetWindowLongPtrfor the window you just created:



    After that, at the time the window was created, the previously installed hook is called.



    The window at this moment is already listed in the table, but not yet initialized.





    A hook invokes SetWindowLongPtrthat raises a flag bServerSideWindowProcin the corresponding window structure.



    And upon returning from the callback, it win32k!xxxCreateWindowExoverwrites the lpfnWndProcvalue from the class field.



    Thus, the window function specified when registering the class will be executed in the kernel:



    Obviously, the simplest thing for which this can be used is the theft of a system token with the subsequent launch of a system shell.





    PS A quick inspection of Windows 8.1 showed that the win32k!xxxCreateWindowExinstallation tagWND->lpfnWndProcand the call win32k!xxxCreateClassSmIcongo in the reverse order compared to earlier versions. Thus, hooking user32!_ClientCopyImagewill no longer help.

    There is a possibility that the “race condition” still exists and can with some probability be exploited above using the two-thread method. In this regard, nothing more accurate can now be said.

    Also popular now: