Setting a created file permissions - c

I would like to know how can I set the permissions of a windows file?
Something like chmod(), instead it's a windows.
For example:
Create the file example.exe, and set its permissions in a way that only the owner
of this file can execute it.
I read that there's an ACL API for c somewhere, but I didn't quite get it.

It's a lot more work than chmod!
I have taken the liberty of creating the file AFTER creating the security descriptor - it is safer. If you do things the other way around (create the file first) then there is a short time when the required access is not set.
Try this:
#include <windows.h>
#include <AclAPI.h>
#include <Lmcons.h>
int main()
{
SECURITY_DESCRIPTOR sd;
EXPLICIT_ACCESS ea[1];
PACL pDacl;
SECURITY_ATTRIBUTES sa;
TCHAR UserBuffer[UNLEN+1];
DWORD ulen = UNLEN;
GetUserName(UserBuffer, &ulen);
InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
BuildExplicitAccessWithName(&ea[0], UserBuffer, GENERIC_EXECUTE,
SET_ACCESS, NO_INHERITANCE);
SetEntriesInAcl(1, ea, NULL, &pDacl);
SetSecurityDescriptorDacl(&sd, TRUE, pDacl, FALSE);
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.bInheritHandle = FALSE;
sa.lpSecurityDescriptor = &sd;
CreateFileA("c:\\temp\\example.exe", GENERIC_EXECUTE, 0, &sa,
CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
return 0;
}

Related

Is there an option to prohibit user from accessing basic file?

I'm currently working on developing some driver. For now connection between kernel and system is done via simple text file created like this:
handle=CreateFile(TEXT("\\\\.\\" FILE_NAME),
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
File is used for transfering data from kernel to system, kernel driver writes file and system app reads from it. My concern is safety of such solution, as for now anyone can simply go into this file, get all data in file, and what's even worse, modify it. Is it possible to make file not accesible for user, but still being accesible for system app?
UPDATE:
After doing some research I found a pattern how to do it for specific users:
ea[1].grfAccessPermissions = ACCESS_SYSTEM_SECURITY | READ_CONTROL | WRITE_DAC | GENERIC_ALL;
ea[1].grfAccessMode = DENY_ACCESS;
ea[1].grfInheritance = NO_INHERITANCE;
ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
ea[1].Trustee.ptstrName = reinterpret_cast<char*>(&everyone_sid);
dwRes = SetEntriesInAclA(2, ea, NULL, &pNewDACL);
if (ERROR_SUCCESS != dwRes) {
printf("SetEntriesInAcl Error %u\n", dwRes);
//TODO: goto Cleanup;
}
PSECURITY_DESCRIPTOR pSD = NULL;
// Initialize a security descriptor.
pSD = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR,
SECURITY_DESCRIPTOR_MIN_LENGTH);
if (NULL == pSD)
{
printf("error");
}
if (!InitializeSecurityDescriptor(pSD,
SECURITY_DESCRIPTOR_REVISION))
{
printf("error");
}
// Add the ACL to the security descriptor.
if (!SetSecurityDescriptorDacl(pSD,
TRUE, // bDaclPresent flag
pNewDACL,
FALSE)) // not a default DACL
{
printf("error");
}
SECURITY_ATTRIBUTES sa;
// Initialize a security attributes structure.
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = pSD;
sa.bInheritHandle = FALSE;
HANDLE hFile = CreateFileA(filename, GENERIC_ALL, 0, &sa, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
By this code I managed to make file not accesible for any user so It's great progress. However, I have no idea how to make it accesible for another project, for example:
int main()
{
std::cout << "Hello World!\n";
std::fstream testfile;
//basically in another project
testfile.open("created_file.txt", ios::out);
testfile.write("elo",3);
testfile.close();
}
I belive that maybe there is a way to get proccess SID and then give full access for it's SID, but question is how could I get process SID?

Sharedmemory between different sessions

I have two applications:
first one: running with SYSTEM Privileges started by a service and the
second one: running still as SYSTEM but with lower privileges (SE_GROUP_INTEGRITY = "S-1-16-4096")
I want both applications to communicate over sharedmemory. Both need to read and write.
In my first application i create the filemapping with specific SECURITY_ATTRIBUTES i learned from this post: How to share memory between services and user processes?
SECURITY_ATTRIBUTES attributes;
ZeroMemory(&attributes, sizeof(attributes));
attributes.nLength = sizeof(attributes);
ConvertStringSecurityDescriptorToSecurityDescriptor(
L"D:P(A;OICI;GA;;;SY)(A;OICI;GA;;;BA)(A;OICI;GWR;;;IU)",
SDDL_REVISION_1,
&attributes.lpSecurityDescriptor,
NULL);
HANDLE test = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 1024, "Global\\Test");
Everything works as expected, but if i then try to open the file mapping in my second application, it crashes with an access violation at OpenFileMapping.
HANDLE test = OpenFileMapping(FILE_ALL_ACCESS, FALSE, 1024, "Global\\Test");
if you want allow access to object for Low Integrity code you need add Low mandatory level (SDDL_ML_LOW) Integrity label (SDDL_MANDATORY_LABEL) to security descriptor. for example
"D:PNO_ACCESS_CONTROLS:(ML;;NW;;;LW)"
so in general code is next:
ULONG CreateSectionWithLowAccess(PHANDLE SectionHandle, ULONG dwMaximumSize, PCWSTR lpName)
{
SECURITY_ATTRIBUTES sa = { sizeof(sa) };
if (ConvertStringSecurityDescriptorToSecurityDescriptorW(L"D:PNO_ACCESS_CONTROLS:(ML;;NW;;;LW)",
SDDL_REVISION_1, &sa.lpSecurityDescriptor, NULL))
{
*SectionHandle = CreateFileMappingW(INVALID_HANDLE_VALUE, &sa, PAGE_READWRITE, 0, dwMaximumSize, lpName);
LocalFree(sa.lpSecurityDescriptor);
return *SectionHandle ? NOERROR : GetLastError();
}
return GetLastError();
}

Program escalates itself from admin to system

I wrote a program that needs to be running as SYSTEM. I add the linker option 'UAC Execution Level' to 'requireAdministrator' and it pops the UAC like it should but now I need to escalate from admin to SYSTEM how can I do that?
I thought about opening the program's token and inject it the SYSTEM token but it is not legit way. How can I do it neatly because I know once you admin you can be SYSTEM.
Write a windows service. It will run as SYSTEM user by default.
A simple tutorial is here, but remember that installing a service requires administrator privileges.
Once you're running as administrator, here are some options:
If you know you're not going to be using GUI functions, you can create a scheduled task that runs your same exe as NT AUTHORITY\SYSTEM within a few seconds, and check within your code which account the process is running as.
Copied from a project of mine and slightly modified:
#include <Windows.h>
#include <WinNls.h>
#include <shobjidl.h>
#include <objbase.h>
#include <ObjIdl.h>
#include <ShlGuid.h>
#include <taskschd.h>
#include <comdef.h>
#include <strsafe.h>
#pragma comment(lib, "taskschd.lib")
#pragma comment(lib, "comsupp.lib")
HRESULT WINAPI CreateSchedTask(WCHAR *wszExePath)
{
ITaskService *pService = NULL;
ITaskFolder *pRoot = NULL;
ITaskDefinition *pTask = NULL;
ITaskSettings *pSettings = NULL;
IRegistrationInfo *pInfo = NULL;
ITriggerCollection *pCollection = NULL;
ITrigger *pTrigger = NULL;
ITimeTrigger *pTime = NULL;
IPrincipal *pPrincipal = NULL;
IActionCollection *pActionCollection = NULL;
IAction *pAction = NULL;
IExecAction *pExecAction = NULL;
IRegisteredTask *pRegTask = NULL;
SYSTEMTIME stNow;
FILETIME ftStart, ftEnd;
ULARGE_INTEGER ulWork;
WCHAR wFmt[100];
VARIANT vBlank = _variant_t();
if (FAILED(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED)))
{
return E_FAIL;
}
//CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_PKT_PRIVACY, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, 0, NULL);
if (FAILED(CoCreateInstance(CLSID_TaskScheduler, NULL, CLSCTX_INPROC_SERVER, IID_ITaskService, (LPVOID *) &pService)))
{
return E_FAIL;
}
pService->Connect(vBlank, vBlank, vBlank, vBlank);
pService->GetFolder(SysAllocString(L"\\"), &pRoot);
pService->NewTask(0, &pTask);
pService->Release();
pTask->get_RegistrationInfo(&pInfo);
pInfo->put_Author(SysAllocString(L"TASKNAMEHERE"));
pInfo->Release();
pTask->get_Settings(&pSettings);
pSettings->put_StartWhenAvailable(VARIANT_TRUE);
pSettings->put_Enabled(VARIANT_TRUE);
pSettings->Release();
pTask->get_Triggers(&pCollection);
pCollection->Create(TASK_TRIGGER_TIME, &pTrigger);
pCollection->Release();
pTrigger->QueryInterface(IID_ITimeTrigger, (LPVOID *)&pTime);
GetLocalTime(&stNow);
SystemTimeToFileTime(&stNow, &ftStart);
ulWork.HighPart = ftStart.dwHighDateTime;
ulWork.LowPart = ftStart.dwLowDateTime;
//20000000000
ulWork.QuadPart += 300000000UI64;
ftStart.dwHighDateTime = ulWork.HighPart;
ftStart.dwLowDateTime = ulWork.LowPart;
FileTimeToSystemTime(&ftStart, &stNow);
// Note: replace -07:00 with the appropriate UTC offset for your time zone
StringCchPrintfW(wFmt, 100, L"%.4hu-%.2hu-%.2huT%.2hu:%.2hu:%.2hu-07:00", stNow.wYear, stNow.wMonth, stNow.wDay, stNow.wHour, stNow.wMinute, stNow.wSecond);
pTime->put_StartBoundary(SysAllocString(wFmt));
ulWork.QuadPart += 900000000UI64;
ftEnd.dwLowDateTime = ulWork.LowPart;
ftEnd.dwHighDateTime = ulWork.HighPart;
FileTimeToSystemTime(&ftEnd, &stNow);
StringCchPrintfW(wFmt, 100, L"%.4hu-%.2hu-%.2huT%.2hu:%.2hu:%.2hu-07:00", stNow.wYear, stNow.wMonth, stNow.wDay, stNow.wHour, stNow.wMinute, stNow.wSecond);
pTime->put_EndBoundary(SysAllocString(wFmt));
pTime->put_Id(SysAllocString(L"TimeTrigger"));
pTime->Release();
pTask->get_Actions(&pActionCollection);
pActionCollection->Create(TASK_ACTION_EXEC, &pAction);
pActionCollection->Release();
pAction->QueryInterface(IID_IExecAction, (LPVOID *)&pExecAction);
pAction->Release();
pExecAction->put_Path(SysAllocString(wszExePath));
pExecAction->Release();
pTask->get_Principal(&pPrincipal);
pPrincipal->put_RunLevel(TASK_RUNLEVEL_HIGHEST);
pPrincipal->put_LogonType(TASK_LOGON_SERVICE_ACCOUNT);
pTask->put_Principal(pPrincipal);
pPrincipal->Release();
pRoot->RegisterTaskDefinition(
SysAllocString(L"System Elevation"),
pTask, TASK_CREATE_OR_UPDATE,
_variant_t(L"NT AUTHORITY\\SYSTEM"),
_variant_t(), TASK_LOGON_SERVICE_ACCOUNT,
_variant_t(L""), &pRegTask);
pRoot->Release();
pTask->Release();
pRegTask->Release();
CoUninitialize();
return S_OK;
}
INT APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, INT nShowCmd)
{
WCHAR wUsername[100], wExePath[MAX_PATH];
GetEnvironmentVariableW(L"USERNAME", wUsername, 100);
if (!wcschr(wUsername, L'$'))
{
GetModuleFileNameW(hInstance, wExePath, MAX_PATH);
CreateSchedTask(wExePath);
}
else
{
// NOTE: MessageBox and other GUI functions won't work since the process isn't running in winsta0\default
// File I/O instead
HANDLE hLog = CreateFileW(L"C:\\Temp\\Log.txt", GENERIC_WRITE | GENERIC_READ, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
DWORD dwWritten;
UINT uLen;
CHAR szBuf[100];
SetFilePointer(hLog, 0, NULL, FILE_END);
StringCchPrintfA(szBuf, 100, "Hello from %S\r\n", wUsername);
StringCbLengthA(szBuf, 100, &uLen);
WriteFile(hLog, szBuf, uLen, &dwWritten, NULL);
CloseHandle(hLog);
}
return 0;
}
Use the Windows Process API to elevate to System. I don't have much in the way of example code for this, but you can look at PAExec, an open source alternative to SysInternals PSExec tool, that allows creating new interactive processes as System.
The idiomatic way of doing this on Windows, which is create a Windows service.

SetSecurityInfo returns access denied

Using C, I'm trying to establish a pipe connection between a process and it's child process, while the child process has a lower mandatory(integrity) level (low, while the parent process is high).
I wrote the following program (it's a simplified version if it), but it fails with: ERROR_ACCESS_DENIED (0x5)
INT wmain(IN SIZE_T nArgc, IN PWSTR *pArgv)
{
SECURITY_ATTRIBUTES securityArrtibutes = { 0 };
HANDLE hPipeRead = NULL;
HANDLE hPipeWrite = NULL;
tSecurityArrtibutes.nLength = sizeof(tSecurityArrtibutes);
tSecurityArrtibutes.bInheritHandle = TRUE;
SetSeSecurityNamePrivilege();
CreatePipe(&hPipeRead, &hPipeWrite, &securityArrtibutes, 0);
ChangeMandatoryLabelHandle(hPipeRead);
}
VOID ChangeMandatoryLabelHandle(HANDLE hObject)
{
BOOL bRetval = FALSE;
DWORD dwError = 0;
PSECURITY_DESCRIPTOR pSecurityDescriptor = NULL;
PACL ptSacl = NULL;
BOOL bSaclPresent = FALSE;
BOOL bSaclDefaulted = FALSE;
PWSTR pSDDL = NULL;
SDDL = L"S:(ML;;LW;;;NW)";
bRetval = ConvertStringSecurityDescriptorToSecurityDescriptorW(pSDDL, SDDL_REVISION_1, &pSecurityDescriptor, NULL);
if (FALSE == bRetval)
... // Handle failure
bRetval = GetSecurityDescriptorSacl(pSecurityDescriptor, &bSaclPresent, &ptSacl, &bSaclDefaulted);
if (FALSE == bRetval)
... // Handle failure
// getting ERROR_ACCESS_DENIED (0x5)
dwErr = SetSecurityInfo(hObject, SE_KERNEL_OBJECT, LABEL_SECURITY_INFORMATION, NULL, NULL, NULL, ptSacl);
if (ERROR_SUCCESS != dwErr)
... // Handle failure
... // Cleanup
}
I followed https://msdn.microsoft.com/en-us/library/windows/desktop/aa379588(v=vs.85).aspx and the remark that
To set the SACL of an object, the caller must have the SE_SECURITY_NAME privilege enabled. :
BOOL SetSeSecurityNamePrivilege()
{
HANDLE hToken;
TOKEN_PRIVILEGES tp;
LUID luid;
if(!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY | TOKEN_IMPERSONATE, &hToken)
return FALSE
if (!LookupPrivilegeValue(NULL, SE_SECURITY_NAME, &luid))
return FALSE;
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
if (bEnablePrivilege)
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
else
tp.Privileges[0].Attributes = 0;
if (!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), (PTOKEN_PRIVILEGES)NULL, (PDWORD)NULL))
return FALSE;
if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
return FALSE;
return TRUE;
}
note: I get the same result when I try to execute it with files, with CreateFile instead of CreatePipe.
In addition if I try to do that with files, and I replace SetSecurityInfo with SetNamedSecurityInfoW, and give it the full path of the file, it works great.
Does anyone have an idea how to make it work? Thanks!
A few notes before addressing the cause of your immediate problem.
First and foremost, you do not need to change the security descriptor at all, and doing so is unlikely to help you achieve your ultimate goal. The security descriptor is only checked when you attempt to open a handle to an object; if you already have a handle, the security descriptor has no effect. Since you are creating an unnamed pipe, you must be passing the handle, not the pipe name, to the child, so you do not need the ChangeMandatoryLabelHandle function at all.
Secondly, the SE_SECURITY_NAME privilege is not needed when setting LABEL_SECURITY_INFORMATION. The mandatory label is logically distinct from the rest of the SACL, and is treated as a special case.
Thirdly, your "S:(ML;;LW;;;NW)" is invalid.
I tried to use it in ConvertStringSecurityDescriptorToSecurityDescriptorW and got error 1336, The access control list (ACL) structure is invalid. Instead, use"D:NO_ACCESS_CONTROLS:(ML;;;;;LW)" or better still use the following code to create a security descriptor with a low label and no DACL:
ULONG cb = MAX_SID_SIZE;
PSID LowLabelSid = (PSID)alloca(MAX_SID_SIZE);
ULONG dwError = NOERROR;
if (CreateWellKnownSid(WinLowLabelSid, 0, LowLabelSid, &cb))
{
PACL Sacl = (PACL)alloca(cb += sizeof(ACL) + sizeof(ACE_HEADER) + sizeof(ACCESS_MASK));
if (InitializeAcl(Sacl, cb, ACL_REVISION) &&
AddMandatoryAce(Sacl, ACL_REVISION, 0, 0, LowLabelSid))
{
SECURITY_DESCRIPTOR sd;
InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE);
SetSecurityDescriptorSacl(&sd, TRUE, Sacl, FALSE);
SECURITY_ATTRIBUTES sa = { sizeof(sa), &sd, TRUE };
// todo something here
}
else
{
dwError = GetLastError();
}
}
else
{
dwError = GetLastError();
}
But again, you need to understand that there is (almost) never any sense in creating a security descriptor for an unnamed object. The security descriptor is only checked when opening an object, and (in user mode) you cannot open an object that does not have a name.
(From kernel mode we can open an object by pointer using ObOpenObjectByPointer.)
(In older versions of Windows, CreatePipe actually created a pipe with a random name, but starting from Windows 7 the pipe really is unnamed, so it cannot be opened with CreateFile or any similar method.)
In any case, it is my opinion that using CreatePipe in this context was a bad choice. This function is not well designed and has too few parameters. There is no option to create a bidirectional pipe or to open the pipe in asynchronous mode. I think it is better to use CreateNamedPipeW and CreateFileW.
(Alternatively, from Windows 7 onwards, you can use ZwCreateNamedPipeFile and ZwOpenFile to create and open an unnamed pipe.)
The proximate problem with the code as posted is that SetSecurityInfo and SetKernelObjectSecurity return ERROR_ACCESS_DENIED when called with the handle returned by CreatePipe. This is because, as described in the documentation for LABEL_SECURITY_INFORMATION:
Right required to set: WRITE_OWNER
Since CreatePipe does not give you the option to select the access rights that the handles are opened with, you have no way of doing this. If you instead use CreateNamedPipe you can set WRITE_OWNER in dwOpenMode.
However, you should note that if you wish to create an object with a special security descriptor, it is preferable to provide that security descriptor when the object is created. There is no point in creating the object with a default security descriptor and then changing it; why do in two operations what you can do in one? In this case, the SECURITY_ATTRIBUTES structure you pass to CreatePipe or CreateNamedPipe can be used to specify the security descriptor, providing another way of addressing your immediate problem, although as previously mentioned this will not in fact be useful.

How to give "Everyone" write permissions via C++ MFC on Windows 8?

Im struggling with changing permissions.
I need, on Windows 8, to change the permissions of a file to have group "Everyone" write permissions.
How to I do that?
Im trying to edit a file with C++ MFC which already exists with no "Write" (Everyone) checked, thats causing me many problems.
Your Application need to have the rights to change the permissions for the file.
#pragma comment(lib, "Advapi32.lib")
#include "Aclapi.h"
#include "Sddl.h"
#include <io.h>
#include <sys/stat.h>
void AllowEveryone(CString path)
{
PACL pDacl,pNewDACL;
EXPLICIT_ACCESS ExplicitAccess;
PSECURITY_DESCRIPTOR ppSecurityDescriptor;
PSID psid;
LPTSTR lpStr;
CString str = path;
lpStr = str.GetBuffer();
GetNamedSecurityInfo(lpStr, SE_FILE_OBJECT,DACL_SECURITY_INFORMATION, NULL, NULL, &pDacl, NULL, &ppSecurityDescriptor);
ConvertStringSidToSid("S-1-1-0", &psid);
ExplicitAccess.grfAccessMode = SET_ACCESS;
ExplicitAccess.grfAccessPermissions = GENERIC_ALL;
ExplicitAccess.grfInheritance = CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE;
ExplicitAccess.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
ExplicitAccess.Trustee.pMultipleTrustee = NULL;
ExplicitAccess.Trustee.ptstrName = (LPTSTR) psid;
ExplicitAccess.Trustee.TrusteeForm = TRUSTEE_IS_SID;
ExplicitAccess.Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
SetEntriesInAcl(1, &ExplicitAccess, pDacl, &pNewDACL);
SetNamedSecurityInfo(lpStr,SE_FILE_OBJECT,DACL_SECURITY_INFORMATION,NULL,NULL,pNewDACL,NULL);
LocalFree(pNewDACL);
LocalFree(psid);
str.ReleaseBuffer();
}

Resources