草庐IT

c++ - 模拟后CreateMutex失败

coder 2023-11-12 原文

这是我要模拟用户然后创建互斥量的代码。未创建互斥锁。我收到ERROR_ACCESS_DENIED错误。

void Impersonate()
{
    DWORD logonType = LOGON32_LOGON_INTERACTIVE;
    DWORD logonProvider = LOGON32_PROVIDER_DEFAULT;
    HANDLE userToken;
    HANDLE hMutex;
    DWORD err;

    LPSTR user = "zoom"; // the user I created myself on my machine. 
    // It has Administrator privileges, and my account, 
    // from which I start the app, is Admin too
    LPSTR password = "zoom";
    LPSTR domain = ".";
    hMutex = NULL;

    LogonUserA(user, domain, password, logonType, logonProvider,&userToken);

    // just to make sure that mutexes are created fine before impersonation
    hMutex = CreateMutexA( NULL, FALSE, "mutex_good" );  

    ImpersonateLoggedOnUser(userToken);

    hMutex = CreateMutexA( NULL, FALSE, "mutex_797" ); // I can set any 
                                                       // random name, no difference
    if( hMutex == NULL )
    {
        err = GetLastError();
        // here err is ERROR_ACCESS_DENIED 
    }

    CloseHandle(userToken);
}

我已经找到了几个类似的主题,但是所有这些主题都在讨论从两个不同的用户上下文创建同名互斥锁,即在模拟之前已经创建了互斥锁“MUTEX_1”,并试图从假冒的对象使用相同的名称调用CreateMutex用户由于缺少特权而失败。

这里不是这种情况,因为我很确定在此代码之前不会创建具有相同名称(或根本没有任何互斥体)的互斥体。

我想我应该将一些非空值传递给CreateMutex,但是究竟是什么呢?

我的Windows安全性不是很好。我知道将NULL作为CreateMutex的第一个参数传递意味着将使用“默认”安全属性。在这种情况下,它将是与线程关联的安全参数,即与模拟用户关联的安全参数。

我的假设正确吗?

最佳答案

首先,您需要了解NT Namespaces并使用WinObj工具。

这就像带有文件夹和不同"file"的内存中的小文件系统(此处"file"下的意思是不同的对象类型-EventMutant(mutex),SectionDevice,...)。每次创建命名对象时,都会将其放置在NT Namespaces中的某个文件夹中。此处的文件夹(如NTFS中的文件夹)具有安全描述符。结果并不是每个人都可以在任何文件夹下创建对象。

解释您对文件系统语言所做的操作(也许会更清楚):

我(John)尝试在%USERPROFILE%\Documents下创建文件“mutex_good”,这没关系。因为这是我的个人文件夹,并且我对此具有写权限。

然后我以zoom登录(模拟)并尝试在%USERPROFILE%\Documents下再次创建文件“mutex_797”(两种情况下%USERPROFILE%都扩展到同一路径,说c:\Users\John模拟不会影响此操作)

zoom无法创建文件。为什么 ?他根本无权这样做。只有JohnAdministartorsSYSTEM具有对c:\Users\John的写权限,但没有zoom的写权限。

现在让我们返回NT Namespaces。当我们调用CreateMutexA( NULL, FALSE, "mutex_797" );时,会在哪里放置"mutex_797"

如果您不使用appcontainer并且不在系统session 0中运行-您将在某些用户session <N>中运行,并且您的命名对象将放置在\Sessions\<N>\BaseNamedObjects目录中,其中N = 1,2。

所以叫CreateMutexA( NULL, FALSE, "mutex_797" );
尝试在\Sessions\<N>\BaseNamedObjects\mutex_797创建互斥锁

但是,在\Sessions\<N>\BaseNamedObjects中存在下一个SymbolicLinks(这类似于NTFS文件系统中的):

Global -> \BaseNamedObjects
Local  -> \Sessions\<N>\BaseNamedObjects
Session -> \Sessions\BNOLINKS

所以说,如果你调用CreateMutexA( NULL, FALSE, "Global\\mutex_797" );
对象管理器尝试将您的互斥锁放在\BaseNamedObjects\mutex_797

有关此阅读的更多信息Kernel object namespaces

当然,我们必须了解How AccessCheck Works

对于定义了下一个访问权限的目录对象:
//
// Object Manager Directory Specific Access Rights.
//

#define DIRECTORY_QUERY                 (0x0001)
#define DIRECTORY_TRAVERSE              (0x0002)
#define DIRECTORY_CREATE_OBJECT         (0x0004)
#define DIRECTORY_CREATE_SUBDIRECTORY   (0x0008)

也可以在DirectoryObject DesiredAccess Flags上了解更多信息

我们需要DIRECTORY_CREATE_OBJECT访问权限(对目录对象的名称创建访问权限)才能在Directory中创建互斥锁(或事件或任何对象)

现在了解为什么您可以在\Sessions\<N>\BaseNamedObjects中创建互斥体,但zoom不能-需要为此文件夹查找Security Descriptor。我把它丢了:
T FL AcessMsK Sid
0 00 000F000F S-1-5-90-0-1 DWM-1
0 00 000F000F S-1-5-18 SYSTEM
0 0B 10000000 S-1-5-18 SYSTEM
0 0B 10000000 S-1-3-0 CREATOR OWNER
0 00 000F000F S-1-5-21-4026734978-3280735129-2412320105-1001 John
0 0B 10000000 S-1-5-5-0-294807 LogonSessionId_0_294807
0 00 0002000F S-1-5-5-0-294807 LogonSessionId_0_294807
0 00 0002000F S-1-5-32-544 Administrators
0 02 00000003 S-1-1-0 Everyone
0 00 00000002 S-1-5-12 RESTRICTED
17 00 00000001 S-1-16-4096 Low Mandatory Level

那么谁在这里有DIRECTORY_CREATE_OBJECT(4)? DWM-1SYSTEMAdministrators,当前登录 session 用户(LogonSessionId_0_294807),当前用户(John)-以及所有。 zoom没有此访问权限。

例如Everyone具有(3)-DIRECTORY_QUERY|DIRECTORY_TRAVERSE-Name lookupQuery,但没有Name creation
您可以问这种情况下在模拟后我可以在哪里创建互斥体?需要使用\BaseNamedObjects(全局命名空间)或\BaseNamedObjects\Restricted目录-我对其进行了安全描述符和结果测试:

用于\BaseNamedObjects
T FL AcessMsK Sid
0 00 0002000F S-1-1-0 Everyone
0 00 00000002 S-1-5-12 RESTRICTED
0 00 000F000F S-1-5-90-0-0 
0 00 000F000F S-1-5-18 SYSTEM
17 00 00000001 S-1-16-4096 Low Mandatory Level

用于\BaseNamedObjects\Restricted
T FL AcessMsK Sid
0 00 0002000F S-1-1-0 Everyone
0 00 0002000F S-1-5-12 RESTRICTED
0 00 000F000F S-1-5-90-0-0 
0 00 000F000F S-1-5-18 SYSTEM
17 00 00000001 S-1-16-4096 Low Mandatory Level

因此,您如何在此处查看Everyone具有2000F-所有必需的访问权限。希望zoomEveryone的成员?下一个代码我肯定会工作
CreateMutexA(0, 0, "Global\\mutex_797");\BaseNamedObjects(全局 namespace )存在一个异常(exception):

The creation of a file-mapping object in the global namespace, by using CreateFileMapping, from a session other than session zero is a privileged operation. Because of this, an application running in an arbitrary Remote Desktop Session Host (RD Session Host) server session must have SeCreateGlobalPrivilege enabled in order to create a file-mapping object in the global namespace successfully. The privilege check is limited to the creation of file-mapping objects, and does not apply to opening existing ones. For example, if a service or the system creates a file-mapping object, any process running in any session can access that file-mapping object provided that the user has the necessary access.



但对于Mutex或说事件-不需要启用SeCreateGlobalPrivilege

您也可以说,但是zoom是管理员帐户,而Administrator可以访问\Sessions\<N>\BaseNamedObjects-为什么这不起作用?因为使用LOGON32_LOGON_INTERACTIVEUAC系统将分配给zoom过滤的 token 。 Administrator组(S-1-5-32-544)存在于 token 中,但仅具有 SE_GROUP_USE_FOR_DENY_ONLY 属性的-结果是它忽略了SID允许访问的ACE。
zoom具有另一个LogonSessionId_0_XXX SID-结果和ERROR_ACCESS_DENIED
如@Harry Johnston所述-如果我们将使用LOGON32_LOGON_BATCH代替LOGON32_LOGON_INTERACTIVE-我们获得了提升的 token -此处Administrator组将具有 SE_GROUP_ENABLED 属性-已启用允许访问的ACE的访问检查

或我提供的方式-在名称前使用Global\前缀-用于将对象放置到\BaseNamedObjects具有完全访问权限的Everyone

I understand passing NULL as a first parameter of CreateMutex means that 'default' security attributes will be used. In this case it will be security parameters associated to the thread, i.e. with impersonated user.



第一个参数-指向SECURITY_ATTRIBUTES的指针使您可以覆盖新对象的默认安全描述符。这是谁将有权访问它的控制权。但这不能使您或多或少地访问尝试在其中放置对象的目录-您必须授予DIRECTORY_CREATE_OBJECT访问权限,而SECURITY_ATTRIBUTES不能影响此操作-这会影响新对象,但不会影响现有目录

最后是NT Namespace的可视化

关于c++ - 模拟后CreateMutex失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41369232/

有关c++ - 模拟后CreateMutex失败的更多相关文章

  1. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  2. ruby - 如何模拟 Net::HTTP::Post? - 2

    是的,我知道最好使用webmock,但我想知道如何在RSpec中模拟此方法:defmethod_to_testurl=URI.parseurireq=Net::HTTP::Post.newurl.pathres=Net::HTTP.start(url.host,url.port)do|http|http.requestreq,foo:1endresend这是RSpec:let(:uri){'http://example.com'}specify'HTTPcall'dohttp=mock:httpNet::HTTP.stub!(:start).and_yieldhttphttp.shou

  3. ruby - 即使失败也继续进行多主机测试 - 2

    我已经构建了一些serverspec代码来在多个主机上运行一组测试。问题是当任何测试失败时,测试会在当前主机停止。即使测试失败,我也希望它继续在所有主机上运行。Rakefile:namespace:specdotask:all=>hosts.map{|h|'spec:'+h.split('.')[0]}hosts.eachdo|host|begindesc"Runserverspecto#{host}"RSpec::Core::RakeTask.new(host)do|t|ENV['TARGET_HOST']=hostt.pattern="spec/cfengine3/*_spec.r

  4. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  5. ruby-on-rails - 创建 ruby​​ 数据库时惰性符号绑定(bind)失败 - 2

    我正在尝试在Rails上安装ruby​​,到目前为止一切都已安装,但是当我尝试使用rakedb:create创建数据库时,我收到一个奇怪的错误:dyld:lazysymbolbindingfailed:Symbolnotfound:_mysql_get_client_infoReferencedfrom:/Library/Ruby/Gems/1.8/gems/mysql2-0.3.11/lib/mysql2/mysql2.bundleExpectedin:flatnamespacedyld:Symbolnotfound:_mysql_get_client_infoReferencedf

  6. ruby - 正则表达式在哪个位置失败? - 2

    我需要一个非常简单的字符串验证器来显示第一个符号与所需格式不对应的位置。我想使用正则表达式,但在这种情况下,我必须找到与表达式相对应的字符串停止的位置,但我找不到可以做到这一点的方法。(这一定是一种相当简单的方法……也许没有?)例如,如果我有正则表达式:/^Q+E+R+$/带字符串:"QQQQEEE2ER"期望的结果应该是7 最佳答案 一个想法:你可以做的是标记你的模式并用可选的嵌套捕获组编写它:^(Q+(E+(R+($)?)?)?)?然后你只需要计算你获得的捕获组的数量就可以知道正则表达式引擎在模式中停止的位置,你可以确定匹配结束

  7. ruby - 如何计算 Liquid 中的变量 +1 - 2

    我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

  8. ruby - 使用 rbenv 和 ruby​​-build 构建 ruby​​ 失败,出现 undefined symbol : SSLv2_method - 2

    我正在尝试在配备ARMv7处理器的SynologyDS215j上安装ruby​​2.2.4或2.3.0。我用了optware-ng安装gcc、make、openssl、openssl-dev和zlib。我根据README中的说明安装了rbenv(版本1.0.0-19-g29b4da7)和ruby​​-build插件。.这些是随optware-ng安装的软件包及其版本binutils-2.25.1-1gcc-5.3.0-6gconv-modules-2.21-3glibc-opt-2.21-4libc-dev-2.21-1libgmp-6.0.0a-1libmpc-1.0.2-1libm

  9. ruby-on-rails - 在这种情况下我如何模拟一个对象?没有明显的方法可以用模拟替换对象 - 2

    假设我在Store的模型中有这个非常简单的方法:defgeocode_addressloc=Store.geocode(address)self.lat=loc.latself.lng=loc.lngend如果我想编写一些不受地理编码服务影响的测试脚本,这些脚本可能已关闭、有限制或取决于我的互联网连接,我该如何模拟地理编码服务?如果我可以将地理编码对象传递到该方法中,那将很容易,但我不知道在这种情况下该怎么做。谢谢!特里斯坦 最佳答案 使用内置模拟和stub的rspecs,你可以做这样的事情:setupdo@subject=MyCl

  10. ruby - "public/protected/private"方法是如何实现的,我该如何模拟它? - 2

    在ruby中,你可以这样做:classThingpublicdeff1puts"f1"endprivatedeff2puts"f2"endpublicdeff3puts"f3"endprivatedeff4puts"f4"endend现在f1和f3是公共(public)的,f2和f4是私有(private)的。内部发生了什么,允许您调用一个类方法,然后更改方法定义?我怎样才能实现相同的功能(表面上是创建我自己的java之类的注释)例如...classThingfundeff1puts"hey"endnotfundeff2puts"hey"endendfun和notfun将更改以下函数定

随机推荐