Exploitation

PYC Files

PYC files are Python bytecode files. They can be decompiled using uncompyle6, like so:

$ uncompyle6 ./PYTHON2.pyc
# uncompyle6 version 3.9.0
# Python bytecode version base 2.7 (62211)
# Decompiled from: Python 3.10.8 (main, Jan 11 2023, 17:52:38) [GCC 9.4.0]
# 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

So for the above example, the password is mysupersecretpassword. We get this by determining that the correct password has 21 characters, where each character is the result of adding 7 to the corresponding character in the string "tfzbwlyzljylawhzzdvyk", modulo 26. This can be achieved by applying a Caesar cipher with a shift of 7 on the string "tfzbwlyzljylawhzzdvyk".

Python

Another Python example:

import sys

def main():
    if len(sys.argv) != 2:
        print 'Invalid args'
        return
    password = sys.argv[1]
    builder = 0
    for c in password:
        builder += ord(c)

    builder = builder << 2
    builder = ~builder
    builder = builder ^ 12648430
    builder = ~builder
    if builder == 12645638 and ord(password[0]) == 78 and len(password) == 11:
        print 'correct'
    else:
        print 'incorrect'


if __name__ == '__main__':
    main()

The way this one was solved is:

  1. The password is 11 characters long.
  2. The first character is N, which is 78 in ASCII.
  3. The password is the result of applying the following operations to the sum of the ASCII values of the characters in the password:
    1. Bitwise left shift by 2.
    2. Bitwise NOT.
    3. Bitwise XOR with 12648430.
    4. Bitwise NOT.
  4. The result of the above operations is 12645638.

So to solve it, we must perform the above operations in reverse order, and then convert the result to ASCII. This can be done in Python:

>>> builder = 12645638
>>> builder = ~builder
>>> builder = builder ^ 12648430
>>> builder = ~builder
>>> builder = builder >> 2
>>> builder
698
# We know the first character is N, so we can subtract 78 from the result
>>> builder = builder - 78
# We know the password is 11 characters long, so we can divide the result by 10
>>> builder = builder / 10
>>> builder
62
# We can now convert the result to ASCII
>>> chr(builder)
'>'
# That leaves us with the final password: 'N>>>>>>>>>>'

Binaries

The first step when reversing a binary is always to run strings and skim the results for anything that looks interesting.