// HackTheBox  ·  writeup

Einladen

HackTheBox Medium tsharkProcmon (procmon-parser)dnfilePyCryptodomepdftotextPython
DFIR

Scenario

Einladen is a captivating medium difficulty Sherlock scenario where your skills are put to the test in a cybersecurity incident involving diplomacy and intrigue. Recently, our team received an invite to a prestigious event at the German embassy to bid farewell to the ambassador. However, suspicions arose when our SIEM tools triggered alerts following the receipt of the email, suggesting it was a phishing attempt. Provided for your analysis are diverse artifacts including numerous binaries, a network capture, DLLs from the host system, and a critical .hta file. Dive into these resources and unravel the mystery.

Executive Summary

A phishing email posing as an embassy farewell invitation sent the victim to a web page that smuggled a ZIP archive to disk through an embedded byte array. The archive held a decoy PDF and an HTA dropper, which wrote a Microsoft-signed executable beside a malicious DLL so the signed binary would sideload it. A separate JavaScript sample carried a Base64-encoded .NET client built on the AsyncRAT design, with an encrypted configuration, a geolocation check that stops it in one country, and a debugger check. It persisted through a Run key and a scheduled task, and its network capture shows it resolving a chat platform subdomain hosted on AWS as its command channel.

Artifacts

Format note: Several answers are masked (e.g. ****v, ******t, a registry path with a leading hive). Count the asterisks before submitting.

Initial Access

Q1 — The victim visited a web page. The HTML file of the web page has been provided as ‘downloader.html’ sample file.The web page downloads a ZIP file named 'Invitation_Farewell_DE_EMB.zip'. What is the SHA-256 hash of the ZIP file?

downloader.html is an HTML smuggling page: it carries the ZIP as a JavaScript byte array (d[]) and rebuilds the file in the browser before offering it as a download. Pull the array out, rebuild the bytes and hash the result. The hash is of the rebuilt ZIP, not of the HTML.

python3 -I -c "import re,hashlib;s=open('downloader.html').read();d=bytes(int(x) for x in re.search(r'd\s*=\s*\[([\d,\s]+)\]',s).group(1).split(','));open('Invitation_Farewell_DE_EMB.zip','wb').write(d);print(hashlib.sha256(d).hexdigest())"
Click flag to reveal 5D4BF026FAD40979541EFD2419EC0B042C8CF83BC1A61CBCC069EFE0069CCD27
Q3 — The threat actor was acting as an embassy of a country. Which country was that?

The ZIP contains a decoy Invitation.pdf next to the HTA. Extracting its text shows the letterhead of an embassy, which names the country the lure impersonates.

pdftotext Invitation.pdf - | head
Click to reveal answer Germany

Execution

Q2 — The downloaded ZIP file contains a HTA file, which creates multiple files. One of those files is a signed fileby Microsoft Corporation. In HTA file, which variable’s value was the content of that signed file?

The HTA drops several files by writing byte arrays held in variables. Parse the arrays out of the script and identify each payload by its header and signature. One of them is msoev.exe, the Microsoft-signed binary that is later used for DLL sideloading next to the malicious mso.dll; the variable holding its bytes is the answer.

python3 -I parse_hta.py invitation.hta
Click flag to reveal msoev
Q12 — The JavaScript file tries to write itself as a .bat file. What is the .bat file name (name+extension) it tries to write itself as?

The JavaScript sample unc.js starts with obfuscated variables, but the tail of the script holds the logic that writes the script to disk as a batch file. Decode the strings in the tail and read the target file name.

head -c 2000 unc.js; tail -c 2000 unc.js
Click to reveal answer richpear.bat
Q13 — The JavaScript file contains a big text which is encoded as Base64. If you decode that Base64 text and write its content as an EXE file. What will be the SHA256 hash of the EXE?

unc.js embeds one very large Base64 blob (line 28). Decode it, write the bytes out as an EXE and hash it. This is the .NET RAT that the remaining questions examine.

sed -n '28p' unc.js | base64 -d > dec.exe && sha256sum dec.exe
Click flag to reveal DB84DB8C5D76F6001D5503E8E4B16CDD3446D5535C45BBB0FCA76CFEC40F37CC
Q7 — What was the parent PID (PPID) of the malware?

Load Logfile.PML with a Procmon parser and list the process records. msoev.exe appears as PID 10044 and its record carries the parent PID of the process that launched it, which is the Explorer shell that opened the sample.

python3 -I pml.py Logfile.PML --processes | grep -i msoev

Tip: Procmon’s Process Tree view shows the same parent relationship if you prefer the GUI.

Click to reveal answer 4156

Defense Evasion

Q11 — Did the malicious mso.dll load by the malware executable successfully?

From Q9 we know the user profile, so search the Procmon events for mso.dll on that Desktop. A Load Image event for it with result SUCCESS means the sideloaded DLL was mapped into msoev.exe; a NAME NOT FOUND would have meant the load failed.

python3 -I pml.py Logfile.PML --ops | grep -i 'mso.dll' | grep -i 'Load Image'
Click flag to reveal yes
Q17 — As an anti-debugging functionality, the malware checks if there is any process running where the process name is a debugger. What is the debugger name it tries to check if that’s running?

The anti-analysis routine looks for a running process by name. Among the user strings is the name of a .NET debugger and decompiler, which is what it hunts for.

python3 -I us.py dec.exe | grep -iE 'dnspy|debug'
Click to reveal answer dnSpy
Q16 — After getting the country code or country name of the victim machine, the malware checks some country codes and a country name. In case of the country name, if the name is matched with the victim machine’s country name, the malware terminates itself. What is the country name it checks with the victim system?

The same user strings hold the country checks that follow the geolocation call: a set of country codes and one country name that, on a match, ends the process.

python3 -I us.py dec.exe | grep -iE 'russia|country'
Click flag to reveal Russia

Persistence

Q18 — For persistence, the malware writes a Registry key where the registry key is hardcoded in the malware in reversed format. What is the registry key after reversing?

Persistence is a Run key. The path is stored reversed in the user strings to avoid a plain string match, so reverse it to read the key.

python3 -I us.py dec.exe | grep -i 'nuR' | rev

Gotcha: The format mask shows the hive abbreviation at the start and a trailing backslash. A bare Software\...\Run\ path is rejected: include the HKCU prefix.

Click to reveal answer HKCU\Software\Microsoft\Windows\CurrentVersion\Run\
Q19 — The malware sets a scheduled task. What is the Run Level for the scheduled task/job it sets?

Alongside the Run key, the malware builds a schtasks command line. Read the /rl switch in that command for the run level.

python3 -I us.py dec.exe | grep -i schtasks
Click flag to reveal highest
Q10 — How many times were the Windows Registry keys set with a data value?

Filter the Procmon events to RegSetValue and count the rows that carry a data value. Counting the rows in the capture gives the total.

python3 -I pml.py Logfile.PML --ops | grep -c RegSetValue
Click to reveal answer 11

Discovery

Q8 — What was the computer name of the victim computer?

The same Procmon capture records the host and user in each process entry. The computer name is the host the capture was taken on.

python3 -I pml.py Logfile.PML --processes | grep -i msoev
Click flag to reveal DESKTOP-O88AN4O
Q9 — What was the username of the victim computer?

The process record for msoev.exe lists the account it ran as; the username is the profile folder seen in the paths, e.g. C:\Users\<user>\Desktop\mso.dll.

python3 -I pml.py Logfile.PML --processes | grep -i msoev
Click to reveal answer TWF
Q15 — The malware sends a HTTP request to a URI and checks the country code or country name of the victim machine. To which URI does the malware sends request for this?

The malware’s user strings include one external geolocation service that returns JSON with the country of the caller. That URI is the one it queries to find where the victim sits.

python3 -I us.py dec.exe | grep -i http
Click flag to reveal http://ip-api.com/json/

Command and Control

Q4 — The malware communicated with a chatting platform domain. What is the domain name (inclusive of sub domain) the malware connects to?

In the packet capture, list the DNS queries and pick out the one that is not a Windows or Microsoft service. A single chat platform subdomain stands out among the lookups the sample made.

tshark -r msoev.pcapng -Y 'dns.flags.response==0' -T fields -e dns.qry.name | sort | uniq -c | sort -rn
Click to reveal answer toyy.zulipchat.com
Q5 — How many DNS A records were found for that domain?

Look at the DNS response for the domain from Q4 and count the answer records of type A.

tshark -r msoev.pcapng -Y 'dns.qry.name=="toyy.zulipchat.com" && dns.flags.response==1' -T fields -e dns.a
Click flag to reveal 6
Q6 — It seems like the chatting service was running on a very known cloud service using a FQDN, where the FQDN contains the IP address of the chatting domain in reversive format somehow. What is the FQDN?

From Q4 and Q5 we have the chat server addresses. The capture also holds PTR lookups, and the reverse record for one of those addresses is an AWS EC2 public hostname, which embeds the IP address in dashed form: ec2-<a>-<b>-<c>-<d>. Match the PTR response to the address the malware connected to.

tshark -r msoev.pcapng -Y 'dns.ptr.domain_name' -T fields -e dns.qry.name -e dns.ptr.domain_name
Click to reveal answer ec2-35-171-197-55.compute-1.amazonaws.com
Q14 — The malware contains a class Client.Settings which sets different configurations. It has a variable ‘Ports’ where the value is Base64 encoded. The value is decrypted using Aes256.Decrypt. After decryption, what will be its value (the decrypted value will be inside double quotation)?

The Ports setting in Client.Settings follows the AsyncRAT configuration layout: a Base64 string decrypted with AES-256, with the key derived from a Base64 master key through PBKDF2. No .NET decompiler was on hand, so read the Base64 strings from the user-string heap with dnfile and decrypt them with the AsyncRAT salt and 50000 iterations. The result is a comma-separated list of ports.

python3 -I dec.py dec.exe
Click flag to reveal 666,777,111,5544

Attack Summary

PhaseAction
Initial AccessPhishing email with an embassy farewell lure leads to downloader.html
Initial AccessHTML smuggling rebuilds Invitation_Farewell_DE_EMB.zip in the browser
ExecutionHTA dropper writes several files, including the signed msoev.exe
Defense Evasionmsoev.exe loads the malicious mso.dll from its own folder (sideload)
ExecutionJavaScript sample writes itself as a batch file and decodes an embedded .NET EXE
DiscoveryClient queries a public geolocation API and exits on a country match
Defense EvasionClient checks for a running debugger by process name
PersistenceRun key (stored reversed in the binary) plus a scheduled task at the highest run level
Command and ControlDNS lookups of a Zulip chat subdomain on AWS; AES-encrypted port list in the client config

IOCs

TypeValue
File (ZIP SHA-256)5D4BF026FAD40979541EFD2419EC0B042C8CF83BC1A61CBCC069EFE0069CCD27
File (decoded EXE SHA-256)DB84DB8C5D76F6001D5503E8E4B16CDD3446D5535C45BBB0FCA76CFEC40F37CC
FileInvitation_Farewell_DE_EMB.zip, msoev.exe, mso.dll, richpear.bat
Domaintoyy[.]zulipchat[.]com
Hostec2-35-171-197-55[.]compute-1[.]amazonaws[.]com
URLhxxp[://]ip-api[.]com/json/
Ports666,777,111,5544
RegistryHKCU\Software\Microsoft\Windows\CurrentVersion\Run\

MITRE ATT&CK

TechniqueIDDescription
Obfuscated Files or Information: HTML SmugglingT1027.006ZIP rebuilt from a byte array in downloader.html
System Binary Proxy Execution: MshtaT1218.005HTA dropper writes the payload files
Command and Scripting Interpreter: JavaScriptT1059.007unc.js decodes and drops the .NET client
Command and Scripting Interpreter: Windows Command ShellT1059.003Script rewrites itself as a .bat
Hijack Execution Flow: DLL Side-LoadingT1574.002Signed msoev.exe loads the malicious mso.dll
Virtualization/Sandbox EvasionT1497.001Debugger process check
System Location Discovery: System Language DiscoveryT1614.001Geolocation lookup and country check; closest ID for a country-based kill switch
Boot or Logon Autostart: Registry Run KeysT1547.001Reversed Run key path written for persistence
Scheduled Task/Job: Scheduled TaskT1053.005schtasks entry at the highest run level
Web Service: Bidirectional CommunicationT1102.002Zulip chat platform as the command channel

Defender Takeaways

Browser-built downloads bypass gateway inspection. The ZIP never crosses the mail gateway or proxy as a file; JavaScript assembles it inside the page. Detect the delivery with web proxy rules on large inline byte arrays, and on archives written to Downloads by a browser process that then contain an .hta.

Block or alert on HTA execution. An archive carrying an HTA that writes an EXE and DLL together is a clear chain. Remove mshta.exe from user reach or alert on it spawning file writes in user profiles.

A signed binary next to an unsigned DLL is the sideload signal. msoev.exe is Microsoft-signed, so reputation checks pass. The detection is an image load of mso.dll from a user-writable folder rather than from the signed binary’s expected location, which Procmon and Sysmon event 7 both show.

Chat platforms are not free of DNS scrutiny. The client used a Zulip subdomain as its channel, and the lookup plus the AWS reverse record are the only network indicators. Alert on workstations resolving chat or collaboration subdomains that the organisation does not use.

Watch Run keys and schtasks /rl highest from user processes. Both persistence routes were written by the same unsigned process within seconds of start. A user-level process creating a high run level task is rare enough to alert on.

Conclusion

The lure, the loader and the client were all built from common parts, and the chain only works because a signed Microsoft binary was allowed to load a DLL from a user folder. The cheapest points to break it are the download of an HTA in an archive and the sideload image load, both of which were visible well before the RAT connected out.