Incomplete; Probably won’t finish
Checkpoint 1: “Air-gapped”
Points 10
The FBI infiltrated SHINY SCORPION’s command & control network!
They’ve passed along the victim database related to the campaign that targeted Keep it Simple Security (KiSSec). They’ve also included a Python script that can deobfuscate and parse the ransomware config.
FBI intelligence indicates that it should be possible to undo the ransomware’s encryption using the information stored in these files!
Before we start any decryption, though, they suggest finding our unique victim ID.
We were given a zip containing most files we would need.
In the FBI directory was a readme, a config parser, and the database of victims that Shiny Scorpion had exploited, клиенты.db
. I opened the binary using https://sqliteviewer.app/ to make the db easier to parse. There were three columns: id
, amt
, and the key
.
id = victim id
amt = money to pay
key = encoded RSA private key
I found a record that looked familiar: the id was the address that our breached company was to send $500,000 worth of bitcoin to as stated in ransom.txt
.
Flag:
14hahahaEvMFqrCd2J9vsNjaUhjEdYCsTnG3r
Checkpoint 2: The last easy one for a while
Points: 10
Now that we know our “customer” ID, we should be able to find the ransomware’s decryption key.
Flag
CTFd has some limitations that make it impossible to submit the key directly 😞
Instead, please generate and submit a SHA256 checksum of the key.
Format
SHA256 digest, 64 hexadecimal digits, case-insensitive
When hashing, ensure that you don’t accidentally introduce any leading or trailing whitespace around the key. Any changes, no matter how small, will generate a completely different hash. Be careful copy/pasting!
I took the key from the user db. I noticed that there was a repeating string at the beginning and end of the key: YF0gY
. As the malware config used a public key and knowing that a private key started with -----BEGIN RSA PRIVATE KEY-----
, I came to the conclusion that it had to be obfuscated. The =
hinted towards base64. I tried it with ROT13, and it worked!
From there, I got the sha256 checksum.
cat key.txt | sha256sum
flag: a92bbe46078d2295353bad012292f84ee0564ffb89f7bbe7cb945b8cbf1d1e51
Note: Check the appendix for the encoded decoded private key.
Checkpoint 3: Infinite monkey theorem
Points: 10
Now that we’ve got the key, we should be able to make some headway on those encrypted files.
The README would be a great place to start!
Flag format
cp3:rest_of_the_flag, including the cp3: part, case-sensitive
- Tried just uploading the file in cyberchef and decrypting with cyberchef, but didn’t work because the message length was invalid.
- RSA is used to encrypt messages that are shorter than the modulus of the public key.
-----BEGIN RSA PRIVATE KEY-----
RSAPrivateKey ::= SEQUENCE {
version Version,
modulus INTEGER, -- n
publicExponent INTEGER, -- e
privateExponent INTEGER, -- d
prime1 INTEGER, -- p
prime2 INTEGER, -- q
exponent1 INTEGER, -- d mod (p-1)
exponent2 INTEGER, -- d mod (q-1)
coefficient INTEGER, -- (inverse of q) mod p
otherPrimeInfos OtherPrimeInfos OPTIONAL
}
-----END RSA PRIVATE KEY-----
As the private key was 4096, the maximum length that a message could be encrypted is 512 bytes.
- Decrypted with the first 512 bytes:
L3NmBaEbnKAsp2uiqJkxK2WyK3WuozEioFRuVFRuVFR=
xjgufagfCj+xBeAm5brk4D==
From base64 ROT13:
flag: cp3:this_should_be_random!!!!!!!
References
- https://security.stackexchange.com/questions/90169/rsa-public-key-and-private-key-lengths
- https://www.dcode.fr/rsa-cipher
Checkpoint 4: Call for backup
Points: 10
We need to decrypt the rest of the README.
It should contain contact information for the contractors that originally set this backup system up.
What is the phone number for their emergency hotline?
Key : cp3:this_should_be_random!!!!!!!
IV: a²{l?¤:³sæ±á
AES Decrypt CBC/NoPadding
flag: +1 (123) 867-5309
Checkpoint 5: Raise the flag.txt
Points: 10
No luck with the contractors yet; even in this emergency their fees were still deemed too high.
The recovery key’s not in the README, so we need to decrypt the rest of the files for them anyways.
Flag format
cp5:the_rest_the_flag
, with or without thecp5
part, case-insensitive
in keyfile bin:
RSA Decrypt the first 512 bytes: cf076bf736b981a70b33e3480127572ea1be1beb97ba2e0 f601f99df6bacac9dd1dd6e7f113cb786
mjqe9mn5tnpYZ+AVNFqKYdT+T+hKhv4XQTrNURq+tb8=
LO+M32hfeW3E3J5/RGl3ut==
base64
Ïk÷6¹§3ãH'W.¡¾ëº.
gG~`ßk¬¬ÑÝn<·
Convert from base 64 Kinda stuck on this. Idea so far:
- Need to decrypt files with RSA key and AES. However, so far, it just isn’t working.
- What I can do so far: Extract the base64 with the RSA key.
- Need to make sense of wtf the key is supposed to be
- Decrypt with AES
- Get rid of first 512 bytes maybe of the decrypted text.
Python Script:
from Crypto.Cipher import AES
def __unpad(plain_text):
last_character = plain_text[len(plain_text) - 1:]
return plain_text[:-ord(last_character)]
for i in range(1, 102):
with open(f"cyberchef/{i}.txt", "r") as aesFile:
aesData = aesFile.read()
aesKey = bytearray.fromhex(aesData[:64])
aesIV = bytearray.fromhex(aesData[64:])
cipher = AES.new(aesKey, AES.MODE_CBC, iv=aesIV)
numString = str(i).rjust(4, "0")
with open(f"old_desktop/desktop cleanup.7z.{numString}.sting", "rb") as cipherFile:
ciphertext = cipherFile.read()
ciphertext = ciphertext[512:]
plaintext = cipher.decrypt(ciphertext)
with open(f"decrypted_stuff/desktop cleanup.7z.{numString}", "wb") as plainFile:
plainFile.write(__unpad(plaintext))
# plaintext = cipher.decrypt(ciphertext)
flag : cp5:i_sure_hope_you_didn't_decrypt_this_manually
Checkpoint 6: Are we there yet?
flag: MFWG233TORPXI2DFOJSSCIJBEE======