I didn’t get to spend a lot of time on the FLARE-On challenges this year, but I worked through the first 2 and used it as an opportunity to learn Radare2 a little better.

Here’s my solution to challenge 2.

$ md5 DudeLocker.exe BusinessPapers.doc
MD5 (DudeLocker.exe) = 4c262d5ab4bf8586d303bfa91a05b42b
MD5 (BusinessPapers.doc) = 857da52bdcaec6da473a59e2fe66df0a

Here is my r2 project file if you want to follow along with my notes. It should be unzipped in “.config/radare2/projects”, edit the challenge2 file and change the line “e file.path = /Users/yourname/challenge02/DudeLocker.exe” to the correct path for DudeLocker.exe, then open it with “r2 -p challenge2”.

Challenge 2 provides two files: an executable and a DOC based on the file extension. However, it appears the DOC has been encrypted. The challenge should be to decrypt this document file by reversing the method of encryption used by DudeLocker.exe.

$ file DudeLocker.exe BusinessPapers.doc
DudeLocker.exe:     PE32 executable for MS Windows (console) Intel 80386 32-bit
BusinessPapers.doc: data
$ xxd BusinessPapers.doc | head
00000000: 1bb9 6ebb 82c9 3d9a e290 fd8d c59a d40f  ..n...=.........
00000010: adb8 9376 511e 5f3a 37b5 d08a b5b8 02ae  ...vQ._:7.......
00000020: 503c 1926 676e 5ecd 48c4 3def d8ed 8ef1  P<.&gn^.H.=.....
00000030: 24af 5f4d 1c0c 7281 d583 a1a5 f729 5c2b  $._M..r......)\+

Running strings on the binary found a few interesting things. Obviously, it’s using a lot of Crypt* functions, which confirms its capabilities. There’s also JFIF, which could indicate a JPEG file, and there is a .JPG filename in the unicode strings. The unicode strings also show some things that may indicate anti-RE elements. Since OutputDebugString is imported, it could be that these are debug messages, rather than output directly to the console.

$ gstrings DudeLocker.exe  | more
...snip...
OutputDebugStringW
FindResourceW
...snip...
CryptAcquireContextW
CryptReleaseContext
CryptDeriveKey
CryptDestroyKey
CryptSetKeyParam
CryptGetKeyParam
CryptGetHashParam
CryptEncrypt
CryptCreateHash
CryptHashData
CryptDestroyHash
...snip...
JFIF
...snip...
$ gstrings -el DudeLocker.exe  | more
Briefcase
\ve_vant_ze_money.jpg
Obviously you're not a reverse engineer...
I'm out of my element

Looking at some info about the file in radare2, it looks like JFIF is in the .rsrc section, which would go along with the theory that it’s a JPEG stored in a resource.

$ r2 DudeLocker.exe
[0x00401b80]> aaaa
[0x00401b80]> izz~JFIF
vaddr=0x00404066 paddr=0x00001866 ordinal=075 sz=5 len=4 section=.rsrc type=ascii string=JFIF
[0x00401b80]> iS
[Sections]
idx=00 vaddr=0x00401000 paddr=0x00000400 sz=3072 vsz=2956 perm=m-r-x name=.text
idx=01 vaddr=0x00402000 paddr=0x00001000 sz=1536 vsz=1390 perm=m-r-- name=.rdata
idx=02 vaddr=0x00403000 paddr=0x00001600 sz=512 vsz=250 perm=m-rw- name=.data
idx=03 vaddr=0x00404000 paddr=0x00001800 sz=136192 vsz=135776 perm=m-r-- name=.rsrc

4 sections

Running the file, doesn’t produce any output. But if we run it with the Sysinternals DebugView open, we can see one of the output strings.

No output when run

DebugView shows debug string output

Radare puts us in the entry0 function, which is a small stub with a call to sub.SHELL32.dll_SHGetFolderPathW_9a0 based on the auto-analysis. We can go into thus function and get a quick overview of what it’s doing by looking at all the "calls" it makes.

[0x00401b80]> s sub.SHELL32.dll_SHGetFolderPathW_9a0
[0x004019a0]> pdf~call
│           0x004019e3      ff1594204000   call dword [sym.imp.SHELL32.dll_SHGetFolderPathW] ; "N%" @ 0x402094 ; get User Desktop path
│       │   0x004019f4      ff1538204000   call dword [sym.imp.KERNEL32.dll_lstrlenW] ; "x#" @ 0x402038
│       │   0x00401a1a      e8e1f5ffff     call sym.buildPathToBriefcase
│       │   0x00401a3b      ff1588204000   call dword [sym.imp.KERNEL32.dll_CreateFileW] ; sym.imp.KERNEL32.dll_CreateFileW
│      ││   0x00401a4e      ff1560204000   call dword [sym.imp.KERNEL32.dll_CloseHandle] ; "F#" @ 0x402060
│     │ │   0x00401a61      ff1540204000   call dword [sym.imp.KERNEL32.dll_OutputDebugStringW] ; sym.imp.KERNEL32.dll_OutputDebugStringW
│     └───> 0x00401a6e      e8cdf5ffff     call sym.checkVolumeSerialNumber ; compares SN to 0x7dab1d35
│     │││   0x00401a87      ff1540204000   call dword [sym.imp.KERNEL32.dll_OutputDebugStringW] ; sym.imp.KERNEL32.dll_OutputDebugStringW
│    │ ││   0x00401aa1      ff157c204000   call dword [sym.imp.KERNEL32.dll_GetProcessHeap] ; sym.imp.KERNEL32.dll_GetProcessHeap
│    │ ││   0x00401aa8      ff1584204000   call dword [sym.imp.KERNEL32.dll_HeapAlloc] ; sym.imp.KERNEL32.dll_HeapAlloc
│    │ ││   0x00401ac2      e879feffff     call sym.decryptKeyString   ; fills seedData
│    │ ││   0x00401ada      e8a1f5ffff     call sym.generateEncryptionKey
│   ││ ││   0x00401aff      e8fcf7ffff     call sym.encryptFilesInFolder
│   │││││   0x00401b1a      ff1534204000   call dword [sym.imp.KERNEL32.dll_lstrcatW] ; "l#" @ 0x402034
│   │││││   0x00401b27      e8f4f6ffff     call sym.writeRansomImage
│   │││││   0x00401b2f      e8bcfbffff     call sym.getVersion
│  ││││││   0x00401b44      e8d7fdffff     call sym.setParameterInfo
│   ││ ││   0x00401b52      ff157c204000   call dword [sym.imp.KERNEL32.dll_GetProcessHeap] ; sym.imp.KERNEL32.dll_GetProcessHeap
│   ││ ││   0x00401b59      ff1580204000   call dword [sym.imp.KERNEL32.dll_HeapFree] ; sym.imp.KERNEL32.dll_HeapFree
│   ││ ││   0x00401b67      e8e4f5ffff     call sym.cleanUpCrypto

This is after I had done my analysis on the file. The steps of the ransomware are as follows:

  1. Determine path to %USERPROFILE%\Desktop\Briefcase.
  2. If this folder doesn’t exist, print debug message “Obviously you’re not a reverse engineer…” and exit.
  3. Compare the hard drive serial number to 0x7dab1d35
  4. If the serial number doesn’t match, print debug message “I’m out of my element” and exit.
  5. Using the hard drive serial number, decrypt 37 bytes of data at 0x403000.
  6. Generate an AES encryption key using the above decrypted string.
  7. Encrypt each file in the folder.
  8. Write the JPEG resource to the “Briefcase” folder and set it as the Desktop wallpaper.

Step 5, where the byte array is decrypted does the following. It basically divides the counter by 4 and uses the remainder to choose one of the bytes of the volume serial number, then XORs the current byte in the string with that value.

│      ││   0x0040195f      8b5508         mov edx, dword [ebp + encryptedKeyString] ; [0x8:4]=4
│      ││   0x00401962      0355fc         add edx, dword [ebp - counter]
│      ││   0x00401965      0fb60a         movzx ecx, byte [edx]       ; get current byte
│      ││   0x00401968      8b45fc         mov eax, dword [ebp - counter]
│      ││   0x0040196b      33d2           xor edx, edx
│      ││   0x0040196d      be04000000     mov esi, 4
│      ││   0x00401972      f7f6           div esi                     ; divide counter by 4
│      ││   0x00401974      8b4510         mov eax, dword [ebp + volumeSerialNumber] ; [0x10:4]=184
│      ││   0x00401977      0fb61410       movzx edx, byte [eax + edx] ; select a byte from VSN based on remainder or division
│      ││   0x0040197b      33ca           xor ecx, edx                ; XOR current byte with above value
│      ││   0x0040197d      8b450c         mov eax, dword [ebp + seedData] ; [0xc:4]=0xffff
│      ││   0x00401980      0345fc         add eax, dword [ebp - counter]
│      ││   0x00401983      8808           mov byte [eax], cl          ; store result in seedData
│      └──< 0x00401985      ebc7           jmp sym.incrementCounter

The byte array below gets decrypted to “thosefilesreallytiedthefoldertogether” and is stored in “seedData”. I was going to write a Python version of this, but figured it would be much easier to just run DudeLocker.exe in a debugger and break right after the decryption function was called.

[0x00401940]> px 37 @  0x403000
- offset -   0 1  2 3  4 5  6 7  8 9  A B  C D  E F  0123456789ABCDEF
0x00403000, 4175 c40e 507b c211 506e d918 5471 c704  Au..P{..Pn..Tq..
0x00403010, 4174 ce19 4175 ce1b 5a71 cf18 4769 c41a  At..Au..Zq..Gi..
0x00403020, 5069 c318 47                             Pi..G

Before sym.decryptKeyString:

before decrypting

After sym.decryptKeyString:

after decrypting

In Step 6, the CBC mode AES key object is generated. This uses the SHA1 hash of the decrypted string to generate the key.

[0x00401580]> s sym.generateEncryptionKey
[0x00401080]> pdf~call
│           0x00401097      ff151c204000   call dword [sym.imp.ADVAPI32.dll_CryptAcquireContextW] ; "l$" @ 0x40201c
│       │   0x004010a1      ff1578204000   call dword [sym.imp.KERNEL32.dll_GetLastError] ; sym.imp.KERNEL32.dll_GetLastError
│      ││   0x004010ba      ff151c204000   call dword [sym.imp.ADVAPI32.dll_CryptAcquireContextW] ; "l$" @ 0x40201c
│    │ │    0x004010e5      e896000000     call sym.deriveAESKey
│    ││││   0x00401104      ff1518204000   call dword [sym.imp.ADVAPI32.dll_CryptReleaseContext] ; sym.imp.ADVAPI32.dll_CryptReleaseContext
│    │││    0x0040111c      ff150c204000   call dword [sym.imp.ADVAPI32.dll_CryptSetKeyParam] ; sym.imp.ADVAPI32.dll_CryptSetKeyParam
│    ││││   0x00401132      e819000000     call sym.cleanUpCrypto
[0x00401080]> s sym.generateEncryptionKey
[0x00401080]> pdf
╒ (fcn) sym.generateEncryptionKey 196
│   sym.generateEncryptionKey (int phKey, int phProv, int seedData, int seedDataLength);
│           ; var int cipher_mode_CBC @ ebp-0x4
│           ; arg int phKey @ ebp+0x8
│           ; arg int phProv @ ebp+0xc
│           ; arg int seedData @ ebp+0x10
│           ; arg int seedDataLength @ ebp+0x14
│           ; CALL XREF from 0x00401ada (sym.main_start)
│           0x00401080      55             push ebp
│           0x00401081      8bec           mov ebp, esp
│           0x00401083      51             push ecx
│           0x00401084      c745fc010000.  mov dword [ebp - cipher_mode_CBC], 1
│           0x0040108b      6a00           push 0
│           0x0040108d      6a18           push 0x18                   ; "@" ; PROV_RSA_AES
│           0x0040108f      6a00           push 0
│           0x00401091      6a00           push 0
│           0x00401093      8b450c         mov eax, dword [ebp + phProv] ; [0xc:4]=0xffff
│           0x00401096      50             push eax
│           0x00401097      ff151c204000   call dword [sym.imp.ADVAPI32.dll_CryptAcquireContextW] ; "l$" @ 0x40201c
...snip...
│   └───└─> 0x004010ce      8b5514         mov edx, dword [ebp + seedDataLength] ; [0x14:4]=0
│    │ │    0x004010d1      52             push edx
│    │ │    0x004010d2      8b4510         mov eax, dword [ebp + seedData] ; [0x10:4]=184
│    │ │    0x004010d5      50             push eax
│    │ │    0x004010d6      6810660000     push 0x6610                 ; CALG_AES_256
│    │ │    0x004010db      8b4d0c         mov ecx, dword [ebp + phProv] ; [0xc:4]=0xffff
│    │ │    0x004010de      8b11           mov edx, dword [ecx]
│    │ │    0x004010e0      52             push edx
│    │ │    0x004010e1      8b4508         mov eax, dword [ebp + phKey] ; [0x8:4]=4
│    │ │    0x004010e4      50             push eax
│    │ │    0x004010e5      e896000000     call sym.deriveAESKey
...snip...
│    │││└─> 0x0040110e      6a00           push 0
│    │││    0x00401110      8d55fc         lea edx, [ebp - cipher_mode_CBC]
│    │││    0x00401113      52             push edx
│    │││    0x00401114      6a04           push 4                      ; KP_MODE
│    │││    0x00401116      8b4508         mov eax, dword [ebp + phKey] ; [0x8:4]=4
│    │││    0x00401119      8b08           mov ecx, dword [eax]
│    │││    0x0040111b      51             push ecx
│    │││    0x0040111c      ff150c204000   call dword [sym.imp.ADVAPI32.dll_CryptSetKeyParam] ; sym.imp.ADVAPI32.dll_CryptSetKeyParam
...snip...

[0x00401080]> s sym.deriveAESKey
[0x00401180]> pdf~call
│       │   0x004011ac      ff1500204000   call dword [sym.imp.ADVAPI32.dll_CryptCreateHash] ; sym.imp.ADVAPI32.dll_CryptCreateHash
│    ││ │   0x004011d4      ff1520204000   call dword [sym.imp.ADVAPI32.dll_CryptHashData] ; sym.imp.ADVAPI32.dll_CryptHashData
│    ││││   0x004011e2      ff1524204000   call dword [sym.imp.ADVAPI32.dll_CryptDestroyHash] ; ",%" @ 0x402024
│   │││ │   0x004011ff      ff1514204000   call dword [sym.imp.ADVAPI32.dll_CryptDeriveKey] ; sym.imp.ADVAPI32.dll_CryptDeriveKey
│   │││ │   0x00401211      ff1524204000   call dword [sym.imp.ADVAPI32.dll_CryptDestroyHash] ; ",%" @ 0x402024
[0x00401180]> pdf
╒ (fcn) sym.deriveAESKey 158
│   sym.deriveAESKey (int encryptionKey, int pointerToCryptoServProv, int algId_AES256, int seedData, int seedDataLength);
│           ; var int hHash @ ebp-0x8
│           ; var int deriveSuccess @ ebp-0x1
│           ; var int local_0h @ ebp-0x0
│           ; arg int encryptionKey @ ebp+0x8
│           ; arg int pointerToCryptoServProv @ ebp+0xc
│           ; arg int algId_AES256 @ ebp+0x10
│           ; arg int seedData @ ebp+0x14
│           ; arg int seedDataLength @ ebp+0x18
│           ; CALL XREF from 0x004010e5 (sym.generateEncryptionKey)
│           0x00401180      55             push ebp
│           0x00401181      8bec           mov ebp, esp
│           0x00401183      83ec08         sub esp, 8
...snip...
|      └──> ;-- sym.createHash:
│      └──> 0x0040119b      8d45f8         lea eax, [ebp - hHash]
│       │   0x0040119e      50             push eax
│       │   0x0040119f      6a00           push 0
│       │   0x004011a1      6a00           push 0
│       │   0x004011a3      6804800000     push 0x8004                 ; CALG_SHA1
│       │   0x004011a8      8b4d0c         mov ecx, dword [ebp + pointerToCryptoServProv] ; [0xc:4]=0xffff
│       │   0x004011ab      51             push ecx
│       │   0x004011ac      ff1500204000   call dword [sym.imp.ADVAPI32.dll_CryptCreateHash] ; sym.imp.ADVAPI32.dll_CryptCreateHash
...snip...
|    ││└──> ;-- sym.hashSeedData:
│    ││└──> 0x004011c6      6a00           push 0
│    ││ │   0x004011c8      8b5518         mov edx, dword [ebp + seedDataLength] ; [0x18:4]=64 ; "@"
│    ││ │   0x004011cb      52             push edx
│    ││ │   0x004011cc      8b4514         mov eax, dword [ebp + seedData] ; [0x14:4]=0
│    ││ │   0x004011cf      50             push eax
│    ││ │   0x004011d0      8b4df8         mov ecx, dword [ebp - hHash]
│    ││ │   0x004011d3      51             push ecx
│    ││ │   0x004011d4      ff1520204000   call dword [sym.imp.ADVAPI32.dll_CryptHashData] ; sym.imp.ADVAPI32.dll_CryptHashData
...snip...
|   │││└──> ;-- sym.deriveKeyUsingHash:
│   │││└──> 0x004011ed      8b4508         mov eax, dword [ebp + encryptionKey] ; [0x8:4]=4
│   │││ │   0x004011f0      50             push eax
│   │││ │   0x004011f1      6a01           push 1                      ; CRYPT_EXPORTABLE
│   │││ │   0x004011f3      8b4df8         mov ecx, dword [ebp - hHash]
│   │││ │   0x004011f6      51             push ecx
│   │││ │   0x004011f7      8b5510         mov edx, dword [ebp + algId_AES256] ; [0x10:4]=184
│   │││ │   0x004011fa      52             push edx
│   │││ │   0x004011fb      8b450c         mov eax, dword [ebp + pointerToCryptoServProv] ; [0xc:4]=0xffff
│   │││ │   0x004011fe      50             push eax
│   │││ │   0x004011ff      ff1514204000   call dword [sym.imp.ADVAPI32.dll_CryptDeriveKey] ; sym.imp.ADVAPI32.dll_CryptDeriveKey

In Step 7, each file in the “Briefcase” folder is iterated over, and folders are entered recursively. For each file, the filename is converted to lowercase then from WideChar to MultiByte, then the MD5 of this format of the filename is taken. This MD5 hash is used as the initialization vector for encrypting the file.

│   ││└───> 0x00401af0      8d95c0fdffff   lea edx, [ebp - str_pathToBriefcase]
│   ││ ││   0x00401af6      52             push edx
│   ││ ││   0x00401af7      8d45ec         lea eax, [ebp - ptr_CryptoServiceProvider]
│   ││ ││   0x00401afa      50             push eax
│   ││ ││   0x00401afb      8d4de8         lea ecx, [ebp - encryptionKey]
│   ││ ││   0x00401afe      51             push ecx
│   ││ ││   0x00401aff      e8fcf7ffff     call sym.encryptFilesInFolder
[0x00401aa0]> s sym.encryptFilesInFolder
[0x00401300]> pdf~call
│           0x0040132b      ff1530204000   call dword [sym.imp.KERNEL32.dll_lstrcpyW] ; "`#" @ 0x402030
│           0x0040133c      ff1534204000   call dword [sym.imp.KERNEL32.dll_lstrcatW] ; "l#" @ 0x402034
│           0x00401350      ff154c204000   call dword [sym.imp.KERNEL32.dll_FindFirstFileW] ; sym.imp.KERNEL32.dll_FindFirstFileW
│     ││    0x00401379      ff1548204000   call dword [sym.imp.KERNEL32.dll_lstrcpynW] ; "T#" @ 0x402048
│     ││    0x00401394      e8f7050000     call sym.checkIfFolder      ; checks dwAttributes of FindFileData to indicate a directory
│    ││││   0x004013ca      e831fcffff     call sym.buildPathToBriefcase
│    ││││   0x004013e1      e81affffff     call sym.encryptFilesInFolder ; recursively encrypt files in subdirs
│   │ ││    0x00401403      e888050000     call sym.checkIfFolder
│   │ │││   0x00401428      e8d3fbffff     call sym.buildPathToBriefcase
│   │ │││   0x00401437      ff1538204000   call dword [sym.imp.KERNEL32.dll_lstrlenW] ; "x#" @ 0x402038
│   │ │││   0x0040144a      ff159c204000   call dword [sym.imp.USER32.dll_CharLowerW] ; ":$" @ 0x40209c
│   │ │││   0x00401456      ff157c204000   call dword [sym.imp.KERNEL32.dll_GetProcessHeap] ; sym.imp.KERNEL32.dll_GetProcessHeap
│   │ │││   0x0040145d      ff1584204000   call dword [sym.imp.KERNEL32.dll_HeapAlloc] ; sym.imp.KERNEL32.dll_HeapAlloc
│   │││││   0x00401474      e8b7020000     call sym.zeroOutBuffer
│   │ │││   0x00401497      ff155c204000   call dword [sym.imp.KERNEL32.dll_WideCharToMultiByte] ; sym.imp.KERNEL32.dll_WideCharToMultiByte
│   │ │││   0x004014ad      e8be020000     call sym.setIVToFilenameMD5
│   │││││   0x004014cb      e830000000     call sym.encryptFile
│ │   ││    0x004014e9      ff1550204000   call dword [sym.imp.KERNEL32.dll_FindNextFileW] ; sym.imp.KERNEL32.dll_FindNextFileW
[0x00401500]> s sym.setIVToFilenameMD5
[0x00401770]> pdf~call
│           0x0040179d      ff1508204000   call dword [sym.imp.ADVAPI32.dll_CryptGetKeyParam] ; sym.imp.ADVAPI32.dll_CryptGetKeyParam ; get block length in bits
│       │   0x004017b3      e898f9ffff     call sym.cleanUpCrypto
│      │    0x004017d1      ff157c204000   call dword [sym.imp.KERNEL32.dll_GetProcessHeap] ; sym.imp.KERNEL32.dll_GetProcessHeap
│      │    0x004017d8      ff1584204000   call dword [sym.imp.KERNEL32.dll_HeapAlloc] ; sym.imp.KERNEL32.dll_HeapAlloc
│      ││   0x004017f7      e854f9ffff     call sym.cleanUpCrypto
│     ││    0x00401810      e81bffffff     call sym.zeroOutBuffer
│     ││    0x0040182b      ff1500204000   call dword [sym.imp.ADVAPI32.dll_CryptCreateHash] ; sym.imp.ADVAPI32.dll_CryptCreateHash
│   ││││    0x00401887      ff1520204000   call dword [sym.imp.ADVAPI32.dll_CryptHashData] ; sym.imp.ADVAPI32.dll_CryptHashData
│   │││││   0x00401895      ff1524204000   call dword [sym.imp.ADVAPI32.dll_CryptDestroyHash] ; ",%" @ 0x402024
│  │││││    0x004018b8      ff1504204000   call dword [sym.imp.ADVAPI32.dll_CryptGetHashParam] ; sym.imp.ADVAPI32.dll_CryptGetHashParam
│ ││││││    0x004018d6      ff150c204000   call dword [sym.imp.ADVAPI32.dll_CryptSetKeyParam] ; sym.imp.ADVAPI32.dll_CryptSetKeyParam
│ │││││││   0x004018e8      ff157c204000   call dword [sym.imp.KERNEL32.dll_GetProcessHeap] ; sym.imp.KERNEL32.dll_GetProcessHeap
│ │││││││   0x004018ef      ff1580204000   call dword [sym.imp.KERNEL32.dll_HeapFree] ; sym.imp.KERNEL32.dll_HeapFree
│ │││││││   0x00401901      e84af8ffff     call sym.cleanUpCrypto
│ ││││││    0x00401911      ff1524204000   call dword [sym.imp.ADVAPI32.dll_CryptDestroyHash] ; ",%" @ 0x402024
[0x00401770]> s sym.encryptFile
[0x00401500]> pdf~call
│           0x0040153f      ff1508204000   call dword [sym.imp.ADVAPI32.dll_CryptGetKeyParam] ; sym.imp.ADVAPI32.dll_CryptGetKeyParam ; getBlockLength
│       │   0x00401555      e8f6fbffff     call sym.cleanUpCrypto
│      │    0x004015ae      ff1588204000   call dword [sym.imp.KERNEL32.dll_CreateFileW] ; sym.imp.KERNEL32.dll_CreateFileW
│     ││    0x004015ca      ff156c204000   call dword [sym.imp.KERNEL32.dll_GetFileSize] ; " #" @ 0x40206c
│    │││    0x004015f4      ff1588204000   call dword [sym.imp.KERNEL32.dll_CreateFileW] ; sym.imp.KERNEL32.dll_CreateFileW
│   ││││    0x00401611      ff157c204000   call dword [sym.imp.KERNEL32.dll_GetProcessHeap] ; sym.imp.KERNEL32.dll_GetProcessHeap
│   ││││    0x00401618      ff1584204000   call dword [sym.imp.KERNEL32.dll_HeapAlloc] ; sym.imp.KERNEL32.dll_HeapAlloc
│  ││││││   0x0040163f      ff1564204000   call dword [sym.imp.KERNEL32.dll_ReadFile] ; ":#" @ 0x402064
│  ││││││   0x00401672      ff1528204000   call dword [sym.imp.ADVAPI32.dll_CryptEncrypt] ; sym.imp.ADVAPI32.dll_CryptEncrypt
│  ││││││   0x00401690      ff1568204000   call dword [sym.imp.KERNEL32.dll_WriteFile] ; ".#" @ 0x402068
│     │││   0x004016b2      ff1560204000   call dword [sym.imp.KERNEL32.dll_CloseHandle] ; "F#" @ 0x402060
│     │││   0x004016c2      ff1560204000   call dword [sym.imp.KERNEL32.dll_CloseHandle] ; "F#" @ 0x402060
│     │││   0x004016d4      ff157c204000   call dword [sym.imp.KERNEL32.dll_GetProcessHeap] ; sym.imp.KERNEL32.dll_GetProcessHeap
│     │││   0x004016db      ff1580204000   call dword [sym.imp.KERNEL32.dll_HeapFree] ; sym.imp.KERNEL32.dll_HeapFree

Step 8 writes the following image to “Briefcase” and sets it as the Desktop wallpaper:

ransom note

This level of analysis was overkill for this challenge, but I wanted to get more practice with Radare2, so I tried to document everything I could in the EXE since it was pretty straightforward. In the end, to do the decryption, we need to create an AES key using the SHA1 hash of “thosefilesreallytiedthefoldertogether” as the shared secret and the MD5 hash of the lowercase of the filename as the initialization vector.

I tried using the built in python Cipher libraries, but they only support a key length of 16, 24, and 32 bytes, and a SHA1 hash is 20 bytes. I found the wincrypto library. The builtin decrypt function uses an IV = ‘\0’ * 16 so I had to call it manually. This was the python script I ended up using.

#!/usr/bin/python

from Crypto.Cipher import AES
from wincrypto import CryptCreateHash, CryptHashData, CryptDeriveKey
from wincrypto.constants import CALG_SHA1, CALG_AES_256
import hashlib
import binascii
import sys

# read in the file
filename = sys.argv[1]
f = open(filename, 'r')
data_enc = f.read()

# decrypt the secret used for the AES key
key_str_enc = "4175c40e507bc211506ed9185471c7044174ce194175ce1b5a71cf184769c41a5069c31847"
key_str_enc = binascii.a2b_hex(key_str_enc)
vsn = "351dab7d"
vsn = binascii.a2b_hex(vsn)
key_str_dec = ""

# divide the counter by 4 and use the remainder to determine which byte of the VSN to use for XOR
for i in range(0, len(key_str_enc)):
    remain = (i % 4)
    key_str_dec += chr(ord(key_str_enc[i]) ^ ord(vsn[remain]))

# hash secret and create the key
sha1_hasher = CryptCreateHash(CALG_SHA1)
CryptHashData(sha1_hasher, key_str_dec)
aes_key = CryptDeriveKey(sha1_hasher, CALG_AES_256)

# get the hash of the filename to create the IV
m = hashlib.md5()
m.update(filename.lower())
iv = m.hexdigest()
iv = binascii.a2b_hex(iv)

# decrypt the file data
data_dec = AES.new(aes_key.key, mode=AES.MODE_CBC, IV=iv).decrypt(data_enc)

# write out the file
fo = open(filename + ".out", 'wb')
fo.write(data_dec)
fo.close()
$ python DudeUnlocker.py BusinessPapers.doc
$ file BusinessPapers.doc*
BusinessPapers.doc:     data
BusinessPapers.doc.out: JPEG image data, JFIF standard 1.01

challenge 2 answer

I was going to share my radare2 project file, but somehow it got corrupted and lost all my work. Luckily, I had r2 open in another window and was able to save a working copy of the project from that one. Definitely learned to make backup copies based on this experience. Also, don’t hit Ctrl-D to exit out. It wrecks the project file.