Nytro Posted September 16, 2020 Report Posted September 16, 2020 HEVD writeups Sep 15, 2020 Yuvaly0 Intro This writeups do not aim to replace all of the existing good places already. I wrote them so I could get deeper understanding of the vulnerabilities I’ve decided to write writeups only for the vulns that interested me the most. There are references to the articles I used in the git repo. At the end of each section, I put a reference to the full source code Non Paged Pool Overflow Double Fetch Non Paged Pool Overflow This bug will occur when writing data passed the end of a buffer, in this case, the buffer is in the non paged pool. For example, a function receives a buffer and just copies it to her buffer without checking its length. Analysing the binary We are interested in the function TriggerNonPagedPoolOverflow First of all the function creates a chunk using the function ExAllocatePoolWithTag, the requested chunk is in size of 0x1f8, it’s tag will be ‘Hack’ and it will be allocated in the non paged pool. We’re given the information mentioned above and some info on our sent buffer Next, they use memcpy to copy our buffer with our given size (the vulnerability) to their buffer without any size checking. Lastly, they free the chunk. Explotation Our goal is to pop a cmd with system permissions Derandomize the pool (get to a predictable state) - pool spray Trigger the overflow and overwrite an address with a shellcode address jump to the shellcode and pop a cmd We cant just the overwrite the buffer because it will mess up the pool structure and cause a BSOD: Derandomize the pool We will be using a technique called pool spray.</br> This technique is used to get the pool to a controlled state, this is possible because of its allocator mechanism. But with what objects? We can use the event object, they are each sizeof 0x40, but if we will multiply by 8 will get 0x200 which is the size of our driver allocated chunk 0x1f8 (+ 0x8 for the _POOL_HEADER struct) The idea is that the first wave will derandomize and the second wave will start in a state where the pool is already derandomized. We could do it in one wave. Some handles address, so we could check the state with windbg We can see that because we freed 8 consecutive chunks, they became one big chunk in size of 0x200 (including the pool header) Trigger Overflow The TypeIndex field in the _OBJECT_HEADER is an index to a table of pointers that will point to different OBJECT_TYPE types. Inside the OBJECT_TYPE, there are a couple of pointers for functions, such as: OkayToCloseProcedure, CloseProcedure.</br> See below So if we could overwrite the pointer to the table, causing it to point to another index in the table say - the first index, 0, is a null pointer, because we are operating on windows 7 we can allocate a null page and simulate the OBJECT_TYPE struct there, giving us the ability to control EIP But we cannot just overwrite the object header with random or even some other chunk metadata because its unsafe. Because we know that we will overwrite an event object we can take one of our known headers, after all, we know all of them are the same (at least until the Lock field offset, which is 0 anyway). Getting system Now we need to concat all of our previous steps and run the program: full source code Double Fetch This kind of bug happens when the user-supplied data is fetched twice, for example, there is an ioctl that receives an array of chars and its length, if the function will check the size and will copy using it (the same reference to the variable). It will expose itself to the double-fetch bug. This is also called TOC-TOU, TimeOfCheck and TimeOfUse, when you are fetching this value for the second time you are exposing yourself to the fact that the user will be able to change this data between the check and the use thus the vulnerability. Analysing the binary We are interested in the function TriggerDoubleFetch. First of all the function prints for us some data. Then a check is made, the size that we supplied vs the size of the kernel buffer size to prevent overflow If we passed the check, our buffer is copied to the kernel buffer using memcpy and the size we sent. The fact that the function “fetches” the size twice we have a window of opportunities to change its value. So if we look again at what we can achieve, we can get OOB(out of bounds) write on the stack. Explotation Ok, so we want two things to happen Change the value before its use and after the check. Jump to an arbitrary address of our choosing So we will run two threads, one that will repeatedly engage with the driver and will trigger a double fetch vulnerability and another to change the value of the size being sent. Ok, let’s create two threads and attach our functions To pop a cmd with system we need to consider something else like our computer resources At first, my VM was with one processor, we must think about our OS resources, for example, how much processors we have? a low number (<4) will give us a hard time when trying to exploit. It took me quite some time to trigger the exploit using two processors Also, we need to consider the fact that our threads are not alone in the system and we are not even in the highest priority for our system Let’s change our threads priority And a check to verify the number of processors Now we can run the exploit with success Another thing we can do is set each of our threads to a different processor, so he will not be competing with our second thread about the processor resources where i represents the location of a bit in a bitmask that represents the processor number</br> (i == 0 -> first processor) of course, we will set by our machine capabilities or the call will fail. full source code updated_at 15-09-2020 Sursa: https://yuvaly0.github.io/2020/09/15/hevd-writeups.html Quote