So this challenge at first glance was intimidating. There was a bit more going on in this one. But always, always, always - code looks scarier than it actually is. But before we get into the code. The download was a .pyc file.

Wut.

I’ve made a few python scripts before and I’ve never seen pyc. Google time.

Oh. Well. This is usually where I stop. I usually skip compiled stuff, and a pyc is a compiled python program.

Luckily there are tools to undo the ugly compiled mess. I’m on a Mac so I used brew to install uncompyle6. Again I googled for a bit.

uncompyle6 is simple. Put in a pyc and out comes code.

This is what my terminal spits out

$ uncompyle6 PYTHON2.pyc
# uncompyle6 version 3.1.1
# Python bytecode 2.7 (62211)
# Decompiled from: Python 2.7.10 (default, Jul 15 2017, 17:16:57)
# [GCC 4.2.1 Compatible Apple LLVM 9.0.0 (clang-900.0.31)]
# Embedded file name: NCL-2015-Python2.py
# Compiled at: 2015-11-12 17:43:01
import sys

def main():
    if len(sys.argv) != 2:
        print 'Invalid args'
        return
    password = sys.argv[1]
    counter = 0
    vals = list('tfzbwlyzljylawhzzdvyk')
    if len(password) != len(vals):
        print 'incorrect'
        return
    while counter < len(password):
        x = ord(password[counter]) + 7
        if x > ord('z'):
            x -= 26
        if chr(x) != vals[counter]:
            print 'incorrect'
            return
        counter += 1

    print 'correct'


if __name__ == '__main__':
    main()
# okay decompiling PYTHON2.pyc

Ugh. I should have put that into a file or something. Run it again but do it better!

$ uncompyle6 PYTHON2.pyc > thisisthecode.py

Head over to sublime text and browse on over to find this beautiful python code that I can actually work with.

import sys

def main():
    if len(sys.argv) != 2:
        print 'Invalid args'
        return
    password = sys.argv[1]
    counter = 0
    vals = list('tfzbwlyzljylawhzzdvyk')
    if len(password) != len(vals):
        print 'incorrect'
        return
    while counter < len(password):
        x = ord(password[counter]) + 7
        if x > ord('z'):
            x -= 26
        if chr(x) != vals[counter]:
            print 'incorrect'
            return
        counter += 1

    print 'correct'


if __name__ == '__main__':
    main()

Okay okay. Let’s try to figure this sucker out. Diving in section by section.

vals = list('tfzbwlyzljylawhzzdvyk')

turns tfzbwlyzljylawhzzdvyk into a list of each letter. so vals[2], the third item in the vals list is z. For example:

if len(password) != len(vals):

if your password isn’t the length of the vals list then no go.

Checking the length of val

len('tfzbwlyzljylawhzzdvyk')
>>>21

So the password is 21 characters.

If you’ve got that far then it runs a while loop.

while counter < len(password):

Starting at the first position, do stuff until we get to the end. Okay simple. So far we are just setting up the parameters of the length of the password and telling the code to check each character until we get to the end. Nothing really important yet.

x = ord(password[counter]) + 7

This is interesting. It looks at the current letter and makes the ord and adds 7 to it. And then sets it to a variable called X. So basically, make the letters into numbers and move them up 7.

this is where you can imagine and assume that this letters to numbers thing is going to at some point be undone. Go ahead and imagine that. Good. Got it? For example, a password of ‘aaa’ would ord into something like ‘111’ and then we add 7 to make it ‘888’ and then back to letters ‘hhh’. Hmm. Whatever that’s weird.

Moving on.

if x > ord('z'):
	x -= 26

Basically if we get to z, go back to a.
This is here so that after the letter z we loop back to a.

This next part is the part that matters most.

if chr(x) != vals[counter]:

So far we have done a lot with shifting things back and forth. So at first glance, this looks confusing, but it basically says, letter for letter, our manipulated password (the plus 7 ord stuff) needs to equal the string in val. Or at least that is what it looks like.

Of course I wrote a test code. I commented some things in the code, but most importantly, before the last if, and before the if statement that loops things back, I print both the vals[counter] and the chr(x)

I then comment out the last if completely so it doesn’t stop running.

import sys

def main():
    if len(sys.argv) != 2:
        print 'Invalid args'
        return
    password = sys.argv[1]
    counter = 0  #counts the length                         
    vals = list('tfzbwlyzljylawhzzdvyk') #list() converts a string into a list made up of the letters
    if len(password) != len(vals): #password must be 21 characters
        print 'length of the password must be 21 letters'
        return
    while counter < len(password): #moving through the letters
        x = ord(password[counter]) + 7 #add 7 to the ord of the letter
        # this is our test code here
        print vals[counter]
        print chr(x)
        #Back to normal code
        if x > ord('z'): # when the ord hits lowercase z, move x back
            x -= 26
        #if chr(x) != vals[counter]: #if the current letter does not equal the counter
           # print 'counter has to equal the thing'

           # return
        
        counter += 1

    


if __name__ == '__main__':
    main()

Then I run it.

$ python PYTHON2-test.py aaaaaaaaaaaaaaaaaaaaa t h f h z h b h w h l h y h z h l h j h y h l h a h w h h h z h z h d h v h y h k h

so. Remember it’s doing a single character print of the vals[counter] then chr(x) and repeating. so every odd character is vals[counter] and every even is chr(x). So split it up and line them side by side and see what we get.

t h
f h
z h
b h
w h
l h
y h
z h
l h
j h
y h
l h
a h
w h
h h
z h
z h
d h
v h
y h
k h

Weirdddd. It worked just like we thought it maybe would. And remember we are printed these two lines of letters because they have to match.

Weeelllll.

Then maybe we can flip the code?

I know we could do this with pencil and paper but why not try to use this code that is already in front of us?

x = ord(password[counter]) + 7

change it to

x = ord(password[counter]) - 7

and of course we have to flip

if x > ord('z'): 
            x -= 26

to

if x < ord('a'):
            x += 26

Remember, this is there so that if the counter goes past z, make it start back at a.

so the oppsite would be: if it subtracts below a, push it back up to z. And while we are here let’s delete the code we put in the print their string. No need.

Now let’s put in their string as the input and see what comes out.

m
_
s
[
p
e
r
s
e
c
r
e
Z
p
a
s
s
]
o
r
d

Eh. it’s not quite looping back the way we want it to.
But wait. let’s look at it for a second.
m_s[persecreZpass]ord
So. Maybe I’m not the best with Python and I messed something up somewhere. But. It’s clear that the password is something in like likes of:
mysupersecretpassword

Let’s try it.

$ python PYTHON2.py mysupersecretpassword
correct

lolll.

Okay done.

-Cheers

Zack.