The Elfscrow Crypto tool is a vital asset used at Elf University for encrypting SUPER SECRET documents. We can't send you the source, but we do have debug symbols that you can use.
Recover the plaintext content for this encrypted document. We know that it was encrypted on December 6, 2019, between 7pm and 9pm UTC.
What is the middle line on the cover page? (Hint: it's five words)
For hints on achieving this objective, please visit the NetWars room and talk with Holly Evergreen.
The hints point to Ron Bowes' presentation.
I managed to follow Ron's presentation and took a look at his decrypting example in detail. I managed to get IDA installed and to load up the executable and debug symbols. I then started to browse the dis-assembled code. It is awhile since I have look at assemble code but I was surprise by how much I remembered and the presentation reminded me about.
I started looking for the decryption routine and found do_decrypt. This line stood out:
.text:00402AA4 push offset aCryptimportkey_0 ; "CryptImportKey failed for DES-CBC key"
There are also super_secure_rand, super_secure_random and generate_key functions
In the generate_key function at .text:00401E0E
there is a call to time that would infer that the seed is time based. The key is 8 bytes based on the comparison at .text:00401E31
.
.text:00401DF0 generate_key proc near ; CODE XREF: do_encrypt+67âp
.text:00401DF0
.text:00401DF0 var_4 = dword ptr -4
.text:00401DF0 arg_0 = dword ptr 8
.text:00401DF0
.text:00401DF0 push ebp
.text:00401DF1 mov ebp, esp
.text:00401DF3 push ecx
.text:00401DF4 push offset aOurMiniatureEl ; "Our miniature elves are putting togethe"...
.text:00401DF9 call ds:__imp____iob_func
.text:00401DFF add eax, 40h
.text:00401E02 push eax ; File
.text:00401E03 call ds:__imp__fprintf
.text:00401E09 add esp, 8
.text:00401E0C push 0 ; Time
.text:00401E0E call time
.text:00401E13 add esp, 4
.text:00401E16 push eax
.text:00401E17 call super_secure_srand
.text:00401E1C add esp, 4
.text:00401E1F mov [ebp+var_4], 0
.text:00401E26 jmp short loc_401E31
.text:00401E28 ; ---------------------------------------------------------------------------
.text:00401E28
.text:00401E28 loc_401E28: ; CODE XREF: generate_key+5Dâj
.text:00401E28 mov eax, [ebp+var_4]
.text:00401E2B add eax, 1
.text:00401E2E mov [ebp+var_4], eax
.text:00401E31
.text:00401E31 loc_401E31: ; CODE XREF: generate_key+36âj
.text:00401E31 cmp [ebp+var_4], 8
.text:00401E35 jnb short loc_401E4F
.text:00401E37 call super_secure_random
.text:00401E3C movzx ecx, al
.text:00401E3F and ecx, 0FFh
.text:00401E45 mov edx, [ebp+arg_0]
.text:00401E48 add edx, [ebp+var_4]
.text:00401E4B mov [edx], cl
.text:00401E4D jmp short loc_401E28
.text:00401E4F ; ---------------------------------------------------------------------------
.text:00401E4F
.text:00401E4F loc_401E4F: ; CODE XREF: generate_key+45âj
.text:00401E4F mov esp, ebp
.text:00401E51 pop ebp
.text:00401E52 retn
.text:00401E52 generate_key endp
.text:00401E52
.text:00401E52 ; ---------------------------------------------------------------------------
.text:00401E53 align 10h
.text:00401E60
.text:00401DC0 super_secure_random proc near ; CODE XREF: generate_key+47âp
.text:00401DC0 push ebp
.text:00401DC1 mov ebp, esp
.text:00401DC3 mov eax, state
.text:00401DC8 imul eax, 343FDh
.text:00401DCE add eax, 269EC3h
.text:00401DD3 mov state, eax
.text:00401DD8 mov eax, state
.text:00401DDD sar eax, 10h
.text:00401DE0 and eax, 7FFFh
.text:00401DE5 pop ebp
.text:00401DE6 retn
.text:00401DE6 super_secure_random endp
.text:00401DC0 super_secure_random proc near ; CODE XREF: generate_key+47âp
.text:00401DC0 push ebp
.text:00401DC1 mov ebp, esp
.text:00401DC3 mov eax, state <- get the current value seed
.text:00401DC8 imul eax, 214013 <- multiply by 214013
.text:00401DCE add eax, 2531011 <- add 2531011
.text:00401DD3 mov state, eax <- store the value of seed
.text:00401DD8 mov eax, state
.text:00401DDD sar eax, 10h <- shift right 16
.text:00401DE0 and eax, 7FFFh <- AND with 7FFF hex
.text:00401DE5 pop ebp
.text:00401DE6 retn
.text:00401DE6 super_secure_random endp
key += ((((seed = (214013 * seed + 2531011) ) >> 16 ) & 0x7fff) & 0x0FF).chr
So my version of the decryptor script was:
require 'openssl'
require 'date'
KEY_LENGTH = 8 # TODO
def generate_key(seed)
key = ""
1.upto(KEY_LENGTH) do
key += ((((seed = (214013 * seed + 2531011) ) >> 16 ) & 0x7fff) & 0x0FF).chr
end
return key
end
def decrypt(data, key)
begin
c = OpenSSL::Cipher.new('DES-CBC') # TODO
c.decrypt
c.key = key
return (c.update(data) + c.final())
# added this so that script does not crash when decryption fails
rescue OpenSSL::Cipher::CipherError => e
end
end
# use this to get list of supported ciphers
#puts OpenSSL::Cipher.ciphers
#exit
# convert time range to epoch seconds
start_sec = DateTime.parse('2019-12-06T19:00:00Z').to_time.to_i
end_sec = DateTime.parse('2019-12-06T21:00:00Z').to_time.to_i
puts "Start time: #{start_sec}"
puts "End time: #{end_sec}"
enc_file = "ElfUResearchLabsSuperSledOMaticQuickStartGuideV1.2.pdf.enc"
dec_file = "tmp2/ElfUResearchLabsSuperSledOMaticQuickStartGuideV1.2.pdf"
# foreach seed which is epoch seconds try to decrypt
(start_sec..end_sec).each { |seed|
# read contents of file in binary format
content = File.binread("#{enc_file}")
# generate a new key
key = generate_key(seed)
# attempt to decrypt
new_content = decrypt(content, key)
# check if there is some contents and if it looks like a pdf file
if new_content && new_content.match(/^%PDF-/)
puts("#{seed} - Generated key: #{key.unpack('H*')}")
File.binwrite("#{dec_file}.#{seed}", new_content)
end
}
$ ruby decryptor.rb
Start time: 1575658800
End time: 1575666000
1575663650 - Generated key: ["b5ad6a321240fbec"]
The original file must have been encrypted at Friday, December 6, 2019 8:20:50 PM UTC
This opened the door to the Bell Tower
Answer
The Answer is “Machine Learning Sleigh Route Finder”