LDAP Injection Attack

Datafarm
4 min readAug 23

--

สวัสดีค่ะผู้อ่านทุกท่าน วันนี้จะพาทุกท่านมาทำความรู้จักกับการโจมตี LDAP Injection ค่ะ ซึ่งเป็นช่องโหว่ที่อยู่ใน OWASP Top 10:2021 ในข้อ A03:2021 — Injection เเต่ก่อนที่จะอธิบายในเรื่องนี้เราขอมาทำความรู้จักกับเรื่องของ LDAP กันก่อนค่ะ

ที่มา : https://ldap.com/

LDAP คืออะไร?

LDAP นั้นย่อมาจาก “Lightweight Directory Access Protocol” ซึ่งเป็นโปรโตคอลที่ใช้ในการเข้าถึงและจัดการข้อมูลในรูปแบบของ Directory หรือที่เรียกว่า LDAP Directory โดยส่วนมากถูกใช้ในการจัดเก็บ และจัดการข้อมูลของบุคคล องค์กร และทรัพยากรต่าง ๆ เช่น ที่อยู่อีเมล รายชื่อผู้ใช้ แผนกองค์กร และอื่น ๆ ภายใน Directory

ในหลายบริษัทมักนำ LDAP มาทำหน้าที่เป็นพื้นที่เก็บข้อมูลสำหรับการยืนยันตัวตนผู้ใช้งานหรือเข้าสู่ระบบ สำหรับการจัดการสิทธิ์ และการควบคุมการเข้าถึงทรัพยากรต่าง ๆ ด้วยค่ะ

LDAP Injection Attack คืออะไร?

ที่มา : https://www.techtarget.com/searchsoftwarequality/definition/LDAP-injection

LDAP Injection เป็นการโจมตีที่ใช้การเเทรกคำสั่งอันตรายที่สามารถเเก้ไข LDAP Query โดยที่แอปพลิเคชันไม่กรองพารามิเตอร์อย่างถูกต้อง ทำให้สามารถเข้าถึง LDAP Server หรือดึงข้อมูลที่ละเอียดอ่อนจาก LDAP Directory ได้โดยที่ตนเองนั้นไม่มีสิทธิ์เข้าถึง ซึ่งคล้ายกับการโจมตี SQL Injection

คำศัพท์พื้นฐานที่ใช้ใน LDAP

  • Directory (ไดเรกทอรี): คือโครงสร้างที่ใช้เก็บข้อมูล และข้อมูลขององค์ประกอบต่าง ๆ ในรูปแบบของรายการ (Entry) ภายในรายการแต่ละรายการจะมี Attributes ที่ใช้กำหนดลักษณะเฉพาะของข้อมูล
  • Entry (รายการ): คือหน่วยข้อมูลที่เก็บข้อมูลในรูปแบบของ attributes ที่มีค่าที่เกี่ยวข้องกับข้อมูล Entry นั้น ๆ
  • Attribute (แอททริบิวต์): คือคุณสมบัติ หรือลักษณะเฉพาะของรายการหรือข้อมูลนั้น ๆ ในแต่ละ attribute จะมีชื่อ และค่าที่ถูกจัดเก็บ ตัวอย่างเช่น “cn” สามารถเก็บชื่อรวม (Common Name) ของบุคคล หรือ “mail” สามารถเก็บที่อยู่อีเมลของบุคคล เป็นต้น
  • ObjectClass (ออบเจ็กต์คลาส): เป็น Attribute ใช้กำหนดลักษณะประเภทของวัตถุใน LDAP Directory เช่น “Person” หรือ “Organization” ซึ่งกำหนดคุณสมบัติ และ Attributes ที่เกี่ยวข้อง
  • Distinguished Name (DN): เป็นรหัสที่ระบุองค์ประกอบใน LDAP Directory ในลักษณะเป็นลำดับชั้น ก็คือการเอา RDN (Relative Distinguished Name) ของ Entry ตั้งแต่ root จนถึงตัวมันเองมาต่อกัน เช่น อย่างรูปด้านล่างจะเป็นเเบบนี้
    “ou=people ,ou=location2 ,dc=company ,dc=com”
  • Base DN (Distinguished Name): เป็นระดับเริ่มต้นที่ใช้เป็นจุดเริ่มค้นหาใน LDAP Directory เมื่อค้นหาข้อมูล ใน LDAP Server จะเก็บข้อมูลในลักษณะ subtree อย่างรูปด้านล่าง Base DN จะเป็น “dc=example,dc=com”
ที่มา : https://saixiii.com/what-is-ldap/
  • Filter (ตัวกรอง): เงื่อนไขที่ใช้ในการค้นหาข้อมูลใน LDAP Directory สามารถระบุเงื่อนไขแบบต่าง ๆ เพื่อค้นหาข้อมูลที่ตรงกับเงื่อนไขนั้น เช่น (cn=John) จะหาข้อมูลที่มี Common Name (cn) เป็น “John”
  • Query: เป็นข้อความที่ใช้ในการส่งคำสั่งค้นหาไปยัง LDAP ServerP เพื่อค้นหา และคืนค่าข้อมูลที่ตรงกับเงื่อนไขที่ระบุใน Query

มาดูการใช้คำสั่ง Query LDAP ขั้นพื้นฐานกัน

ใน Search Filter ที่ใช้งานใน LDAP Query นั้นจะต้องเขียนตาม Syntax (ไวยากรณ์) ที่ถูกต้องตามใน RFC 4515 โดยภายในตัวของ Filter นั้นจะประกอบไปด้วย Attribute มากกว่า 1 ตัว เเละจากนั้นนำ Attribute ที่กำหนดมารวมกันได้โดยใช้ตัวดำเนินการเชิงตรรกะ ทั้งหมดออกมาเป็น LDAP Query เพื่อนำไปค้นหาข้อมูลของ Entry

ตัว Search filter ของ LDAP สามารถใช้ตัวดำเนินการเชิงตรรกะเพื่อรวม Attribute เข้าด้วยกันในการค้นหา ตามตารางด้านล่างนี้:

ตัวอย่างการใช้งาน:

(cn=Jonh*) >> ค้นหาทุกรายการที่ common name มีตัวอักษร Jonh นำหน้าอยู่ (เครื่องหมายดอกจัน (*) หมายถึงตัวอักษรอะไรก็ได้)

(!(cn=Jonh*)) >> ค้นหาทุกรายการที่ common name ไม่มีตัวอักษร Jonh นำหน้าอยู่

(&(cn=J*)(cn=*Doe)) >> ใช้ดำเนินการเชิงตรรกะ AND ซึ่งก็คือสัญลักษณ์ “&” เพื่อค้นหา entry ทุกรายการที่ common name มีตัวอักษร J นำหน้าอยู่เเละลงท้ายด้วยคำว่า Doe

(|(cn=Jonh*)(cn=Elisa*)) >> ใช้ดำเนินการเชิงตรรกะ OR ซึ่งก็คือสัญลักษณ์ “|” เพื่อค้นหา entry ทุกรายการที่ common name มีตัวอักษร Jonh หรือ Elisa นำหน้าอยู่

LDAP Injection Attack ทำงานอย่างไร?

ผู้ใช้งานจะส่งคำขอ LDAP Query ไปยัง LDAP Server เพื่อหา/เเก้ไขข้อมูลตัว entry ที่ตรงกับ Filter ที่เจาะจงไว้ในคำขอ หากพบรายการที่ตรงกับ Filter ใน LDAP Query ตัวของ LDAP Server จะส่งคืนข้อมูลของตัว Entry ที่ผู้ใช้งานร้องขอกลับมา ซึ่งจะทำงานคล้าย ๆ กับ SQL injection โดยในช่องโหว่ของ LDAP injection มีสาเหตุที่เกิดจาก แอปพลิเคชันไม่กรองข้อมูลที่รับจากผู้ใช้งานอย่างถูกต้อง ทำให้สามารถอินพุตเข้าไปในโค้ดคำสั่งของ LDAP Query ได้โดยตรง ส่งผลให้สามารถเเก้ไขค่าสตริงของ LDAP Syntax เพื่อใช้ Filter ค้นหาอย่างไม่เหมาะสม

ซึ่งจะทำให้ LDAP Server ทำการดำเนินการค้นหารวมถึงเเก้ไขโครงสร้าง LDAP Directory ต่าง ๆ ที่อาจเป็นอันตรายเเละนอกเหนือการสิทธิ์ที่ได้รับในระบบ

ชนิดของ LDAP Injection Attack

1. Authentication Bypass

ในหน้าที่ใช้เข้าสู่ระบบมักจะมีช่องสำหรับกรอกข้อความอยู่สองช่อง หนึ่งสำหรับชื่อผู้ใช้งาน เเละอีกหนึ่งสำหรับรหัสผ่าน โดยตัวที่อินพุตที่ผู้ใช้งานต้องกรอกคือ USER (Uname) และ PASSWORD (Pwd) เพื่อใช้ยืนยันการมีอยู่ของทั้ง 2 อย่างนี้ในระบบ โดยจะสร้าง Search Filter ที่ใช้งานใน LDAP Query เเละส่งไปยัง LDAP Server ตามด้านล่างนี้

(&(USER=Uname)(PASSWORD=Pwd))

สำหรับผู้ใช้ทั่วไปที่ไม่ประสงค์ร้าย Filter ผลลัพธ์ควรเป็นดังนี้:

(&(USER=johndoe)(PASSWORD=johnspwd))

หากตัว USER เเละ PASSWORD ทั้งคู่นี้เป็นจริง ชื่อผู้ใช้งาน และรหัสผ่านจะมีอยู่ใน LDAP Directory ดังนั้นผู้ใช้งาน จึงสามารถเข้าสู่ระบบได้

เเต่ถ้าเป็นผู้ไม่ประสงค์ดีป้อนชื่อผู้ใช้งานที่มีอยู่ในระบบ เช่น “johndoe” เเละตามด้วย “)(&)” เพื่อทำให้ข้ามการตรวจสอบรหัสผ่านได้สำเร็จ ทำให้เมื่อทราบชื่อผู้ใช้งานแล้ว สตริงใด ๆ ก็สามารถใช้เป็นค่า PASSWORD ได้จากนั้น LDAP Query ต่อไปนี้จะถูกส่งไปยัง LDAP Server ดังนี้ :

(&(USER=johndoe)(&))(PASSWORD=Pwd))

หรืออีกวิธีที่ทำให้ผู้ไม่ประสงค์ดี สร้าง Filter ที่เป็นจริงเสมอ ทำให้สามารถเข้าถึงได้โดยไม่ต้องมีชื่อผู้ใช้หรือรหัสผ่านที่ถูกต้องโดยการใส่ “*)(USER=*))(|(USER=*”

(&(USER=*)(USER=*))(|(USER=*)(PASSWORD=Pwd))

ซึ่งจะอ่านได้เป็น (USER=*) AND (USER=*) ซึ่งเป็นจริงเสมอ กับอีกส่วนที่ไม่ทำงานจะเป็น (USER=*) OR (PASSWORD=Pwd) ซึ่งส่งผลให้ ถ้าหากเราเข้าสู่ระบบสำเร็จเราจะเป็นผู้ใช้งาน ที่เป็นคนเเรกสุดที่อยู่ใน LDAP Directory

2. Information Disclosure

หากแอปพลิเคชันที่มีช่องโหว่ใช้ Filter LDAP สำหรับตรวจสอบปริมาณทรัพยากร โดยการแจ้งให้ผู้ใช้งานทราบว่าทรัพยากรใดมีอยู่ในระบบบ้าง ขอยกตัวอย่างเป็น เว็บไซต์ขายของที่ให้ผู้ใช้งานสามารถมองหาสินค้า1 หรือสินค้า2 ที่ต้องการ และดูว่ามีจำหน่ายหรือไม่ ในสถานการณ์นี้จะสร้าง Search Filter ที่ใช้งานใน LDAP Query ออกมาเป็น:

(|(type=Resource1)(type=Resource2))

ทั้ง Resource1 และ Resource2 แสดงประเภทของทรัพยากรในระบบ Resource1=สินค้า1 และ Resource2=สินค้า2 เพื่อแสดงสินค้า1 และสินค้า2 ทั้งหมดที่มีจำหน่ายในระบบ ถ้าผู้ไม่ประสงค์ดีต้องการรู้รายชื่อผู้ใช้งานทั้งหมดสามารถทำได้ โดยการใส่ “)(uid=*)” เข้าไปใน Resource1=สินค้า1 ซึ่งจะได้ Search filter ที่ใช้งานใน LDAP Query ออกมาเป็น:

(|(type=สินค้า1)(uid=*))(type=สินค้า2))

จากนั้น LDAP Server จะแสดงสินค้า1 เเละ Object ผู้ใช้งาน (uid) ทั้งหมดในระบบ

3.BLIND LDAP Injections

ในการใส่โค้ดที่ใส่เข้าไปใน Filter LDAP อาจจะทำให้แอปพลิเคชันสร้างการตอบสนองอื่น ๆ ออกมาซึ่งเเตกต่างจาก 2 ข้อเเรกที่จะเเสดงข้อมูลที่เราต้องการอย่างชัดเจน อย่างเช่นไม่สามารถเห็นความแตกต่างของการแสดงผลที่หน้าเว็บไซต์ได้อย่างชัดเจน แต่เราจะสามารถเห็นความแตกต่างก็ต่อเมื่ออินพุตที่เราพยายาม Inject เข้าไป ตรงตามเงื่อนไขที่เราตั้งไว้ ผลลัพธ์จริงหรือผลลัพธ์เท็จ(true/false) ผู้ไม่ประสงค์ดีสามารถสังเกตเเละใช้ประโยชน์จากพฤติกรรมนี้ เพื่อรับคำตอบสำหรับคำถามที่จริงหรือเท็จจาก LDAP Server ได้ เราเรียกเทคนิคเหล่านี้ว่า Blind Attacks แม้ว่าการโจมตีแบบ Blind LDAP Injection ผู้ไม่ประสงค์ดีใช้การแทรก LDAP แบบ BLIND เพื่อรับข้อมูลที่ละเอียดอ่อนจาก LDAP Directory ได้

3.1 AND Blind LDAP Injection

ยกตัวอย่างคร่าว ๆ ที่ใช้ AND Blind LDAP Injection

ลองนึกภาพร้านค้าออนไลน์ที่สามารถเเสดงรายการสินค้า ทั้งหมดจาก LDAP Directory ซึ่งจะได้ Search filter ที่ใช้งานใน LDAP Query ออกมาเป็น:

(&(objectClass=ชนิดสินค้า)(type=ชื่อสินค้า))

สินค้าที่มีอยู่ จะแสดงผลออกมาในหน้าแอปพลิเคชันให้ผู้ใช้เห็นรูปหรือไม่ก็รายการสินค้า หากไม่พบสินค้าที่ระบุไว้ในระบบเลยผู้ใช้งานจะไม่เห็นรายการใด ๆ ในหน้าเเอป นี่คือที่มาของ Blind LDAP Injection ลองเเทรก
“*)objectClass=*))(&(objectClass=void”
ลงในช่องกรอกชนิดสินค้า ซึ่งจะได้ Search filter ที่ใช้งานใน LDAP Query ออกมาเป็น:

(&(objectClass=*)(objectClass=*))(&(objectClass=void)(type=ชื่อสินค้า))

ซึ่งจะทำให้ตัว LDAP Server จะทำงานเเค่คำสั่ง
“(&(objectClass=*)(objectClass=*))”
อย่างเดียว คือชื่อสินค้าทุกชนิดจะขึ้นในหน้าแอปพลิเคชัน เพราะ objectClass=* นี้จะ Filter ส่งสินค้าทุกอย่างที่มีใน objectClass (ชนิดสินค้า) มาซึ่งเราจะขอกำหนดให้การตอบสนองหน้าแอปพลิเคชันเมื่อชื่อสินค้าทุกชนิดจะขึ้นในหน้าแอปพลิเคชันนั้น คือ true (จริง) เเละในขณะที่การตอบสนองหน้าแอปพลิเคชันไม่ขึ้นสินค้าใด ๆ เป็น false (เท็จ)

ทีนี้ผู้ไม่ประสงค์ดีก็จะมีตัวเลือกในการใช้เทคนิค Blind Injection อีกหลาย ๆ เเบบเพื่อใช้ในการหาข้อมูลในระบบ อย่างเช่นตัวอย่างด้านล่างนี้

(&(objectClass=*)(objectClass=users))(&(objectClass=foo)(type=ชื่อสินค้า))
(&(objectClass=*)(objectClass=Resources))(&(objectClass=foo)(type=ชื่อสินค้า))

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

3.2 OR Blind LDAP Injection

ตัวอย่างในการ OR Blind LDAP Injection :

(|(objectClass=void)(objectClass=void))(&(objectClass=void)(type=ชื่อสินค้า))

ตัว LDAP Query ตัวนี้จะไม่มีชื่อสินค้าอะไรตอบกลับมาถ้าหากเป็นเท็จ หรือถ้าหากจริงก็จะยังขึ้นชื่อสินค้าอยู่ สามารถลองใช้ในการหาข้อมูลในระบบ อย่างเช่นตัวอย่างด้านล่างนี้

(|(objectClass=void)(objectClass=users))(&(objectClass=void)(type=ชื่อสินค้า))
(|(objectClass=void)(objectClass=Resources))(&(objectClass=void)(type=ชื่อสินค้า))

ขอเเนะนำ Payload ต่าง ๆ ของสำหรับ LDAP Injection ใน HackTrick : https://book.hacktricks.xyz/pentesting-web/ldap-injection เพื่อนำไปใช้เป็นตัวอย่างในการศึกษาเพิ่มเติม

สุดท้ายนี้ก็หวังว่าผู้อ่านทุกคนจะได้ความรู้เรื่อง LDAP Injection Attack กันไปบ้างไม่มากก็น้อย ขอขอบคุณผู้อ่านทุกคนที่เข้ามาอ่านบทความนี้จนจบด้วยนะคะ

--

--