{"id":43563,"date":"2014-11-21T07:00:00","date_gmt":"2014-11-21T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2014\/11\/21\/is-it-wrong-to-call-shfileoperation-from-a-service-revised\/"},"modified":"2014-11-21T07:00:00","modified_gmt":"2014-11-21T07:00:00","slug":"is-it-wrong-to-call-shfileoperation-from-a-service-revised","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20141121-00\/?p=43563","title":{"rendered":"Is it wrong to call SHFileOperation from a service? Revised"},"content":{"rendered":"<p>My initial reaction to this question was to say, &#8220;<a href=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2013\/12\/06\/10474322.aspx\">I don&#8217;t know if I&#8217;d call it wrong, but I&#8217;d call it highly inadvisable<\/a>.&#8221;\n I&#8217;d like to revise my guidance.\n It&#8217;s flat-out wrong, at least in the case where you call it while impersonating.\n The registry key <code>HKEY_CURRENT_USER<\/code> is <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/windows\/desktop\/ms724836(v=vs.85).aspx\"> bound to the current user at the time the key is first accessed by a process<\/a>:<\/p>\n<blockquote class=\"q\"><p> The mapping between <b>HKEY_CURRENT_USER<\/b> and <b>HKEY_USERS<\/b> is per process and is established the first time the process references <b>HKEY_CURRENT_USER<\/b>. The mapping is based on the security context of the first thread to reference <b>HKEY_CURRENT_USER<\/b>. If this security context does not have a registry hive loaded in <b>HKEY_USERS<\/b>, the mapping is established with <b>HKEY_USERS\\.Default<\/b>. After this mapping is established it persists, <u>even if the security context of the thread changes<\/u>. <\/p><\/blockquote>\n<p> Emphasis mine.\n This means that if you impersonate a user, and then access <code>HKEY_CURRENT_USER<\/code>, then that binds <code>HKEY_CURRENT_USER<\/code> to the impersonated user. Even if you stop impersonating, future references to <code>HKEY_CURRENT_USER<\/code> will still refer to that user.\n This is probably not what you expected.\n The shell takes a lot of settings from the current user. If you impersonate a user and then call into the shell, your service is now using that user&#8217;s settings, which is effectively an elevation of privilege: An unprivileged user is now modifying settings for a service. For example, if the user has customized the Print verb for text files, and you use <code>Shell&shy;Execute<\/code> to invoke the <code>print<\/code> verb on a text document, you are at the mercy of whatever the user&#8217;s <code>print<\/code> verb is bound to. Maybe it runs Notepad, but maybe it runs pwnz0rd.exe. You don&#8217;t know.\n Similarly, the user might have a per-user registered <a href=\"http:\/\/msdn.microsoft.com\/library\/cc144063\"> copy hook<\/a> or namespace extension, and now you just loaded a user-controlled COM object into your service.\n In both cases, this is known to insiders as <i>hitting the jackpot<\/i>.\n Okay, so what about if you call <code>Shell&shy;Execute<\/code> or some other shell function while not impersonating? You might say, &#8220;That&#8217;s okay, because the current user&#8217;s registry is the service user, not the untrusted attacker user.&#8221; But look at that sentence I highlighted up there. Once <code>HKEY_CURRENT_USER<\/code> get bound to a particular user, it remains bound to that user <i>even after impersonation ends<\/i>. If somebody else inadvisedly called a shell function while impersonating, and that shell function happens to be the first one to access <code>HKEY_CURRENT_USER<\/code>, then your call to a shell function while not impersonating will still use that impersonated user&#8217;s registry. Congratulations, you are now running untrusted code, and you&#8217;re not even impersonating any more!<\/p>\n<p> So my recommendation is <i>don&#8217;t do it<\/i>. Don&#8217;t call shell functions while impersonating unless the function is explicitly documented as supporting impersonation. (The only ones I&#8217;m aware of that fall into this category are functions like <code>SHGet&shy;Folder&shy;Path<\/code> which accept an explicit token handle.) Otherwise, you may have created (or in the case of copy hooks, definitely created) a code injection security vulnerability in your service. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>My initial reaction to this question was to say, &#8220;I don&#8217;t know if I&#8217;d call it wrong, but I&#8217;d call it highly inadvisable.&#8221; I&#8217;d like to revise my guidance. It&#8217;s flat-out wrong, at least in the case where you call it while impersonating. The registry key HKEY_CURRENT_USER is bound to the current user at the [&hellip;]<\/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":[25],"class_list":["post-43563","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>My initial reaction to this question was to say, &#8220;I don&#8217;t know if I&#8217;d call it wrong, but I&#8217;d call it highly inadvisable.&#8221; I&#8217;d like to revise my guidance. It&#8217;s flat-out wrong, at least in the case where you call it while impersonating. The registry key HKEY_CURRENT_USER is bound to the current user at the [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/43563","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=43563"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/43563\/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=43563"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=43563"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=43563"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}