Skip to content

Commit

Permalink
add desktop, various refactoring, soft fail for when home dir is set …
Browse files Browse the repository at this point in the history
…wrong, other fixes
  • Loading branch information
partouf committed Sep 9, 2023
1 parent 0ea0718 commit b03a684
Show file tree
Hide file tree
Showing 7 changed files with 84 additions and 29 deletions.
2 changes: 2 additions & 0 deletions include/access.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,6 @@ namespace cewrapper
void grant_access_to_path(wchar_t *container_sid, wchar_t *dir, uint32_t permissions);
void grant_access_to_registry(wchar_t *container_sid, wchar_t *key, uint32_t permissions, registry_type_t regtype);

void remove_access_to_path(wchar_t *container_sid, wchar_t *dir, uint32_t permissions);

};
1 change: 1 addition & 0 deletions include/checks.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@ namespace cewrapper
void OutputErrorMessage(DWORD err, const wchar_t *action);
void CheckWin32(BOOL res, const wchar_t *action);
void CheckStatus(DWORD status, const wchar_t *action);
void CheckStatusAllowFail(DWORD status, const wchar_t *action);

}; // namespace cewrapper
1 change: 1 addition & 0 deletions include/exitcodes.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ enum class SpecialExitCode : DWORD
InvalidArgs = 2,
ProcessTookTooLong = 3,
ProcessTookTooLongMethod2 = 9,
ErrorWhenExecutingProcess = 254,
UnknownErrorWhileWaitingOnProcess = 255,
};
27 changes: 26 additions & 1 deletion src/access.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,32 @@ void cewrapper::grant_access_to_path(wchar_t *container_sid, wchar_t *dir, uint3

ACL *newAcl = nullptr;
cewrapper::CheckStatus(SetEntriesInAclW(1, &access, prevAcl, &newAcl), L"SetEntriesInAclW");
cewrapper::CheckStatus(SetNamedSecurityInfoW(dir, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, nullptr, nullptr, newAcl, nullptr),
cewrapper::CheckStatusAllowFail(SetNamedSecurityInfoW(dir, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, nullptr, nullptr, newAcl, nullptr),
L"SetNamedSecurityInfoW");
}

void cewrapper::remove_access_to_path(wchar_t *container_sid, wchar_t *dir, uint32_t permissions)
{
EXPLICIT_ACCESSW access = {};
{
access.grfAccessPermissions = permissions;
access.grfAccessMode = REVOKE_ACCESS;
access.grfInheritance = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE;
access.Trustee.TrusteeForm = TRUSTEE_IS_SID;
access.Trustee.TrusteeType = TRUSTEE_IS_GROUP;
access.Trustee.ptstrName = container_sid;
}

PSECURITY_DESCRIPTOR pSecurityDescriptor = nullptr;
ACL *prevAcl = nullptr;
cewrapper::CheckStatus(GetNamedSecurityInfoW(dir, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, nullptr, nullptr,
&prevAcl, nullptr, &pSecurityDescriptor),
L"GetNamedSecurityInfoW");

ACL *newAcl = nullptr;
cewrapper::CheckStatus(SetEntriesInAclW(1, &access, prevAcl, &newAcl), L"SetEntriesInAclW");
cewrapper::CheckStatusAllowFail(SetNamedSecurityInfoW(dir, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, nullptr,
nullptr, newAcl, nullptr),
L"SetNamedSecurityInfoW");
}

Expand Down
4 changes: 2 additions & 2 deletions src/appcontainer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,9 @@ void cewrapper::AppContainer::InitializeCapabilities()
sec_cap.CapabilityCount = 1;

// https://learn.microsoft.com/en-us/previous-versions/windows/apps/hh780593(v=win.10)#diagnostic-tool-for-network-isolation
// CreateCapabilitySID(sec_cap.Capabilities, 0, WinCapabilityInternetClientSid);
//CreateCapabilitySID(sec_cap.Capabilities, 0, WinCapabilityInternetClientSid);
// CreateCapabilitySID(sec_cap.Capabilities, 0, WinCapabilityInternetClientServerSid);
// CreateCapabilitySID(sec_cap.Capabilities, 0, WinCapabilityPrivateNetworkClientServerSid);
//CreateCapabilitySID(sec_cap.Capabilities, 1, WinCapabilityPrivateNetworkClientServerSid);


// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/596a1078-e883-4972-9bbc-49e60bebca55
Expand Down
8 changes: 8 additions & 0 deletions src/checks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,11 @@ void cewrapper::CheckStatus(DWORD status, const wchar_t *action)
OutputErrorMessage(status, action);
throw std::exception("abort");
}

void cewrapper::CheckStatusAllowFail(DWORD status, const wchar_t *action)
{
if (status == ERROR_SUCCESS)
return;

OutputErrorMessage(status, action);
}
70 changes: 44 additions & 26 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,19 @@ DWORD SpawnProcess(const cewrapper::Job &job, STARTUPINFOEX &si, HANDLE hUserTok
if (config.extra_debugging)
std::wcerr << "Running " << config.progid.c_str() << " " << cmdline.data() << "\n";

// todo: find out the precedence of si.StartupInfo.dwFlags and those passed directly to CreateProcess
si.StartupInfo.dwFlags = CREATE_UNICODE_ENVIRONMENT | CREATE_SUSPENDED;
// sometimes a desktop is required, otherwise we can the process might end up with a 0xc0000142 exit code (STATUS_DLL_INIT_FAILED)
// https://comp.os.ms-windows.programmer.win32.narkive.com/cBqcgpKg/createprocessw-in-a-service-fails-with-error-c0000142-dll-initialization-failed-due-to-desktop
// https://www.betaarchive.com/wiki/index.php/Microsoft_KB_Archive/165194
wchar_t *desktop = static_cast<wchar_t *>(malloc(64));
lstrcpyW(desktop, L"winsta0\\default");
si.StartupInfo.lpDesktop = desktop;

PROCESS_INFORMATION pi = {};
if (hUserToken == nullptr)
{
cewrapper::CheckWin32(CreateProcessW(config.progid.c_str(), cmdline.data(), nullptr, nullptr, false,
EXTENDED_STARTUPINFO_PRESENT | CREATE_UNICODE_ENVIRONMENT, nullptr,
EXTENDED_STARTUPINFO_PRESENT | CREATE_UNICODE_ENVIRONMENT | CREATE_SUSPENDED,
nullptr,
nullptr, &si.StartupInfo, &pi),
L"CreateProcessW");
}
Expand Down Expand Up @@ -80,7 +85,7 @@ DWORD SpawnProcess(const cewrapper::Job &job, STARTUPINFOEX &si, HANDLE hUserTok
}
}

DWORD app_exit_code = (DWORD)SpecialExitCode::UnknownErrorWhileWaitingOnProcess;
DWORD app_exit_code = std::to_underlying(SpecialExitCode::UnknownErrorWhileWaitingOnProcess);

if (maxtime > 0 && timespent >= maxtime)
{
Expand Down Expand Up @@ -109,6 +114,8 @@ DWORD SpawnProcess(const cewrapper::Job &job, STARTUPINFOEX &si, HANDLE hUserTok
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);

free(desktop);

return app_exit_code;
}

Expand All @@ -122,8 +129,8 @@ DWORD execute_using_lower_rights(const cewrapper::Job &job)
L"SaferComputeTokenFromLevel");

STARTUPINFOEX si;
ZeroMemory(&si, sizeof(STARTUPINFO));
si.StartupInfo.cb = sizeof(STARTUPINFO);
ZeroMemory(&si, sizeof(STARTUPINFOEX));
si.StartupInfo.cb = sizeof(STARTUPINFOEX);

DWORD app_exit_code = SpawnProcess(job, si, hToken);

Expand Down Expand Up @@ -154,23 +161,20 @@ DWORD execute_using_appcontainer(const cewrapper::Job &job)
// todo: do we need to use this at some point? -> https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-deleteprocthreadattributelist
}

std::wstring home_dir;

if (config.home_set)
{
auto &dir = config.home;
if (config.debugging)
std::wcerr << "granting access to: " << dir << "\n";
cewrapper::grant_access_to_path(container.getSid(), dir.data(), GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE);
home_dir = config.home;
}
else
{
// access to its own directory
auto dir = std::filesystem::path(config.progid).parent_path().wstring();
if (config.debugging)
std::wcerr << "granting access to: " << dir << "\n";
cewrapper::grant_access_to_path(container.getSid(), dir.data(), GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE);
home_dir = std::filesystem::path(config.progid).parent_path().wstring();
}

// todo: revoke access from the home path after we're done executing if the path keeps existing (should actually just be deleted, so revoking really isn't needed)
if (config.debugging)
std::wcerr << "granting access to: " << home_dir << "\n";
cewrapper::grant_access_to_path(container.getSid(), home_dir.data(), GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE);

for (auto &allowed : config.allowed_dirs)
{
Expand All @@ -182,14 +186,20 @@ DWORD execute_using_appcontainer(const cewrapper::Job &job)
for (auto &allowed : config.allowed_registry)
{
if (config.debugging)
std::wcerr << "granting access to registry: " << allowed.path << ", r" << allowed.rights << "\n";
std::wcerr << "granting access to registry: " << allowed.path << ", r" << std::hex << allowed.rights << "\n";
cewrapper::grant_access_to_registry(container.getSid(), allowed.path.data(), allowed.rights, allowed.type);
}

if (config.wait_before_spawn)
Sleep(10000);
Sleep(5000);

return SpawnProcess(job, si);
auto processExitCode = SpawnProcess(job, si);

if (config.debugging)
std::wcerr << "revoking access to: " << home_dir << "\n";
cewrapper::remove_access_to_path(container.getSid(), home_dir.data(), GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE);

return processExitCode;
}

int wmain(int argc, wchar_t *argv[])
Expand All @@ -199,7 +209,7 @@ int wmain(int argc, wchar_t *argv[])
std::wcerr << L"Too few arguments\n";
std::wcerr << L"Usage: cewrapper.exe [-v] [--config=/full/path/to/config.json] [--home=/preferred/cwdpath] "
L"[--time_limit=1] ExePath [args]\n";
return (int)SpecialExitCode::NotEnoughArgs;
return std::to_underlying(SpecialExitCode::NotEnoughArgs);
}

try
Expand All @@ -211,19 +221,27 @@ int wmain(int argc, wchar_t *argv[])
if (cewrapper::Config::get().debugging)
std::cerr << e.what() << "\n";
std::wcerr << L"Invalid arguments\n";
return (int)SpecialExitCode::InvalidArgs;
return std::to_underlying(SpecialExitCode::InvalidArgs);
}

cewrapper::Job job(cewrapper::Config::get());

DWORD app_exit_code{};
if (cewrapper::Config::get().use_appcontainer)
DWORD app_exit_code = std::to_underlying(SpecialExitCode::ErrorWhenExecutingProcess);
try
{
app_exit_code = execute_using_appcontainer(job);
if (cewrapper::Config::get().use_appcontainer)
{
app_exit_code = execute_using_appcontainer(job);
}
else
{
app_exit_code = execute_using_lower_rights(job);
}
}
else
catch (std::exception &e)
{
app_exit_code = execute_using_lower_rights(job);
if (cewrapper::Config::get().debugging)
std::cerr << e.what() << "\n";
}

return app_exit_code;
Expand Down

0 comments on commit b03a684

Please sign in to comment.