Solve time: 91 mins
Flag: [email protected]
This challenge was a nice little ransomware decryption challenge. I completed this challenge statically which I am proud of (too lazy to install a windows VM).
Once I unpacked the chall zip, I was presented with a folder called Files
and a file called UnlockYourFiles.exe
.
Running file on the binary showed me it was a windows binary.
UnlockYourFiles.exe: PE32 executable (console) Intel 80386, for MS Windows
The crux of the chall was realizing we could guess the xor key by realizing that latin_alphabet.txt.encrypted
is 26 bytes so probably one byte for each letter of the alphabet. I was able to confirm this guess by using it the key to decrypt the rest of the file. The xor decryption routine only operated on 8 bytes at a time. Here’s the xor decryption routine pseudcode:
1004011f0 void do_xor(int32_t arg1, int32_t arg2)
2
3004011f0 {
4004011f0 int32_t ebx;
5004011f3 int32_t var_8 = ebx;
6004011fc char* ecx = nullptr;
7004011fc
800401201 while (ecx < 8)
900401201 {
1000401201 ebx = ecx[arg2];
110040120f ecx[arg1] = ROLB(ecx[arg1] ^ ebx, ecx) - ecx;
1200401212 ecx += 1;
1300401201 }
14004011f0 }
Where arg1 is the encrypted buf and arg2 is the key.
I rewrote the algorithm in python:
1def decrypt(buf,key):
2 ecx = 0
3 ebx = 0
4
5 while ecx < 8:
6 ebx = key[ecx]
7 buf[ecx] = rol(buf[ecx] ^ ebx,ecx) - ecx
8 ecx += 1
I then wrote a key search function based on the idea that we knew the original contents of latin_alphabet.txt.encrypted
.
1with open("Files/latin_alphabet.txt.encrypted","rb") as file:
2 bvar = file.read()
3
4known_cipher = "ABCDEFGH"
5
6def solve_for_key(buf):
7 key = []
8 for ecx in range(8):
9 for k in range(255):
10 ebx = k
11 out = rol(buf[ecx] ^ ebx,ecx) - ecx
12 if out == ord(known_cipher[ecx]):
13 key.append(k)
14
15 return key
16key = solve_for_key(bvar)
17print(key)
I started with lowercase “abcdefgh” but it didn’t work so I swapped it for “ABCDEFGH” and then it worked. It took me a while to correctly implement rol in python. Got confused between hex and dec conversions and how to handle the high bits.
My decryption routine worked on text until it got to the encrypted images and then it would totally break. I realized it was a bug in my sub instruction implementation. The assembly sub instructions wraps around when it goes negative my python implementation did not. So I added:
1can = l - ecx
2if can < 0:
3 can = 255 + (l - ecx)
4out.append(can)
Which was still wrong! It should be 256.
1can = l - ecx
2if can < 0:
3 can = 256 + (l - ecx)
4out.append(can)
And then I could decrypt the images as well!
Final solve script
1import glob
2with open("Files/latin_alphabet.txt.encrypted","rb") as file:
3 bvar = file.read()
4
5print(len(bvar))
6
7known_cipher = "ABCDEFGH"
8
9
10
11def rol(val,shift):
12 return (val << shift | ((val >> (8 - shift)) )) & 0xFF
13
14def decrypt(buf,key,length=8):
15 out = []
16 ecx = 0
17 ebx = 0
18
19 while ecx < length:
20 ebx = key[ecx]
21 l = rol(buf[ecx] ^ ebx,ecx)
22 can = l - ecx
23 if can < 0:
24 can = 256 + (l - ecx)
25 out.append(can)
26
27 ecx += 1
28
29 return out
30
31
32assert rol(0x26,4) == 0x62
33
34
35def solve_for_key(buf):
36 key = []
37 for ecx in range(8):
38 for k in range(255):
39 ebx = k
40 out = rol(buf[ecx] ^ ebx,ecx) - ecx
41 if out == ord(known_cipher[ecx]):
42 key.append(k)
43
44 return key
45
46def apply_key(buf,key):
47 no_bufs = len(buf) // 8
48 out = []
49 for i in range(no_bufs):
50 start = i*8
51 end = i*8+8
52 s = buf[start:end]
53 p = decrypt(s,key)
54 out.extend(p)
55
56
57 r_len = (len(buf) // 8) *8
58 l = len(buf)
59 # decrypt last bit
60 if r_len != l:
61 diff = l- r_len
62 s = buf[r_len:]
63 p = decrypt(s,key,diff)
64 out.extend(p)
65
66 return out
67
68key = solve_for_key(bvar)
69print("keylen:",len(key))
70
71def decrypt_file(path):
72 with open(path,"rb") as file:
73 bvar = file.read()
74
75 decrypted_path = path[:-10]
76
77 pvar = apply_key(bvar,key)
78
79
80
81 with open(decrypted_path,"wb") as file:
82 file.write(bytes(pvar))
83
84
85
86for file in glob.glob("Files/*.encrypted"):
87 print(file)
88 decrypt_file(file)
Bling Bling
> python3 solve.py
26
keylen: 8
Files/critical_data.txt.encrypted
Files/cicero.txt.encrypted
Files/commandovm.gif.encrypted
Files/capa.png.encrypted
Files/flarevm.jpg.encrypted
Files/latin_alphabet.txt.encrypted
> cat critical_data.txt
(>0_0)> [email protected] <(0_0<)