content-image
ARTICLES | 04 March 2021

ชำแหละ Zerologon (CVE-2020-1472)

author-image

Witsarut Limsuwan

สองสามวันที่ผ่านมานี้หลายคนอาจจะได้ยินเรื่องช่องโหว่ระดับความรุนแรงสูงมาก (CVSS v3 score เต็ม 10 ไม่มีหัก) ของ Windows ที่ชื่อว่า Zerologon กันมาบ้างแล้ว มีผลกระทบกับ Domain Controller รุนแรงถึงขนาดที่ว่า สามารถเข้ายึด active directory และกลายเป็น domain admin ได้แทบจะในทันที

โดยสิ่งที่ได้รับผลกระทบจากช่องโหว่นี้คือ Netlogon Remote Protocol ซึ่งเป็น Remote Procedure Call (RPC) interface ที่ถูกใช้เพื่อ secure ช่องทางการสื่อสารระหว่างเครื่อง server ที่ join-domain กับ Domain Controller (DC) นอกจากนั้น Netlogon ยังถูกใช้ในหลาย ๆ operation ที่มีความสำคัญใน domain มากขนาดขาดไม่ได้เลยทีเดียว

Too Long; don’t read. (TL;DR)

TL;DR

TL;DR

สำหรับบุคคลทั่วไปที่ไม่ได้อยากอ่านละเอียดเชิงลึกของช่องโหว่นี้ สามารถอ่านรายละเอียดคร่าว ๆ ที่ตรงนี้ได้ครับ

ช่องโหว่นี้มีสาเหตุมาจากการเข้ารหัสแบบ AES-128-CFB8 บน Netlogon Remote Protocol มีจุดบกพร่องในการ implement ทำให้ hacker สามารถที่จะโจมตีผ่านช่องโหว่ดังกล่าวและเข้ายึด active directory ได้ทันที ซึ่งมีความรุนแรงมากและกระทบกับ Windows Server ที่เป็น Domain Controller (DC) ตาม version ต่อไปนี้

  • Windows Server 2008 R2 for x64-based Systems Service Pack 1
  • Windows Server 2008 R2 for x64-based Systems Service Pack 1 (Server Core installation)
  • Windows Server 2012
  • Windows Server 2012 (Server Core installation)
  • Windows Server 2012 R2
  • Windows Server 2012 R2 (Server Core installation)
  • Windows Server 2016
  • Windows Server 2016 (Server Core installation)
  • Windows Server 2019
  • Windows Server 2019 (Server Core installation)
  • Windows Server, version 1903 (Server Core installation)
  • Windows Server, version 1909 (Server Core installation)
  • Windows Server, version 2004 (Server Core installation)

บางท่านอาจจะคิดว่าองค์กรมีอุปกรณ์ monitor ที่ detect ช่องโหว่นี้ได้อยู่แล้ว หากโดนโจมตี แต่หารู้ไหมว่า การโจมตีด้วยช่องโหว่นี้เพียงเวลาสั้น ๆ ก็สามารถ replicate ข้อมูลบน active directory ออกมาได้ทั้งหมด ถึงต่อให้ detect พบ แต่ข้อมูลบน active directory ก็อาจจะหลุดไปแล้วก็เป็นได้ เพราะฉะนั้นควรรีบอัพเดท patch โดยทันทีครับ

วิธีการแก้ไขและการตรวจสอบ

ดูรายละเอียด patch ได้ที่:

แต่อย่าลืมทดสอบอัพเดท patch ในเครื่องทดสอบ ก่อนที่จะอัพเดทบน production จริงนะครับ

หรือ admin ท่านใดอยากทราบว่า server ที่ใช้อยู่มีช่องโหว่ไหม สามารถใช้ script ใน ด้านล่าง เพื่อตรวจสอบได้ครับ โดยจะเป็น script ที่ใช้ในการตรวจสอบเท่านั้นไม่ได้มีผลกระทบอะไรกับระบบ เนื่องจาก script ไม่ได้ไปทำการเปลี่ยน computer password ของ Domain Controller ให้เป็นค่าว่าง (empty) แต่อย่างใด:

https://github.com/SecuraBV/CVE-2020-1472

นอกจากนี้ ยังมี security researcher พบว่า Samba version < 4.8 บน linux ก็มีช่องโหว่นี้ด้วยเช่นเดียวกัน (Samba ก็ support Netlogon และค่า IV เป็น 0 คงที่เหมือนกัน): https://twitter.com/wdormann/status/1305908429664419840

จบตรงนี้สำหรับคนที่ไม่อยากอ่านยาว.. แต่สำหรับใครที่อยากเข้าใจช่องโหว่นี้ให้มากขึ้น ก็ตามมาได้เลยครับ บอกเลยว่าไม่ได้เข้าใจยากอย่างที่คิด และมีวิธีการต่าง ๆ ในการหาวิธี bypass security mechanism ต่าง ๆ เพื่อหาทาง compromise Domain Controller ที่น่าสนใจเลยทีเดียว

Image

Image

เริ่มต้นกันด้วย.. Netlogon Remote Protocol คืออะไร?

Netlogon Remote Protocol เป็น Remote Procedure Call (RPC) interface ที่ถูกใช้เพื่อ secure ช่องทางการสื่อสารระหว่างเครื่อง domain member กับ Domain Controller (DC) และเช่นเดียวกันกับ RPC อื่น ๆ ที่มีการใช้งาน dynamic port และสามารถใช้งานผ่าน SMB named pipes ที่ port TCP/445 ได้อีกด้วย

Netlogon เองมีหน้าที่ที่สำคัญใน domain เช่น เป็น protocol ที่ OS ใช้ในการเปลี่ยน computer account password กับ DC เป็นต้น

Domain member ทุกเครื่องจะมี computer account อยู่บน active directory เสมอ และมี password ที่เป็นค่าสุ่มและถูกเปลี่ยนอัตโนมัติทุก ๆ 30 วัน

นอกจากนี้ Netlogon ยังมีหน้าที่อีกมากมายที่สำคัญต่อ domain โดยสามารถดูรายละเอียดได้ที่ protocol specification ของ Microsoft ครับ

ขั้นตอนเริ่มต้นของ Netlogon เป็นอย่างไร?

ก่อนที่จะเจาะลงไปถึงจุดอ่อนที่เป็นช่องโหว่ของ protocol นี้ ขั้นแรกเราจะต้องมาทำความเข้าใจขั้นตอนการทำ session key negotiation และการยืนยันตัวตนของ Netlogon กันซะก่อน สำหรับหลักการในการยืนยันตัวตนของ Netlogon นั้นจะใช้ shared secret (ความลับที่รู้อยู่แล้วของทั้งสองฝ่าย) ในการพิสูจน์ว่า แต่ละฝั่งของการสื่อสารนั้น คือเครื่องที่อยากสื่อสารด้วยจริง ๆ (Mutual authentication) ไม่ใช่ใครก็ไม่รู้เนียนมาคุยด้วย เพื่อล้วงความลับ

ข้างล่างจะเป็นการอธิบายขั้นตอนการทำ session key negotiation และการยืนยันตัวตนของ Netlogon แบบ simplified ครับ

Workflow

Workflow

ขั้นตอนที่ 1 แลกข้อมูลกันก่อน ในขั้นตอนแรกเริ่ม client (เครื่องที่เป็น domain member) จะส่ง challenge ซึ่งเป็นค่าสุ่มมีขนาด 8 bytes ไปหา server และ server ก็จะส่ง challenge ที่ตัวเองสุ่มได้กลับไปหา client

ขั้นตอนที่ 2 แยกกัน generate Session key — จากนั้นทั้งสองฝั่งก็จะนำค่า client challenge, server challenge (ในรูปคือ challenges) และ shared secret (ในรูปคือ secret) ที่ได้มาเข้าฟังก์ชัน \KDF (key derivation function) (เบื้องหลังจริง ๆ คือ HMAC-SHA256) เพื่อสร้าง Session key ขนาด 16 bytes ขึ้นมา

Shared secret คือ computer account password ซึ่งจะถูกจัดเก็บไว้ใน registry HKLM\Security\Policy\Secret\$MACHINE.ACC ที่ฝั่ง client และอีกที่คือ ใน active directory บน Domain Controller

ขั้นตอนที่ 3 แลก credential —เริ่มแรก client จะทำการ encrypt challenge ของตัวเองด้วย session key ที่ generate ขึ้นมาจากขั้นตอนที่ 2 ด้วย cipher AES-128-CFB8(ในรูปคือฟังก์ชัน Encrypt) จะได้ผลลัพธ์ออกมาเป็น client credential และส่งไปหา server

จากนั้นหน้าที่ของ server คือการนำ session key ของตนเอง (แยกกันคำนวณก็จริงแต่ค่าที่ออกมาต้องได้ค่าเดียวกัน) และ client challenge มา generate credential โดยใช้วิธีเดียวกันกับที่ client ทำ และนำค่าที่ได้มาเปรียบเทียบกับ client credential ที่ client ส่งมา (protocol specification section 3.1.4.1 ข้อ 6)

ถ้าไม่ตรงกันฝั่ง server ก็จะ ส่งผลไปบอก client ว่าไม่ถูกต้อง และหยุดการคุยกันแต่เพียงเท่านี้ แต่ถ้าตรงกัน server ใช้ server challenge ในการ generate server credential ของตนเองขึ้นมาและส่งไปให้ client

จากนั้น client จะทำการตรวจสอบโดยใช้วิธีการเดียวกันกับ server หากค่าที่ได้มาถูกต้อง ทั้งสองฝั่งก็จะใช้ session key ที่ตกลงกัน ในการ signed และ sealed (encrypted) packet ที่จะส่งหากันต่อจากนี้

จุดอ่อนที่หัวใจ ของ Netlogon

จากขั้นตอน session key negotiation และยืนยันตัวตนของทั้งสองฝั่งจะเห็นได้ว่าค่าที่สำคัญมาก เลยคือ session key (ซึ่งได้มาจาก shared secret ซึ่งก็คือ computer account password อีกทีหนึ่ง)

Workflow

Workflow

Source: https://www.secura.com/pathtoimg.php?id=2055

ลองจินตนาการว่าตัวเองเป็น hacker แล้วพยายามจะปลอมตัวว่าเป็นเครื่อง server เครื่องหนึ่งที่เป็น domain member (ในรูปคือ Client) เพื่อทำรายการต่าง ๆ บน Netlogon Remote Protocol จะเห็นได้ว่าแทบไม่มีทางเป็นไปได้ ถ้าไม่ได้ทำการ compromise เครื่อง server ดังกล่าวมาก่อน เนื่องจากที่จะต้องรู้ค่า shared secret ในการสร้าง session key ขึ้นมา

แต่ !! จากช่องโหว่ที่ถูกค้นพบนี้ ทำให้เราไม่จำเป็นต้องรู้ shared secret หรือ session key ก็จะสามารถปลอมตัวเป็นเครื่อง server เครื่องใดที่อยู่ใน domain ก็ได้ !! ทำได้ยังไงนั่น มาเริ่มกันเลยครับ..

จุดอ่อนของฉัน อยู่ตรงที่ AES-128-CFB8 ~♪

Workflow

Workflow

Source: https://www.secura.com/pathtoimg.php?id=2055

ในขั้นตอนที่ 3 method ที่ใช้ generate credential คือ method ComputeNetLogonCredential ซึ่งเบื้องหลังก็คือการเอา \challenge มาเข้ารหัสด้วย shared secret โดยใช้ cipher \AES-128 ในโหมด CFB8 (8-bit cipher feedback)

หากลองอ่าน protocol specification ของ Netlogon ที่ section 3.1.4.4.1 จะพบว่ามีเข้ารหัสโดยใช้ Initialization Vector (IV) ที่มีการ fix ค่าไว้เป็น 0 !!

Code

Code

Source: https://docs.microsoft.com/en-us/openspecs/windows%5Fprotocols/ms-nrpc/ff8f970f-3e37-40f7-bd4b-af7336e4792f (section: 3.1.4.4.1)

ซึ่งไม่เป็นไปตาม security best practice ในการใช้งาน IV กับ AES-128-CFB8 เนื่องจากค่า IV ควรจะที่เป็นค่าสุ่มใหม่ทุกครั้งที่มีการเข้ารหัส (NONCE) การที่ IV เป็นค่าที่คาดเดาล่วงหน้าได้นั้นทำให้ ความปลอดภัยในการใช้งาน AES-128-CFB8 นั้นลดลงไป (อ้างอิง NIST SP 800–38A)

Workflow

Workflow

นอกจากนี้ ขั้นตอนที่ server ทำการตรวจสอบ client credential นั้น มีวิธีการ คือ

นำ session key ของตนเอง และ client challenge มา generate credential โดยใช้วิธีเดียวกันกับที่ client ทำ (ใช้ AES-128-CFB8 ที่ IV = 0)

และนำค่าที่ได้มาเปรียบเทียบกับ client credential ที่ client ส่งมา

ถ้าไม่ตรงกันฝั่ง server ก็จะ ส่งผลไปบอก client ว่าไม่ถูกต้อง และหยุดการคุยกันแต่เพียงเท่านี้ แต่ถ้าตรงกัน server จะใช้ server challenge ในการ generate server credential ของตนเองขึ้นมาและส่งไปให้ client

โดยจุดอ่อนตรงนี้เป็นจุดที่สำคัญจุดแรกที่ทำให้ hacker สามารถใช้เทคนิคเดียวกันในการทะลวง security mechanism จุดอื่น ๆ ที่เหลือได้ทั้งหมด จนสามารถ compromise Domain Controller ได้

IV ใน AES-128-CFB8 ถูก fix เป็น 0 ทั้งหมดแล้วยังไง?

ก่อนที่จะดูในกรณีที่ IV ถูก fix ค่าเป็น 0 เรามาดูขั้นตอนการเข้ารหัสแบบ AES-128-CFB8 กันก่อน โดยจะมีขั้นตอนคร่าว ๆ ตามรูปด้านล่าง

block สีส้ม คือ IV

block สีฟ้า คือ plaintext

block สีเขียว คือ output ที่ได้มาจากการ encrypt ด้วย AES

block สีแดง คือ ciphertext ที่เป็นผลลัพธ์จาก mode CFB8

อธิบาย

อธิบาย

Source: https://www.secura.com/pathtoimg.php?id=2055

สำหรับ AES cipher นั้นโอกาสของแต่ละ bit ของ output (ในรูปคือสีเขียว) ที่จะเป็น 0 หรือเป็น 1 นั้น มีค่าเท่ากัน คือ 1/2 ไม่ว่า input หรือ key ที่ใส่เข้ามาจะเป็นค่าอะไรก็ตาม พูดอีกแง่คือ ไม่มี bias ทางสถิติ จึงทำให้ความน่าจะเป็นที่ในแต่ละ bit จะมีค่าเป็น 0 หรือ 1 ออกมาพอ ๆ กัน

และหากใช้สมมติฐานนี้ในการคำนวณว่ามีความเป็นไปได้ (probability) เท่าไหร่ที่ byte แรกของ output จาก AES จะมีค่าเป็น 0 ?

คำตอบก็คือ

(1/2)\*(1/2)\*(1/2)\*(1/2)\*(1/2)\*(1/2)\*(1/2)\*(1/2) = 1/2⁸ =1/256

โดยมาจากโอกาสที่แต่ละ bit จะเป็น 0 ทั้งหมดทั้ง 8 bits

และถ้า IV มีค่าเป็น 0 ทั้งหมด, plaintext มีค่าเป็น 0 ทั้งหมด แถมค่า byte แรกของ output จาก AES ออกมาเป็น 0 อีก เปรียบเสมือนการเรียงตัวกันของดวงอาทิตย์, ดวงจันทร์ และ โลก ตอนเกิดสุริยุปราคา พอดีเป๊ะ

Meme

Meme

จะทำให้เกิดอาการ 0 lock กล่าวคือ ต่อให้เข้ารหัสด้วย AES ไปอีกซักกี่รอบ ผลลัพธ์สุดท้าย (ciphertext สีแดงในรูป) ก็จะออกมาเป็น 0 อยู่ดี ตามรูปด้านล่าง

block สีส้ม คือ IV ซึ่งถูก fix เป็น 0 ทั้งหมด

block สีฟ้า คือ plaintext ซึ่งเป็นค่าที่ client สามารถกำหนดได้และในกรณีนี้ถูก fix เป็น 0 ทั้งหมดเช่นเดียวกัน (ในกรณีนี้คือ client challenge)

block สีเขียว คือ output ที่ได้มาจากการ encrypt ด้วย AES (key ในกรณีนี้คือ session key\)

block สีแดง คือ ciphertext ที่เป็นผลลัพธ์จาก mode CFB8 ซึ่งในกรณีนี้จะถูกใช้เป็น client credential

Code

Code

Source: https://www.secura.com/pathtoimg.php?id=2055

จากการคำนวณโอกาสที่ byte แรกของ output จาก AES เป็น 0 คือ 1 ใน 256 นั้น ทำให้สามารถสรุปได้ว่า..

ถ้า IV มีค่าเป็น 0 ทั้งหมด และ plaintext มีค่าเป็น 0 ทั้งหมดแล้ว จะมีโอกาส 1 ครั้งจาก 256 ครั้ง ที่ ciphertext จะมีค่าเป็น 0 ทั้งหมดโดยไม่จำเป็นต้องสนใจว่าจะใช้ key อะไรในการ encrypt

หรือจะพูดให้ง่ายขึ้นในอีกมุมคือ ถ้าสุ่ม key ในการ encrypt ไปเรื่อย ๆ ภายใต้เงื่อนไขนี้ จะมี 1 ครั้งจาก 256 ครั้ง ที่ ciphertext จะออกมาเป็น 0 ทั้งหมด

พูดมาซะยืดยาว ถึงตอนนี้แล้วยังจำได้กันอยู่ไหมครับว่า key ในการ encrypt เพื่อ generate client credential คือ \session key ที่เราไม่รู้ค่านั้นเอง

และเนื่องจาก computer account จะไม่ถูก lock แม้ว่าจะมีการ login ผิดเกิดขึ้นซ้ำ ๆ และหากส่ง client credentail ผิดไป 1 ครั้ง กระบวนการตั้งแต่การส่ง challenge, สร้าง session key จะต้องเริ่มใหม่ทั้งหมด ทำให้ session key เป็นค่าใหม่ทุกครั้ง

จากการคำนวณและเหตุผลข้างบนทั้งหมด ทำให้สรุปได้ว่า เราสามารถส่ง client challenge และ client credential ที่มีค่าเป็น 0 ทั้งหมด ไปยัง server เรื่อย ๆ จนกว่า server จะบอกว่า client credential ถูกต้องได้ โดยจะมีโอกาสที่ถูกต้อง 1 ครั้ง จากการส่งทั้งหมด 256 ครั้ง (โดยเฉลี่ย) ตามรูป

Source: https://www.secura.com/pathtoimg.php?id=2055

โดยวิธีการโจมตีการเข้ารหัสเพื่อหาจุดอ่อนในลักษณะนี้ที่ hacker สามารถเลือก plaintext ในการ encrypt เพื่อให้ได้ ciphertext ที่เป็นคู่กันออกมา และใช้ประโยชน์จากคู่ plaintext, ciphertext วิเคราะห์หาความสัมพันธ์และหาจุดอ่อนของการเข้ารหัสแบบนี้ มีชื่อเรียกในวงการว่าChosen-plaintext Attack (CPA)

แต่เมื่อ bypass ขั้นตอน session key negotiation และการยืนยันตัวตนได้เรียบร้อยแล้ว ก็จะไปติดอีกขั้นที่ได้พูดถึงไปตอนต้น ๆ คือ ขั้นที่ packet ที่จะส่งหากันหลังจากที่ยืนยันตัวตนเรียบร้อยแล้ว จะถูก sign และ encrypt ด้วย session key อีกทีหนึ่ง (และ cipher ไม่ใช่ AES-128-CFB8) ซึ่งแน่นอนว่าเราไม่รู้ session key จึงทำให้ sign และ encrypt ไม่ได้… เจอทางตันซะแล้วใช่ไหม…

Workflow

Workflow

Workflow

Workflow

ยังครับ ยังไม่ตัน.. มีทางแก้อยู่อีกวิธีหนึ่งคือ ในขั้นตอนที่ client ส่ง client credential ไปหา server นั้น client จะเรียกใช้ method NetrServerAuthenticate3(protocol specificationsection 3.5.4.4.2)ในการส่ง client credential ไปยัง server ซึ่งใน method นี้จะสามารถส่ง NegotiateFlags ไปบอก server เพื่อปฏิเสธการ sign/encrypt ได้ ทำให้หลังจากที่ยืนยันตัวตนเสร็จแล้ว ก็จะไม่มีการ sign/encrypt packet ด้วย session key เกิดขึ้น

Workflow

Workflow

Bypass Authenticator Verification

งั้นเราก็สามารถปิดเกม เรียกใช้งาน method อะไรก็ได้บน Netlogon ได้แล้วซิ?

เดี๋ยวก่อน… ใจเย็น ๆ ถ้าลองไปอ่าน protocol spec ที่ section 3.1.4.5ดูจะพบว่า ในหลาย ๆ method ที่มีความสำคัญ client จะต้องแนบ authenticator ของตัวเอง (NETLOGONAUTHENTICATOR) ไปใน request ด้วยเสมอ

Workflow

Workflow

และหากดูขั้นตอนการตรวจสอบ authenticator ในฝั่ง server ตามรูปด้านล่าง

Workflow

Workflow

Source: https://docs.microsoft.com/en-us/openspecs/windows%5Fprotocols/ms-nrpc/ff8f970f-3e37-40f7-bd4b-af7336e4792f (section: 3.1.4.5)

  1. server นำค่า client credential ที่ได้รับมาจาก client ในขั้นตอนแรก ๆ (ServerStoredCredential) มาบวกกับค่า Timestamp ใน authenticator ที่ client ส่งมา (ClientAuthenticator.Timestamp)
  2. นำค่าที่ได้ไปเข้ารหัสด้วย session key โดยใช้ method ComputeNetLogonCredential (ซึ่งเบื้องหลังก็คือ \AES-128-CFB8 ที่ fix ค่า IV ไว้เป็น 0 ทั้งหมด)
  3. จากนั้นจึงนำค่าที่ได้มาเทียบกับ credential ใน authenticator ที่ client ส่งมา (ClientAuthenticator.Credential) ว่าเท่ากันหรือไม่ ถ้าเท่ากันก็ถือว่า \authenticator ที่ส่งมานั้นถูกต้อง

แล้ว authenticator ในฝั่ง client generate ขึ้นมายังไง?

วิธีในการ generate authenticator ขึ้นมาเป็นไปตามด้านล่าง

Workflow

Workflow

Source: https://docs.microsoft.com/en-us/openspecs/windows%5Fprotocols/ms-nrpc/ff8f970f-3e37-40f7-bd4b-af7336e4792f (section: 3.1.4.5)

จะเห็นได้ว่าค่าที่มีความสำคัญ คือ

  1. ClientAuthenticator.Timestamp — เป็น POSIX Time
  2. ClientAuthenticator.Credential — ซึ่งมาจาก ClientStoreCredential + TimeNow และเข้ารหัสด้วย session key โดยใช้ AES-128-CFB8

ClientStoreCredential ตอนเริ่มแรก จะมีค่าเท่ากับ client credential (ในกรณีนี้คือเป็น 0) และค่าจะถูกเพิ่มขึ้นเรื่อย ๆ ขณะมีการเรียกใช้งาน method กับ server

ซึ่งค่าของ ClientAuthenticator.Timestamp และ ClientAuthenticator.Credential เป็นค่าที่สำคัญที่ server จะใช้ในการตรวจสอบ หากเราบังคับให้ทั้งสองค่าเป็น 0 ทั้งหมดแล้ว ก็จะสามารถ bypass การตรวจสอบ authenticator ได้ เหมือนกับขั้นตอน session key negotiation และยืนยันตัวตนในตอนแรกเริ่ม

กุญแจสำคัญในการ Compromise Domain Controller !!

เมื่อหาวิธี bypass การตรวจสอบ authenticator ได้แล้ว ขั้นตอนต่อไปคือการหา method ที่จะใช้งานเพื่อ compromise Domain Controller ให้ได้ โดย method ที่ได้รับเลือก นั้นก็คือ…

NetrServerPasswordSet2(protocol specificationsection 3.5.4.4.5) — เป็น method ที่ใช้สำหรับเปลี่ยน password ของ computer account ซึ่ง computer account ที่ตกเป็นเป้าหมายก็คือ Domain Controller นั้นเอง

ซึ่ง parameter ที่เราจะต้องใช้ใน method NetrServerPasswordSet2 มีดังนี้

Workflow

Workflow

Source: https://docs.microsoft.com/en-us/openspecs/windows\protocols/ms-nrpc/ff8f970f-3e37-40f7-bd4b-af7336e4792f (section: 3.5.4.4.5)

Parameter ที่สำคัญนอกจาก AccountName, ComputerName และ Authenticator (ที่มีค่าเป็น 0) แล้ว ก็คือ ClearNewPassword

``

และ.. ClearNewPassword เป็นค่าที่ถูก encrypt ด้วย session key โดยใช้ \AES-128-CFB8 อีกเช่นเดียวกัน

ค่าของ ClearNewPassword ก่อนที่จะถูก encrypt นั้นจะมีรูปแบบดังนี้ (protocol specificationsection 2.2.1.3.7)

Workflow

Workflow

Source: https://docs.microsoft.com/en-us/openspecs/windows%5Fprotocols/ms-nrpc/ff8f970f-3e37-40f7-bd4b-af7336e4792f (section: 2.2.1.3.7)

Buffer มีรูปแบบตามรูปด้านล่าง

Source: https://docs.microsoft.com/en-us/openspecs/windows%5Fprotocols/ms-nrpc/ff8f970f-3e37-40f7-bd4b-af7336e4792f (section: 2.2.1.3.7)

และ Length ขนาด 4 bytes เอาไว้ระบุขนาดของ password ใหม่

รวมทั้งหมด ClearNewPassword จะมีขนาดเป็น 512 + 4 = 516 bytes

ซึ่งทั้งค่า Buffer และ Length สามารถเป็น 0 ได้ทั้งหมด และเข้าทางจุดอ่อนของ AES-128-CFB8 พอดี

จากเหตุผลข้างบน เลยส่งผลให้การโจมตีด้วยช่องโหว่นี้ทำให้ computer account password เป็นค่าว่าง (empty) นั่นเอง

Workflow

Workflow

ภาพรวมขั้นตอนการโจมตีทั้งหมด

เมื่อนำขั้นตอนการโจมตีที่อธิบายไปข้างต้นทั้งหมดมารวมกันในภาพเดียวให้เป็นภาพง่าย ๆ ก็จะเป็นไปตามด้านล่าง

Workflow

Workflow

หมายเหตุ การเปลี่ยน password โดยวิธีนี้เป็นการเปลี่ยน password บน active directory เท่านั้น ไม่ได้ไปเปลี่ยนค่าที่ถูกเก็บไว้ที่ registry HKLM\Security\Policy\Secret\$MACHINE.ACC ด้วย ทำให้เครื่องที่ตกเป็นเป้าหมาย ไม่สามารถที่จะ authenticate กับ Domain Controller ได้อีก และแน่นอนหากเครื่องที่ตกเป็นเป้าหมายคือ Domain Controller ก็จะทำให้เครื่องทำงานผิดปกติได้

ซึ่งวิธีการแก้ไขปัญหาข้างต้นทำได้ด้วยการเปลี่ยน computer account password บน active directory ให้กลับไปเป็นค่าเดิม

เปลี่ยน computer account password ของ DC ได้แล้วยังไงต่อ?

Computer account ของ DC นั้น มีสิทธิในการ replicate active directory ผ่าน Domain Replication Service (DRS) protocol ออกมา ซึ่งสามารถทำได้โดยการใช้ Mimikatz: https://adsecurity.org/?p=1729

หรือ secretsdump ของ Impacket: https://github.com/SecureAuthCorp/impacket/blob/master/examples/secretsdump.py

โดยจะได้ hash ของ account ออกมาทั้งหมด รวมถึง hash ของ Domain Administrator ที่สามารถใช้เทคนิค Pass-the-Hash ในการ compromise เครื่อง server ใน domain ต่อไปได้

หรือ

Hash ของ krbtgt account ซึ่งสามารถใช้สร้าง Golden Ticket เพื่อใช้ในการเข้า compromise เครื่อง server ใน domain ได้ทั้งหมด

Workflow

Workflow

PoC script สำหรับโจมตี

ไม่กี่ชั่วโมงหลังจากที่รายละเอียดช่องโหว่นี้ถูกประกาศออกมา ก็มี PoC script สำหรับโจมตีออกมามากมาย เช่น https://github.com/dirkjanm/CVE-2020-1472

พูดถึงทฤษฎีกันมามาก เรามาลองทดสอบใช้ PoC script จริงกันดีกว่า

ตรวจสอบ computer account password ก่อนลอง

ทั้งหมดนี้เป็นการทดสอบบน Domain Controller ใน Lab นะครับ ไม่ได้ทดสอบกับเครื่องชาวบ้านแต่อย่างใด LOL

ก่อนอื่นเรามาดู password ของ computer account ทั้งที่เก็บไว้บน active directory กับใน registry ของเครื่อง กันดีกว่าว่ามีค่าเหมือนกันไหม

cve-2020-1472

cve-2020-1472

NTLM hash จาก active directory (NTDS.dit)

cve-2020-1472

cve-2020-1472

NTLM hash จาก registry (วิธี dump: https://www.ired.team/offensive-security/credential-access-and-credential-dumping/dumping-lsa-secrets#registry)

จะเห็นได้ว่า NTLM hash ของ computer account ทั้งสองค่าเหมือนกันอยู่

ทดสอบใช้ PoC script โจมตี

Clone script มาจาก Github แล้วลองกับ Domain Controller กันเลย

``

cve-2020-1472

cve-2020-1472

เมื่อ exploit สำเร็จโดยใช้ระยะเวลาไม่นาน ก็ใช้ secretsdump replicate ข้อมูลบน active directory ออกมา โดยใช้ computer account (ในตัวอย่างคือ WIN-VE222S1IUPQ$) และ password ที่เป็นค่าว่าง (empty)

cve-2020-1472

cve-2020-1472

NTLM hash จาก active directory

NTLM hash ของ computer account บน active directory เป็นค่าว่าง (empty) ไปแล้ว

แต่หากทดสอบนำ NTLM hash จาก registry ของเครื่อง Domain Controller หลังจากที่ถูกโจมตีสำเร็จแล้ว มาตรวจสอบใหม่ จะพบว่า NTLM hash ไม่ได้เป็นค่าว่าง (empty) เหมือนกับบน active directory ซึ่งถ้าไม่แก้ไขให้กลับไปเหมือนกัน Domain Controller อาจจะมีปัญหาในการทำงานได้

cve-2020-1472

cve-2020-1472

NTLM hash จาก registry

จบไปแล้วสำหรับการชำแหละช่องโหว่ Zerologon ในครั้งนี้ เนื่องจากต้องอาศัยรายละเอียดค่อนข้างเยอะในหลายส่วนด้วยกัน หากมีข้อมูลในส่วนไหนผิดพลาดไปก็สามารถ feedback กลับมาได้นะครับ

“Good engineering involves thinking about how things can be made to work; the security mindset involves thinking about how things can be made to fail.” — Bruce Schneier"

References

https://www.secura.com/blog/zero-logon

https://nakedsecurity.sophos.com/2020/09/17/zerologon-hacking-windows-servers-with-a-bunch-of-zeros/

https://docs.microsoft.com/en-us/openspecs/windows%5Fprotocols/ms-nrpc/ff8f970f-3e37-40f7-bd4b-af7336e4792f

Advertorial

นอกจากช่องโหว่ Zerologon ตัวนี้แล้ว ยังมีช่องโหว่อื่น ๆ อีกมากมายที่ทำให้ active directory มีความเสี่ยง

แล้วจะหาความเสี่ยงเหล่านั้นได้อย่างไร?
หนึ่งในวิธีที่ได้ผลคือการทำ VA/Pentest ซึ่งทีมเรามีความถนัดในเรื่องนี้

หากต้องการคำแนะนำเพิ่มเติม Incognito Lab ยินดีให้คำปรึกษาโดยไม่คิดค่าบริการ

และนอกจาก VA/Pentest แล้ว เรายังมี service อื่น ๆ อีกมากมาย ศึกษาเพิ่มเติมได้จากเอกสารข้างล่างนี้ครับ

IncognitoLab

IncognitoLab

IncognitoLab

IncognitoLab

logologo

INCOGNITO LAB CO., LTD.

38 Soi Petchakasem 30, Petchakasem Road, Pak Khlong Phasi Charoen, Phasi Charoen, Bangkok 10160

©2025 Incognito Lab Co., Ltd. All rights reserved

Terms & Conditions Privacy Policy