{"id":107528,"date":"2022-12-01T07:11:46","date_gmt":"2022-12-01T15:11:46","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=107528"},"modified":"2022-12-01T07:11:46","modified_gmt":"2022-12-01T15:11:46","slug":"20221201-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20221201-46\/?p=107528","title":{"rendered":"Not even trying to cross an airtight hatchway: Calling a function in your own process by synthesizing a function pointer"},"content":{"rendered":"<p>A security vulnerability report arrived that went roughly like this:<\/p>\n<blockquote class=\"q\">\n<p>I have found a security vulnerability in the <code>CONTOSO.DLL<\/code> dynamic-link library. [Long description of methodology omitted, including discussion of dead ends and failed attempts. The short version is &#8220;I looked for code that calls <code>printf<\/code> with a format string that is generated at runtime rather than a hard-coded string. That code is subject to a format string attack.&#8221;]<\/p>\n<p>Attached is a proof of concept.<\/p>\n<pre>int main()\r\n{\r\n    \/\/ vulnerable function is at offset 0x12345\r\n    auto p = (LPBYTE)LoadLibrary(\"contoso.dll\") + 0x12345;\r\n    auto fn = (void(*)(char const*, int))p;\r\n\r\n    \/\/ Call the function with a %n format string\r\n    fn(\"%n\", 42);\r\n}\r\n<\/pre>\n<p>I am requesting a bounty for this report.<\/p>\n<p>Note that this is the first security vulnerability I have found and submitted. I acknowledge that my understanding is incomplete. Please provide additional advice and assistance to help me become a better security researcher. I look forward to your reply.<\/p>\n<\/blockquote>\n<p>This is like calling the natural gas utility company&#8217;s emergency number to report a major gas leak in your house. The gas company sends a technician over, and they can&#8217;t find any leak. They ask how you came to suspect that there&#8217;s a gas leak, and you tell them, &#8220;Oh, I didn&#8217;t smell anything.\u00b9 I called you because I&#8217;m hoping to learn more about how to recognize the smell of gas. Do you have any tips?&#8221;<\/p>\n<p>Yes, the tip is that if you don&#8217;t know how to recognize the smell of gas, you can use existing educational materials to learn how to recognize the smell of gas. Don&#8217;t call the emergency line to learn what gas smells like.\u00b2 The emergency line is not intended to be used as a source of training data. There are other places to learn more about the smell of gas.<\/p>\n<p>In this case, no security boundary has been crossed. The &#8220;vulnerable&#8221; code is loaded into the attacker&#8217;s process, and the attacker is calling it directly. Attackers who want to attack their own processes don&#8217;t need the help of <code>contoso.dll<\/code>.<\/p>\n<p>For example, they could have gone directly to the C runtime library.<\/p>\n<pre>int main()\r\n{\r\n    \/\/ vulnerable function is called \"printf\"\r\n    auto p = GetProcAddress(LoadLibrary(\"ucrtbase.dll\"), \"printf\");\r\n    auto fn = (void(*)(char const*, ...))p;\r\n\r\n    \/\/ Call the function with a %n format string\r\n    fn(\"%n\", 42);\r\n}\r\n<\/pre>\n<p>which simplifies to<\/p>\n<pre>int main()\r\n{\r\n    \/\/ Call printf with a %n format string\r\n    printf(\"%n\", 42);\r\n}\r\n<\/pre>\n<p>The internal function they found in <code>contoso.dll<\/code> is a passthrough to <code>printf<\/code>. It is called only with known format strings which match the rest of the <code>printf<\/code> parameters. The string is not hard-coded because the format string is looked up at runtime to match the user&#8217;s preferred language. There is no way to get this DLL to pass an untrusted format string to <code>printf<\/code>, at least not through the function under attack.<\/p>\n<p>Besides, if you are interested in doing dangerous things by calling functions in a way that cannot be externally triggered, then <code>printf<\/code> is a particularly complicated to do it. Much easier is to find a function that ends with something like<\/p>\n<pre>    mov     qword ptr [rdx], rcx\r\n    ... other instructions that you can stage mitigations for\u00b3 ...\r\n    ret\r\n<\/pre>\n<p>Put the desired value in <code>ecx<\/code> and the desired target address in <code>edx<\/code>, and call that function! No need to drag <code>printf<\/code> into it.<\/p>\n<p>And if you&#8217;re still learning about searching for security vulnerabilities, please don&#8217;t send in reports until you&#8217;ve learned the part about exploitability. Thanks.<\/p>\n<p>\u00b9 Yes, natural gas is odorless. The smell is added by gas companies.<\/p>\n<p>\u00b2 It is common for parents at my children&#8217;s Chinese-language school to socialize in the cafeteria while the students are attending their lessons. There was a time a few years ago where one of the parents thought they smelled gas. They asked others to check it out, and opinions were mixed. Some people agreed that they smelled gas, but others thought it was something else. Eventually, the source of the odor was identified: Somebody had brought durian fruit as a snack and was eating it in the cafeteria.<\/p>\n<p>\u00b3 For example, I found this sequence:<\/p>\n<pre>    mov     dword ptr [rdx],ecx\r\n    mov     rbx,qword ptr [rsp+88h]\r\n    mov     eax,ebp\r\n    add     rsp,40h\r\n    pop     r15\r\n    pop     r14\r\n    pop     r13\r\n    pop     r12\r\n    pop     rdi\r\n    pop     rsi\r\n    pop     rbp\r\n    ret\r\n<\/pre>\n<p>You can stage a call to this by pre-pushing the registers and return address onto the stack and pre-subtracting <code>40h<\/code> from <code>rsp<\/code>, then calling the function.<\/p>\n<p>Hey look, in the same DLL, I found this instruction sequence:<\/p>\n<pre>    mov     dword ptr [rax],ecx\r\n    ret\r\n<\/pre>\n<p>That will work great.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>You can already attack yourself in far more interesting ways.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[26],"class_list":["post-107528","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-other"],"acf":[],"blog_post_summary":"<p>You can already attack yourself in far more interesting ways.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/107528","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=107528"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/107528\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=107528"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=107528"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=107528"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}