Jack64 Crypto Challenge Walkthrough

This Crypto Challenge was originally made by Jack64 for BSides Lisbon. You can find the CTF here: https://ctf.hackersanonymous.net/Jack64_crypto_challenge/.

At first glance we get presented with a webpage with a login form. We are given an encrypted admin password and told logging in as the fsociety user encrypts the password you login with. Knowing this, my first assumption is that our goal is to brute force the encrytped admin password by entering different passwords as the fsociety user until the encrytped password we get as fsociety matches the encrypted admin password.

First things first, this will only work if the same password always produces the same encrypted password. If this is true, then if we get the password that produces the same encrypted admin password we should then be able to login using that password. We try user:fsociety pass: aaaaa a few times and compare the results. Turns out, it encrypts the same way everytime and gives us consistent output!

Now we just need to slightly alter the password each time and see how it changes output. First I start with aaaaa, then aaaab, then aaaac.

 aaaaa: 6262620d626e27d0b86262
 aaaab: 6262620d62<changed>81</changed>27d0b86262
 aaaac: 6262620d62<changed>34</changed>27d0b86262

It seems all the characters are the same except for the 2 after 0d62. So changing the 5th char in a 5 char long string affects those 2 digits. Great! Now we know that each character in our password string changes 2 characters in our encrypted password. We just had to slowly change the string until every point in the encrypted password matches the encrytped admin password! First my goal was to get the 65 at the beggining. Changing aaaaa 1 char at a time all the way to bbbbb shows it doesn't change that 62 to a 65. I decide then to try to increase the string 1 character at a time with success! Turns out the beggining 2 chars and last 2 chars change with the length of the password string. Turns out, at 9 chars (aaaaaaaaa), we get 65...65!

 aaaaaaaaa: 65f2c60dd86e27d0b82265

Now we know our password is 9 chars long! We simply have to now change each digit one at a time to find which part of the encrypted password each digit affects, and match that part in the encrypted password to the relevant part in our encrypted admin password. I decide to make a script that goes through one digit at a time, checks to see where the encrypted password changes depending on the digit we use, and then tries to match that point in the encrypted password to the point in the encrypted admin password.

Here is my script:

#!/usr/bin/python
#admin=65db10ef46c78b7fd65865
import string, requests, difflib

#current = "65f2c60d466e27d0b85865"
final = "65db10ef46c78b7fd65865"
baseline = "65f2c60dd86e27d0b82265"
chars = string.printable
passw = {}
finpass = []

for n in range(1, 10):
#    print n
#    r1 = requests.post("https://ctf.hackersanonymous.net/Jack64_crypto_challenge/login.php", data={'username':'fsociety', 'password':'%s%s%s' % ('a' * (9-n), 'a', 'a' * (n-1))})
     r2 = requests.post("https://ctf.hackersanonymous.net/Jack64_crypto_challenge/login.php", data={'username':'fsociety', 'password':'%s%s%s' % ('a' * (9-n), 'b', 'a' * (n-1))})
#    base = r1.text
     diff = r2.text
     xy = 0
     passw[n] = []
     displ = [i for i in xrange(len(baseline)) if baseline[i] != diff[i]]
#    print displ
     for i in final:
          xy+=1
          if xy == (displ[0] + 1):
               passw[n].append(i)
          if xy == (displ[1] + 1):
               passw[n].append(i)
               currvars = ''.join(passw[n])
               print 'Matching %s' % currvars
#     print passw
#     exit(0)

     for char in chars:
          #print 'char is %s' % char
          xy = 0
          passwd = {}
          passwd[char] = []
          r = requests.post("https://ctf.hackersanonymous.net/Jack64_crypto_challenge/login.php", data={'username':'fsociety', 'password':'%s%s%s' % ('a' * (9-n), char, 'a' * (n-1))})
          #print '%s%s%s' % ('a' * (9-n), char, 'a' * (n-1))
          r.status_code, r.reason
          for i in r.text:
               xy+=1
               if xy == (displ[0] + 1):
                    passwd[char].append(i)
               if xy == (displ[1] + 1):
                    passwd[char].append(i)
                    thisvar = ''.join(passwd[char])
#                    print thisvar
          #print(r.text)
          if thisvar == currvars:
#              print('True')
               finpass.append(char)
               break

print ''.join(finpass)[::-1]

Using this script I successfully bruteforced the password as Bs1d3sr0x and logged in!