ใน OWASP Top 10 มีความเสี่ยงหนึ่งที่ถูกเพิ่มเข้ามานั่นคือ A8:2017-Insecure Deserializationซึ่งเป็นช่องโหว่ที่ไม่พบมากนัก แต่ก็ถือว่าเป็นช่องโหว่อีกช่องโหว่หนึ่งที่รุนแรงมากเช่นกัน เรามาดูกันดีกว่าว่ามันคืออะไรครับ

PHP Object 

จาก Class จะเห็นถึงการสร้าง PHP Object จาก class นะครับ และมีการเรียกใช้ฟังก์ชั่น PrintVariable() จาก class ที่ถูกสร้างมา ทีนี้ Class นั้นสามารถมี function ที่เรียกว่า Magic function ได้ โดย magic function ดังกล่าวจะขึ้นต้นด้วย “__” เช่น __construct, __destruct, __toString, __sleep, __wakeup และอื่นๆ

โดยแต่ละ magic function นั้นจะถูกใช้งานแตกต่างกัน

  • __construct จะถูกใช้เมื่อ object ถูกสร้าง (constructor)
  • __destruct จะถูกใช้เมื่อ object ถูกทำลาย (destructor)
  • __toString จะถูกใช้เมื่อ object ถูกใช้ไปเป็น string

ยกตัวอย่าง magic function

ผลลัพธ์คือ

จะเห็นว่า __construct, __destruct และ __toString. จะทำงานในช่วงเวลาที่แตกต่างกัน (event) ทีนี้มันเกี่ยวอะไรกับ PHP Object Serialization มาดูกัน

PHP Object Serialization

Serialization คือวิธีการในการที่เราจะ save object ที่เราสร้างขึ้นแล้วเก็บไปใช้ต่อได้ โดยการจะทำดังกล่าวจะต้องเรียกใช้ function “serialize” โดยผลลัพธ์ที่ return กลับมาจาก function ดังกล่าวจะเป็นลักษณะ string ซึ่งอยู่ในลักษณะที่เป็น serialize object และหากเราต้องการนำกลับมาให้อยู่ในรูปแบบเดิมก็ต้องใช้ function “unserialize” นั่นเอง

ผลลัพธ์คือ

จะเห็นว่าจาก object ถูกแปลเปลี่ยนกลายเป็น O:4:”User”:2:{s:3:”age”;i:20;s:4:”name”;s:4:”John”;}

ทีนี้หากต้องการจะเอา serialize object กลับมาใช้จะเขียนเป็น

ผลลัพธ์คือ

***  Magic number ของ Serialize object คือ “ac ed” (hex) ครับ จากนั้นจะต่อด้วย Serialization protocol version “00 05” แล้วตามด้วยประเภทของ object ใน serialize object 

Serialization magic functions

ทีนี้อย่างที่เราทราบกันว่า constructor (__construct) และ destructor (__destruct) จะถูกเรียกใช้งานเมื่อ object ถูก created และ destroyed, และยังมี magic functions อีกมากมายที่จะถูกเรียกใช้เมื่อมีการถูกทำ serialized และ unserialized:

  • __sleep magic method ถูกใช้เมื่อ object ถูกทำ serialized โดย __sleep จะ return กลับด้วย array ของชื่อตัวแปลที่ถูก serialize
  • __wakeup magic method ถูกใช้เมื่อทำ deserialized (หรือก็คือเรียกใช้ function unserialize)

ทดสอบใช้งาน magic function เมื่อทำ serialization

ผลลัพธ์คือ

PHP Object Injection

หลังที่เราเข้าใจ serialization และ unserialization แล้ว ทีนี้เรามาดูตัวอย่างการ exploit กันบ้าง โดยคราวนี้จะยกตัวอย่าง php code ที่จะเก็บ log ไว้ในไฟล์ชั่วคราว นั่นหมายความว่าตอนทำ object จะเรียก __wakeup function ขึ้นมา แล้วจากนั้นจะทำการสร้างไฟล์ด้วย function ดังกล่าว  และเมื่อทำการ destroy object ก็จะเรียกใช้งาน __destruct เพื่อลบไฟล์ที่เคยเป็นไฟล์ชั่วคราวมาก่อนนั่นเอง

(test04-1.php)

เรียกใช้งาน test04-1.php (test04-2.php)

ทีนี้ลองมาใช้ในรูปแบบของ serialization กันบ้าง (test04-3.php)
ทีนี้หากเรารันโดย input เป็น valid serialize data จะได้ผลลัพธ์ตามด้านล่าง

แต่ถ้าหากเราเปลี่ยน object ที่ส่งไปให้ไปเป็น LogFile Object ล่ะจะเกิดอะไรขึ้น โดยเราจะเริ่มจากการสร้าง serialize object ที่ชื่อว่า LogFile เสียก่อน โดยการเขียน php เป็น

ผลลัพธ์ที่ได้คือ

ทีนี้เราย้อนกลับไป input test04-3.php ให้เป็น O:7:”LogFile”:1:{s:8:”filename”;s:9:”.htaccess”;}

จะพบว่า file .htaccess ถูกลบทิ้ง เพราะเนื่องด้วยตอนที่ __destruct function ถูกเรียก(เมื่อ object ถูกทำลาย) เพราะเรากำหนดค่าของ filename ผ่าน serialize object ที่เราสร้างขึ้นมานั่นเอง

injection points ที่มักพบได้

อย่างที่เห็นเราจะทำการ inject object ใดๆได้ จำเป็นต้องทราบของ magic function เหล่านั้นเสียก่อนว่า class นั้นๆกำหนดไว้อย่างไร ซึ่งมันมีความเป็นไปได้ที่จะ inject ได้ในหลายๆ magic function

วิธีการแก้ไข

เปลี่ยนจากใช้ “unserialize” function กับข้อมูลที่ user input เข้ามา ไปใช้ “json_decode”แทน

ตัวอย่าง Application ที่มีช่องโหว่ PHP Object Serialization

Source:: SecurityCafe