Skip to content

Commit

Permalink
Adding SID parameter to the configuration options
Browse files Browse the repository at this point in the history
  • Loading branch information
sagiesec committed Jun 8, 2023
1 parent 2b16952 commit 0656cea
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 4 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@

# I Need More Information
Check out our [RPC Firewall](https://zeronetworks.com/blog/stopping_lateral_movement_via_the_rpc_firewall/) blog post or our [BlackHat talk](https://www.youtube.com/watch?v=hz_YPIMeBMI) to gain better understanding of RPC, RPC attacks and the solution: the RPC Firewall.

Join our [|Zero| Labs](https://join.slack.com/t/minus273celsius/shared_invite/zt-1ulg46s8x-N0P9sEzmv3SbYTlDXVSf2g) Slack Community workspace for any questions, issues, or simlpy to shout out.

We would love to hear from you also via email (if you are that type of person). Contact us at [[email protected]](mailto:[email protected])

# Get Started
Expand Down Expand Up @@ -141,7 +143,7 @@ This file uses the following configuration options:
|uuid:| Match a specific uuid | both RPC Firewall and Filters|
|action:| Can be either **allow** or **block** (default allow)| both RPC Firewall and Filters|
|audit:| Can be either **true** or *false*. Controls whether events are written to the *RPCFW* log (default false)| both RPC Firewall and Filters|
|sid:| matches an authenticated user to a [security identifier](https://docs.microsoft.com/en-us/windows/security/identity-protection/access-control/security-identifiers). Could be specific user or group. | RPC Filters only
|sid:| matches an authenticated user to a [security identifier](https://docs.microsoft.com/en-us/windows/security/identity-protection/access-control/security-identifiers). Could be specific user or group. | both RPC Firewall and Filters



Expand Down
2 changes: 2 additions & 0 deletions rpcFirewall/config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ using OpNumFilter = std::optional<DWORD>;
using UUIDFilter = std::optional<std::wstring>;
using AddressFilter = std::optional<std::wstring>;
using protocolFilter = std::optional<std::wstring>;
using SIDFilter = std::optional<std::wstring>;

struct RpcCallPolicy
{
Expand All @@ -20,6 +21,7 @@ struct LineConfig
AddressFilter source_addr;
RpcCallPolicy policy;
protocolFilter protocol;
SIDFilter sid;
bool verbose;
};

Expand Down
89 changes: 86 additions & 3 deletions rpcFirewall/dllmain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <iomanip>
#include "config.hpp"
#include "rpcWrappers.hpp"
#include <sddl.h>

#pragma comment(lib, "Ws2_32.lib")

Expand Down Expand Up @@ -375,6 +376,15 @@ protocolFilter extractProtocolFromConfigLine(const std::wstring& confLine)
return protocol.empty() ? protocolFilter{} : protocolFilter{ protocol };
}

SIDFilter extraceSIDFromConfigLine(const std::wstring& confLine)
{
std::wstring sid = extractKeyValueFromConfigLine(confLine, _T("sid:"));

std::transform(sid.begin(), sid.end(), sid.begin(), ::toupper);

return sid.empty() ? SIDFilter{} : SIDFilter{ sid };

}

void loadPrivateBufferToPassiveVectorConfiguration()
{
Expand Down Expand Up @@ -410,6 +420,8 @@ void loadPrivateBufferToPassiveVectorConfiguration()
lineConfig.policy = extractPolicyFromConfigLine(confLineString);
lineConfig.verbose = extractVerboseFromConfigLine(confLineString);
lineConfig.protocol = extractProtocolFromConfigLine(confLineString);
lineConfig.sid = extraceSIDFromConfigLine(confLineString);

passiveConfigVector.push_back(lineConfig);
}
}
Expand Down Expand Up @@ -496,6 +508,77 @@ bool checkProtocol(const protocolFilter& protFilter, const std::wstring& protoco
return false;
}

// Function to check if the RPC caller has access based on the security descriptor
bool checkIfSIDBelongstoSD(SIDFilter sidFilter)
{
WRITE_DEBUG_MSG(_T("Entering checkIfSIDBelongstoSD ..."));
if (!sidFilter.has_value())
{
return true;
}

std::wstring securityDescriptorString = L"O:BAG:BAD:(A;;FA;;;" + sidFilter.value() + L")";

PSECURITY_DESCRIPTOR pSecurityDescriptor = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);


if (!ConvertStringSecurityDescriptorToSecurityDescriptorW(securityDescriptorString.c_str(),
SDDL_REVISION_1, &pSecurityDescriptor, nullptr))
{
WRITE_DEBUG_MSG(_T("ConvertStringSecurityDescriptorToSecurityDescriptorW failed..."));
return false;
}

WRITE_DEBUG_MSG(_T("Calling RpcImpersonateClient"));

RPC_STATUS status = RpcImpersonateClient(nullptr);
if (status != RPC_S_OK)
{
WRITE_DEBUG_MSG_WITH_STATUS(_T("RpcImpersonateClient failed"), status);
LocalFree(pSecurityDescriptor);
return false;
}

HANDLE hToken = nullptr;
if (!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, true, &hToken))
{
WRITE_DEBUG_MSG_WITH_GETLASTERROR(_T("OpenThreadToken failed"));
RpcRevertToSelf();
LocalFree(pSecurityDescriptor);
return false;
}

GENERIC_MAPPING mapping;
mapping.GenericRead = FILE_GENERIC_READ;
mapping.GenericExecute = FILE_GENERIC_EXECUTE;
mapping.GenericWrite = FILE_GENERIC_WRITE;
mapping.GenericAll = FILE_ALL_ACCESS;

DWORD dwAccessDesired = FILE_GENERIC_READ;
MapGenericMask(&dwAccessDesired, &mapping);

DWORD dwAccessGranted;
BOOL bResult;
BOOL bAccessStatus = FALSE;
PRIVILEGE_SET PrivilegeSet;
DWORD dwPrivSetSize = sizeof(PRIVILEGE_SET);

PrivilegeSet.PrivilegeCount = 0;
PrivilegeSet.Control = 0;
bResult = AccessCheck(pSecurityDescriptor, hToken, dwAccessDesired, &mapping, &PrivilegeSet, &dwPrivSetSize, &dwAccessGranted, &bAccessStatus);
if (!bResult)
{
WRITE_DEBUG_MSG_WITH_GETLASTERROR(_T("AccessCheck failed"));
}

WRITE_DEBUG_MSG_WITH_STATUS(_T("AccessCheck returned "), bAccessStatus);

RpcRevertToSelf();
LocalFree(pSecurityDescriptor);
CloseHandle(hToken);
return bAccessStatus;
}

RpcCallPolicy getMatchingPolicy(const RpcEventParameters& rpcEvent)
{
const ConfigVector& configurationVector = config.getActiveConfigurationVector();
Expand All @@ -505,9 +588,10 @@ RpcCallPolicy getMatchingPolicy(const RpcEventParameters& rpcEvent)
const bool UUIDMatch = checkUUID(lc.uuid, rpcEvent.uuidString);
const bool AddressMatch = checkAddress(lc.source_addr, rpcEvent.sourceAddress);
const bool OpNumMatch = checkOpNum(lc.opnum, rpcEvent.OpNum);
const bool ProtocolMatch = checkProtocol(lc.protocol, rpcEvent.protocol);
const bool ProtocolMatch = checkProtocol(lc.protocol, rpcEvent.protocol);
const bool SIDMatch = checkIfSIDBelongstoSD(lc.sid);

if (UUIDMatch && AddressMatch && OpNumMatch && ProtocolMatch)
if (UUIDMatch && AddressMatch && OpNumMatch && ProtocolMatch && SIDMatch)
{
WRITE_DEBUG_MSG(_T("Rule Matched for RPC call."));

Expand Down Expand Up @@ -1029,7 +1113,6 @@ void processRPCCall(wchar_t* functionName, PRPC_MESSAGE pRpcMsg)

long WINAPI detouredNdrStubCall2(void* pThis, void* pChannel, PRPC_MESSAGE pRpcMsg, unsigned long* pdwStubPhase)
{
WRITE_DEBUG_MSG(L"NdrStubCall2 Called!....");
processRPCCall((wchar_t*)_T("NdrStubCall2"), pRpcMsg);

return realNdrStubCall2(pThis, pChannel, pRpcMsg, pdwStubPhase);
Expand Down

0 comments on commit 0656cea

Please sign in to comment.