Cover photo by https://unsplash.com/@invent
Scenario
“You are after an organised crime group which is responsible for the illegal weapon market in your country. As a secret agent, you have infiltrated the group enough to be included in meetings with clients. During the last negotiation, you found one of the confidential messages for the customer. It contains crucial information about the delivery. Do you think you can decrypt it?” - HTB challenge
Let’s begin
We’re given two files from the zip file, msg.enc and chall.py.
The content of the msg.enc
The content of the chall.py
It seems like the encryption algorithm used to generate msg.enc. There we can see that MSG is imported from the “secret” which we are trying to recover. If you take a closer look into the encryption function, there is a modulo operation used, which indicates that it is impossible to make a symmetrical decrypting equation (well, at least in my head).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
import string
# from secret import MSG
def encryption(msg):
ct = []
for char in msg:
ct.append((123 * char + 18) % 256)
return bytes(ct)
#ct = encryption(MSG)
# f = open('./msg.enc','w')
# f.write(ct.hex())
# f.close()
sample1 = b'a'
sample2 = b'ab'
ct1 = encryption(sample1)
ct2 = encryption(sample2)
print(ct1.hex())
print(ct2.hex())
|
Modified some codes to see how this works.
The output:
1
2
|
ad # from b'a'
ad28 # from b'ab'
|
This encryption algorithm takes each bytes in the string, does some maths, and prints out in the ‘double digit’ hex format.
‘a’ -> ‘ad’,
‘b’ -> ‘28’
With knowing all these, one thing we can try is to map all printable characters to those encrypted hex outputs. At the end, we can split the encrypted message by chunk of two bytes and use the map to convert those back to plain text.
Example:
secret = 6e0a9372ec49a3
6e0a9372ec49a3 -> 6e|0a|93|72|ec|49|a3 -> map[‘62’], map[‘0a’], map[‘93’], map[‘72’] …
Decryption code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
import string
def createMap(msg):
MAP = dict()
for char in msg:
enc = (123 * char + 18) % 256
ct = hex(enc)[2:].zfill(2) # Just in case if the hex is only one digit. ex) 0xa > 0x0a
MAP[ct] = chr(char)
return MAP
S = string.printable.encode() # Assign all printable characters in byte format to variable 'S'
MAP = createMap(S)
secret = input('\nEnter encrypted message:\n\n')
print('\n\nRecovered message:\n')
for i in range(0, len(secret), 2):
ct = secret[i:i+2]
print(MAP[ct], end='')
print()
|
Content of MAP
variable above:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
|
22 -> 0
9d -> 1
18 -> 2
93 -> 3
0e -> 4
89 -> 5
04 -> 6
7f -> 7
fa -> 8
75 -> 9
ad -> a
28 -> b
a3 -> c
1e -> d
99 -> e
14 -> f
8f -> g
0a -> h
85 -> i
00 -> j
7b -> k
f6 -> l
71 -> m
ec -> n
67 -> o
e2 -> p
5d -> q
d8 -> r
53 -> s
ce -> t
49 -> u
c4 -> v
3f -> w
ba -> x
35 -> y
b0 -> z
4d -> A
c8 -> B
43 -> C
be -> D
39 -> E
b4 -> F
2f -> G
aa -> H
25 -> I
a0 -> J
1b -> K
96 -> L
11 -> M
8c -> N
07 -> O
82 -> P
fd -> Q
78 -> R
f3 -> S
6e -> T
e9 -> U
64 -> V
df -> W
5a -> X
d5 -> Y
50 -> Z
ed -> !
68 -> "
e3 -> #
5e -> $
d9 -> %
54 -> &
cf -> '
4a -> (
c5 -> )
40 -> *
bb -> +
36 -> ,
b1 -> -
2c -> .
a7 -> /
f0 -> :
6b -> ;
e6 -> <
61 -> =
dc -> >
57 -> ?
d2 -> @
cb -> [
46 -> \
c1 -> ]
3c -> ^
b7 -> _
32 -> `
2b -> {
a6 -> |
21 -> }
9c -> ~
72 ->
65 ->
e0 ->
51 ->
5b ->
d6 ->
|
Result:
The nuclear will arrive on friday.
And we got the flag.
HTB{l00k_47_y0u_r3v3rs1ng_3qu4710n5_c0ngr475}