Description :

This client displays nice ASCII Art, can it query anything else?
The aart_client binary is the source of the traffic that was captured in aart_client_capture.pcap.
Understand the network communication protocol and find the flag in the pcap!

Provided files :

  • aart_client (ELF 64 bits)
  • aart_client_capture.pcap


The flag was sent in a protobuf obfuscated communication over HTTP.
Using reverse engineering and a bit of guessing, we found the flag in the permuted and xored HTTP response.

We were the first to solve this challenge amongst the 31 teams who solved it.
This write up will NOT cover all the details about the challenge but only our way to quickly solve it without losing too much time reversing it.


We used Wireshark to view the PCAP content : 6 HTTP POST requests and their responses.
Hex encoded data is sent in form data and in HTTP response.


The binary is a C++ ELF 64 bits linked with Google Protocol Buffers library (protobuf).
The linked library was an old version of libprotobuf and we didn’t want to spend time downgrading libprotobuf so we solved it without launching it.

The first thing to do against a binary using protobuf is to extract the protocols used, the tool Protod  managed to recover the following proto file :

message AartMessage {     
    enum AartMessageType {
        R_HELLO = 0;
        R_CAPABILITIES = 1;
        R_OPERATION = 2;
    required AartMessage.AartMessageType type = 1;
    required string client_id = 2;
    required string content = 3;

Then, we reversed it a little :

  1. The binary checks for argv[1] and uses it as the server address, then it initializes a 32 bytes long random string (alpha lowercase).
  2. We identified a function preparing and sending a POST request, this function is called twice first with HELLO then with GET_IMAGE.
  3. Some functions seems to xor strings.


Using the proto file, we forged a message to find the serialized format of the messages.

>>> msg
 client_id: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
 content: "abcd"
>>> msg.SerializeToString()
 '\x08\x02\x12 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\x1a\x04abcd'

The first request data contains a 32 bytes random string, ‘LLHE’ and some bytes of the serialized protobuf message (0x8, 0x12, 0x20, 0x1A).

After some guesses, we found that the string is reversed and characters are swapped two by two :

>>> message.decode('hex')
 '\x00LLHE\x1a\x05uenylmzdahlblpiclwybmevhyembvmpz\x12 \x08d'
>>> ''.join(map(lambda x: x[::-1], cut(message.decode('hex')[::-1], 2)))
 '\x08d\x12 pzvmmbyevhmeyblwiclplbahzdlmnyue\x1a\x05HELL\x00'

Note : We can see that the last character of « HELLO » string is not included in the packet.

The second and the last responses were larger than the other messages, in the challenge description, the author said that the challenge is about ASCII Art, as ASCII art contains a lot of spaces, we tried xoring these messages with spaces (bytes 0x20).
The ‘s‘ character is repeated many times in the resulted string, if we XOR the data with ‘s‘, we obtain a nice ASCII art of a spaceship.

Knowing that the data is xored with only one byte, we found the response content by guessing the message format : protobuf header and client_id 32 bytes identifier previously sent. (We don’t know why the first byte is null but it didn’t matter)

So, we know that the binary sends 2 HTTP requests, the first one seems to list the commands : GET_IMAGE and GET_FLAG then the binary calls the GET_IMAGE to get the ASCII art in response.


In the PCAP, we can see that in the second exchange, the length of the response is completely different from the ASCII art size, it isn’t calling GET_IMAGE but GET_FLAG.
So, the flag is in the data of the 4 HTTP response :

Yeah ! The flag is there but as we have seen before, the last character isn’t, so, after few tries we found the real flag :

Leave a Comment

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *