.Net 反序列化攻擊 101


.Net 反序列化一直是一個很熱門的話題,但是因為背後通常都是 Windows,搭建題目不便的原因,導致 CTF 通常很少出現。 這邊會用一個很簡單的例子,從 .Net 麻瓜的 Hello World 開始介紹。

因為不想用肥肥 CS,因此使用 csc 進行編譯,需要先把 C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0 加到 path

0x1 Hello World

身為一個不熟 C# 的人,凡事從 Hello World 開始

using System;
namespace helloworld{
    class Program{
        static void Main(string[] args){
            Console.WriteLine("Hello World!");
        }
    }
}

編譯

csc /reference:C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF\PresentationFramework.dll;C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF\WindowsBase.dll /t:exe /out:hello.exe hello.cs

可以順利的 Hello World!

0x2 Hello Class

C# 中,Class 的寫法是這樣

using System;
namespace hello_class{
    class Program{
        static void Main(string[] args){
            Meow myMeow = new Meow();
            myMeow.MeowName = "Steven";
            myMeow.Meowww();
        }
    }
    public class Meow{
        public string MeowName{
            get;
            set;
        }
        public void Meowww(){
            Console.WriteLine("Hello " + MeowName + " meow meow!");
        }
    }
}

編譯

csc /reference:C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF\PresentationFramework.dll;C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF\WindowsBase.dll /t:exe /out:hello_class.exe hello_class.cs

0x3 Serialize

如同其他程式語言一樣, C# 也有序列化功能,可以把 Class 的 Public data 存出來

using System;
using System.Xml.Serialization;
using System.IO; 

namespace serial_class{
    class Program{
        static void Main(string[] args){
            Meow myMeow = new Meow();
            myMeow.MeowName = "Steven";
            myMeow.Meowww();

            var ser = new XmlSerializer(typeof(Meow));
            TextWriter writer = new StreamWriter("serial_meow.xml");
            ser.Serialize(writer,myMeow);
            writer.Close();
        }
    }
    public class Meow{
        public string MeowName{
            get;
            set;
        }
        public void Meowww(){
            Console.WriteLine("Hello " + MeowName + " meow meow!");
        }
    }
}

Compile

csc /reference:C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF\PresentationFramework.dll;C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF\WindowsBase.dll /t:exe /out:serial_class.exe serial_class.cs

serial_meow.xml 檔案內容會是這樣

<?xml version="1.0" encoding="utf-8"?>
<Meow xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <MeowName>Steven</MeowName>
</Meow>

先不管 xmlns:xsdxmlns:xsi,其實它就是一個 Class Name (Meow) 包了裡面的 public string MeowName

0x4 Unserialize

using System;
using System.Xml.Serialization;
using System.IO; 
namespace unserial_class{
    class Program{
        static void Main(string[] args){
            var streamReader = new StreamReader("serial_meow.xml");
            var ser = new XmlSerializer(typeof(Meow));
            Meow myMeow = (Meow)ser.Deserialize(streamReader);
            myMeow.Meowww();
        }
    }
    public class Meow{
        public string MeowName{
            get;
            set;
        }
        public void Meowww(){
            Console.WriteLine("Hello " + MeowName + " meow meow!");
        }
    }
}

編譯

csc /reference:C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF\PresentationFramework.dll;C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF\WindowsBase.dll /t:exe /out:unserial_class.exe unserial_class.cs

透過這隻程式,我們可以把 XML 檔案給還原回原本的 Class

0x5 Unserialize 2.0

.Net 中的反序列化,會去 Call set 的 Method,如同下面的程式碼,程式輸出結果會 Print 出 Set Value!!,因此我們只需要掌握某些會 Set Value 的 Class Public data member,就有機會用反序列化做壞事。

using System;
using System.Xml.Serialization;
using System.IO; 
//4
namespace unserial_class{
    class Program{
        static void Main(string[] args){
            var streamReader = new StreamReader("serial_meow.xml");
            var ser = new XmlSerializer(typeof(Meow));
            Meow myMeow = (Meow)ser.Deserialize(streamReader);
            // myMeow.Meowww();
        }
    }
    public class Meow{
        private string _MeowName;
        public string MeowName{
            get { 
                    Console.WriteLine("Get Value!!"); 
                    return _MeowName;
                }
            set {
                    _MeowName = value; 
                    Console.WriteLine("Set Value!!");
                }
        }
        public void Meowww(){
            Console.WriteLine("Hello " + MeowName + " meow meow!");
        }
    }
}

0x6 ObjectDataProvider

ObjectDataProvider 是一個 WPF 的東東,我們只要呼叫了 ObjectDataProvider,它就會自動幫我們去執行 Class 中的 Method

編譯前請確定把 C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF\PresentationFramework.dll 加入 Reference 中

using System;
using System.Windows.Data;

namespace odp{
    class Program{
        static void Main(string[] args){
           ObjectDataProvider odp = new ObjectDataProvider();
           odp.ObjectInstance = new Meow();
           odp.MethodName = "Meowww";
           // but this can't deserialize
        }
    }
    public class Meow{
        public string MeowName{
            get;
            set;
        }
        public void Meowww(){
            Console.WriteLine("Hello meow meow!");
        }
    }
}

程式執行結果會順利的 Print 出 Hello meow meow!,不過 ObjectDataProvider 無法被反序列化 QQ

0x7 ExpandedWrapper Serialize

我們可以借助 ExpandedWrapper 來幫 ObjectDataProvider 進行序列化,未來只需要反序列化這一包,程式就會乖乖去執行我們設定好的 Class Method

使用 ExpandedWrapper 需要確保將 C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF\WindowsBase.dll 加入 Reference

using System;
using System.Windows.Data;
using System.Data.Services.Internal;
using System.Xml.Serialization;
using System.IO;

namespace odp{
    class Program{
        static void Main(string[] args){
           ExpandedWrapper<Meow, ObjectDataProvider> expandedWrapper = new ExpandedWrapper<Meow, ObjectDataProvider>();
           expandedWrapper.ProjectedProperty0 = new ObjectDataProvider();
           expandedWrapper.ProjectedProperty0.ObjectInstance = new Meow();
           expandedWrapper.ProjectedProperty0.MethodName = "Meowww";

            var ser = new XmlSerializer(typeof(ExpandedWrapper<Meow, ObjectDataProvider>));
            TextWriter writer = new StreamWriter("expandedWrapper_serial_meow.xml");
            ser.Serialize(writer,expandedWrapper);
            writer.Close();
        }
    }
    public class Meow{
        public string MeowName{
            get;
            set;
        }
        public void Meowww(){
            Console.WriteLine("Hello meow meow!");
        }
    }
}

0x8 ExpandedWrapper Deserialize

透過以下程式,我們可以順利的幫 ExpandedWrapper 進行反序列化,順便它也會去執行 Meow.Meowww()

using System;
using System.Xml.Serialization;
using System.IO; 
using System.Windows.Data;
using System.Data.Services.Internal;

namespace unserial_class{
    class Program{
        static void Main(string[] args){
            var streamReader = new StreamReader("expandedWrapper_serial_meow.xml");
            var ser = new XmlSerializer(typeof(ExpandedWrapper<Meow, ObjectDataProvider>));
            ser.Deserialize(streamReader);
        }
    }
    public class Meow{
        public string MeowName{
            get;
            set;
        }
        public void Meowww(){
            Console.WriteLine("Hello " + MeowName + " meow meow!");
        }
    }
}

其實到這一步,我們已經可以執行程式裡面的任何 Class 中的 Function 了,也可以找到某些讀寫檔的 Function (Gadget) 來進行跳躍。

0xF Reference

https://github.com/Ivan1ee/NET-Deserialize

,

發表迴響