{"id":98875,"date":"2018-05-30T07:00:00","date_gmt":"2018-05-30T21:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/?p=98875"},"modified":"2019-03-13T00:44:35","modified_gmt":"2019-03-13T07:44:35","slug":"20180530-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20180530-00\/?p=98875","title":{"rendered":"When you call <CODE>Open&shy;Thread&shy;Token<\/CODE> while impersonating, you have to say who is asking for the thread token"},"content":{"rendered":"<p>A customer reported that <code>Open&shy;Thread&shy;Token<\/code> was failing with the error <code>ACCESS_<\/code><code>DENIED<\/code> and wanted help understanding why. They shared a code fragment which operates on an account name <code>test<\/code> with no special privileges. <\/p>\n<pre>\n<i>\/\/ Code in italics is wrong\n\nint main()\n{\n  HANDLE hToken = NULL;\n\n  \/\/ This succeeds.\n  LogonUser(L\"test\", L\".\", L\"test@123\",\n    LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT,\n    &amp;hToken);\n\n  \/\/ This also succeeds.\n  ImpersonateLoggedOnUser(hToken);\n\n  \/\/ During this Sleep, <a HREF=\"https:\/\/processhacker.sourceforge.io\/\">Process Hacker<\/a> shows that the thread\n  \/\/ is impersonating.\n  Sleep(10'000);\n\n  \/\/ This fails with ERROR_ACCESS_DENIED.\n  OpenThreadToken(GetCurrentThread(), TOKEN_QUERY,\n    FALSE, &amp;hToken);\n\n  return 0;\n}<\/i>\n<\/pre>\n<p>According to <a HREF=\"https:\/\/msdn.microsoft.com\/en-us\/library\/windows\/desktop\/aa379296(v=vs.85).aspx\">the documentation for <code>Open&shy;Thread&shy;Token<\/code><\/a>: <\/p>\n<blockquote CLASS=\"q\">\n<p><i>OpenAsSelf<\/i> [in] <\/p>\n<p><b>TRUE<\/b> if the access check is to be made against the process-level security context. <\/p>\n<p><b>FALSE<\/b> if the access check is to be made against the current security context of the thread calling the <b>Open&shy;Thread&shy;Token<\/b> function. <\/p>\n<p>The <i>OpenAsSelf<\/i> parameter allows the caller of this function to open the access token of a specified thread when the caller is impersonating a token at <b>Security&shy;Identification<\/b> level. <u>Without this parameter, the calling thread cannot open the access token on the specified thread  because it is impossible to open executive-level objects by using the <b>Security&shy;Identification<\/b> impersonation level<\/u>. <\/p>\n<\/blockquote>\n<p>Furthermore, as I discussed <a HREF=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/\">some time ago<\/a>, <\/p>\n<blockquote CLASS=\"q\">\n<p>When a new kernel object is created, and you don&#8217;t provide an explicit security descriptor for the new object, then the object is given a default security descriptor. And that default security descriptor comes from the default DACL of the token that is in effect at the point of the call. <\/p>\n<p>When you apply this rule to tokens, you find that, even though the behavior is consistent with other kernel objects, it also means that it is <u>very easy to create a token that doesn&#8217;t have access to itself<\/u>. When you impersonate with that token, bad things happen. <\/p>\n<\/blockquote>\n<p> The code fragment above passes <code>FALSE<\/code>, which means that the access check is made against the current security context, which is the impersonated test user, and that user doesn&#8217;t have access to the token. <\/p>\n<p>Note that changing <code>FALSE<\/code> to <code>TRUE<\/code> is only the first step in what may be a long uphill struggle. One of my colleagues on the security team added that if you don&#8217;t have the <b>Se&shy;Impersonate&shy;Privilege<\/b> for your process, you will run into other problems as well. The customer didn&#8217;t explain the scenario where they think impersonation is a step in the solution, so it&#8217;s hard to elaborate on what else can go wrong, because we don&#8217;t know what they&#8217;re trying to do. <\/p>\n<p><b>Bonus reading<\/b>: <a HREF=\"https:\/\/blogs.msdn.microsoft.com\/mithuns\/2007\/07\/03\/seimpersonateprivilege\/\">Changes to  <b>Se&shy;Impersonate&shy;Privilege<\/b> in Windows Vista<\/a>. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>I am for you.<\/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-98875","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>I am for you.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/98875","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=98875"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/98875\/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=98875"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=98875"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=98875"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}