netmsg-1
You managed to got your hands on a secure commandline messaging application used by some suspicious people, along with the username/password `delta_star` / `whiskey_demon`. Reportedly, there is some hidden functionality in the backend that has been since removed from the client. Figure out a way to access it to get the flag.
We have a Go binary that acts as a client for a server, which we do not have access to.
We can log in using the credentials in the description. The flag functionality is unavailable, but we have to figure out how it is implemented.
There are multiple architectures provided for this challenge, but the one that is most readable in IDA is x86, 32-bit.
The initial connection and login are not relevant for stage 1 of this challenge, but will be for stage 2.
In the main function, after logging in, there is a big switch statement, which contains all possible messages we can send to the server.
Notice that before every SendWrapped
there is a flag being set on buf[4]
. This is the message type, so the server knows what we are trying to call. However, the flag function (with menu option f
) does not include any call to SendWrapped
, instead it prints that the functionality is unavailable:
After checking every functionality and its corresponding type, we notice that the only number missing on buf[4]
is 8. We can take an educated guess that that is the type for the flag functionality. We still don’t know the way the client and the server interact, but we can dynamically debug the binary, break into any functionality, replace the type with the flag’s and see what we receive from the server.
Let’s take any simple functionality, that includes a send and receive. The m
(for view mailbox
) is a good candidate. We can place a breakpoint where buf[4]
is set, and one on RecvWrapped
.
Here is the instruction that sets 8
as the message type. We can step over it, then replace the byte at esp + 4
with 8 with set {char}($esp + 4) = 8
.
In RecvWrapped
, we notice there’s some kind of decryption involved. We also notice that there is no “decrypt” function, only “encrypt”, meaning that we are dealing with a symmetric encryption. There’s also a function named UnmarshalBinary
, which transforms a byte stream into a Go object.
If we let the program run after modifying the byte it will crash, because it expects a certain layout for mailbox results. Instead, we can step over until after the call to UnmarshalBinary
and see that our server response resides in a register in plaintext:
So here’s our flag, without needing to understand the connection mechanism. We still need to do that for the next stage, though.