{"id":38253,"date":"2004-08-04T08:49:00","date_gmt":"2004-08-04T08:49:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2004\/08\/04\/why-shared-sections-are-a-security-hole\/"},"modified":"2004-08-04T08:49:00","modified_gmt":"2004-08-04T08:49:00","slug":"why-shared-sections-are-a-security-hole","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20040804-00\/?p=38253","title":{"rendered":"Why .shared sections are a security hole"},"content":{"rendered":"<p><P>\nMany people will recommend using shared data sections as a way\nto share data between multiple instances of an application.\nThis sounds like a great idea, but in fact it&#8217;s a security hole.\n<\/P>\n<P>\nProper shared memory objects created by\n<A HREF=\"http:\/\/msdn.microsoft.com\/library\/en-us\/fileio\/base\/createfilemapping.asp\">\nthe CreateFileMapping function<\/A>\ncan be secured.\nThey have security descriptors that let you specify which users\nare allowed to have what level of access.\nBy contrast, anybody who loads your EXE or DLL gets access to your\nshared memory section.\n<\/P>\n<P>\nAllow me to demonstrate with an intentionally insecure program.\n<\/P>\n<P>\nTake\n<A href=\"http:\/\/weblogs.asp.net\/oldnewthing\/archive\/2003\/07\/23\/54576.aspx\">\nthe scratch program<\/A> and make the following changes:\n<\/P>\n<PRE>\n<FONT COLOR=\"blue\">#pragma comment(linker, &#8220;\/SECTION:.shared,RWS&#8221;)\n#pragma data_seg(&#8220;.shared&#8221;)\nint g_iShared = 0;\n#pragma data_seg()<\/p>\n<p>void CALLBACK TimerProc(HWND hwnd, UINT, UINT_PTR, DWORD)\n{\n  int iNew = g_iShared + 1;\n  if (iNew == 10) iNew = 0;\n  g_iShared = iNew;\n  InvalidateRect(hwnd, NULL, TRUE);\n}<\/FONT><\/p>\n<p>BOOL\nOnCreate(HWND hwnd, LPCREATESTRUCT lpcs)\n{\n    <FONT COLOR=\"blue\">SetTimer(hwnd, 1, 1000, TimerProc);<\/FONT>\n    return TRUE;\n}<\/p>\n<p>void\nPaintContent(HWND hwnd, PAINTSTRUCT *pps)\n{\n  <FONT COLOR=\"blue\">TCHAR sz[2];\n  wsprintf(sz, TEXT(&#8220;%d&#8221;), g_iShared);\n  TextOut(pps-&gt;hdc, 0, 0, sz, 1);<\/FONT>\n}\n<\/PRE>\n<P>\nGo ahead and run this program.  It counts from 0 to 9 over and over\nagain.  Since the TimerProc function never lets g_iShared go above 9,\nthe wsprintf is safe from buffer overflow.\n<\/P>\n<P>\nOr is it?\n<\/P>\n<P>\nRun this program.  Then use the runas utility to run a second copy\nof this program under a different user.  For extra fun, make one of\nthe users an administrator and another a non-administrator.\n<\/P>\n<P>\nNotice that the counter counts up at double speed.  That&#8217;s to be\nexpected since the counter is shared.\n<\/P>\n<P>\nOkay, now close one of the copies and relaunch it under a debugger.\n(It&#8217;s more fun if you let the administrator&#8217;s copy run free and\nrun the non-administrator&#8217;s copy run under a debugger.)\nLet both programs run, then break into the debugger and change the\nvalue of the variable g_iShared to something really big, say, 1000000.\n<\/P>\n<P>\nNow, depending on how intrusive your debugger is, you might or might\nnot see the crash.  Some debuggers are &#8220;helpful&#8221; and &#8220;unshare&#8221; shared\nmemory sections when you change their values from the debugger.\nHelpful for debugging (maybe), bad for my demonstration (definitely).\n<\/P>\n<P>\nHere&#8217;s how I did it with the built-in ntsd debugger.\nI opened a command prompt, which runs as myself (and I am not an\nadministrator).\nI then used the runas utility to run the scratch program as\nadministrator.\nIt is the administrator&#8217;s copy of the scratch program that I&#8217;m going\nto cause to crash even though I am just a boring normal non-administrative\nuser.\n<\/P>\n<P>\nFrom the normal command prompt, I typed\n&#8220;ntsd scratch&#8221; to run the scratch program under the debugger.\nFrom the debugger prompt, I typed &#8220;u TimerProc&#8221; to disassemble the\nTimerProc function, looking for\n<PRE>\n01001143 a300300001       mov     [scratch!g_iShared (01003000)],eax\n<\/PRE>\n(note: your numbers may differ).\nI then typed &#8220;g 1001143&#8221; to instruct the debugger to\nexecute normally until that instruction is reached.\nWhen the debugger broke, I typed\n&#8220;r eax=12341234;t&#8221; to change the value of the eax register\nto 0x12341324 and then trace one instruction.\nThat one-instruction trace wrote the out-of-range value into\nshared memory, and one second later, the administrator version\nof the program crashed with a buffer overflow.\n<\/P>\n<P>\nWhat happened?\n<\/P>\n<P>\nSince the memory is shared, all running copies of the scratch\nprogram have access to it.  ALl I did was use the debugger\nto run a copy of the scratch program and change the value of\nthe shared memory variable.  Since the variable is shared,\nthe value also changes in the administrator&#8217;s copy of the program,\nwhich then causes the wsprintf buffer to overflow,\nthereby crashing the administrator&#8217;s copy of the program.\n<\/P>\n<P>\nA denial of service is bad enough, but you can really do fun\nthings if a program keeps anything of value in shared memory.\nIf there is a pointer, you can corrupt the pointer.\nIf there is a string, you can remove the null terminator and\ncause it to become &#8220;impossibly&#8221; long, resulting in a potential\nbuffer overflow if somebody copies it without checking the length.\n<\/P>\n<P>\nAnd if there is a C++ object with a vtable, then you have just hit\nthe mother lode!  What you do is redirect the vtable to a\nbogus vtable (which you construct in the shared memory section),\nand put a function pointer entry in that vtable that points into\nsome code that you generated (also into the shared memory section)\nthat takes over the machine.  (If NX is enabled, then the attack\nis much harder but still possible in principle.)\n<\/P>\n<P>\nEven if you can&#8217;t trigger a buffer overflow by messing with variables\nin shared memory, you can still cause the program to behave erratically.\nJust scribbling random numbers all over the shared memory section will\ncertainly induce &#8220;interesting&#8221; behavior in the program under attack.\n<\/P>\n<P>\nMoral of the story: Avoid shared memory sections.\nSince you can&#8217;t attach an ACL to the section, anybody who\ncan load your EXE or DLL can modify your variables and cause\nhavoc in another instance of the program that is running at a\nhigher security level.\n<\/P><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Many people will recommend using shared data sections as a way to share data between multiple instances of an application. This sounds like a great idea, but in fact it&#8217;s a security hole. Proper shared memory objects created by the CreateFileMapping function can be secured. They have security descriptors that let you specify which users [&hellip;]<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-38253","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Many people will recommend using shared data sections as a way to share data between multiple instances of an application. This sounds like a great idea, but in fact it&#8217;s a security hole. Proper shared memory objects created by the CreateFileMapping function can be secured. They have security descriptors that let you specify which users [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/38253","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=38253"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/38253\/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=38253"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=38253"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=38253"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}