ångstromCTF lithp
Lyell Read
Tags
Problem
My friend gave me this program but I couldn’t understand what he was saying – what was he trying to tell me?
Author: fireholder
Points: 60
Solution
First things first, let’s open that lisp program . . . It actually is lisp… oh god what have I just gotten into?
The first lines were most important in solving this challenge the way I did it. It reads:
(defparameter *encrypted* '(8930 15006 8930 10302 11772 13806 13340 11556 12432 13340 10712 10100 11556 12432 9312 10712 10100 10100 8930 10920 8930 5256 9312 9702 8930 10712 15500 9312))
(defparameter *flag* '(redacted))
(defparameter *reorder* '(19 4 14 3 10 17 24 22 8 2 5 11 7 26 0 25 18 6 21 23 9 13 16 1 12 15 27 20))
Well, then. Given that I do not want to read more lisp than I have to (lest I end up depressed), let’s try to make some sense just based on those variables. With quite a bit of certainty, it appears that reorder is as it is named – an array of indexes that will reorder something. My guess is that it is applied like this:
flag: 97 99 116 102 123 ... 125
encrypt flag
for entry[i] in encrypted_flag: place that element at output[reorder[i]]
Now we need to try to unjumble this. I wrote up this mess to do that:
#!/usr/bin/python
positions = [19, 4, 14, 3, 10, 17, 24, 22, 8, 2, 5, 11, 7, 26, 0, 25, 18, 6, 21, 23, 9, 13, 16, 1, 12, 15, 27, 20]
values = [8930, 15006, 8930, 10302, 11772, 13806, 13340, 11556, 12432, 13340, 10712, 10100, 11556, 12432, 9312, 10712, 10100, 10100, 8930, 10920, 8930, 5256, 9312, 9702, 8930, 10712, 15500, 9312]
output = []
for item in range (0, max(positions) + 1):
index = positions.index(item) #get the index in values of element number item
output.append(values[index]) #place that at the end of the output list
print (output)
$python3 ./undo_reorder.py
[9312, 9702, 13340, 10302, 15006, 10712, 10100, 11556, 12432, 8930, 11772, 10100, 8930, 5256, 8930, 10712, 9312, 13806, 10100, 8930, 9312, 8930, 11556, 10920, 13340, 10712, 12432, 15500]
Apparently, that should be in the right order. Let’s think about it with ASCII on the mind, we should have ‘actf{…}’. Looks about right with two very similar values in the spots where we would expect ‘{‘ and ‘}’…
But those aren’t ASCII! yeah, but they are transformations of ascii values. It cannot be a scalar that is added to the ASCII values of the respective flag characters, as the ‘{‘ and ‘}’ values would have to be 2 apart (‘{‘ = 123, ‘}’ = 125). There could be a scalar value that all the ASCII codes are multiplied by. Let’s check that first value, 9312, which should be related to ASCII 97 (‘a’):
>>>9312/97
96
…interesting. Another: 15006 which should correspond to ‘{‘ or ASCII 123:
>>>15006/123
122
OK. So the algorithm to encrypt the flag is just:
for x in flag:
code = ascii value of x
encrypted_value = code * (code-1)
Now we can complete the script:
sorted = [9312, 9702, 13340, 10302, 15006, 10712, 10100, 11556, 12432, 8930, 11772, 10100, 8930, 5256, 8930, 10712, 9312, 13806, 10100, 8930, 9312, 8930, 11556, 10920, 13340, 10712, 12432, 15500]
letters = []
decoded = []
solved = []
for ascii in range (0, 128):
letters.append(ascii*(ascii-1)) #create an array of all ascii values such that the index is the original value, and the value at that index is the encoded value.
for x in sorted:
if x in letters:
decoded.append(letters.index(x)) #create a decoded array of values
for x in decoded:
solved.append(chr(x)) #convert to chars
print (''.join(solved)) #print that flag
These two scrips together make up decode_lithp.py.
$python3 ./undo_encrypt.py
actf{help_me_I_have_a_lithp}