> For the complete documentation index, see [llms.txt](https://simon-6.gitbook.io/simoncyber/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://simon-6.gitbook.io/simoncyber/ctf-writeups/picoctf-2024/reverse-engineering/weirdsnake-medium.md).

# weirdSnake (Medium)

<figure><img src="/files/NpOTzBPRoZuPSQMuhJlr" alt=""><figcaption></figcaption></figure>

```
  1           0 LOAD_CONST               0 (4)
              2 LOAD_CONST               1 (54)
              4 LOAD_CONST               2 (41)
              6 LOAD_CONST               3 (0)
              8 LOAD_CONST               4 (112)
             10 LOAD_CONST               5 (32)
             12 LOAD_CONST               6 (25)
             14 LOAD_CONST               7 (49)
             16 LOAD_CONST               8 (33)
             18 LOAD_CONST               9 (3)
             20 LOAD_CONST               3 (0)
             22 LOAD_CONST               3 (0)
             24 LOAD_CONST              10 (57)
             26 LOAD_CONST               5 (32)
             28 LOAD_CONST              11 (108)
             30 LOAD_CONST              12 (23)
             32 LOAD_CONST              13 (48)
             34 LOAD_CONST               0 (4)
             36 LOAD_CONST              14 (9)
             38 LOAD_CONST              15 (70)
             40 LOAD_CONST              16 (7)
             42 LOAD_CONST              17 (110)
             44 LOAD_CONST              18 (36)
             46 LOAD_CONST              19 (8)
             48 LOAD_CONST              11 (108)
             50 LOAD_CONST              16 (7)
             52 LOAD_CONST               7 (49)
             54 LOAD_CONST              20 (10)
             56 LOAD_CONST               0 (4)
             58 LOAD_CONST              21 (86)
             60 LOAD_CONST              22 (43)
             62 LOAD_CONST              23 (106)
             64 LOAD_CONST              24 (123)
             66 LOAD_CONST              25 (89)
             68 LOAD_CONST              26 (87)
             70 LOAD_CONST              27 (18)
             72 LOAD_CONST              28 (62)
             74 LOAD_CONST              29 (47)
             76 LOAD_CONST              20 (10)
             78 LOAD_CONST              30 (78)
             80 BUILD_LIST              40
             82 STORE_NAME               0 (input_list)

  2          84 LOAD_CONST              31 ('J')
             86 STORE_NAME               1 (key_str)

  3          88 LOAD_CONST              32 ('_')
             90 LOAD_NAME                1 (key_str)
             92 BINARY_ADD
             94 STORE_NAME               1 (key_str)

  4          96 LOAD_NAME                1 (key_str)
             98 LOAD_CONST              33 ('o')
            100 BINARY_ADD
            102 STORE_NAME               1 (key_str)

  5         104 LOAD_NAME                1 (key_str)
            106 LOAD_CONST              34 ('3')
            108 BINARY_ADD
            110 STORE_NAME               1 (key_str)

  6         112 LOAD_CONST              35 ('t')
            114 LOAD_NAME                1 (key_str)
            116 BINARY_ADD
            118 STORE_NAME               1 (key_str)

  9         120 LOAD_CONST              36 (<code object <listcomp> at 0x7f704e8a4d40, file "snake.py", line 9>)
            122 LOAD_CONST              37 ('<listcomp>')
            124 MAKE_FUNCTION            0
            126 LOAD_NAME                1 (key_str)
            128 GET_ITER
            130 CALL_FUNCTION            1
            132 STORE_NAME               2 (key_list)

 11     >>  134 LOAD_NAME                3 (len)
            136 LOAD_NAME                2 (key_list)
            138 CALL_FUNCTION            1
            140 LOAD_NAME                3 (len)
            142 LOAD_NAME                0 (input_list)
            144 CALL_FUNCTION            1
            146 COMPARE_OP               0 (<)
            148 POP_JUMP_IF_FALSE      162

 12         150 LOAD_NAME                2 (key_list)
            152 LOAD_METHOD              4 (extend)
            154 LOAD_NAME                2 (key_list)
            156 CALL_METHOD              1
            158 POP_TOP
            160 JUMP_ABSOLUTE          134

 15     >>  162 LOAD_CONST              38 (<code object <listcomp> at 0x7f704e8a4df0, file "snake.py", line 15>)
            164 LOAD_CONST              37 ('<listcomp>')
            166 MAKE_FUNCTION            0
            168 LOAD_NAME                5 (zip)
            170 LOAD_NAME                0 (input_list)
            172 LOAD_NAME                2 (key_list)
            174 CALL_FUNCTION            2
            176 GET_ITER
            178 CALL_FUNCTION            1
            180 STORE_NAME               6 (result)

 18         182 LOAD_CONST              39 ('')
            184 LOAD_METHOD              7 (join)
            186 LOAD_NAME                8 (map)
            188 LOAD_NAME                9 (chr)
            190 LOAD_NAME                6 (result)
            192 CALL_FUNCTION            2
            194 CALL_METHOD              1
            196 STORE_NAME              10 (result_text)
            198 LOAD_CONST              40 (None)
            200 RETURN_VALUE

Disassembly of <code object <listcomp> at 0x7f704e8a4d40, file "snake.py", line 9>:
  9           0 BUILD_LIST               0
              2 LOAD_FAST                0 (.0)
        >>    4 FOR_ITER                12 (to 18)
              6 STORE_FAST               1 (char)
              8 LOAD_GLOBAL              0 (ord)
             10 LOAD_FAST                1 (char)
             12 CALL_FUNCTION            1
             14 LIST_APPEND              2
             16 JUMP_ABSOLUTE            4
        >>   18 RETURN_VALUE

Disassembly of <code object <listcomp> at 0x7f704e8a4df0, file "snake.py", line 15>:
 15           0 BUILD_LIST               0
              2 LOAD_FAST                0 (.0)
        >>    4 FOR_ITER                16 (to 22)
              6 UNPACK_SEQUENCE          2
              8 STORE_FAST               1 (a)
             10 STORE_FAST               2 (b)
             12 LOAD_FAST                1 (a)
             14 LOAD_FAST                2 (b)
             16 BINARY_XOR
             18 LIST_APPEND              2
             20 JUMP_ABSOLUTE            4
        >>   22 RETURN_VALUE

```

***

### What is Python Bytecode?

"In Python, **bytecode** is a low-level set of instructions that is portable across different platforms, which means it can be executed on any machine that has a compatible [CPython](https://realpython.com/ref/glossary/cpython/) interpreter."

Essentially Python is a High Level Language that we can understand quite easily, but for some PVM (Python Virtual Machine) to process it, it needs to compile your code to machine code. The bytecode is stored in .pyc and then in pycache. In here, it loads values, instructions, and functions.

***

### Solving It&#x20;

Beware since I'm completly new to Python Bytecode, I'll be using this:

{% embed url="<https://www.youtube.com/watch?v=DvtUAX5OZ18>" %}

Before diving in, let's understand the syntax.

```
Basic Bytecode Instructions:
LOAD_CONST n - Loads a constant value onto the stack

LOAD_CONST 0 (4) means "load constant at index 0, which is the value 4"
Constants are stored in a separate table

BUILD_LIST n - Creates a list from the top n items on the stack

BUILD_LIST 40 takes the top 40 values from the stack and makes a list

STORE_NAME n - Pops the top value from stack and stores it in a variable

STORE_NAME 0 (input_list) stores the value in variable named "input_list"

LOAD_NAME n - Loads a variable's value onto the stack

LOAD_NAME 1 (key_str) pushes the value of "key_str" onto the stack

BINARY_ADD - Pops two values, adds/concatenates them, pushes result
```

The first function of the program is creating a list consisting of 40 constants. It stores this into a variable called "input list". And by doing so, this would pop the values on the stack and move it into the list.

```
2          84 LOAD_CONST              31 ('J')
             86 STORE_NAME               1 (key_str)

  3          88 LOAD_CONST              32 ('_')
             90 LOAD_NAME                1 (key_str)
             92 BINARY_ADD
             94 STORE_NAME               1 (key_str)

  4          96 LOAD_NAME                1 (key_str)
             98 LOAD_CONST              33 ('o')
            100 BINARY_ADD
            102 STORE_NAME               1 (key_str)

  5         104 LOAD_NAME                1 (key_str)
            106 LOAD_CONST              34 ('3')
            108 BINARY_ADD
            110 STORE_NAME               1 (key_str)

  6         112 LOAD_CONST              35 ('t')
            114 LOAD_NAME                1 (key_str)
            116 BINARY_ADD
            118 STORE_NAME               1 (key_str)
```

Now this one is almost the same except it uses characters. The first thing it does is load J as a constant and then stores it as a variable "key\_str". This pops the J from the stack, but it returns once we do the "Load\_name" shortly after. It adds the "*" to the stack. However, it does not become "J\_", it becomes "\_J".* This is because it takes in the lower value first on the stack than the higher values.&#x20;

<figure><img src="/files/UayTegRhwZjyVQJNPM0B" alt=""><figcaption></figcaption></figure>

However, the picture on the bottom is a little different (it loads "o"). It first loads the variable, and then loads the const. This *appends* the constant at the end of the key\_str. Hence it then becomes "\_Jo". It's all about the order of the stack.

<figure><img src="/files/hy309B8psmuWOoZiq9eo" alt=""><figcaption></figcaption></figure>

At the end of the process it becomes "t\_Jo3".

***

At line 120, it loads a list comprehension and loads a memory address (0x7f704e8a4df0). It loads its function name, and creates a function from the object. It then takes the previous key, and iterates it to call function to key\_list.&#x20;

**Result:** `key_list = [116, 95, 74, 111, 51]` (ASCII values of 't', '\_', 'J', 'o', '3')

```
Disassembly of <code object <listcomp> at 0x7f704e8a4d40, file "snake.py", line 9>:
  9           0 BUILD_LIST               0
              2 LOAD_FAST                0 (.0)
        >>    4 FOR_ITER                12 (to 18)
              6 STORE_FAST               1 (char)
              8 LOAD_GLOBAL              0 (ord)
             10 LOAD_FAST                1 (char)
             12 CALL_FUNCTION            1
             14 LIST_APPEND              2
             16 JUMP_ABSOLUTE            4
        >>   18 RETURN_VALUE
```

This is a for loop that takes the ord() of every character. This is how the key list is created!&#x20;

***

```
 11     >>  134 LOAD_NAME                3 (len)
            136 LOAD_NAME                2 (key_list)
            138 CALL_FUNCTION            1
            140 LOAD_NAME                3 (len)
            142 LOAD_NAME                0 (input_list)
            144 CALL_FUNCTION            1
            146 COMPARE_OP               0 (<)
            148 POP_JUMP_IF_FALSE      162
```

It first loads the length function in python and the key list. This basically compares the len(key\_list) < len(input\_list). If it isn't true, it jumps to another code.

```
 12         150 LOAD_NAME                2 (key_list)
            152 LOAD_METHOD              4 (extend)
            154 LOAD_NAME                2 (key_list)
            156 CALL_METHOD              1
            158 POP_TOP
            160 JUMP_ABSOLUTE          134
```

This called the extend method. This basically extends itself and calls it! key\_list.extend(key\_list) and pops it. It jump back again for another loop.

```
>>  162 LOAD_CONST              38 (<code object <listcomp> at 0x7f704e8a4df0, file "snake.py", line 15>)
            164 LOAD_CONST              37 ('<listcomp>')
            166 MAKE_FUNCTION            0
            168 LOAD_NAME                5 (zip)
            170 LOAD_NAME                0 (input_list)
            172 LOAD_NAME                2 (key_list)
            174 CALL_FUNCTION            2
            176 GET_ITER
            178 CALL_FUNCTION            1
            180 STORE_NAME               6 (result)

 18         182 LOAD_CONST              39 ('')
            184 LOAD_METHOD              7 (join)
            186 LOAD_NAME                8 (map)
            188 LOAD_NAME                9 (chr)
            190 LOAD_NAME                6 (result)
            192 CALL_FUNCTION            2
            194 CALL_METHOD              1
            196 STORE_NAME              10 (result_text)
            198 LOAD_CONST              40 (None)
            200 RETURN_VALUE
```

First of all, it does this: zip(input\_list, key\_list). This joins both of the list. It then calls the function, which xors it.

```
 15           0 BUILD_LIST               0
              2 LOAD_FAST                0 (.0)
        >>    4 FOR_ITER                16 (to 22)
              6 UNPACK_SEQUENCE          2
              8 STORE_FAST               1 (a)
             10 STORE_FAST               2 (b)
             12 LOAD_FAST                1 (a)
             14 LOAD_FAST                2 (b)
             16 BINARY_XOR
             18 LIST_APPEND              2
             20 JUMP_ABSOLUTE            4
        >>   22 RETURN_VALUE
```

Right Here! It then stores it into a variable "result".&#x20;

<figure><img src="/files/udMrFUEqfOasIJIMCzXu" alt=""><figcaption></figcaption></figure>

Lastly, the last piece of code.&#x20;

{% hint style="info" %}
map() function in Python applies a given function to each element of an iterable (list, tuple, set, etc.) and returns a map object (iterator). It is a higher-order function used for uniform element-wise transformations, enabling concise and efficient code.

Let's start with a simple example of using **map()** to convert a list of strings into a list of integers.

```
s = ['1', '2', '3', '4']
```

```
res = map(int, s)
```

```
print(list(res))
```

\
**Output**

```
[1, 2, 3, 4]
```

**Explanation: map()** applies **int()** to each element in **s** which changes their datatype from string to int.
{% endhint %}

In this, it does map(chr, result), converting the numbers back into a character! The "".join() method just joins the elements in a list.&#x20;

***

Now that we know what the code is doing, let's create a script.&#x20;

<figure><img src="/files/yzyLgyh3dSTKiM2DjJfq" alt=""><figcaption></figcaption></figure>

key\_list is the ASCII values of the string "t\_Jo3". Since the byte length of key\_list and input\_list is different, we need the values at least in term of size to match. Hence, it repeats itself until they match.

Next, we have 2 compare 2 characters in each list using zip and the bit wise operator, "^".  After that, we'll need to convert each ASCII character back to its alphabet. Because if we print out result, we'll just have:

```
[112, 105, 99, 111, 67, 84, 70, 123, 78, 48, 116, 95, 115, 79, 95, 99, 111, 78, 102, 117, 115, 49, 110, 103, 95, 115, 110, 64, 107, 101, 95, 53, 49, 54, 100, 102, 97, 101, 101, 125]
```

Hence, we use the "map" to apply "chr" to each element in result. Since chr(112) returns p, it would just repeat for the rest. And finally, we'll end up with our flag: "picoCTF{N0t\_sO\_coNfus1ng\_sn\@ke\_516dfaee}"
