0xL4ugh CTF 2023

3 minute read



we are presented with an exe file that is written in OOP here’s a quick blog post about how to understand OOP in assemply

Once you opened it you will be asked to enter the flag.

error loading

So let’s reverse it out. I started with correcting the naming on the assembly as mentioned in my blog post

error loading

Our input length is compared at the start with “26” So we now know the length of the flag.

error loading

What happens here is a shift left operation with 4 digits and because a 4-digit shift in binary is one digit shift in hexadecimal we are actually flipping the ASCII of the entered character

error loading

41 --> 14
42 --> 24 ...etc

So We just need to flip the reference that our input will be compared with to get our flag.

So this

error loading

will be this

error loading


Here we are presented with a python byte code assembly you may take a while if it’s the first time looking at a python byte code assembly

  2           0 LOAD_CONST               1 (0)
              2 LOAD_CONST               0 (None)
              4 IMPORT_NAME              0 (base64)
              6 STORE_FAST               0 (base64)

  3           8 LOAD_CONST               1 (0)
             10 LOAD_CONST               2 (('Fernet',))
             12 IMPORT_NAME              1 (cryptography.fernet)
             14 IMPORT_FROM              2 (Fernet)
             16 STORE_FAST               1 (Fernet)
             18 POP_TOP

  4          20 LOAD_CONST               3 (b'gAAAAABj7Xd90ySo11DSFyX8t-9QIQvAPmU40mWQfpq856jFl1rpwvm1kyE1w23fyyAAd9riXt-JJA9v6BEcsq6LNroZTnjExjFur_tEp0OLJv0c_8BD3bg=')
             22 STORE_FAST               2 (encMessage)

  5          24 LOAD_FAST                0 (base64)
             26 LOAD_METHOD              3 (b64decode)
             28 LOAD_CONST               4 (b'7PXy9PSZmf/r5pXB79LW1cj/7JT6ltPEmfjk8sHljfr6x/LyyfjymNXR5Z0=')
             30 CALL_METHOD              1
             32 STORE_FAST               3 (key_bytes)

  6          34 BUILD_LIST               0
             36 STORE_FAST               4 (key)

  7          38 LOAD_FAST                3 (key_bytes)
             40 GET_ITER
        >>   42 FOR_ITER                 9 (to 62)
             44 STORE_FAST               5 (k_b)

  8          46 LOAD_FAST                4 (key)
             48 LOAD_METHOD              4 (append)
             50 LOAD_FAST                5 (k_b)
             52 LOAD_CONST               5 (160)
             54 BINARY_XOR
             56 CALL_METHOD              1
             58 POP_TOP
             60 JUMP_ABSOLUTE           21 (to 42)

 10     >>   62 LOAD_GLOBAL              5 (bytes)
             64 LOAD_FAST                4 (key)
             66 CALL_FUNCTION            1
             68 STORE_FAST               4 (key)

 11          70 LOAD_FAST                1 (Fernet)
             72 LOAD_FAST                4 (key)
             74 CALL_FUNCTION            1
             76 STORE_FAST               6 (fernet)

 12          78 LOAD_FAST                6 (fernet)
             80 LOAD_METHOD              6 (decrypt)
             82 LOAD_FAST                2 (encMessage)
             84 CALL_METHOD              1
             86 LOAD_METHOD              7 (decode)
             88 CALL_METHOD              0
             90 STORE_FAST               7 (decMessage)

 13          92 LOAD_GLOBAL              8 (print)
             94 LOAD_FAST                7 (decMessage)
             96 CALL_FUNCTION            1
             98 POP_TOP
            100 LOAD_CONST               0 (None)
            102 RETURN_VALUE

You will notice by looking carefully at the use of the fornet module for encrypting the FLAG So take a look at the fornet documentation and you will notice a lot of similarities between the assembly and the code presented there.

just the key is not randomly generated it’s base64 encoded value XORed with key “160”

here is the script that can reverse it back

  the script takes the assembly file as an argument.
from cryptography.fernet import Fernet
import base64


_key = []
for k_b in key_bytes:

key = bytes(_key)
f = Fernet(key)

token = b'gAAAAABj7Xd90ySo11DSFyX8t-9QIQvAPmU40mWQfpq856jFl1rpwvm1kyE1w23fyyAAd9riXt-JJA9v6BEcsq6LNroZTnjExjFur_tEp0OLJv0c_8BD3bg='

decmessage= f.decrypt(token).decode("utf-8") 

And here is the result.

error loading

Let’s Go

We are given a Linux binary which also asks for Flag to check if it’s right.

error loading

So for reversing I used a remote debugging session from Linux to my windows machine.

I found the binary is not stripped which makes it easier than it’s

There are two paths in that binary the first one is doing something to our input and the second one is comparing the result to a constant value.


error loading

So let’s check what happens in our input. Here we have three paths to follow and the variable that determines which of them will be taken is an operation on the input character.

error loading

To make it easy, the assembly here checks where is the region of the character in the ASCII table.

error loading

and take an action based on if it’s

  • Small Letter
  • Capital Letter
  • Number
  • Symbol

And if it’s a letter, it will add 16 to its ASCII code.

error loading

So we need to subtract 16 from each char in our constant to get our flag.

So our flag will be e507bf78ab5d6a99941222eebcf94464