The Peace Pipe at's Final CTF 2014

Last week was the Final CTF. In this post I discuss one of my favorite crypto problems in that CTF: the "Peace Pipe".

Understanding the Problem

The problem starts with this weird story:

After a long day, you sit around a campfire in the wild wild web with a few Sioux you met today.
To celebrate friendship one of them takes out his wooden peace pipe and minutes later everyone seems to be pretty dizzy.
You remember that their war chief "Makawee" started something to say about a secret tipi filled with fire-water (the good stuff). But when he noticed your interest he immediately stopped talking.
You recall that "Makawee" spoke with "Wahkoowah" about that issue, but it ended with a fight.
Since then Makawee wouldnt talk to Wahkoowah anymore. While they argued "Chapawee" wrote something down.
Maybe you can exploit their dizzyness to find out the location of the tipi.

Then it gives us three ports in the host. With the first one, we talk to Chapawee: 1432

With the second, we talk to Wankoowah: 1433

Finally, with the third, we talk to Makawee: 1434

It was obvious that this game was about fooling our fellow stoned native-Americans.

A Dialogue with Chapawee

When we netcat to Chapawee he answers:

$  nc 1432
Hi I'm Chapawee. I know the truth about the stars
Say stars for more

We answer stars and get a funny menu:

        I can tell you the truth about
        * constellation
        * namestar [starname] [key_of_truth]   Adds a public key to a user.
                                               Existing users cannot be
                                               overwritten. Input is
        * showstar [starname]                  Reads the public key from the

The first option constellation, shows a very interesting scheme:

Choosing the options namestar we are able to pick a (new) name to add a key. Picking the option showstar we are able to see the key for some name (for example, for Wahkoowar, Makawee, or any new name we had added before).

So, from the above scheme, we know:

  1. How a message (t) is created with someone's public key, a random rational number (r_w), and a given modulo number (p). The only unknown here is r_w, which is a rational number (Q). This mean that any plans to brute force the messages wouldn't work (however, if r_w was an integer, this task could be achieved).

  2. Everyone has a private key that is modulo p. We never learn anything about anyone's private keys. We just know that they could be of the order of p (which is a really large number, ~1E2048).

  3. Wahkoowah and Makawee have a shared secret key. The way they share this key without knowing each other's private key is by this tricky transformation:

Notice that we can move the multiplications' modulo operation to the end, due to this propriety.

In conclusion, all we need to do is to convince Wahkoowah that we are Makawee (by telling him we are Makawee, so he can use his public key, and by sending him a correct t_m). If this works, he will give us a token. Then, if we send this token to Makawee, we get our flag.

A Dialogue with Wankoowah

Now, let's see what Wankoowah has to say:

$ nc 1433
Hi, I'm Wahkoowah. Who are you? Too foggy...

We try a couple of possibilities to check the outputs:

$ nc 1433
Hi, I'm Wahkoowah. Who are you? Too foggy...
Hi noone
Cannot find it...
Ncat: Broken pipe.

$ nc 1433
Hi, I'm Wahkoowah. Who are you? Too foggy...
Oh its you, Im so sorry. Can we talk now?
This is your key of truth
With magic I did this:
We continue our conversation, right?

The magic is the message t_w, created with Makawee's public key. Wahkoowah then ask for t_m...

A Dialogue with Makawee

Let's see what Makawee has to say:

$ nc 1434
Hi, I'm, Makawee, and you are? Too bright here...
noone ... do I know you?
Cannot find it...

Ncat: Broken pipe.

$ nc 1434
Hi, I'm, Makawee, and you are? Too bright here...
I dont talk to you anymore. That thing with my daughter...

Ncat: Broken pipe.

Mmmm, we need to make Makawee use Wankoowah's key without him knowing it!

Since Chapawee allows us to add keys to names, let's create some name with Wahkoowah's key (say "mrwhite") and send this to Makawee:

$ nc 1432
Hi I'm Chapawee. I know the truth about the stars
Say stars for more

        I can tell you the truth about
        * stars
        * constellation
        * namestar [starname] [key_of_truth]   Adds a public key to a user.
                                               Existing users cannot be
                                               overwritten. Input is
        * showstar [starname]                  Reads the public key from the

namestar mrwhite 218b783ec5676cbddd378ceb724820444599f22cdcfda0a5a195b3a8fbf4ab5c915703420ad3b84531c54b838b23858fb84fcaf04d4932d4b9ef861c7ae9b635c9d3f56dfb100aa47297afcd94df41efa9f5ecba6483c5328e43ec457027ee4efcecefa094a83945106d7da1878c1f47516c2f2578170eeb36955d8bd16e0d106f9e2effe9debff41e551db4ac2e87bc8a9378d8eadb042bee18f4ad72ab721833a27154a7318b8cbe6f98fb3c82da32d1688fdcdb718fb15d9d5e6276b037cef62d953c09b23ebe90d0b13f61cd1643e5e1b0a433d5e2522ec5a028817891b6df444e983e1e0ff2356044fea67c616dce6b4bd53b17ea8bc51ef816ab8f2d9e
Add the star to the sky...
Set the star for mrwhite: 218b783ec5676cbddd378ceb724820444599f22cdcfda0a5a195b3a8fbf4ab5c915703420ad3b84531c54b838b23858fb84fcaf04d4932d4b9ef861c7ae9b635c9d3f56dfb100aa47297afcd94df41efa9f5ecba6483c5328e43ec457027ee4efcecefa094a83945106d7da1878c1f47516c2f2578170eeb36955d8bd16e0d106f9e2effe9debff41e551db4ac2e87bc8a9378d8eadb042bee18f4ad72ab721833a27154a7318b8cbe6f98fb3c82da32d1688fdcdb718fb15d9d5e6276b037cef62d953c09b23ebe90d0b13f61cd1643e5e1b0a433d5e2522ec5a028817891b6df444e983e1e0ff2356044fea67c616dce6b4bd53b17ea8bc51ef816ab8f2d9e

Sending it to Makawee:

$ nc 1434
Hi, I'm, Makawee, and you are? Too bright here...
mrwhite ... do I know you?
Disguise does not help

Oh no, the plan did not work! We can't send exactly Wahkoowah's key! We need to be even more tricky...

Crafting a Solution

Master in Disguising

Every key in this problem is given by mudulus p. This means that we have infinite values that map to the same original key. My first attempt was to multiply the original key by p, so that, when it receives the modulo operation, it circles once more returning to the original value.

It didn't work. The reason is that p is too large. When multiplied by the key (that is large itself) we loose precision and we don't go back to the original value. We need to keep the values in the same scale!

Let's take a look again at the way the messages are generated:

We notice that the public key is exponentiated by r_m. It means that, if r_m is an even number, two values of the public key are mapped to the same value of the final message: +pubk and -pubk.

That's all we need! We are going to disguise Makawee by creating a star with the negative value of Wahkoowah's key.

Automatizing the Process and getting the Flag!

All right, now we know how to make Wahkoowah and Makawee talk and how to get t_m and t_w. We are ready to generate the token that will lead us to the flag.

Notice again that since these messages are generated with random numbers, they will differ each time. However, we know from above that they carry unique information that leads to a common key (and the flag). I wrote the following script to automatize the process:

import socket

PORTm = 1434
PORTw = 1433
HOST = ''

def peace_pipe():

    """ Get the magic message from some user to calculate rm """
    # create sockets
    sm = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sw = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    # connect to w
    sw.connect((HOST, PORTw))
    sec = sw.recv(4096)
    tw = sec.split("did this:")[1].split("\n")[1].strip()
    print "\nMagic from w to m: " + tw

    # connect to m
    sm.connect((HOST, PORTm))
    sec = sm.recv(4096)
    tm = sec.split("did this:")[1].split("\n")[1].strip()
    print "\nMagic from m to w: " + tm

    # send w's magic to m's
    print sm.recv(4096)

    # send m's magic to get the token
    token = sw.recv(4096)
    token = token.split('\n')[1].strip()
    print "Token is: " + token

    # finally, send token back to m
    print sm.recv(4096)


if __name__ == "__main__":

Running it leads us to the flag:


Magic from w to m: 2f2f5d280871947836e9b5665986c1b75e732d88ae3d464b65d24ea7e41c33c491060379ac4f3dc4a7231f43d6a11b5bfd3a780d8ac46bd1a4cfd99ac041434cb82c5941f17e68a4f180101ece166a1b4da6ea32d62455bd7472892ed9b67fe2122e0b331048e4a11d98422f04ec3063a3652a0e1a90e13a740905bb3a22c9b5e39d1e0fa97f10bff34d76243b9211afd1131b0f6e33d4d99c8069c462677ce67401214c943fee13252060aa02b8b1525ed0af8c9aa5ad5dee64dbb0c275dd6147754c7dfaf3218caf35d7837925215a04bb315e91441306ef0d29f0da733b7e4ac92b500dc522de11c5f5af58248ed5f762b854f40f0adf4b681a937d17a1c0

Magic from m to w: e9eedf64931d5f77f5d061a0f411f9d385144f33fe1419905fdb24a0537cc205a7f99e083f37f98af8553795f1a71f83b7924620790845c3a48bb71a9b70a0f9e5ab95dda40ec4e229bc6a6cd146779de74b7237e42d01e2538c093407165afc79776bbd9bcdefa1d9af27a39f17610b4b9060c2b0ca5203457061facdc68257433253366937cef469261492ac81c177f42f10beea386ddfa09069a5fa2ae2e39a41eeecebdba622b79231cd5f206d0a70c71aa3eb5f706a16c99173f79f97e7f3408b544df556e3779f6d49441c04d33438b9604392f90bca6c2a8c3181b12ec5d492ef2184b9db69fdd1b6247150e3b55f8ee65d113c5350b4b097abadddc9
Bit more truth is missing

Token is: 5QAWhcwSaQicM8LitDGz6To69sBtsO8ASL27zxql8hW8aziveW0B0epJz2PKIFo/K4A=
I knew you are able to see IT. Lets get drunk, I tell you where

That's it! Hack all the things!