Post

Wierd Code

This is a writeup of the coding challenge Weird code from the Security Valley CTF

Premise

I’ve found a weird piece of code in the internet. That looks strange….but there is a flag inside. I belive that! Help me, plz.

Link: https://github.com/SecurityValley/PublicCTFChallenges/tree/master/coding/weird_code

Challenge code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
##################################################
 15           0 LOAD_GLOBAL              0 (print)
              2 LOAD_CONST               1 ('loading application')
              4 CALL_FUNCTION            1
              6 POP_TOP

 17           8 LOAD_GLOBAL              1 (magic)
             10 LOAD_CONST               2 ('8934')
             12 LOAD_GLOBAL              2 (get_flag)
             14 CALL_FUNCTION            0
             16 CALL_FUNCTION            2
             18 STORE_FAST               0 (d)

 19          20 LOAD_GLOBAL              0 (print)
             22 LOAD_FAST                0 (d)
             24 CALL_FUNCTION            1
             26 POP_TOP
             28 LOAD_CONST               0 (None)
             30 RETURN_VALUE
None
##################################################
  4           0 LOAD_CONST               1 ('k\\PbYUHDAM[[VJlVAMVk[VWQE')
              2 RETURN_VALUE
None
##################################################
  7           0 LOAD_CONST               1 (b'')
              2 STORE_FAST               2 (out)

  9           4 LOAD_GLOBAL              0 (range)
              6 LOAD_GLOBAL              1 (len)
              8 LOAD_FAST                1 (f)
             10 CALL_FUNCTION            1
             12 CALL_FUNCTION            1
             14 GET_ITER
        >>   16 FOR_ITER                46 (to 64)
             18 STORE_FAST               3 (i)

 10          20 LOAD_FAST                2 (out)
             22 LOAD_GLOBAL              2 (bytes)
             24 LOAD_GLOBAL              3 (ord)
             26 LOAD_FAST                1 (f)
             28 LOAD_FAST                3 (i)
             30 BINARY_SUBSCR
             32 CALL_FUNCTION            1
             34 LOAD_GLOBAL              3 (ord)
             36 LOAD_FAST                0 (k)
             38 LOAD_FAST                3 (i)
             40 LOAD_GLOBAL              1 (len)
             42 LOAD_FAST                0 (k)
             44 CALL_FUNCTION            1
             46 BINARY_MODULO
             48 BINARY_SUBSCR
             50 CALL_FUNCTION            1
             52 BINARY_XOR
             54 BUILD_LIST               1
             56 CALL_FUNCTION            1
             58 INPLACE_ADD
             60 STORE_FAST               2 (out)
             62 JUMP_ABSOLUTE           16

 12     >>   64 LOAD_FAST                2 (out)
             66 RETURN_VALUE
None

Solution

Here we have to do a little bit of reverse engineering. As we can see, we have what looks like some assembled form of python code. There are a few things of interest here. For starters, the line 1 ('k\\PbYUHDAM[[VJlVAMVk[VWQE') contains what looks like an encoded message. Furthermore, we have what looks like a key via the '8934' line.

We can also see what looks like a for loop from the lines

1
2
3
  9           4 LOAD_GLOBAL              0 (range)
              6 LOAD_GLOBAL              1 (len)
              8 LOAD_FAST                1 (f)

furthermore, we have what looks like a traversal of each character in f which have been changed first to their decimal format via ord, then into byte form via bytes.

1
2
3
4
5
 10          20 LOAD_FAST                2 (out)
             22 LOAD_GLOBAL              2 (bytes)
             24 LOAD_GLOBAL              3 (ord)
             26 LOAD_FAST                1 (f)
             28 LOAD_FAST                3 (i)

Lastly, here we see another variable k, which uses both i and the length of k

1
2
3
4
5
6
             34 LOAD_GLOBAL              3 (ord)
             36 LOAD_FAST                0 (k)
             38 LOAD_FAST                3 (i)
             40 LOAD_GLOBAL              1 (len)
             42 LOAD_FAST                0 (k)
             44 CALL_FUNCTION            1

We also see XOR and Modulo being utilized after the previous code block thanks to the lines:

1
2
3
4
             46 BINARY_MODULO
             48 BINARY_SUBSCR
             50 CALL_FUNCTION            1
             52 BINARY_XOR

Now with the knowledge gathered from the previous code blocks, we can attempt to piece them together into something comprehensive. An example of this would be something like:

1
2
3
4
5
6
7
8
9
10
f = 'k\\PbYUHDAM[[VJlVAMVk[VWQE'

k = '8934'

out = b''

for i in range(len(f)):
    out += bytes([ord(f[i]) ^ ord(k[i % len(k)])])

print(out.decode("utf-8"))

Which when run prints out our flag: SecVal{[redacted]}

This post is licensed under CC BY 4.0 by the author.