Newport Blake CTF 2023
Itchy Scratchy [464 pts]
Challenge Description:
Yeah sorry, I couldn’t resist. Use Turbowarp if you want.
Head over to Turbowarp and load the Scratch file in. Let’s take a look inside.
Immediately, you can observe two sections of code. One in the sprite aatrox
and one in the Backdrop.
Here’s the sprite’s code:
And here’s the backdrop’s code:
Let’s first take a look at the sprite code. Immediately, we observe that our first answer must be isaac newton
.
Following our answer, the letter #, i.e. the index (1-based index) of each letter of answer
in alpha
is added to name
. (Take a look at the code itself if you’re confused by the explanation). But wait… where are alpha
and name
?
Fortunately, I remembered from a while ago where lists were located in Scratch, and quickly navigated to the Variables
section of the left-hand code blocks panel. There, I checked each of the lists and rearranged them on screen so they were all visible. input
and name
were initially empty, until I ran the program and put in isaac newton
, which filled in name
for me. I assumed these lists might be useful somehow, so I exported them all by right-clicking on each list and clicking Export
.
Now that the sprite’s code is essentially finished, let’s take a look at the backdrop’s code.
Immediately, we can observe that it is asking us to input a flag, as the answer should start with nbctf{
and end with }
.
Then, we enter 2 for loops, one after the other.
The first one adds the 1-based index of each letter of answer
in alpha
(not including the flag prefix and suffix) to input
.
The second loop seems to be where the main logic is happening. I simply reversed the code in Python at this point to figure out what it was doing:
enc = [902,764,141,454,207,51,532,1013,496,181,562,342]
alpha = ["z","v","t","w","r","c","a","5","7","n","4","9","u","2","b","y","1","j","d","q","o","6","g","0","k","s","x","f","i","8","p","e","l","m","h","3"]
name = [29,26,7,7,6,0,10,32,4,3,21,10]
for i in range(1, 13):
j = ((i)**2 + name[i - 1]) % len(name) + 1
rightside = enc[i - 1] - name[i - 1] * name[j - 1]
print(f'inp[{i - 1}] * inp[{j - 1}] = {rightside}')
Basically, I just printed out what the program was testing. This actually created a system of equations as follows:
inp[0] * inp[6] = 612
inp[1] * inp[6] = 504
inp[2] * inp[4] = 99
inp[3] * inp[11] = 384
inp[4] * inp[7] = 15
inp[5] * inp[0] = 51
inp[6] * inp[11] = 432
inp[7] * inp[0] = 85
inp[8] * inp[1] = 392
inp[9] * inp[7] = 85
inp[10] * inp[10] = 121
inp[11] * inp[10] = 132
At this point, I immediately thought of z3. But, after failing to use z3 (I had never used it before), I realized I could probably pretty easily brute force this! Staring with the 2nd to last equation, it is trivial to brute force all the values:
inp[0] * inp[6] = 612 # inp[0] = 17
inp[1] * inp[6] = 504 # inp[1] = 14
inp[2] * inp[4] = 99 # inp[2] = 33
inp[3] * inp[11] = 384 # inp[3] = 32
inp[4] * inp[7] = 15 # inp[4] = 3
inp[5] * inp[0] = 51 # inp[5] = 3
inp[6] * inp[11] = 432 # inp[6] = 36
inp[7] * inp[0] = 85 # inp[7] = 5
inp[8] * inp[1] = 392 # inp[8] = 28
inp[9] * inp[7] = 85 # inp[9] = 17
inp[10] * inp[10] = 121 # inp[10] = 11
inp[11] * inp[10] = 132 # inp[11] = 12
Thus, knowing the values of input
, it becomes trivial to reverse the first Scratch for loop to get the flag!
inp = [0] * 12
inp[0] = 17
inp[1] = 14
inp[2] = 33
inp[3] = 32
inp[4] = 3
inp[5] = 3
inp[6] = 36
inp[7] = 5
inp[8] = 28
inp[9] = 17
inp[10] = 11
inp[11] = 12
[print(alpha[i - 1], end='') for i in inp]
Wrap the result in nbctf{}
to get:
nbctf{12lett3rf149}