Gone with the wind, can you find my flag?
ncat --ssl without-a-trace.chal.uiuc.tf 1337
Here’s the Python source:
1 | import numpy as np |
First blooded this challenge!
Here’s a quick outline of the key observations to make about check()
:
- We control only the diagonals – every other cell of the matrix is 0
- Because of the above property of the matrix,
check()
will only add tores
when the permutation is in sorted/original order. (any other permutation will result in at least 2 cells filled with a 0, and since it’s multiplication,curr
will be 0) sign(sigma)
is constant sincesigma
can only be the ascending order of[0,1,2,3,4]
.- Therefore,
check()
just confirms none of the user-inputted cells are 0 – if one of them was 0, the sorted permutation also wouldn’t work by the same logic explained above.
Now explaining fun()
:
- The diagonals are filled with numbers calculated from the flag bytes.
- The flag matrix is multiplied by the user-input-controlled matrix.
- The sum of all the cells of the matrix are provided to the user.
- Because of the shape of the flag matrix and the user-input-controlled matrix, the matrix will look like this:
1 | [ |
So the server essentially gives us the dot product of two vectors, one filled with the flag numbers and one filled with our input numbers, in order.
Since we can query the server multiple times (by just connecting multiple times), we can just send an initial [1,1,1,1,1]
and then send [2,1,1,1,1]
, [1,2,1,1,1]
, etc. This will give us a nice system of equations where we can subtract, for example, the result of [1,1,1,1,1]
from [2,1,1,1,1]
to calculate the first flag number. Then we run long_to_bytes()
on each flag number to calculate the entire flag!
1 | from pwn import * |
uiuctf{tr4c1ng_&&_mult5!}