|
| 1 | +--- |
| 2 | +title: "ångstromCTF lithp" |
| 3 | +author: "Lyell Read" |
| 4 | +date: 2019-04-26T00:00:00-07:00 |
| 5 | +categories: ['Writeups'] |
| 6 | +tags: ['angstromctf'] |
| 7 | +caption: "" |
| 8 | + |
| 9 | +draft: false |
| 10 | +--- |
| 11 | + |
| 12 | +## Problem |
| 13 | + |
| 14 | +My friend gave me [this](https://github.com/lyellread/ctf-writeups/blob/master/angstromctf-2019/lithp-60/lithp.lisp) program but I couldn’t understand what he was saying – what was he trying to tell me? |
| 15 | + |
| 16 | +Author: fireholder |
| 17 | + |
| 18 | +Points: 60 |
| 19 | + |
| 20 | +## Solution |
| 21 | + |
| 22 | +First things first, let’s open that lisp program . . . It actually is lisp… oh god what have I just gotten into? |
| 23 | + |
| 24 | +The first lines were most important in solving this challenge the way I did it. It reads: |
| 25 | + |
| 26 | +``` |
| 27 | +(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)) |
| 28 | +(defparameter *flag* '(redacted)) |
| 29 | +(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)) |
| 30 | +``` |
| 31 | + |
| 32 | +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: |
| 33 | + |
| 34 | +``` |
| 35 | +flag: 97 99 116 102 123 ... 125 |
| 36 | +encrypt flag |
| 37 | +for entry[i] in encrypted_flag: place that element at output[reorder[i]] |
| 38 | +``` |
| 39 | + |
| 40 | +Now we need to try to unjumble this. I wrote up this mess to do that: |
| 41 | + |
| 42 | +``` |
| 43 | +#!/usr/bin/python |
| 44 | +
|
| 45 | +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] |
| 46 | +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] |
| 47 | +output = [] |
| 48 | +
|
| 49 | +for item in range (0, max(positions) + 1): |
| 50 | + index = positions.index(item) #get the index in values of element number item |
| 51 | + output.append(values[index]) #place that at the end of the output list |
| 52 | +
|
| 53 | +print (output) |
| 54 | + |
| 55 | +$python3 ./undo_reorder.py |
| 56 | +[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] |
| 57 | +``` |
| 58 | + |
| 59 | +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 ‘}’… |
| 60 | + |
| 61 | +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’): |
| 62 | + |
| 63 | +``` |
| 64 | +>>>9312/97 |
| 65 | +96 |
| 66 | +``` |
| 67 | + |
| 68 | +…interesting. Another: 15006 which should correspond to ‘{‘ or ASCII 123: |
| 69 | + |
| 70 | +``` |
| 71 | +>>>15006/123 |
| 72 | +122 |
| 73 | +``` |
| 74 | + |
| 75 | +OK. So the algorithm to encrypt the flag is just: |
| 76 | + |
| 77 | +``` |
| 78 | +for x in flag: |
| 79 | + code = ascii value of x |
| 80 | + encrypted_value = code * (code-1) |
| 81 | +``` |
| 82 | + |
| 83 | +Now we can complete the script: |
| 84 | + |
| 85 | +``` |
| 86 | +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] |
| 87 | +
|
| 88 | +letters = [] |
| 89 | +decoded = [] |
| 90 | +solved = [] |
| 91 | +
|
| 92 | +for ascii in range (0, 128): |
| 93 | + 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. |
| 94 | +
|
| 95 | +for x in sorted: |
| 96 | + if x in letters: |
| 97 | + decoded.append(letters.index(x)) #create a decoded array of values |
| 98 | +
|
| 99 | +for x in decoded: |
| 100 | + solved.append(chr(x)) #convert to chars |
| 101 | +
|
| 102 | +print (''.join(solved)) #print that flag |
| 103 | +``` |
| 104 | + |
| 105 | +These two scrips together make up [decode_lithp.py](https://github.com/lyellread/ctf-writeups/blob/master/angstromctf-2019/lithp-60/decode_lithp.py). |
| 106 | + |
| 107 | +``` |
| 108 | +$python3 ./undo_encrypt.py |
| 109 | +actf{help_me_I_have_a_lithp} |
| 110 | +``` |
0 commit comments