OK, did some investigations.
Full algorithm:
Dropper determinates OS type and depending on this acts differently.
In case of x86-32 dropper decrypts and drops component internally named
SeServer32.dll to the %TEMP% folder and after this injects it into Explorer.exe memory with CreateRemoteThread(LoadLibrary).
In case of x86-64 dropper decrypts and drops x64 component internally named
Se.exe to the %TEMP% folder and starts Se.exe with parameters ON or OFF (affect what it will do with UAC next). Se.exe extracts and drops x64 dll
SeServer64.dll and after this injects it into Explorer.exe memory with CreateRemoteThread(LoadLibrary);
SeServer32 and SeServer64 are both created from one source and doing the same stuff.
Inside SeServer library implemented small LPC based server, dll creates and waits for commands on named port
{A67077FD-5A57-4d0e-8D2A-3BC14D2E7D8A}0.1. Dll acquires COM object with
{4D111E08-CBF7-4f12-A926-2C7920AF52FC} which stands for
ISecurityEditor.
Interface
Access permissions
Client side (in case of x64 it is SE.exe) connects to the named port
{A67077FD-5A57-4d0e-8D2A-3BC14D2E7D8A}0.1 and sends requests as LPC messages. There two type of requests -
GetSecurityDescriptor and
SetSecurityDescriptor.
On
GetSecurityDescriptor command SeServer dll uses
ISecurityEditor->GetSecurity method and replies back to the caller with acquired data.
On
SetSecurityDescriptor command SeServer dll uses
ISecurityEditor->SetSecurity method and replies back to the caller was it successful or not.
Communication in details.
Se.exe/dropper requests security data for the HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System key, so it can save SD and restore it after.
SeServerXX.dll receives parameters and uses it for
ISecurityEditor->GetSecurity as shown below
Code: Select allpObjectName = MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System
ObjectType = SE_REGISTRY_KEY
SecurityInfo = DACL_SECURITY_INFORMATION
ppSecurityDescriptor = pointer to buffer to store output info.
The calls of interface methods happens not inside explorer.exe but in
COM Surrogate process DllHost.exe - running at
High Integrity Level. When GetSecurity method called DllHost.exe calls
RegQueryKeySecurity API.
After successful method call ppSecurityDescriptor buffer filled with
Code: Select allD:AI(A;ID;KR;;;BU)(A;CIIOID;GR;;;BU)(A;ID;KA;;;BA)(A;CIIOID;GA;;;BA)(A;ID;KA;;;SY)(A;CIIOID;GA;;;SY)(A;CIIOID;GA;;;CO)
Dropper/SE.exe saves this information for later use and calls server dll again with request
SetSecurityDescriptor.
SeServerXX.dll receives parameters and uses it for
ISecurityEditor->SetSecurity as shown below
Code: Select allpObjectName = MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System
ObjectType = SE_REGISTRY_KEY
SecurityInfo = DACL_SECURITY_INFORMATION
SecurityDescriptor = D:(A;;GA;;;WD)
Where DACL =
(Allow access at level GENERIC_ALL for EVERYONE)
When
ISecurityEditor->SetSecurity method called DllHost.exe calls
RegSetKeySecurity API.
After successful call of this method Dropper/Se.exe calls usual
RegOpenKeyExW for HKLM\Software\Microsoft\Windows\CurrentVersion\Policies\System with
Read/Write access flags. Because key security replaced with new values this call is succesful. Next it overwrites the following values:
ConsentPromptBehaviorAdmin
ConsentPromptBehaviorUser
EnableLUA
with 0 and saves previous values to the following keys (they used if malware want to restore previous UAC state - Se.exe "ON" param, see above).
HKCU\Software\Microsoft\icp
HKCU\Software\Microsoft\lps
HKCU\Software\Microsoft\qmd
After this malware restores HKLM\Software\Microsoft\Windows\CurrentVersion\Policies\System key security with
SetSecurityDescriptor(PreviouslySavedValues) call.
ISecurityEditor undocumented Microsoft backdoor interface. Quick C interface definition, ripped partially from Simda binary, unexpected MS symbols (forgotten to strip private info?) and debugging.
Code: Select allEXTERN_C const IID IID_ISecurityEditor;
typedef interface ISecurityEditor ISecurityEditor;
typedef struct ISecurityEditorVtbl
{
BEGIN_INTERFACE
HRESULT(STDMETHODCALLTYPE *QueryInterface)(
__RPC__in ISecurityEditor * This,
/* [in] */ __RPC__in REFIID riid,
/* [annotation][iid_is][out] */
_COM_Outptr_ void **ppvObject);
ULONG(STDMETHODCALLTYPE *AddRef)(
__RPC__in ISecurityEditor * This);
ULONG(STDMETHODCALLTYPE *Release)(
__RPC__in ISecurityEditor * This);
HRESULT(STDMETHODCALLTYPE *GetSecurity)(
__RPC__in ISecurityEditor * This
/* [in] */ LPWSTR pObjectName,
/* [in] */ SE_OBJECT_TYPE ObjectType,
/* [in] */ SECURITY_INFORMATION SecurityInfo,
/* [in][out] */ PSECURITY_DESCRIPTOR *ppSecurityDescriptor
);
HRESULT(STDMETHODCALLTYPE *SetSecurity)(
__RPC__in ISecurityEditor * This
/* [in] */ LPWSTR pObjectName,
/* [in] */ SE_OBJECT_TYPE ObjectType,
/* [in] */ SECURITY_INFORMATION SecurityInfo,
/* [in] */ PSECURITY_DESCRIPTOR SecurityDescriptor
);
END_INTERFACE
} ISecurityEditorVtbl;
interface ISecurityEditor
{
CONST_VTBL struct ISecurityEditorVtbl *lpVtbl;
};
This Simda code is very old. It was created in the end of 2010 and for my big surprise I was unable to find any references to this anywhere.
Solution for UAC bypass - turn it on maximum and think twice before clicking OK, even if UAC window prompt you as Microsoft actions.
Global solution - use normal user instead of default admin.
P.S.
Maybe I will try to reimplement this and try with other objects as seems it can work with more of SE_OBJECT_TYPE.