Thursday, July 11, 2019

# Asis CTF Quals 2019 - A delicious soup

Hi everyone! C:

This is a crypto challenge that I enjoyed a lot and I wanted to make my first blog post on my blog with this writeup, so finally now I have it :D

## So basically we have…

This is the flag encrypted:

``````11d.3ilVk_d3CpIO_4nlS.ncnz3e_0S}M_kn5scpm345n3nSe_u_S{iy__4EYLP_aAAall
``````

and this is the code that encrypted that:

``````import random
from flag import flag

def encrypt(msg, perm):
W = len(perm)
while len(msg) % (2*W):
msg += "."
msg = msg[1:] + msg[:1]
msg = msg[0::2] + msg[1::2]
msg = msg[1:] + msg[:1]
res = ""
for j in xrange(0, len(msg), W):
for k in xrange(W):
res += msg[j:j+W][perm[k]]
msg = res
return msg

def encord(msg, perm, l):
for _ in xrange(l):
msg = encrypt(msg, perm)
return msg

W, l = 7, random.randint(0, 1337)
perm = range(W)
random.shuffle(perm)

enc = encord(flag, perm, l)
f = open('flag.enc', 'w')
f.write(enc)
f.close()
``````

We need to reverse this code and create a decrypt function.

## Reversing…

• So, first let’s look at the starting lines: we have a random list from 0 to 6 and a random number from 0 to 1337;
• The `encord` function call `encrypt` function L(random number(0,1337)) times;
• In the `encrypt` function, the first `while` will just add 2 points on encrypted flag;
• The `msg[1:] + msg[:1]` will put the first char at the end;
• The `msg[0::2] + msg[1::2]` will split the `msg` and zip;
• The `msg[1:] + msg[:1]` will put the first char back at the end again;
• The last double `for` will shuffle the `msg` with the random list logic.

## Solution…

The weakness of this crypto is that the key(The random list) has 5040 possibilities, so we just need to brute it C:

We can do it with `itertools.permutations`

## The Jurandir Solver

``````import itertools

def str_perm(flag, p):
res = ""

for j in xrange(0, 70, 7):
for k in xrange(7):
res += flag[j:j+7][p.index(k)]
return res

def shuf(flag):
flag = flag[-1:] + flag[:-1]
new = ""

for i, j in zip(flag[:len(flag)//2], flag[len(flag)//2:]):
new += i+j
flag = new
flag = flag[-1:] + flag[:-1]
return flag

def main():
perm = list(itertools.permutations([0,1,2,3,4,5,6]))

for idx, p in enumerate(perm):
flag = first_flag
print str(idx)+"/5040"

for _ in xrange(1337):
res = str_perm(flag, p)
res = shuf(res)

if res.startswith("ASIS{"):
print res
exit(1)
flag = res

if __name__ == "__main__":
main()
``````

Running the solver, after 805 iterations, we have the flag: `ASIS{1n54n3ly_Simpl3_And_d3lic1Ous_5n4ckS_eVEn_l4zY_Pe0pL3_Can_Mak3}`