# Using dotnetfile to get a Sunburst timeline for intelligence gathering **[r136a1.info/2022/06/18/using-dotnetfile-to-get-a-sunburst-timeline-for-intelligence-gathering/](https://r136a1.info/2022/06/18/using-dotnetfile-to-get-a-sunburst-timeline-for-intelligence-gathering/)** #### Jun 18, 2022 • tool, malware You may have heard of dotnetfile, a library to extract header information from .NET assemblies. Basically, these files are made of the common language runtime ( CLR ) data located in the .NET header and the actual byte code, both “encapsulated” in a PE file. Compared to the PE header of an unmanaged native file, the CLR header contains much more runtime information. Some of this data can be useful for static malware detection, threat hunting and intelligence gathering as I’ll show in this blog post. We’ll take a look at a part of the SolarWinds incident, the malware known as Sunburst. More precisely, we’ll create a timeline of the legitimate and backdoored Orion IT management software DLLs named SolarWinds.Orion.Core.BusinessLayer.dll with the help of dotnetfile . You’ll see how easy it is to get an overview of the this part of the attack with just a few lines of code. One of the characteristics of the Sunburst backdoor is the usage of various unmanaged functions. .NET offers a mechanism called P/Invoke that let’s you use unmanaged Windows API functions in your managed code. The information which functions are used can be found in the CLR metadata table named ImplMap. We can easily extract this data from a .NET assembly with the help of dotnetfile as we’ll see. ## Create a Sunburst timeline based on unmanaged backdoor functions #### As initially described, the developers of Sunburst used unmanaged functions in their backdoor code. This list of functions be seen with a CLR header viewer like the one built into dnSpy: To extract the list of functions, we can use the following example script from the dotnetfile documentation: ``` from dotnetfile import DotNetPE dotnet_file = DotNetPE('/Users//my_dotnet_assembly.exe') if dotnet_file.metadata_table_exists('ImplMap'): unmanaged_functions = dotnet_file.ImplMap.get_unmanaged_functions() for unmanaged_function in unmanaged_functions: print(f'{unmanaged_function}') Result: CLSIDFromString CloseHandle AdjustTokenPrivileges LookupPrivilegeValueW GetCurrentProcess OpenProcessToken InitiateSystemShutdownExW In comparison, the legitimate versions of this DLL do not use Windows API functions or only CLSIDFromString as introduced in Orion version 2015.1 . With this knowledge, we can create a script that runs on all copies of SolarWinds.Orion.Core.BusinessLayer.dll that we can get (e.g. from Virustotal) to show which versions have been backdoored. Additionally to the list of unmanaged functions retrieved via ImplMap.get_unmanaged_functions, we get the assembly version information of each file via Assembly.get_assembly_version_information. At last, we get the compilation timestamps with pefile which is easy as dotnetfile is build on top of it. The timestamps are used to sort the data in ascending order to see when the backdoor was added and removed. Example script: ``` ----- ``` import sys import lief from dotnetfile import DotNetPE from datetime import datetime from hashlib import sha256 from distutils.version import LooseVersion from typing import List, Dict lief.logging.disable() def deduplicate(data_list: List[Dict]) -> List[Dict]: result = [] for data in data_list: # Add file info if version not in the list if not any(i['Version'] == data['Version'] for i in result): result.append(data) # Overwrite file info element if already in list but file is signed + valid (preferable) elif any(i['Version'] == data['Version'] for i in result) and \ data['Signature'] == 'OK': for index, item in enumerate(result): if item['Version'] == data['Version']: result[index] = data return result def get_files_with_infos(dir_path: str) -> List: file_infos = [] for root, _, files in os.walk(dir_path): for file in files: file_absolute_path = os.path.join(root, file) dotnet_file = DotNetPE(file_absolute_path) metadata_tables = dotnet_file.existent_metadata_tables() entry = {} # Get assembly version information if 'Assembly' in metadata_tables: assembly_version_info = dotnet_file.Assembly.get_assembly_version_information() version_info = f'{assembly_version_info.MajorVersion}.{assembly_version_info.MinorVersion}.' \ f'{assembly_version_info.BuildNumber}.{assembly_version_info.RevisionNumber}' entry['Version'] = version_info # Get unmanaged functions if 'ImplMap' in metadata_tables: unmanaged_functions = '|'.join(dotnet_file.ImplMap.get_unmanaged_functions()) entry['Unmanaged_functions'] = unmanaged_functions # Get compilation timestamp comp_time_stamp = datetime.fromtimestamp(dotnet_file.FILE_HEADER.TimeDateStamp).strftime( '%Y-%m-%d %H:%M:%S') entry['Timestamp'] = comp_time_stamp # Get signature information pe = lief.parse(file_absolute_path) entry['Signature'] = str(pe.verify_signature()).replace('VERIFICATION_FLAGS.', '') # Get SHA-256 hash with open(file_absolute_path, 'rb') as f: entry['Hash'] = sha256(f.read()).hexdigest() file_infos.append(entry) # Deduplicate and take valid signed file if available. For the rest (invalid/bad/... signature), we # don't care result = deduplicate(file_infos) return result def print_information_ascending(dir_path: str) -> None: file_infos = get_files_with_infos(dir_path) file_infos_sorted = sorted(file_infos, key=lambda x: LooseVersion(x['Timestamp'])) ``` ----- ``` output = ', '.join([': '.join(i) for i in file_info.items()]) print(output) if __name__ == "__main__": print_information_ascending(sys.argv[1]) #### Result: ``` ----- ``` a033d513a3c0e0d0199f06ea4124ab652d5698cecdd276fdb4f4abff6e3602f2 Version: 2011.2.5.2234, Timestamp: 2011-11-04 18:07:31, Signature: NO_SIGNATURE, Hash: 14e799bbdd6517411b41043802a45c85316dc1cc5c61b0f54b043079ec14112b Version: 2012.1.12.2305, Timestamp: 2012-07-23 13:12:23, Signature: NO_SIGNATURE, Hash: 99cb98b81bca424e109a4c087144fceffdb6e447877fc473ac5be1ea78e55fd9 Version: 2012.1.5.2202, Timestamp: 2012-09-24 16:48:03, Signature: NO_SIGNATURE, Hash: ad240c7d94308277b241fa060f96f409ecb657a59e639e8f2e79431eb99b9352 Version: 2012.2.13.2381, Timestamp: 2013-01-15 09:40:08, Signature: NO_SIGNATURE, Hash: acced46ef306939821b0b87671b50a9e93e8eb89c79ba0b81d105ef069d67e21 Version: 2013.2.3.684, Timestamp: 2013-08-20 19:12:32, Signature: OK, Hash: 72f63760a0bd95681d8c78c881e07870b910899c70b52e0e2827317f378773df Version: 2014.1.1.872, Timestamp: 2013-11-17 03:18:43, Signature: NO_SIGNATURE, Hash: 051e831eaf5bacf840ef6e2af369d6b4b4cd32abd3e10cb1ac80d66e0bb38775 Version: 2013.2.12.2040, Timestamp: 2013-12-04 12:41:57, Signature: NO_SIGNATURE, Hash: 218b25e0507f24e1ab9e231c93d84535d19526241d489985c2770919747f2257 Version: 2014.2.1.1111, Timestamp: 2014-04-08 03:15:00, Signature: OK, Hash: 8d11616c14afc5b2c1b3ee9ee6d46a20cdae31b25e0cd7fbc374b5517b264dd2 Version: 2014.2.11.1229, Timestamp: 2014-08-06 16:48:31, Signature: NO_SIGNATURE, Hash: dffcc5d7e3ec31a745d59a7f4cd5da1df58ead2d21f57aa04c0b8066f85e4c6a Version: 2015.1.25300.8197, Unmanaged_functions: CLSIDFromString, Timestamp: 2015-05-27 12:36:44, Signature: NO_SIGNATURE, Hash: ae95f1b751bf47a83f106e9c019a0051239234f95920581b3f7c8debdc32a5d6 Version: 2015.1.35100.9209, Unmanaged_functions: CLSIDFromString, Timestamp: 2015-12-17 12:51:37, Signature: NO_SIGNATURE, Hash: d84c2167b03db3760bcf7a76b84534f50910f72a53bc1f5cefcd72784ff75a58 Version: 2016.1.5300.1028, Unmanaged_functions: CLSIDFromString, Timestamp: 2016-05-27 20:04:52, Signature: OK, Hash: 3b4b1d5ebb83fd4d505e0b75673027e80f98861b92b35e0adcd21e2b48ced2d9 Version: 2017.1.100.1628, Unmanaged_functions: CLSIDFromString, Timestamp: 2017-01-26 17:12:52, Signature: NO_SIGNATURE, Hash: 6112ba344a40bc1942ef0b593950542fcc7f67f7ccf1e5274e56e34735efed1b Version: 2017.1.5300.1698, Unmanaged_functions: CLSIDFromString, Timestamp: 2017-02-21 14:53:54, Signature: NO_SIGNATURE, Hash: f33c1cb46ad1c82d99f3e92b40e8994aa2d6ec116e9846c131bfcd15de8fa52c Version: 2017.3.5200.1780, Unmanaged_functions: CLSIDFromString, Timestamp: 2017-08-18 00:46:52, Signature: OK, Hash: 1e229359698c276b2398bfffaa4fb809919e4aaf1c9007d7670866159ecf9ad1 Version: 2018.2.5200.5660, Unmanaged_functions: CLSIDFromString, Timestamp: 2018-08-14 09:52:18, Signature: OK, Hash: 5e4276dc1c9e1e5ef02e75972c59212806dc6a3d13cd2ccafd26af14cb12289b Version: 2018.2.5200.5675, Unmanaged_functions: CLSIDFromString, Timestamp: 2018-09-25 08:12:02, Signature: NO_SIGNATURE, Hash: f707ba597c299f503d425867152f6a039b95a401dfa1a6cba8654b65adab78ba Version: 2018.4.5200.10541, Unmanaged_functions: CLSIDFromString, Timestamp: 2018-11-07 21:05:48, Signature: OK, Hash: 6b295fd9a1c87263613a0d7f23c6c0ece010a038dcce1dd112888bfaff22099e Version: 2019.2.5200.5206, Unmanaged_functions: CLSIDFromString, Timestamp: 2019-05-18 11:09:22, Signature: OK, Hash: 86901758745e39d3b39bf1373a34fc475e29b3cc418059b54f0ded6bdd5fda01 Version: 2019.4.5200.8890, Unmanaged_functions: CLSIDFromString, Timestamp: 2019-10-10 15:26:39, Signature: OK, Hash: d3c6785e18fba3749fb785bc313cf8346182f532c59172b69adfb31b96a5d0af Version: 2019.4.5200.8950, Unmanaged_functions: CLSIDFromString, Timestamp: 2019-11-11 23:34:28, Signature: OK, Hash: 9bee4af53a8cdd7ecabe5d0c77b6011abe887ac516a5a22ad51a058830403690 Version: 2019.4.5200.8996, Unmanaged_functions: CLSIDFromString, Timestamp: 2019-12-09 18:12:09, Signature: OK, Hash: bb86f66d11592e3312cd03423b754f7337aeebba9204f54b745ed3821de6252d Version: 2019.4.5200.9001, Unmanaged_functions: CLSIDFromString, Timestamp: 2020-01-03 16:22:18, Signature: OK, Hash: ae6694fd12679891d95b427444466f186bcdcc79bc0627b590e0cb40de1928ad Version: 2019.4.5200.9045, Unmanaged_functions: CLSIDFromString, Timestamp: 2020-01-24 12:24:39, Signature: OK, Hash: 9d6285db647e7eeabdb85b409fad61467de1655098fec2e25aeb7770299e9fee Version: 2019.4.5200.9073, Unmanaged_functions: CLSIDFromString|CloseHandle|AdjustTokenPrivileges|LookupPrivilegeValueW|GetCurrentProcess|OpenProcessToken|InitiateSystemShutdownExW Timestamp: 2020-03-17 14:08:19, Signature: OK, Hash: db9e63337dacf0c0f1baa06145fd5f1007002c63124f99180f520ac11d551420 Version: 2019.4.5200.9078, Unmanaged_functions: CLSIDFromString|CloseHandle|AdjustTokenPrivileges|LookupPrivilegeValueW|GetCurrentProcess|OpenProcessToken|InitiateSystemShutdownExW Timestamp: 2020-03-19 10:32:21, Signature: OK, Hash: 0f5d7e6dfdd62c83eb096ba193b5ae394001bac036745495674156ead6557589 Version: 2020.2.100.12219, Unmanaged_functions: CLSIDFromString|CloseHandle|AdjustTokenPrivileges|LookupPrivilegeValueW|GetCurrentProcess|OpenProcessToken|InitiateSystemShutdownExW Timestamp: 2020-03-24 04:00:16, Signature: OK, Hash: dab758bf98d9b36fa057a66cd0284737abf89857b73ca89280267ee7caf62f3b Version: 2019.4.5200.9083, Unmanaged_functions: CLSIDFromString|CloseHandle|AdjustTokenPrivileges|LookupPrivilegeValueW|GetCurrentProcess|OpenProcessToken|InitiateSystemShutdownExW Timestamp: 2020-03-24 09:52:34, Signature: OK, Hash: 32519b85c0b422e4656de6e6c41878e95fd95026267daab4215ee59c107d6c77 Version: 2020.2.100.12299, Unmanaged_functions: CLSIDFromString|CloseHandle|AdjustTokenPrivileges|LookupPrivilegeValueW|GetCurrentProcess|OpenProcessToken|InitiateSystemShutdownExW Timestamp: 2020-03-25 20:03:48, Signature: OK, Hash: abe22cf0d78836c3ea072daeaf4c5eeaf9c29b6feb597741651979fc8fbd2417 Version: 2020.2.100.12367, Unmanaged_functions: CLSIDFromString|CloseHandle|AdjustTokenPrivileges|LookupPrivilegeValueW|GetCurrentProcess|OpenProcessToken|InitiateSystemShutdownExW Timestamp: 2020-04-20 10:51:43, Signature: OK, Hash: 2ade1ac8911ad6a23498230a5e119516db47f6e76687f804e2512cc9bcfda2b0 Version: 2020.2.5200.12394, Unmanaged_functions: CLSIDFromString|CloseHandle|AdjustTokenPrivileges|LookupPrivilegeValueW|GetCurrentProcess|OpenProcessToken|InitiateSystemShutdownExW Timestamp: 2020-04-21 16:53:33, Signature: OK, Hash: 019085a76ba7126fff22770d71bd901c325fc68ac55aa743327984e89f4b0134 Version: 2020.2.5300.12432, Unmanaged_functions: CLSIDFromString|CloseHandle|AdjustTokenPrivileges|LookupPrivilegeValueW|GetCurrentProcess|OpenProcessToken|InitiateSystemShutdownExW Timestamp: 2020-05-11 23:32:40, Signature: OK, Hash: ce77d116a074dab7a22a0fd4f2c1ab475f16eec42e1ded3c0b0aa8211fe858d6 Version: 2020.4.100.910, Unmanaged_functions: CLSIDFromString|CloseHandle|AdjustTokenPrivileges|LookupPrivilegeValueW|GetCurrentProcess|OpenProcessToken|InitiateSystemShutdownExW Timestamp: 2020-05-30 11:07:55, Signature: OK, Hash: fcbf4463ffe1f1d3152d65e3b0918d5229997f7b6dcd92ff4e4aec43c8edd890 Version: 2020.4.100.944, Unmanaged_functions: i | l dl | dj k i il | k i il l | | k | i i h d ``` ----- ``` Version: 2020.2.15300.12747, Unmanaged_functions: CLSIDFromString, Timestamp: 2020-08-04 15:43:08, Signature: OK, Hash: 018de33dc3a5e8f07207b4349a9d7cf4c59c9d183cc0069014b33e692c54efb5 Version: 2020.2.15300.12766, Unmanaged_functions: CLSIDFromString, Timestamp: 2020-08-11 15:40:55, Signature: OK, Hash: 143632672dcb6ef324343739636b984f5c52ece0e078cfee7c6cac4a3545403a Version: 2020.2.15300.12901, Unmanaged_functions: CLSIDFromString, Timestamp: 2020-12-11 00:40:07, Signature: OK, Hash: cc870c07eeb672ab33b6c2be51b173ad5564af5d98bfc02da02367a9e349a76f Version: 2019.4.5200.9106, Unmanaged_functions: CLSIDFromString, Timestamp: 2020-12-14 03:59:21, Signature: OK, Hash: 8dfe613b00d495fb8905bdf6e1317d3e3ac1f63a626032fa2bdad4750887ee8a Version: 2020.2.45100.13073, Unmanaged_functions: CLSIDFromString, Timestamp: 2021-01-06 12:53:09, Signature: OK, Hash: 6e91c1cd907c10ba05f6e2c6b37990b1c061a06803d50d34521efa0f4796f7dd Version: 2020.2.45100.13097, Unmanaged_functions: CLSIDFromString, Timestamp: 2021-01-14 13:12:20, Signature: OK, Hash: 55e4ec31ae9bd625f28d924ee3cca3c97bc816d249709ba5a29607608bebd7e9 Version: 2020.2.55200.29741, Unmanaged_functions: CLSIDFromString, Timestamp: 2021-03-01 20:24:04, Signature: OK, Hash: 74ab5f1405f89462b1e8de99f87ece9e474ab1a2b5d2f59f19bfa822d59405ed Version: 2020.2.65100.50257, Unmanaged_functions: CLSIDFromString, Timestamp: 2021-08-13 16:14:12, Signature: OK, Hash: d0c79a03a58981e1850e4ec5bc860c65f6042df7b1a4539470f5da86b4c6ac01 Version: 2016.2.5300.959, Unmanaged_functions: CLSIDFromString, Timestamp: 2022-05-09 22:08:23, Signature: NO_SIGNATURE, Hash: 14426746efc5a8e3ee45749df2055efa70f680de8832e0bb1ea734efeefde935 ## Timeline evaluation #### For a better overview, let’s put the data in a table: ``` #### Signed with valid signature SHA-256 No a033d513a3c0e0d0199f06ea4124ab652d5698cecdd276fdb4f4abff6e3602f2 No 14e799bbdd6517411b41043802a45c85316dc1cc5c61b0f54b043079ec14112b No 99cb98b81bca424e109a4c087144fceffdb6e447877fc473ac5be1ea78e55fd9 No ad240c7d94308277b241fa060f96f409ecb657a59e639e8f2e79431eb99b9352 No acced46ef306939821b0b87671b50a9e93e8eb89c79ba0b81d105ef069d67e21 Yes 72f63760a0bd95681d8c78c881e07870b910899c70b52e0e2827317f378773df No 051e831eaf5bacf840ef6e2af369d6b4b4cd32abd3e10cb1ac80d66e0bb38775 No 218b25e0507f24e1ab9e231c93d84535d19526241d489985c2770919747f2257 Yes 8d11616c14afc5b2c1b3ee9ee6d46a20cdae31b25e0cd7fbc374b5517b264dd2 No dffcc5d7e3ec31a745d59a7f4cd5da1df58ead2d21f57aa04c0b8066f85e4c6a No ae95f1b751bf47a83f106e9c019a0051239234f95920581b3f7c8debdc32a5d6 No d84c2167b03db3760bcf7a76b84534f50910f72a53bc1f5cefcd72784ff75a58 Yes 3b4b1d5ebb83fd4d505e0b75673027e80f98861b92b35e0adcd21e2b48ced2d9 No 6112ba344a40bc1942ef0b593950542fcc7f67f7ccf1e5274e56e34735efed1b No f33c1cb46ad1c82d99f3e92b40e8994aa2d6ec116e9846c131bfcd15de8fa52c Yes 1e229359698c276b2398bfffaa4fb809919e4aaf1c9007d7670866159ecf9ad1 Yes 5e4276dc1c9e1e5ef02e75972c59212806dc6a3d13cd2ccafd26af14cb12289b #### Orion DLL version Backdoored #### Compilation timestamp #### 2010.1.0.0 No 2010-06-25 04:39:04 2011.2.5.2234 No 2011-11-04 18:07:31 2012.1.12.2305 No 2012-07-23 13:12:23 2012.1.5.2202 No 2012-09-24 16:48:03 2012.2.13.2381 No 2013-01-15 09:40:08 2013.2.3.684 No 2013-08-20 19:12:32 2014.1.1.872 No 2013-11-17 03:18:43 2013.2.12.2040 No 2013-12-04 12:41:57 2014.2.1.1111 No 2014-04-08 03:15:00 2014.2.11.1229 No 2014-08-06 16:48:31 2015.1.25300.8197 No 2015-05-27 12:36:44 2015.1.35100.9209 No 2015-12-17 12:51:37 2016.1.5300.1028 No 2016-05-27 20:04:52 2017.1.100.1628 No 2017-01-26 17:12:52 2017.1.5300.1698 No 2017-02-21 14:53:54 2017.3.5200.1780 No 2017-08-18 00:46:52 2018.2.5200.5660 No 2018-08-14 09:52:18 ----- #### Signed with valid signature SHA-256 No f707ba597c299f503d425867152f6a039b95a401dfa1a6cba8654b65adab78ba Yes 6b295fd9a1c87263613a0d7f23c6c0ece010a038dcce1dd112888bfaff22099e Yes 86901758745e39d3b39bf1373a34fc475e29b3cc418059b54f0ded6bdd5fda01 Yes d3c6785e18fba3749fb785bc313cf8346182f532c59172b69adfb31b96a5d0af Yes 9bee4af53a8cdd7ecabe5d0c77b6011abe887ac516a5a22ad51a058830403690 Yes bb86f66d11592e3312cd03423b754f7337aeebba9204f54b745ed3821de6252d Yes ae6694fd12679891d95b427444466f186bcdcc79bc0627b590e0cb40de1928ad Yes 9d6285db647e7eeabdb85b409fad61467de1655098fec2e25aeb7770299e9fee Yes db9e63337dacf0c0f1baa06145fd5f1007002c63124f99180f520ac11d551420 Yes 0f5d7e6dfdd62c83eb096ba193b5ae394001bac036745495674156ead6557589 Yes dab758bf98d9b36fa057a66cd0284737abf89857b73ca89280267ee7caf62f3b Yes 32519b85c0b422e4656de6e6c41878e95fd95026267daab4215ee59c107d6c77 Yes abe22cf0d78836c3ea072daeaf4c5eeaf9c29b6feb597741651979fc8fbd2417 Yes 2ade1ac8911ad6a23498230a5e119516db47f6e76687f804e2512cc9bcfda2b0 Yes 019085a76ba7126fff22770d71bd901c325fc68ac55aa743327984e89f4b0134 Yes ce77d116a074dab7a22a0fd4f2c1ab475f16eec42e1ded3c0b0aa8211fe858d6 Yes fcbf4463ffe1f1d3152d65e3b0918d5229997f7b6dcd92ff4e4aec43c8edd890 Yes 73b11757ef0ec615690156bc09341be30a89d661182f9f4cc0dc2b4e2c4b3a50 Yes 018de33dc3a5e8f07207b4349a9d7cf4c59c9d183cc0069014b33e692c54efb5 Yes 143632672dcb6ef324343739636b984f5c52ece0e078cfee7c6cac4a3545403a Yes cc870c07eeb672ab33b6c2be51b173ad5564af5d98bfc02da02367a9e349a76f Yes 8dfe613b00d495fb8905bdf6e1317d3e3ac1f63a626032fa2bdad4750887ee8a Yes 6e91c1cd907c10ba05f6e2c6b37990b1c061a06803d50d34521efa0f4796f7dd Yes 55e4ec31ae9bd625f28d924ee3cca3c97bc816d249709ba5a29607608bebd7e9 Yes 74ab5f1405f89462b1e8de99f87ece9e474ab1a2b5d2f59f19bfa822d59405ed #### Orion DLL version Backdoored #### Compilation timestamp #### 2018.2.5200.5675 No 2018-09-25 08:12:02 2018.4.5200.10541 No 2018-11-07 21:05:48 2019.2.5200.5206 No 2019-05-18 11:09:22 2019.4.5200.8890 No 2019-10-10 15:26:39 2019.4.5200.8950 No 2019-11-11 23:34:28 2019.4.5200.8996 No 2019-12-09 18:12:09 2019.4.5200.9001 No 2020-01-03 16:22:18 2019.4.5200.9045 No 2020-01-24 12:24:39 2019.4.5200.9073 Yes 2020-03-17 14:08:19 2019.4.5200.9078 Yes 2020-03-19 10:32:21 2020.2.100.12219 Yes 2020-03-24 04:00:16 2019.4.5200.9083 Yes 2020-03-24 09:52:34 2020.2.100.12299 Yes 2020-03-25 20:03:48 2020.2.100.12367 Yes 2020-04-20 10:51:43 2020.2.5200.12394 Yes 2020-04-21 16:53:33 2020.2.5300.12432 Yes 2020-05-11 23:32:40 2020.4.100.910 Yes 2020-05-30 11:07:55 2020.4.100.944 Yes 2020-06-03 19:02:59 2020.2.15300.12747 No 2020-08-04 15:43:08 2020.2.15300.12766 No 2020-08-11 15:40:55 2020.2.15300.12901 No 2020-12-11 00:40:07 2019.4.5200.9106 No 2020-12-14 03:59:21 2020.2.45100.13073 No 2021-01-06 12:53:09 2020.2.45100.13097 No 2021-01-14 13:12:20 2020.2.55200.29741 No 2021-03-01 20:24:04 ----- #### Signed with valid signature SHA-256 Yes d0c79a03a58981e1850e4ec5bc860c65f6042df7b1a4539470f5da86b4c6ac01 No 14426746efc5a8e3ee45749df2055efa70f680de8832e0bb1ea734efeefde935 #### Orion DLL version Backdoored #### Compilation timestamp #### 2020.2.65100.50257 No 2021-08-13 16:14:12 2016.2.5300.959 No 2022-05-09 22:08:23 #### The entries marked in red are the Sunburst samples, the one marked in blue is the Sunburst sample which contains only test code. The last entry can be ignored since the sample dataset contains only 2016.2 files with invalid signatures. These files cannot be considered trustworthy as shown by the compilation timestamp of the sample. However, all files that are important to us have valid signatures. From the data, we can make some observations, which I will describe in more detail later: 1. The attackers created 10 backdoored versions over the course of ~3 months 2. The first backdoored version was spread on 2020-03-17, the last on 2020-06-03 3. The first backdoored Orion version was 2019.4.5200.9073, the last was 2020.4.100.944 ### Point 1 #### The first five backdoored versions are created at a higher frequency than any legitimate updates. There are only days in between them or have even been created on the same day. This raises suspicions that the attackers could have been able to trigger the creation of Orion updates. They may not just have waited until the SolarWinds developers released updates to inject Sunburst, as one might conclude from reading the Sunspot analysis. Having full control over the entire development pipeline makes it much easier to coordinate such a crucial mission. While this is a noisier approach than passively waiting for official Orion releases, it also increases the chances of success. However, this is only a theory and may not be true as I do not have a complete sample set as indicated in the next chapter. ### Point 2 #### Our data shows that the first backdoored sample was created on March 17, 2020, whereas the SolarWinds investigation shows February ``` 20, 2020 . This means our sample data set is unfortunately incomplete, so the assumption in point 1 may also be incorrect. The last backdoored release on June 3, 2020 coincides with the statement from SolarWinds. ### Point 3 #### This is the most interesting point cause of the two backdoored Orion versions 2020.4.100.910 and 2020.4.100.944 that stand out. These versions are not shown to be affected as a result of the SolarWinds investigation. This specific version 2020.4 is not even shown on the Orion release notes page. We can also see that after the attackers have stopped to spread Sunburst samples, the 2020 version continues with 2020.2 by the SolarWinds developers. This could mean that the attackers somehow created the 2020.4 branch. It goes without saying that all the hypotheses made in points 1 and 3 must be taken with a grain of salt. Since I do not have a complete set of Orion samples and no insights into any non-public investigation results, this is only speculation. ## Conclusion #### With the help of dotnetfile you can pull information from .NET header’s on scale. As I showed on the Sunburst example, you can create a version timeline of several samples in no time compared to manually collecting the data. One of the sources of information can be the ImplMap table where unmanaged functions are located. In this article, I just gave a very simple example of intelligence gathering. You can do much more with this library in terms of malware detection and threat hunting. It just takes a little creativity and imagination, there is a lot of information to discover in the CLR header. ## Sample set hashes (SHA-256) ``` ----- ``` 019085a76ba7126fff22770d71bd901c325fc68ac55aa743327984e89f4b0134 019af890df78f69847b4493a536559e69f1734e40bf08bb46ea98d9682389829 02dfee607de7969d23551b8f9f5d605ec95cfdf5b7822376f8b4df456a6ca8c7 051e831eaf5bacf840ef6e2af369d6b4b4cd32abd3e10cb1ac80d66e0bb38775 0dbbf3949dfbeb53767aab3f8fe0534e686b955b43367700808c8c44e22d8e00 0f5d7e6dfdd62c83eb096ba193b5ae394001bac036745495674156ead6557589 13bfd97ccb585c082495242ebd73fe779576920b0f0ab3c5adea13f7d75f6aac 143632672dcb6ef324343739636b984f5c52ece0e078cfee7c6cac4a3545403a 14426746efc5a8e3ee45749df2055efa70f680de8832e0bb1ea734efeefde935 14e799bbdd6517411b41043802a45c85316dc1cc5c61b0f54b043079ec14112b 1bb7c3edb5a8e3c6d5f77e57a84b80a11b08ed10c0ee2a5ef14856e38872b917 1e229359698c276b2398bfffaa4fb809919e4aaf1c9007d7670866159ecf9ad1 218b25e0507f24e1ab9e231c93d84535d19526241d489985c2770919747f2257 23428bd54c823125553463dc4d1faf6e2c03f09d6652d61ae4e49f93d0de3ec5 2435fd31855898ed41d194570febc50f3027aa584298ff264cd99f8c84b0ec57 2881406f09bb21bf62abfe2541eb2bebb1db5209e8faf4490eb23b398ad80438 2ade1ac8911ad6a23498230a5e119516db47f6e76687f804e2512cc9bcfda2b0 317a0c715cbd83061e10cb7a1eaccde4786ab848a8881e91f960d7606b9352c6 32519b85c0b422e4656de6e6c41878e95fd95026267daab4215ee59c107d6c77 3b4b1d5ebb83fd4d505e0b75673027e80f98861b92b35e0adcd21e2b48ced2d9 3e96a5d3307158a0c1af97e154f797286ffe77590acf6e051c9aa6b6508c1b9a 42e73c85b07d89956e94db832d6501c823ae00684c50d9c9163194357c3dd3ed 468d425643350410c1cb43841244f8c0accad58d6e6bc99239dac7aac4e6fd90 46a64842fc7e1137f2e344df46523710b5420d9625606454004f24c3faeb1051 502857c523178fb69190984271f5c6948ff17b0db85aa3c23b2a68a09c0bddc8 51ae0f0648cb8db221fb46b95bf709e5fb10dc65be8156f48991aa59a4405db6 53bfbe32676f6990a49bb2a001eaa78a8cc2ba9c0f3eb484337c1d7a2f56ce72 55e4ec31ae9bd625f28d924ee3cca3c97bc816d249709ba5a29607608bebd7e9 5b448751ea1c845ce3f9b979799369ba44585e72199c1252b16e7e5b8dd588fd 5b931138fb32e03f651c6c8c6c4fc40c9b78441e04f7d6026394d210749ac3d9 5d6cd94a87f0154fa2deaf2ad0931394256f26ca6278a3549596f89b053b0ef4 5e4276dc1c9e1e5ef02e75972c59212806dc6a3d13cd2ccafd26af14cb12289b 608d1994238fea66c22e45817fb2c24f7fdcf8d86adfbd015f8dab05c3f699d9 6112ba344a40bc1942ef0b593950542fcc7f67f7ccf1e5274e56e34735efed1b 6b295fd9a1c87263613a0d7f23c6c0ece010a038dcce1dd112888bfaff22099e 6bc622ceb9729abd6b27d228efe9b9741a752aa6cff5f81216297575029e4e08 6e91c1cd907c10ba05f6e2c6b37990b1c061a06803d50d34521efa0f4796f7dd 6f9bfc4379a904e34aa0d8c24fd4256cdd0b4a51e6b1f7bf0fa75a7bc2c79a0a 72f63760a0bd95681d8c78c881e07870b910899c70b52e0e2827317f378773df 73b11757ef0ec615690156bc09341be30a89d661182f9f4cc0dc2b4e2c4b3a50 74ab5f1405f89462b1e8de99f87ece9e474ab1a2b5d2f59f19bfa822d59405ed 84dc86c1707edf58a795063d7ca32a063b42b3e6bc397cfce05dc56a4b7f7db4 86901758745e39d3b39bf1373a34fc475e29b3cc418059b54f0ded6bdd5fda01 8d11616c14afc5b2c1b3ee9ee6d46a20cdae31b25e0cd7fbc374b5517b264dd2 8dfe613b00d495fb8905bdf6e1317d3e3ac1f63a626032fa2bdad4750887ee8a 9590b202876f06678d4af637c303aaecbd45ebde8abd3ec0eaa5b7d88c54bce6 99cb98b81bca424e109a4c087144fceffdb6e447877fc473ac5be1ea78e55fd9 9bee4af53a8cdd7ecabe5d0c77b6011abe887ac516a5a22ad51a058830403690 9d6285db647e7eeabdb85b409fad61467de1655098fec2e25aeb7770299e9fee a033d513a3c0e0d0199f06ea4124ab652d5698cecdd276fdb4f4abff6e3602f2 a25cadd48d70f6ea0c4a241d99c5241269e6faccb4054e62d16784640f8e53bc a5813de9e453c86c9ea07668deb090691d568cb0dad80197319a2d5657ee170c abe22cf0d78836c3ea072daeaf4c5eeaf9c29b6feb597741651979fc8fbd2417 acced46ef306939821b0b87671b50a9e93e8eb89c79ba0b81d105ef069d67e21 ad240c7d94308277b241fa060f96f409ecb657a59e639e8f2e79431eb99b9352 ae6694fd12679891d95b427444466f186bcdcc79bc0627b590e0cb40de1928ad ae95f1b751bf47a83f106e9c019a0051239234f95920581b3f7c8debdc32a5d6 afb8f6d5c7e3b55a79257d0c4736fec6e52abfa3e1540bcfd16b954bd422b33c b3b7107f7784f728c3339e679ce153897dbd44bde4799eb10f32972813169f2a b9ce678f9daf32c526211edea88b5ec104538c75fad13767ea44309e9f81dbfc b9defa16d1aa92d85d1d5d47339c999eee42aa3b9ada5dd4d5a158efcadd509a bb86f66d11592e3312cd03423b754f7337aeebba9204f54b745ed3821de6252d c419b50e1fd87884019c83b7fc4f8096adc9f2c7da15409d0f77613e28d81103 c5e76c932daf2c508547d5a910172d919dbe69d62808d0d94ee32af860708ba8 cbc24292a8b09dde6ff95d4a5c00c5e741d85cfc26510fabafbc14565c623966 cc870c07eeb672ab33b6c2be51b173ad5564af5d98bfc02da02367a9e349a76f ce77d116a074dab7a22a0fd4f2c1ab475f16eec42e1ded3c0b0aa8211fe858d6 ced0a4be5059c986965b070edd8a1706657f834629a31b599baef5ddca6e375d d0c79a03a58981e1850e4ec5bc860c65f6042df7b1a4539470f5da86b4c6ac01 d3c6785e18fba3749fb785bc313cf8346182f532c59172b69adfb31b96a5d0af d84c2167b03db3760bcf7a76b84534f50910f72a53bc1f5cefcd72784ff75a58 dab758bf98d9b36fa057a66cd0284737abf89857b73ca89280267ee7caf62f3b db9e63337dacf0c0f1baa06145fd5f1007002c63124f99180f520ac11d551420 dcbf229f582756bf3f730efa3f460c4381b8e042bbfd4aa1ebe5c763f7c27546 dee8216b2e7b04754501ebc3c19e5351c60ba83f5664bf6172589a94e4ed3592 dffcc5d7e3ec31a745d59a7f4cd5da1df58ead2d21f57aa04c0b8066f85e4c6a e60f0fd87784f7d3c4b17331676e570554616cdae40a1e4503932f5680820cf7 f b d d f b d bf d d f ``` ----- ``` f707ba597c299f503d425867152f6a039b95a401dfa1a6cba8654b65adab78ba fcbf4463ffe1f1d3152d65e3b0918d5229997f7b6dcd92ff4e4aec43c8edd890 ``` -----