Tags: pyc re python 

Rating:

We need a way to decompile this pyc code so that we can access the original python script. I use [pycdc.exe][pycdc.exe] for this. It will just return the code in the terminal so either copy it directly from there or pipe the output to a file.

{% highlight python %}
class Dill:
prefix = 'sun{'
suffix = '}'
o = [
5,
1,
3,
4,
7,
2,
6,
0]

def __init__(self = None):
self.encrypted = 'bGVnbGxpaGVwaWNrdD8Ka2V0ZXRpZGls'

def validate(self = None, value = None):
if not value.startswith(Dill.prefix) or value.endswith(Dill.suffix):
return False
value = None[len(Dill.prefix):-len(Dill.suffix)]
if len(value) != 32:
return False
#create a list of 4 chars each and adding to c
c = (lambda .0 = None: [ value[i:i + 4] for i in .0 ])(range(0, len(value), 4))
#value = None((lambda .0 = None: [ c[i] for i in .0 ])(Dill.o))
value = (lambda .0=None: [c[i] for i in .0])(Dill.o)
if value != self.encrypted:
return False
{% endhighlight %}

Now that we have the code, we can start breaking it down. Right away we see a `self.encrypted` value of `bGVnbGxpaGVwaWNrdD8Ka2V0ZXRpZGls` which I can assume is the string we need to decode. Moving through the code it starts by checking that the value has the prefix of 'sun{' and ends with '}' to match the flag standard for this ctf. Next it is checking that the length is 32 characters long which doesn't affect us much. I explain in my code comment that the `c = lambda ...` is simply breaking apart the input into groups of 4 chars and appending them to the list 'c'. So we can start easy and break our encrypted string into groups of four.

`c = [bGVn, bGxp, aGVw, aWNr, dD8K, a2V0, ZXRp, ZGls]`

Now onto the next lambda function for *value*. You can see that I have a commented out value expression which was the original output of the decompiler but is incorrect. The decompiler will sometimes return slightly off code which will need to be manually corrected. The uncommented line is my corrected version of the code and what I will be reversing. This line is iterating through the values of c and reordering them based on Dill.o (a list of values from 0-7). This is pretty easy to reverse as we would just move the values back to where they were before (i.e the current c[0] would move to position 5). I will show the basic process below:

{% highlight python %}
0 1 2 3 4 5 6 7 # final positions
c = bGVn bGxp aGVw aWNr dD8K a2V0 ZXRp ZGls
5 1 3 4 7 2 6 0 # where they need to move back to

original = [ZGls, bGxp, a2V0, aGVw, aWNr, bGVn, ZXRp, dD8K]
{% endhighlight %}

So we are left with the string *ZGlsbGxpa2V0aGVwaWNrbGVnZXRpdD8K* as the decrypted version. Moving over to cyberchef, we can try and decode it to see if it is correct. Running it through a base64 decrypt we get *dilllikethepicklegetit?*. So that tells us that it is correct. Back to the submission page we can enter the flag `sun{ZGlsbGxpa2V0aGVwaWNrbGVnZXRpdD8K}`. Make sure you do not keep trying to enter the decrypted version like I did for 5 minutes.

[pycdc.exe]: https://github.com/extremecoders-re/decompyle-builds