Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Low integrity to medium/high integrity pipe security descriptor

I'm having trouble setting up the security descriptor when creating a NamedPipe. I want the pipe created in Windows service (high integrity) to be opened from medium and low integrity processes.

I'm working on Windows 7 x64. I don't quite understand what I'm doing here, but here is the code I use to create a security descriptor for the pipes I create. Following code doesn't let me open pipes created in both high and medium integrity leve from low integrity processes:



    PSID psidWorldSid = NULL, pAdminSID = NULL, pLowSID = NULL, pHighSID = NULL;
    WCHAR wszIntegritySid[] = L"S-1-16-4096";
    WCHAR wszSystemSid[] = L"S-1-16-16384";
    PACL pACL = NULL;
    PSECURITY_DESCRIPTOR pSD = NULL;
    SECURITY_ATTRIBUTES sa;
    SID_IDENTIFIER_AUTHORITY SIDAuthNT = SECURITY_NT_AUTHORITY;
    SID_IDENTIFIER_AUTHORITY siaWorldSidAuthority = SECURITY_WORLD_SID_AUTHORITY;
    EXPLICIT_ACCESS ea[4];

    //  Create a security descriptor for the log file that allows
    //  access from both the privileged service and the non-privileged
    //  user mode programs

    AllocateAndInitializeSid(&siaWorldSidAuthority, 1,
        SECURITY_WORLD_RID,
        0, 0, 0, 0, 0, 0, 0,
        &psidWorldSid);

    ZeroMemory(&ea, sizeof(ea));
    ea[0].grfAccessPermissions = FILE_ALL_ACCESS | GENERIC_WRITE | GENERIC_READ;
    ea[0].grfAccessMode = SET_ACCESS;
    ea[0].grfInheritance= NO_INHERITANCE;
    ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
    ea[0].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
    ea[0].Trustee.ptstrName  = (LPTSTR) psidWorldSid;

    // Create a SID for the BUILTIN\Administrators group.
    AllocateAndInitializeSid(&SIDAuthNT, 2,
        SECURITY_BUILTIN_DOMAIN_RID,
        DOMAIN_ALIAS_RID_ADMINS,
        0, 0, 0, 0, 0, 0,
        &pAdminSID);

    // Initialize an EXPLICIT_ACCESS structure for an ACE.
    // The ACE will allow the Administrators group full access to
    // the key.
    ea[1].grfAccessPermissions = FILE_ALL_ACCESS | GENERIC_WRITE | GENERIC_READ;
    ea[1].grfAccessMode = SET_ACCESS;
    ea[1].grfInheritance= NO_INHERITANCE;
    ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
    ea[1].Trustee.TrusteeType = TRUSTEE_IS_GROUP;
    ea[1].Trustee.ptstrName  = (LPTSTR) pAdminSID;

    AllocateAndInitializeSid(&siaWorldSidAuthority, 1,
        SECURITY_MANDATORY_LOW_RID,
        0,
        0, 0, 0, 0, 0, 0,
        &pLowSID);

    ea[2].grfAccessPermissions = FILE_ALL_ACCESS | GENERIC_WRITE | GENERIC_READ;
    ea[2].grfAccessMode = SET_ACCESS;
    ea[2].grfInheritance= NO_INHERITANCE;
    ea[2].Trustee.TrusteeForm = TRUSTEE_IS_SID;
    ea[2].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
    ea[2].Trustee.ptstrName  = (LPTSTR) pLowSID;

    AllocateAndInitializeSid(&siaWorldSidAuthority, 1,
        SECURITY_MANDATORY_HIGH_RID,
        0,
        0, 0, 0, 0, 0, 0,
        &pHighSID);

    ea[3].grfAccessPermissions = FILE_ALL_ACCESS | GENERIC_WRITE | GENERIC_READ;
    ea[3].grfAccessMode = SET_ACCESS;
    ea[3].grfInheritance= NO_INHERITANCE;
    ea[3].Trustee.TrusteeForm = TRUSTEE_IS_SID;
    ea[3].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
    ea[3].Trustee.ptstrName  = (LPTSTR) pHighSID;

    SetEntriesInAcl(4, ea, NULL, &pACL);

    pSD = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH); 
    InitializeSecurityDescriptor( pSD, SECURITY_DESCRIPTOR_REVISION);
    SetSecurityDescriptorDacl( pSD, TRUE, pACL, FALSE );
    ZeroMemory( &sa, sizeof(SECURITY_ATTRIBUTES));


    sa.nLength              = sizeof(SECURITY_ATTRIBUTES);
    sa.lpSecurityDescriptor = pSD;
    sa.bInheritHandle       = FALSE;

    m_hPipe = CreateNamedPipeA(
                m_szName.c_str(),
                PIPE_ACCESS_DUPLEX,
                PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | BlockFlag,
                PIPE_UNLIMITED_INSTANCES,
                BUFFER_SIZE,
                BUFFER_SIZE,
                NMPWAIT_USE_DEFAULT_WAIT,
                &sa
                );

    if (psidWorldSid) 
        FreeSid(psidWorldSid);
    if (pAdminSID) 
        FreeSid(pAdminSID);
    if (pLowSID) 
        FreeSid(pLowSID);
    if (pHighSID) 
        FreeSid(pHighSID);
    if (pACL) 
        LocalFree(pACL);
    if (pSD) 
        LocalFree(pSD);

It seems to work almost fine when I create a security descriptor from string:

ConvertStringSecurityDescriptorToSecurityDescriptorW( L"S:(ML;;NW;;;LW)", SDDL_REVISION_1, &pSD, NULL);

When I create security descriptor from the string as above I can at least open pipes created with medium integrity permissions from low integrity processes.

Thank you for any suggestions.

Regards, Kuba

like image 747
blackd0t Avatar asked Mar 06 '12 17:03

blackd0t


2 Answers

The code you show appears to be creating a Security Descriptor and setting up its Discretionary Access Control List (DACL). The DACL has nothing at all to do with the integrity control mechanism.

In order for low integrity processes to open a handle via which to write to your named pipe, the named pipe object needs to be marked Low Integrity in its Mandatory Integrity Label. This label lives in the System Access Control List (SACL), not in the DACL. That is what the S:(... prefix means in the SDDL string representation of the security descriptor which you used to create the SD via ConvertStringSecurityDescriptorToSecurityDescriptorW.

If you want to do this long-hand without starting from the SDDL representation, you have to create an ACE of the correct type, SYSTEM_MANDATORY_LABEL_ACE, initialised with the SID for Low Integrity (S-1-16-4096) and an appropriate integrity policy (e.g. SYSTEM_MANDATORY_LABEL_NO_WRITE_UP), and then put it into the SACL via SetSecurityDescriptorSacl.

like image 155
Chris Dickson Avatar answered Oct 01 '22 22:10

Chris Dickson


I was able to resolve the problem. As Chris pointed out, the pipe was created properly with low integrity permissions although I missed the part where I made it available for users.

I resolved this by setting SDDL like this: S:(ML;;NW;;;LW)D:(A;;0x12019f;;;WD) This will set permissions for Everyone user allowing him to open, write, read the pipe. I've checked and now the pipe can be accessed globally from any integrity level and from any account.

Better way would be to set up 0x12019b permissions for "Everyone" as it will give all users access to the pipe without permissions to add new instances to the pipe. Then you'd have to add 0x12019f permissions only for the user who creates the pipes, but I had no idea how to get the ID of the current user.

In my situation that fits nicely as I only report data information from other processes for parsing by the system service, but if you use pipes to control the system service you may not want to set up security descriptor in a different way. It is very important to be careful about any buffer/heap overflows when you send data to system service through pipes as it may cause a security flaw leaving a vulnerability that could allow local privilege escalation.

I hope this question helps someone else.

Roger, out!

like image 44
blackd0t Avatar answered Oct 01 '22 23:10

blackd0t