guest@websec: ~/websec/14-deserialization-and-xxe/th — zsh — 100×40 เขียนโดย SaKKo ENTH โค้ด:

guest@websec ~ % man 14-deserialization-and-xxe

14 · Deserialization และ XXE

รูปแบบข้อมูลบางแบบสร้าง object อะไรก็ได้ อ่านไฟล์ได้ หรือขยายเป็นหลายกิกะไบต์ ถ้า parse จากคนแปลกหน้า input จะเป็นคนกำหนดว่าเซิร์ฟเวอร์ทำอะไร

14.1 Deserialization ที่ไม่ปลอดภัย

JSON สร้างได้แค่ข้อมูลธรรมดา แต่ Marshal ของ Ruby และ YAML ที่มีแท็ก object สร้าง class อะไรก็ได้

ผู้โจมตีจึงเลือกได้ว่าจะสร้าง object อะไร ร้อย class ธรรมดาไม่กี่ตัวเข้าด้วยกัน ก็รันโค้ดได้จาก request เดียว

Rails โดนเรื่องนี้ในปี 2013: POST เดียวยึดแอป Rails ตัวไหนบนอินเทอร์เน็ตก็ได้
sim: การโหลดเอกสาร YAMLจำลองพฤติกรรมของ Psych ด้วยการจับรูปแบบ

YAML.unsafe_load

YAML.load (Psych 4+, Ruby 3.1+)

JSON.parse

วิธีป้องกัน:

  • ใช้ JSON กับทุกอย่างที่มาจากภายนอก
  • ต้องรับ YAML จากผู้ใช้? ใช้ YAML.safe_load
  • ห้าม Marshal.load ข้อมูลที่ไม่น่าเชื่อถือ
Rails สมัยใหม่ปลอดภัยโดยค่าเริ่มต้น: คุกกี้แบบ JSON ไม่ parse XML params และ YAML แบบปลอดภัย ตรวจแอปเก่า ว่ามี cookie serializer แบบ :marshal หรือ Marshal.load ไหม
# safe by default on Ruby 3.1+ (Psych 4)
YAML.load(user_yaml)                                        # plain types only
YAML.safe_load(user_yaml, permitted_classes: [Date, Symbol])
JSON.parse(user_json)

YAML.unsafe_load(user_yaml)        # arbitrary objects
Marshal.load(Base64.decode64(params[:state]))   # RCE

# config/initializers/cookies_serializer.rb (older apps: check this!)
Rails.application.config.action_dispatch.cookies_serializer = :json
// JS: JSON.parse is data-only. Danger comes from libraries that revive objects
JSON.parse(body);                                   // plain data
require("node-serialize").unserialize(body);        // has executed functions (CVE-2017-5941)
yaml.load(text)                                     // js-yaml 3.x: can build functions (4.x is safe)

14.2 XML External Entities (XXE)

XML ชี้ไปยังไฟล์ภายนอกได้ parser ที่ไม่ระวังจะอ่าน /etc/passwd แล้วส่งกลับมา หรือขยายไฟล์ 1 KB เป็นหลายกิกะไบต์

XML ซ่อนอยู่ใน SAML, RSS, SVG และไฟล์ Office

sim: billion laughsentity ซ้อนกันระเบิดออกได้อย่างไร

Nokogiri ปลอดภัยโดยค่าเริ่มต้น แค่อย่าส่ง noent หรือ dtdload
doc = Nokogiri::XML(upload.read)                 # safe defaults
doc = Nokogiri::XML(upload.read) { |c| c.strict.nonet }

Nokogiri::XML(xml) { |c| c.noent.dtdload }        # enables XXE
Nokogiri::XML(xml, nil, nil, Nokogiri::XML::ParseOptions::NOENT)