Skip to main content
  1. My Blog Posts and Stories/

GreyCTF 2023 Finals: Custom Protocol

·914 words·5 mins

This is the author’s writeup for the challenges Custom Protocol in the web category.

This describes the intended solution when I made the challenge.

Challenge description #

I have made a custom protocol inspired by rome. I’m sure no one can crack it.

  • Junhua

There is no source code provided for the challenge, only a link to the website.

My Notes #

  • This was meant to be a easy challenge.
  • Wanted to make a more complex protocol for this challenge but there was insufficient time.
  • The source code can be found here
  • Should have think of a way for the users to discover the location of the source code themselves
    • IE: added a ls command or something similar, and scramble results with the protocol as well.

The website #

Custom Protocol Home Page
Custom Protocol Home Page

When we first visit the website, we will be greeted with the screen shown above. There seems to be a nonsense instruction set with what looks like random letters.

There is an example for printing Hello World provided by the webpage.

Prints Hello World
Website Prints hello world

Upon submitting the code, the website prints Hello World! to the screen as expected.

Solving for the solution #

When face with such a challenge, the first course of action map the words of something we know to something we do not know.

Here are the list of things that we know

  1. kmdio Uryyb_Jbeyq! prints Hello World!
  2. kmdio is the instruction and Uryyb_Jbeyq! is the arguments passed to the instruction.

Upon close inspection, we can see that Uryyb_Jbeyq! and Hello World! has the same number of characters and the ! at the end is the same.

This will mean that there is a mapping of letters from the first argument to the second argument. Here are a list of arguments we can infer

U -> H
r -> e
y -> l
b -> o
_ -> SPACE
J -> W
e -> o
q -> r
! -> !

They all seem to have a rotation of 13 characters with the _ replacing the space. Symbols seems to be unreplaced.

With this knowledge, we can use the same set of rotations for the instruction set. However, kmdio rotates into xzqvb instead of anything legible.

By trying out other rotations, we can see that with a rotation of 5, kmdio will become print. With this, we now know that the instruction set is a series of character rotations.

Author’s Note: At this point, we can come up with a brute force solution. IE: Try all rotations to find out the instruction set. As it has a small number of rotations, this is a viable (and probably faster) solution. However, in this writeup, I will be going through the expected solution.

We have to now figure out how the character rotations are sequenced. Why is the first string rotated by 5 while the second string is rotated by 10?

This is where we can come to the second conclusion. The first string is of length 5 while the second string is of length 12.

What will happen if we pass the instruction set into the print command and see what they spit out?

The command kmdio lejc returns qjoh. This is 1 rotation off of ping. From this we can infer that there is an increase of 1 rotation for each position the argument is in.

This is the full custom protocol. With tools we have at hand, we have think of ways to leak the flag.

Reversing the instruction set #

With the protocol, we know that the instructions at the front will be rotated by the number of characters which they are offset.

This allows us to get these instructions.

read: Maybe read something?
ping: Returns `pong`
print: Prints the next argument

Author’s note During this section of the challenge, I received tickets asking for the location of the source code file. A hint was added that the source code is at main.go.

With the hint, we know that we must first read main.go to get the source code before we can find other ways to get the flag.

By encrypting ./main.go by rotating the characters -(9 -> len + 1 -> arg1) times, we get ./cqyd.we. By passing concatenating it together with the read command, we get this nawz ./cqyd.we.

Leaked source code
Leaking the source code

By passing this into the website, we can see that the source code is leaked.

optCodeMap = map[string] func(map[string] string, string)(string, error) {
        "read": func(map[string] string, fileName string)(string, error) {
            file, err: = os.Open(fileName) if err != nil {
                return "", fmt.Errorf(caesarCipher(err.Error(), len(err.Error())))
            defer file.Close() result, err: = io.ReadAll(file) if err != nil {
                return "", err
            return string(result), nil
        "ping": func(map[string] string, s string)(string, error) {
            return "pong", nil
        "print": func(m map[string] string, s string)(string, error) {
            if val, ok: = m[s];
            ok {
                return val, nil
            return s, nil
        "giv3-fl4g-p1s": func(map[string] string, string)(string, error) {
            return fmt.Sprintf("Good job, you broke the protocol: %s", flag), nil

From the source code, we can see that there is an operation called giv3-fl4g-p1s which we can call to view the flag.

By rotating the characters 13 times (length of the command), we get tvi3-sy4t-c1f. We can call this command and get the flag.

Getting the flag
Getting the flag

Flag: grey{c43sar g0t 4n 1nj3cti0n f4618314c4d25169f5735ca0d4a29e41}

  1. CyberChef - Used to do the character rotations
  2. CleanCSS - Used to clean go code
  3. Source Code