00:00:00.083-->00:00:05.333 Hey guys, so. Today, I will try to Demystify Windows Kernel Exploitation by Abusing GDI 00:00:05.333-->00:00:10.750 Objects. My name is Saif. I’m Egyptian and I work for Sensepost. That’s the Egyptian 00:00:10.750-->00:00:17.542 traditional dress over there. Now I want to start by saying why am I doing this so um, a 00:00:17.542-->00:00:22.917 year and a half ago I started getting into binary auditing and wanted to do static analysis and 00:00:22.917-->00:00:28.375 finding vulnerabilities. And I found CTF’s really enjoyable but as- at the same time they don’t 00:00:28.375-->00:00:33.250 really present real world scenarios. So I decided to go for patch diffing and finding 1 00:00:33.250-->00:00:39.042 days. And the result was epic and I hope you guys like it through the talk. So what we 00:00:39.042-->00:00:45.458 will learn through this talk is first Abusing two types of GDI Objects, to gain ring zero 00:00:45.458-->00:00:50.458 exploit primitives. The next thing is analyzing two one days MS16-098, MS17-017 by using this 00:00:54.583-->00:00:59.583 techniques. Now the complex is pretty complex, um I will try to simplify it as much as possible; 00:01:02.917-->00:01:08.000 however, there is a full white paper um and the slides and the exploit code and everything that 00:01:08.000-->00:01:13.000 is up on GitHub at the moment. You can access it on that link. The first thing that I have to 00:01:16.458-->00:01:21.167 talk about before we get- get into the true stuff is the kernel pool. You can think of 00:01:21.167-->00:01:25.792 the kernel pool as the heap memory fo- that the Windows kernel uses. The first thing 00:01:25.792-->00:01:30.375 that the kernel pool that, is that any object that allocated to the pool will have a size a 00:01:30.375-->00:01:36.250 pool header attached to it. For 64 bit systems this headers is 8 bytes in size and for 86 bit 00:01:36.250-->00:01:41.250 systems this header is 8 bytes in size. The next thing is that small allocations, or 00:01:43.250-->00:01:48.458 allocations smaller than thousand bytes will be allocated to a pool page that has the size 00:01:48.458-->00:01:52.625 of one thousand bytes. So the kernel pool is effectively different mented into two 00:01:52.625-->00:01:57.375 thousand byte pages. And the allocation dynamics works as followings. SO the first 00:01:57.375-->00:02:02.083 allocation will be allocated from the beginning of the page. Subsequent allocations will be 00:02:02.083-->00:02:07.083 allocated by the end of the page. The next thing I want to talk about is kernel pool 00:02:12.625-->00:02:19.083 spraying. Why do we do kernel pool spraying or feng-shui in the exploit development? First 00:02:19.083-->00:02:25.250 of all it is used to get the pu- kernel pool memory in deterministic state. The way it 00:02:25.250-->00:02:30.625 does it is by doing a series of allocations and deallocations. The series of deallocations is 00:02:30.625-->00:02:34.458 used to create memory holes between that hopefully our vulnerable object will be 00:02:34.458-->00:02:39.792 allocated too. And thus having our vulnerable object allocated in a space between objects under 00:02:39.792-->00:02:45.792 our control that we can abuse to gain an extra exploit primitive or a- an extra access to the 00:02:45.792-->00:02:50.792 memory next to it. The next thing I want to follow through is kernel pool corruption. And 00:02:52.875-->00:02:57.875 we will focus about x86 integer overflows or integer overflows in general. So, the first 00:03:00.792-->00:03:05.792 equation to talk about is FFFFFF 80 plus 81 will result in 1. While that’s not really the 00:03:08.917-->00:03:13.917 truth behind it. The truth is that it actually results in a much larger number 01000001. But 00:03:16.542-->00:03:23.167 x86 registers can only hold up to 4 bytes in memory. So this number is larger than 4 bytes 00:03:23.167-->00:03:30.167 max int and the most significant byte or D word anything that is larger than four byte will then 00:03:30.167-->00:03:35.167 be truncated, thus equals to one. First part I want to address is linear overflows. And 00:03:38.708-->00:03:43.792 this can be a result of mem copies with a larger size than the located object or a memory 00:03:43.792-->00:03:48.833 copying group that is larger than the allocated object. So if an overflowed size will supply 00:03:48.833-->00:03:53.208 the location object it would result in a very small object being allocated and then a 00:03:53.208-->00:03:58.042 memory copying loop or a memory copying function will try to copy a large number of data to 00:03:58.042-->00:04:04.833 that small sized allocation. Effectively overflowing the next object in memory with the amount 00:04:04.833-->00:04:09.833 of bytes that it tries to copy. The next one is out of bounds writes. So if you think of an 00:04:12.542-->00:04:16.667 overflowed size that will allocate the smaller object and then the function expects that 00:04:16.667-->00:04:21.125 object to be of a certain size and tries to write to a certain offset of it, it will 00:04:21.125-->00:04:26.125 effectively write this object or this data in an out of bounds location from that location of 00:04:28.625-->00:04:32.958 the allocated size. Now both of these you will see how we can exploit them when we get to the 00:04:32.958-->00:04:39.333 exploitation part of the one days And now I want to talk about how I was able to gain 00:04:39.333-->00:04:43.750 exploitation primitives out of these type of com- pool corruptions. And one of the 00:04:43.750-->00:04:49.833 things that we I’m gonna focus about is actually the abuse of GDI objects. Now there are 00:04:49.833-->00:04:53.000 certain objects that are allocated to kernel memory that has some interesting 00:04:53.000-->00:04:58.750 characteristics that can give us some sort of memory reading writing primitives For example, 00:04:58.750-->00:05:04.167 if we want to get a relative number read and write. Which is basically reading and writing in 00:05:04.167-->00:05:08.917 the memory location adjacent or relative to the object location in memory. The object that can 00:05:08.917-->00:05:14.083 be abused has to have a size member that can be extended to be able to access out of bounds 00:05:14.083-->00:05:18.958 memory adjacent to it’s location. If you want to get arbitrary memory read and write 00:05:18.958-->00:05:23.708 the object has to have some sort of data point in memory that if you can corrupt or control its 00:05:23.708-->00:05:29.792 value you will be able to read and write from any location in memory of kernel read space. And 00:05:29.792-->00:05:32.958 if you look at the process of who this is done. If you consider that we have two 00:05:32.958-->00:05:37.667 objects that are allocated adjacent to each other and these objects both have a size member 00:05:37.667-->00:05:42.917 and a data pointer member We can use the first object or any pool corruption primitive to actually 00:05:42.917-->00:05:48.292 corrupt the size of the first object. Thus extending that, that amount of memory that it 00:05:48.292-->00:05:54.250 can read and basically go into the adjacents object’s memory and then use the first object as 00:05:54.250-->00:06:00.000 a manager to actually overwrite the address or the data pointer of the second object and use the 00:06:00.000-->00:06:04.750 second object as a worker to read and write from any point in memory. Now this exploitation 00:06:04.750-->00:06:09.750 technique can be used in kernel and is heavily used in browsers as well. The first of these 00:06:09.750-->00:06:14.833 objects that can be abused is the bitmaps. Now GDI bitmaps techniques have been there from 00:06:14.833-->00:06:21.583 2015. So the first people who talked about it was Ski Team and it was later heavily detailed by 00:06:21.583-->00:06:28.417 eh Nico Kimono I hope I said this right and Diego Juarez. Um, the kernel, the bitmap is 00:06:28.417-->00:06:35.083 presented in memory by a surf object and has a pool tag of GH question mark 5 which represents 00:06:35.083-->00:06:40.208 a number that differs from one system to another. So this can be zero or one or two depending 00:06:40.208-->00:06:45.333 on the version of Windows or Gla5 when its allocated the look inside list which is outside of 00:06:45.333-->00:06:51.958 this talk. And uh this is how the surf object structure looks in kernel memory. So you notice 00:06:51.958-->00:06:55.792 that I highlighted a couple of numbers which are interesting to us. First of all is the 00:06:55.792-->00:07:00.417 sizlmitmap which represents the width and height of the bitmap. So if you can corrupt any of 00:07:00.417-->00:07:05.250 these numbers you’d be able to effectively extend the size and gain relative memory to read and 00:07:05.250-->00:07:10.250 write. The other number the pvScan0 which is a pointer to the bitmap data. The way you can 00:07:12.708-->00:07:17.583 allocate bitmaps to memory is by calling create bitmap user mode function. The- This takes the 00:07:17.583-->00:07:23.000 width, a height, the planes, bitsperpixel and bits of the bitmap and allocates a bitmap in 00:07:23.000-->00:07:28.000 memory. The way you can Free bitmaps is by calling delete object. The next point is the 00:07:31.875-->00:07:36.542 way you can read the bitmap memory is by using GetBitmapBits. These are all 00:07:36.542-->00:07:41.250 user mode functions, you can code them from any application. And the way you can write to 00:07:41.250-->00:07:46.250 bitmap memory is by using SetBitMapBits. So how do you exploit or abuse Bitmaps? 00:07:48.667-->00:07:52.958 Basically, if you consider that we have two bitmaps that are allocated adjacent to each other 00:07:52.958-->00:07:57.958 as a result of our kernel pool spray. You, if you have a pull corruption that allows you to 00:07:57.958-->00:08:02.583 overwrite the width or the height of a sizlBitmap; that effectively extends this bitmap 00:08:02.583-->00:08:07.875 to write into the adjacent Bitmap memory and then we can use that as a manager and 00:08:07.875-->00:08:12.875 overwrite the pvScan0 of the second bitmap and then we’re able to read and write from any 00:08:12.875-->00:08:17.875 point in memory. The next thing I want to discuss is an undisclosed technique that has 00:08:20.125-->00:08:24.833 not been discussed anymore, anywhere. Um, I just had that conversation with Scabi about it 00:08:24.833-->00:08:29.500 and he mentioned that they have seen some in the wild but it has not been documented anyway, so 00:08:29.500-->00:08:34.708 this is effectively sort of an 0hday technique. And the way we are, the way we address it, or 00:08:34.708-->00:08:41.292 the object that we use is actually color palettes. So color palettes are interesting 00:08:41.292-->00:08:48.208 objects they are presented in kernel memory by using the palette or the XEPAL object name 00:08:48.208-->00:08:52.833 and the have the PoolTag of Gh number 8 or Gla8. This is the x86 structure of the object. And 00:08:52.833-->00:08:57.833 this is the 64 bit structure of the object. Now, the members highlighted are in red are the 00:09:00.417-->00:09:06.750 interested, numb- interesting members to us. So you find that the cEntries member which 00:09:06.750-->00:09:12.625 represents the entries count of the palette can be overwritten or extended uh which allow, 00:09:12.625-->00:09:17.375 which gives us relative memory read and write primitive. And the second number that we can 00:09:17.375-->00:09:23.167 abuse is the pFirstColor pointer. So this is a pointer to the array of colors of that 00:09:23.167-->00:09:26.958 color palette which is highlighted in green and usually allocated by the end of the 00:09:26.958-->00:09:31.958 object. So, you can allocate GDI palettes by using the KA palette function that takes a logical 00:09:36.458-->00:09:42.792 palette structure that contains the palette entries as well as the palette ah, un, entry 00:09:42.792-->00:09:47.958 numbers and the palette version and the palette entries contain the RGB color value for each 00:09:47.958-->00:09:52.958 palette. You can free palette objects from kernel memory by using delete object. And you can 00:09:56.750-->00:10:02.708 read palette memory by using get palette memory get palette entries function from user mode 00:10:02.708-->00:10:08.042 and you have two functions to actually write to uh to palette memory in the kernel which are 00:10:08.042-->00:10:12.375 SetPaletteEntries and AnimatePalette and we will look at the difference- differences 00:10:12.375-->00:10:17.375 between them in a bit. So how do you exploit palettes? If we have a pool spray that results in two 00:10:20.167-->00:10:24.875 adjacent palettes be- allocated in memory and we have a pool corruption primitives that 00:10:24.875-->00:10:29.625 allows us to actually increase or extend the size or the number of entries of the specific 00:10:29.625-->00:10:35.042 palette that will give us relative read and write into the adjacent object which is another 00:10:35.042-->00:10:40.083 palette. We can abuse that by overwriting the pFirstcolor pointer and use the second 00:10:40.083-->00:10:46.792 palette to read and write from anywhere in kernel memory. So there are some technique 00:10:46.792-->00:10:52.458 restrictions in regards to using color palettes in exploitation. First of all the minimum palette 00:10:52.458-->00:10:57.458 allocation size for x86 system is 98 bytes and D8 bytes for x64 ones. So when you corrupt the c 00:11:01.125-->00:11:07.000 entries member it has to be larger than these values. The next restriction is related to 00:11:07.000-->00:11:11.708 setpaletteentries function when you try to write to palette memory using setpaletteentries 00:11:11.708-->00:11:18.250 if you clobber any of the fuc- the current member any of these members it will block the 00:11:18.250-->00:11:22.000 writing to memory which effectively will result in a blue screen of death or will 00:11:22.000-->00:11:27.000 result in erroring out without actually writing to kernel memory. So the first restriction 00:11:29.292-->00:11:34.042 in regards to SetPaletteEntries when you call SetPaletteEntries from user mode it will reach 00:11:34.042-->00:11:39.292 GRESetPaletteEntries and then it will call XEPAL object ulSetEntries and you see in the 00:11:39.292-->00:11:44.250 highlighted parts the palette is actually checking for the pTransCurrent and the pTransOld 00:11:44.250-->00:11:49.375 which are the transformations that happen on the specific color palette. If any of these 00:11:49.375-->00:11:54.458 members are set it will try to access this memory location and then will try to end the value 00:11:54.458-->00:11:59.000 in it by zero. So if these member notifications were set and not allocated it will error 00:11:59.000-->00:12:04.208 out without writing anything to memory. The next restriction is that when you call 00:12:04.208-->00:12:09.625 SetPaletteEntries and after the previous function was called it will actually try to access the 00:12:09.625-->00:12:15.042 hdcHead number which presents the owner context of the palette, if this value was set, 00:12:15.042-->00:12:20.625 it would try to get the owner of the palette to set its value in the device context. Now this 00:12:20.625-->00:12:24.500 will effectively result in a blue screen of death which will kill the whole system and not 00:12:24.500-->00:12:29.542 error out and not write anything. The second restriction I want to talk about is about 00:12:29.542-->00:12:35.833 AnimatePalette. So AnimatePalette has to have the pointer pointed to pFirstColor 00:12:35.833-->00:12:40.042 has to be of an odd value, the first byte of it, has to be an odd value. And we know the 00:12:40.042-->00:12:45.042 reason why, thank you MSDN, said specifically that AnimatePalette would only work on entries that 00:12:47.083-->00:12:52.417 has the PC_Reserved flag set and that flag is effectively one so that’s why you can see 00:12:52.417-->00:12:57.417 highlighted there that the function tries to test for one before writing. Now this didn’t 00:12:57.417-->00:13:02.333 really present any problems in eight- actually six systems since you could easily control 00:13:02.333-->00:13:07.417 where the palette is and control the first byte of the pulled memory to be an odd value, 00:13:07.417-->00:13:13.500 however in 64 bit systems it proved to be a bit of a problem set the first um part of the 00:13:13.500-->00:13:18.500 address since it’s always FF. [sighs] Now we need to move on to the next step of 00:13:21.750-->00:13:28.083 exploitation. What we need to do is we need to try to steal a system Eprocess Token and what 00:13:28.083-->00:13:34.042 this is is that each process that is running on the system is represented by an Eprocess 00:13:34.042-->00:13:39.917 structure in kernel memory, this structure contains very interested members. It contains 00:13:39.917-->00:13:45.750 a member such as an ImageName which is the exe name and it contains a token. The token is 00:13:45.750-->00:13:50.542 the most interesting part of it since this token represents the security permission that this 00:13:50.542-->00:13:55.500 process has. Also it has a member that is the ActiveProcessLinks which is a 00:13:55.500-->00:14:00.458 double link list that is actually pointing to the next Eprocess entry in kernel memory, 00:14:00.458-->00:14:06.833 and the UniqueProcessID which is the PID of the current process. The offsets to these members 00:14:06.833-->00:14:11.125 differs from one system to another, and specifically for this talk we’ll be covering 00:14:11.125-->00:14:17.208 Windows 8 point 1 64 bits, and Windows 7 SP1 at- for X86 Bits and these are the offsets to 00:14:17.208-->00:14:22.708 these members. And the game plan we have to actually exploit this or get the system token of the 00:14:22.708-->00:14:27.583 system process is first we need to get the address of the eprocess, or the system’s 00:14:27.583-->00:14:33.250 eprocess structure in memory. And the way we can do this is actually there’s an exported 00:14:33.250-->00:14:37.750 symbol called PSInitialSystemProcess, so if you load then TOS kernel into 00:14:37.750-->00:14:43.375 TOXE into your program’s memory and get its offset and subtract it from the base of the NTOS 00:14:43.375-->00:14:49.208 kernel memory, you’ll get an offset that this specific entry is located in the kernel and 00:14:49.208-->00:14:54.542 then you can easily leak the NTOS base kernel address from the drivers and then just add 00:14:54.542-->00:14:58.625 that this offset to it and successfully you clogged the system EProcess structure 00:14:58.625-->00:15:04.417 location from the kernel mode. Then we use the Arbitrary read primitive that we got to 00:15:04.417-->00:15:09.625 actually read the token of the system process and move on to iterating over the 00:15:09.625-->00:15:14.542 ActiveProcessLinks until the process current ID or the UniqueProcessID represents the 00:15:14.542-->00:15:19.583 CurrentProcessID and use the Arbitrary write primitive to just replace our Current Process 00:15:19.583-->00:15:25.417 Token with the system one effectively gaining an innovative type privileges. The 00:15:25.417-->00:15:31.083 first exploit I want to talk about is actually MS17-017 while I read of the death I don’t know 00:15:31.083-->00:15:36.208 if that’s true, um Microsoft has actually released it back in March um and that’s the patch 00:15:36.208-->00:15:42.458 that I reversed but it can be MS17-013 as well, but I am not very sure about it. It affects 00:15:42.458-->00:15:49.292 um all versions of Windows but um I found it very difficult to exploit it on 64 bit ones um so 00:15:49.292-->00:15:55.750 I was only able to exploit it on Windows Sp1 X86 and it tri- the function that is vulnerable is 00:15:55.750-->00:16:00.583 ENGRealizeBrush and the type of the vulnerability is an Integer overflow that leads to an Out Of 00:16:00.583-->00:16:06.500 Bounds Write. First of all, the first step that I took to analyze this kind of exploit is 00:16:06.500-->00:16:12.500 to actually diff the patch that was released. It was released back in March 2017. This is the 00:16:12.500-->00:16:19.042 function that is uh vulnerable which is ENGRealizeBrush and this is the patch. So it was 00:16:19.042-->00:16:23.875 very difficult to find out where the problem actually is as you can see there were many changes, 00:16:23.875-->00:16:28.833 all of the changes were related to some integral checking mechanisms, or integral checking 00:16:28.833-->00:16:34.750 functions um so I decided to look at the function itself, and the first step to do that is 00:16:34.750-->00:16:40.833 actually find a way to trigger that function from user mode. So if you look, the first function 00:16:40.833-->00:16:45.625 you need to call is CreatePatternBrush and this will create a brush using a specific 00:16:45.625-->00:16:51.083 bitmap that you supplied, and then use the function PatBlt which actually writes the brush 00:16:51.083-->00:16:56.083 pattern to a specific path in memory. And then this will lead effectively to that function. So 00:16:58.667-->00:17:04.042 the way you do it in code in C code is this, this is actually an expert of the exploit code so 00:17:04.042-->00:17:09.042 in the future any of that th- uh code that is between this uh tangle is actually expert from 00:17:12.042-->00:17:18.333 exploit code itself. And the above code will reach this following Ida snipped with a 00:17:18.333-->00:17:23.333 controlled value in edi. The first step that this code will do is actually get the value of 00:17:23.333-->00:17:29.542 edi, which is the bitmap width. And then it will get ecx and multiply it with this value, 00:17:29.542-->00:17:34.750 which is at the time is 20, and this can be controlled by the bitmap format, and then it will 00:17:34.750-->00:17:40.250 divide this value by 8, and then it will multiply both values, the width and the height after 00:17:40.250-->00:17:45.583 the formula calculations and then it will add 4- 44 to it, which obviously if you don’t 00:17:45.583-->00:17:51.042 have checking leading to that function you can easily overflow but what happens in the 00:17:51.042-->00:17:55.458 overflowed function? So when I overflow the integer what will happen later? Is the most 00:17:55.458-->00:18:01.542 important part. So if you notice- if you follow the instructions of what happened 00:18:01.542-->00:18:05.583 with this overflowed integer you notice that it will leach the following code snippet, or the 00:18:05.583-->00:18:11.292 code branch, which is actually an location function. So this overflowed integer ca- will be 00:18:11.292-->00:18:16.625 added to 40 again and then passed as the size value for our location function, so if you 00:18:16.625-->00:18:21.125 remember we said that if you’re able to influence the size of any location, and overflow the 00:18:21.125-->00:18:26.417 integer into a smaller size, then the location will result in a smooth location that is 00:18:26.417-->00:18:33.000 unexpected by the function itself, or by the system. So after that location happens. We 00:18:33.000-->00:18:39.000 can try to trigger this, a specific number of bytes that the object will actually 00:18:39.000-->00:18:45.333 allocate. So we need a 10 byte object to be allocated and we know why 10 bytes specifically 00:18:45.333-->00:18:50.333 in the late- next slide. So we know that the overflowed value is 1000000 10 and then we have 00:18:52.708-->00:18:57.708 to subtract 40 and 44 from it and we will reach the following number which is FFFFFF8C and 00:18:59.917-->00:19:04.917 then if you take the result and look at the factors of that result- the factors of that 00:19:04.917-->00:19:09.208 integer watch- which- presents- which two numbers when multiplied together will 00:19:09.208-->00:19:14.208 actually result in that value we’ll uh we’ll come out to 8C and 1D4 1D4 1. If we take 8C as 00:19:17.750-->00:19:22.458 the width and effectively reverse the calculations that happened in the previous slide 00:19:22.458-->00:19:29.125 by multiplying it by 8 and then dividing it by 20 will result in 23. So if I take this and carry 00:19:29.125-->00:19:34.125 the bitmap that will be used by the CreatePatternBrush by having the width of 23 and a height of 00:19:36.875-->00:19:42.167 1D4 1D4 1, I will effectively leach that location function with the locator uh with the 00:19:42.167-->00:19:47.167 controlled value of 10 bytes. And then after the fe- uh the function allocates the object it 00:19:50.375-->00:19:55.375 assigns the address of the location to the esi and the next step it takes is actually try to 00:19:57.583-->00:20:03.042 re- to write to certain offsets of esi. So the function is expecting esi to be of a certain 00:20:03.042-->00:20:09.083 size, hopefully minimum of 84 since if you supplied zero it would be added to 40 and then 44 00:20:09.083-->00:20:14.333 and it will become an 84 byte structure. So what happens when we overflow it with a 10- when 00:20:14.333-->00:20:19.333 we actually allocate a 10 byte structure is that the lost highlighted uh in blue value 00:20:22.167-->00:20:28.667 will actually write to an out of bounds offset of the object, so esi plus 3C is actually out of 00:20:28.667-->00:20:34.458 bounds, since that location size is 10 bytes and it gets added to a pool header of 8 bytes which 00:20:34.458-->00:20:40.833 makes it 18 bytes so esi plus 3c will actually write to the next object in memory. The problem is 00:20:40.833-->00:20:45.708 that this object actually is allocated at the end of the page uh this object gets freed at the 00:20:45.708-->00:20:51.917 end of the function which if you c- if you have it in the middle of a pool page it will 00:20:51.917-->00:20:55.750 effectively corrupt the next chunk’s header and that will be a problem when it gets freed at 00:20:55.750-->00:21:01.625 the end of the execution since it will de- di- the whole system will use screen with a bad pool 00:21:01.625-->00:21:06.625 header value. So why specifically 10 bytes object? If you look at the calculation, the 00:21:10.917-->00:21:16.458 allocated object size is 10, and then the bitmap pool header if it’s an adjacent bitmap is 8 00:21:16.458-->00:21:22.125 bytes and then the bitmap or the surf object starts with a base object of 10 bytes and the 00:21:22.125-->00:21:28.333 offset to the bitmap height is 14 will result in 3C which is the same value that it 00:21:28.333-->00:21:33.333 application tries to write to. So now we have three options, we can use this extended size 00:21:35.333-->00:21:40.167 bitmap to actually override the address of an adjacent bitmap which is the old technique and 00:21:40.167-->00:21:45.750 gain the ability to read and write and it will work find uh and then we can gain system. We 00:21:45.750-->00:21:50.750 can use the extended bitmap to demonstrate the arbitrary read and write capability of a 00:21:50.750-->00:21:56.042 palette object or we can bi- do bit of work and this is what we are chose to go with and use the 00:21:56.042-->00:22:00.917 extended bitmap to actually extend an adjacent pallet to gain relative read and write and 00:22:00.917-->00:22:06.333 demo how the relative read and write impacts work and then use the extended palette to actually 00:22:06.333-->00:22:11.708 override the pFirstColor member of this next palette and gain arbitrary kernel read and write 00:22:11.708-->00:22:17.792 from there. The first thing is first so we need- as I mentioned the object is allocated in the 00:22:17.792-->00:22:22.792 perner eh- in if the object was allocated in the middle of a pool page, then when the object 00:22:22.792-->00:22:27.167 gets freed at the end of the function the system will blue screen of death. So how do we 00:22:27.167-->00:22:31.792 get over that is by allocating the object at the end of the page, so when the object gets 00:22:31.792-->00:22:36.000 freed there is not a next chunk header and the pool will not- pool checking functions will not 00:22:36.000-->00:22:40.750 be able to check the next pool header and thus the free will work normally and the 00:22:40.750-->00:22:45.958 application or the system will not crash. And the first thing we need to do is, we know that 00:22:45.958-->00:22:51.208 the pool pages are separated into 1000 bytes each and we need- we know that our object 00:22:51.208-->00:22:56.125 will be in total 18 bytes, 10 bytes for the object that we supply, and 8 bytes for the pool 00:22:56.125-->00:23:01.125 header So we allocate a bitmap of size FE8 which will leave. We allocate around 2000 of these 00:23:04.042-->00:23:08.333 til the puh- the pool memory becomes in a domestic state which will leave an 18 byte 00:23:08.333-->00:23:13.333 unallocated memory at the end of the pool. Then we use the window class memory uh menu name which 00:23:16.500-->00:23:21.625 is available for the page session pool to allocate 18 byte strings that will fill in the 00:23:21.625-->00:23:26.625 unallocated 18 bytes memory. Then we freed the bitmap that we just allocated and continue to 00:23:29.958-->00:23:34.958 allocate an adjacent bitmap or a next bitmap of size 7F8 and then allocate palettes of sizes 7e8 00:23:37.375-->00:23:42.375 effectively filling the 1000 page- or the 1000 byte pool page with our controlled objects. 00:23:44.375-->00:23:51.000 Then we free some of the 18 byte menu names that we allocated and hopefully if everything worked 00:23:51.000-->00:23:56.250 we should find our object allocated at the end of the pool page as we see in front of you. 00:23:56.250-->00:24:00.125 So now the object is allocated in the end of the pool page, when the function frees the 00:24:00.125-->00:24:04.958 object, it will free it fine, and also we have an adjacent bitmap and if we remember the 00:24:04.958-->00:24:10.125 calculations that if it’s right with 3c when it has an adjacent bitmap it will actually extend 00:24:10.125-->00:24:15.125 the size of this bitmap. So the adjacent- when we look at the uh bitmap adjacent bitmap in memory 00:24:18.583-->00:24:24.250 we’ll notice that in the first part, or in the top part, the size is 18, 1A8 by 1 which is 00:24:24.250-->00:24:29.792 the width and height and after that overflow or the out of bounds rights happen we noticed 00:24:29.792-->00:24:34.750 that the size would be 1A8 and the height would be 6 effectively extending the size 00:24:34.750-->00:24:39.750 and it will effectively read past it’s bounds. So the next step to do is to actually extend 00:24:42.667-->00:24:49.167 that bitmap object to read and write to the next adjacent palette and change the c entries 00:24:49.167-->00:24:54.167 member from 1e3 which is the original size of the adjacent palette to FFFFFFFF effectively 00:24:58.042-->00:25:04.667 gaining relative read and write to 4 gigabytes of kernel memory. So how do we find this manager 00:25:04.667-->00:25:09.000 palette in the allocations? So we have two tho- around two thousand palettes that are being 00:25:09.000-->00:25:13.875 allocated in memory, how do I found the specific one that was extended? Is by roofing- looping 00:25:13.875-->00:25:18.542 over that get Palette entries function until one of the getpalette entries codes will 00:25:18.542-->00:25:25.125 result in the return value of a larger number than expected which is the size of 1e3 so 00:25:25.125-->00:25:31.708 until we find one that returns a number like larger than 388 that’s our manager palette, that 00:25:31.708-->00:25:37.792 will be used to actually overwrite the next palette in memory. So if we look at the 00:25:37.792-->00:25:42.833 next palette in memory, the top part is before we actually try to overwrite to and we will use 00:25:42.833-->00:25:48.292 SetPaletteEntries on the manager palette to actually set the pfirstColor and update it to our 00:25:48.292-->00:25:53.042 value under our control. So some of the data that we were reading using getpalette entries will 00:25:53.042-->00:25:57.208 contain actually some pool addresses. That will allow us to leak some pull addresses and 00:25:57.208-->00:26:00.875 calculate from it a header address from one of them which is the beginning of the pool 00:26:00.875-->00:26:06.250 page. So if we change the palette entries of one of the pool pages to the beginning of a 00:26:06.250-->00:26:11.333 pool page effectively pointing to the bitmap header, since we need to get this header to 00:26:11.333-->00:26:17.125 actually fix the bitmap object, because if we leave it as is, by the time we finish the execution 00:26:17.125-->00:26:23.250 that system will crash because there were pool headers that were corrupted. So the way we 00:26:23.250-->00:26:27.625 can find it is again by looping over our allocated palettes using getpalette entries, 00:26:27.625-->00:26:32.000 finding the first byte- the palette entry with the first byte of 35 which represents the 00:26:32.000-->00:26:37.833 number 5 and if you remember the bitmap object has a tag of GH5 which is part of the pool 00:26:37.833-->00:26:42.833 header, so the first byte of that object will be actually 5. So the first- then we can use an 00:26:46.042-->00:26:51.333 extended palette which we extended the size as a manager palette and use it to set the 00:26:51.333-->00:26:56.458 pFirstColor of the adjacent palette object, of the worker palette object, and then use the 00:26:56.458-->00:27:02.583 worker palette object to actually gain kernel- arbitrary kernel read and write. So the 00:27:02.583-->00:27:09.083 next step would be to use these primitives to actually read and change the current process token 00:27:09.083-->00:27:14.167 privileges. So we start by getting the initial system process and as I explained 00:27:14.167-->00:27:18.833 earlier calculating the address of this kernel system process and then using the arbitrary 00:27:18.833-->00:27:23.833 read to read the security token and then use a kernel writer replace our own and we will see 00:27:23.833-->00:27:28.833 now directly exactly how this happened. So we start by using a low privilege user. And I’ve put 00:27:34.333-->00:27:39.958 in the code some debug breaks so when we execute the code it will actually break on kernel memory, 00:27:39.958-->00:27:44.958 we just reload our symbols again. And we find our place. So on the right is our code, we 00:27:47.333-->00:27:53.083 trigger the overflow and break on the location functions to- to see where exactly if everything 00:27:53.083-->00:27:58.542 went right and you can see the pool layout went correct so we have our object allocated at the 00:27:58.542-->00:28:04.083 end and we have an extended palette and our bitmap and our manager palette and the worker 00:28:04.083-->00:28:08.625 palette in there. I’m sorry if it’s a bit fast, all the videos will be available on the GitHub 00:28:08.625-->00:28:13.792 page. And then I modified the gdi object dump window bug extension to actually dump this 00:28:13.792-->00:28:19.542 structure from a pointer, we can see the original bitmap size which was 1 and 1e3 and after 00:28:19.542-->00:28:25.750 the overwrite we can see that the height of the bitmap changed to 6. Next we view the palette 00:28:25.750-->00:28:30.750 object that is adjacent to this bitmap to see if what changes happen in memory. And we notice 00:28:40.333-->00:28:45.333 that it’s original size is 1e3 and then after we use SetPaletteEntries to actually 00:28:48.125-->00:28:53.125 overwrite its members we notice that the size will change from 1e3 to FFFFFF and now if we take 00:28:55.750-->00:29:02.625 a look at the next palette entry in memory we notice that the pFirstColor member value is the 00:29:02.625-->00:29:07.625 default value of the original value and after we overwrite the values using SetPaletteEntries, 00:29:10.708-->00:29:15.708 the value has changed pointing to a beginning of a page or a bitmap object. And if we dump 00:29:20.250-->00:29:25.250 the memory that is located at this location, now this is the updated pfirstColor and if we 00:29:27.833-->00:29:32.792 look at the memory that is in that location we’ll notice an original bit- this is the 00:29:32.792-->00:29:38.542 clobbered bitmap header and we already read the original bitmap header and after we write to it 00:29:38.542-->00:29:45.167 we have successfully modified the header to our fixed one, and this is going over the eprocess 00:29:45.167-->00:29:50.167 token stealing so if you look at the eprocess structure that is saved in our code and dump the 00:29:52.667-->00:29:58.500 image file name and token we see that this is actually a system process and that this token is 00:29:58.500-->00:30:03.500 the system token. If we move on to get our current process itself we notice that the 00:30:06.125-->00:30:11.542 process name is exactly our exploit name and the token is uh normal token or a no- low 00:30:11.542-->00:30:17.167 privileges user token. After we use the arbitrary read and arbitrary write to actually 00:30:17.167-->00:30:22.167 replace our- uh our current process token with a system one this means that we successfully 00:30:24.375-->00:30:30.292 actually got system privileges and when we continue execution and go back to our virtual 00:30:30.292-->00:30:37.083 machine when we’ll notice that we’re actually system now. So that’s the first exploit I want 00:30:37.083-->00:30:42.625 to talk about so from a low privilege user abusing gdi objects and abusing gdi palettes 00:30:42.625-->00:30:47.958 to effectively gain system privileges on a system basically doing a revision of privilege 00:30:47.958-->00:30:52.958 on- from a low privilege user. The next exploit is MS16-098 which is a region ob- affecting 00:30:57.042-->00:31:04.000 the region object and it’s an int- integer overflow leading to a pool overflow. If you look at 00:31:04.000-->00:31:09.458 the start by patch diffing we notice that the function UlongMulti is added to the fixed 00:31:09.458-->00:31:14.875 function which effectively checks if the 2 integers supplied will result in an 00:31:14.875-->00:31:20.625 overflowed value, and then it will pass this value back to our allocation function, that’s the 00:31:20.625-->00:31:25.625 patched version. The unpatched version though will multi- do some calculations on our 00:31:25.625-->00:31:30.625 register and then pass the value directly to our allocation function that will allocate that 00:31:32.750-->00:31:38.375 value. So again how we reach this function? If we look at the function sign ticks that is 00:31:38.375-->00:31:44.333 defined in Ida which is differ function we notice that it works on epath objects. So the way I 00:31:44.333-->00:31:49.333 did it was I just Googled for MSDN fill and path and I reached a function fillpath. So when I 00:31:51.917-->00:31:56.500 call fillpath from user memory and I take the example code out of Ida I look as if I’m not 00:31:56.500-->00:32:00.583 actually hitting the function that I’m supposed to hit, but instead I’m hitting the first 00:32:00.583-->00:32:05.917 function of the series which is EngFastFill. By analyzing this function I found out that it’s 00:32:05.917-->00:32:10.333 actually checking the type of the device context that I’m doing this fillpath in and turns 00:32:10.333-->00:32:15.583 out that it required a memory bitmap path ob- uh device context. And this is the code 00:32:15.583-->00:32:21.000 that is used to actually reach the vulnerable function. So the next step would be to control 00:32:21.000-->00:32:26.750 the location size. So we know that the value is that these instruction load effective 00:32:26.750-->00:32:31.750 address rax plus rax times 2 into ecx is effectively multiplying this value by 3 and 00:32:37.458-->00:32:42.333 then shifting the- this value by 4 or enable is act- effectively multiplying this value again by 00:32:42.333-->00:32:47.333 16. So if we get the max end value and divide it by 3 and then add 1 to it so we can 00:32:49.875-->00:32:54.875 actually overflow it it will reshu- result in 5555555 6 and then to check if we multiply 00:32:56.958-->00:33:02.958 this value by 3 again we’ll notice that the value will be 100000 2, now that’s before the 00:33:02.958-->00:33:07.958 shifting, so after we shifted by 4 it will result in 10000000 20 and if you look at that value 00:33:11.375-->00:33:16.917 and you know that this exploit is actually affecting Windows 8 64bit then you notice that this 00:33:16.917-->00:33:23.292 value will not overflow at 64 bit register however I notice during my analysis of 2 exploits 00:33:23.292-->00:33:29.250 so far that if any- some of the allocation functions who end up getting called, the size is 00:33:29.250-->00:33:34.417 actually s- uh casted into a 32 bit register before the allocation effectively 00:33:34.417-->00:33:40.250 truncating its value. So this value will be 20 which will be supplied to the allocation. Now 00:33:40.250-->00:33:45.250 how can we actually control this allocation size? Well a fun to- uh book was by Nicholas Kimono 00:33:47.250-->00:33:52.250 which was great uh it was for MS16 039 um and the exploit code itself or the func- the 00:33:55.542-->00:33:59.667 vulnerable function looks to be exactly copy pasted from the current function I was analyzing 00:33:59.667-->00:34:04.625 and he pointed out that the number of points in a given path is what- what actually controls 00:34:04.625-->00:34:10.083 this allocation value. So how can I control the number of points in a path? By using the 00:34:10.083-->00:34:15.083 user mode function PolyLineTo and supplying a point array. Calling this function 156 times 00:34:18.083-->00:34:23.083 with 3 FE01 points will result in a controlled value being allocated in kernel memory so if 00:34:28.750-->00:34:35.458 you multiplied the two numbers it will result in 55555 6 now someone will tell me this is 00:34:35.458-->00:34:41.250 much smaller than the value that we discussed during the calculations, and you are right. 00:34:41.250-->00:34:46.250 And due to the shifting of 4, this value will actually the- result in 1000000 5 and after it 00:34:50.708-->00:34:55.708 gets shifted by enable this value will be 50 and the 1 will be truncated. We do our pool 00:34:58.167-->00:35:04.667 feng shui and the exact same thing as the last exploit so we cate- we allocated uh large size 00:35:04.667-->00:35:10.833 bitmap and you notice that this time I left an allocated space of 80, the reason being at that 00:35:10.833-->00:35:15.667 time I didn’t know a function that I can abuse like the menu name to actually allocate and 00:35:15.667-->00:35:21.958 deallocate small sized objects so I went uh with a weird way with the next step allocating 2 00:35:21.958-->00:35:28.125 accelerator objects which have a fixed size of 40 bytes and then I allocate the bitmap and 00:35:28.125-->00:35:33.125 allocate a region object of size BC0, now this is just padding, we don’t actually need this 00:35:33.125-->00:35:37.583 object, but if we allocate the bitmap adjacent to our- our vulnerable object directly it 00:35:37.583-->00:35:42.708 will actually uh the overflow will not result in overwriting any of the interesting members 00:35:42.708-->00:35:47.708 that we find. And then we allocate the space that is left with 3C0 with our bitmap and 00:35:50.208-->00:35:55.083 free our accelerator tables and hopefully if everything went right, we should find the 00:35:55.083-->00:35:59.750 following pool layout which shows uh that our object is allocated at the end of a pool 00:35:59.750-->00:36:05.333 page so when the object is freed it will not crash the system and the bitmap and original object 00:36:05.333-->00:36:10.333 is adjacent to it. So we needed to control the overflow since if we overwrite this large number 00:36:13.250-->00:36:18.250 of points to a small allocation size it will actually blue screen of the system faster than 00:36:18.250-->00:36:23.958 we than we can do anything. The function responsible for copying points is bContructGET and it 00:36:23.958-->00:36:30.458 calls out addEdgeToGet, this function will actually cast the previous Point dot Y to R 10 and 00:36:30.458-->00:36:35.458 the current point dot Y to R 11. Then it will check the current point dot Y against a certain 00:36:38.250-->00:36:44.583 value which on my system was 1F0 and it proved to be working on all systems. Now this value is 00:36:44.583-->00:36:51.375 actually a shifted value by 4. So that current point dot Y will be shifted by 4 and then 00:36:51.375-->00:36:56.208 compared to this value, if the value was more than the- the comparison results in a value 00:36:56.208-->00:37:02.458 more than the 1F0 then it will not copy the point, if it’s less than it will copy the point, and 00:37:02.458-->00:37:07.250 this gives us a primitive to actually control how many points are copied to memory, thus 00:37:07.250-->00:37:13.583 controlling the overflow number. So the way we can control it is by actually setting in our point 00:37:13.583-->00:37:18.583 array, the third point to 20 decimal which is 14 hex shifted by 4 equals 1, 4, 0 which is 00:37:20.917-->00:37:27.000 less than 1F0 so until we hit a specific point of the pointing line to loop which is 1F 00:37:27.000-->00:37:31.792 iterations, that will copy exactly the number of points needed to overflow the bitmap 00:37:31.792-->00:37:38.500 height and width. So before the overflow on the top we can see that the system bitmap is 00:37:38.500-->00:37:43.500 actually um 1 and 52 and after the overflow happens the system bitmap is 1 and FFFF effectively 00:37:47.875-->00:37:52.750 extending its size and where this value comes from is actually the same function that 00:37:52.750-->00:37:56.958 copies the point will subtract the previous point dot Y from the current point dot Y and if 00:37:56.958-->00:38:01.500 it was signed- if it was unsigned it will write 1 to that offset, and if it was signed it 00:38:01.500-->00:38:06.500 will write FFFF to a second offset. We’ll again loop over GetBitmaps this time to find our 00:38:09.167-->00:38:16.000 worker and luckily enough the next hand in was the worker or the next bitmap in memory. And 00:38:16.000-->00:38:20.250 we get some of the addresses that are leaked using Get bit- GetBitmapbits and from them 00:38:20.250-->00:38:24.500 calculate the offsets or the addresses of the overflown objects so we can fix their 00:38:24.500-->00:38:30.958 headers and then we can use set bitmap bits on the manager to actually set the previous scan 0 00:38:30.958-->00:38:36.417 of the worker and use the worker bitmap to write to anywhere in memory arbitrary read and write, 00:38:36.417-->00:38:42.875 and then we use this to fix the bitmap or- and the region object overflow headers and ultimately 00:38:42.875-->00:38:47.875 steal the system token and this is the video of it happening. So we again we’re using uh low 00:38:51.667-->00:38:57.500 privilege user and we have debugger breakpoints set in our exploit code, we run our 00:38:57.500-->00:39:02.500 exploit, then at this point I didn’t know so much SCR so we stay black like this [laughter] 00:39:13.208-->00:39:20.125 [clears throat] now we break at our debugger, we see that actually we are just before the 00:39:20.125-->00:39:25.125 the vulnerable function or triggering the integer overflow. So we break at the allocation 00:39:33.125-->00:39:39.917 and after the allocation, after the write, and we’ll continue execution, we’ll notice that at 00:39:39.917-->00:39:45.583 the allocation we control the value and we’ll be able to allocate a 50 byte object and 00:39:45.583-->00:39:50.583 try to copy around 5 gigs of points to it which will result in byte overflow but luckily we 00:39:53.500-->00:39:58.750 found a way to actually control the overflow as I explained earlier and if you look at the 00:39:58.750-->00:40:03.083 layout of the pool after the allocation we’ll notice that it’s the same layer that was 00:40:03.083-->00:40:08.083 shown previously and we have a allocated object, the manager bitmap, and the worker bitmap. 00:40:13.583-->00:40:19.542 And we use the gray GDI object uh dump extension after litigation to actually dump 00:40:19.542-->00:40:24.542 these bitmaps from memory so we can see the structures clearly we see that the manager bitmap, 00:40:27.333-->00:40:32.333 sizlbitmap was size is 1 and 52 and after the overflow or the point copying we find that the 00:40:35.250-->00:40:40.250 size is now 1 and FFFFFFFF effectively extending the bitmap reading or writing functionality 00:40:43.792-->00:40:48.792 to 4 gigs of kernel memory and then we continue execution and we can see that we can use this 00:40:51.792-->00:40:56.542 manager bitmap to actually override an adjacent bitmap objects pvscan0 this is the 00:40:56.542-->00:41:01.542 original pvscan0 of the worker bitmap and after we use the bitmap bits we’re able to 00:41:04.792-->00:41:10.417 overwrite it with a value that we control pointing to one of the clobbered headers of the 00:41:10.417-->00:41:15.625 bitmap or region objects and if we dump the memory we’ll see that this value of the header is 00:41:15.625-->00:41:20.750 actually clobbered and not a valid header and then we use the leak addresses and the read 00:41:20.750-->00:41:26.125 getbitmapbits to actually read a proper header and fix that object’s header and then if we 00:41:26.125-->00:41:31.125 continue execution we reach the part where we’re stealing the system’s token. And now we 00:41:43.167-->00:41:48.167 verify that it’s actually a system token and not an eprocess. And this is the token 00:41:54.792-->00:41:59.792 value, then we go into finding our current process, Eprocess structure in memory. And we use 00:42:14.792-->00:42:20.000 the arbitrary kernel memory read and write to actually overwrite this value with a system process 00:42:20.000-->00:42:25.000 token and we verify that our current process was actually overwritten by a system process 00:42:37.500-->00:42:42.500 token and we just continue execution [bumps microphone] And go back to our virtual machine 00:42:49.167-->00:42:54.167 to find that real system [applause] So the conclusions of this talk that we have not only 00:43:04.333-->00:43:09.417 1 but a new dis- undisclosed technique to GDI objects that we can abuse to gain arbitrary 00:43:09.417-->00:43:13.833 kernel memory read and write. And abuse per- kernel pool corruptions we can identify 00:43:13.833-->00:43:19.333 hopefully and exploit the same type of vulnerabilities in kernel and any other objects and 00:43:19.333-->00:43:24.333 the tools used in this talk was Ida, BinDiff, WinDBg, and VMware and guys you can get ahold of me 00:43:27.083-->00:43:31.333 at that my email or my Twitter handle and if you have any questions, modifications, 00:43:31.333-->00:43:36.333 suggestions, or if you ever find Diego Juarez because I really would like to meet him uhm 00:43:38.375-->00:43:42.083 there’s not enough time to take questions on stage so I’ll be heading to the chill out lounge 00:43:42.083-->00:43:47.333 just next to this room if you guys have any questions or have any suggestions please um get 00:43:47.333-->00:43:52.333 me- catch me there, thank you! [applause]