PoliCTF Write-Up: bin-pwn 400

November 19, 2012

For this challenge, we were supposed to connect via SSH to a server hosted by the organizers. When connected, we were greated with the string “loS”, then a couple of dots (one new dot per second) and finally

ghItlh pIqaD (a..y)

As we all know, Google is a hackers greatest weapon, so let’s throw that into Google. Just searching for the first term shows us that this is Klingon o_O We found a translator, that tells us that we are appearantly supposed to “Write in klingon alphabet”. So, we looked up the klingon alphabet and tried a couple of chars. When we tried “ch”, we got

ghItlh teywI' pong (main.cpp, ...)

as the result. This roughly translates to “Write file name” and there is a hint! So let’s try to enter “main.cpp” and see what happens here…

#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;
 } 

Ok, so this the main file. It includes a custom header file called “prompt.h”. So, let’s look at that and the .cpp file belonging to it. The h shows us:

#pragma once
#include "data.h"
#include <string>
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;
 };

The cpp shows us:

 #include "prompt.h"
 #include "util.h"
 #include <iostream>
 #include <fstream>
 #include <iomanip>
 using namespace std;
 void Prompt::run()
 {
 string line;
 cout<<"ghItlh pIqaD (a..y)"<<endl;
 while(getline(cin,line))
 {
 if(line.empty()) return;
 if(execute(line)) cout<<"Qagh ghItlhqa'"<<endl;
 else cout<<"ghItlh pIqaD (a..y)"<<endl;
 }
 }

 bool Prompt::execute(const string& command)
 {
 static const string alphabet[]=
 {
 "a", "b", "ch", "D", "e", "gh", "H", "I", "j", "l", "m", "n",
 "ng", "o", "p", "q", "Q", "r", "S", "t", "tlh", "u", "v", "w",
 "y" //,"'"
 };
 bool found=false;
 for(int i=0;i<sizeof(alphabet)/sizeof(alphabet[0]);i++)
 {
 if(command!=alphabet[i]) continue;
 found=true;
 break;
 }
 if(found==false) return true;
 if(command=="ch")
 {
 dump();
 } else if(command=="gh")
 {
 add();
 } else if(command=="ng")
 {
 addOp();
 } else if(command=="tlh")
 {
 get();
 } else {
 cout<<"Hutlh"<<endl;
 }
 return false;
 }

 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;
 }

 void Prompt::add()
 {
 cout<<"ghItlh De'"<<endl;
 float temp;
 cin>>temp;
 cin.get();
 data.add(temp);
 }

 void Prompt::addOp()
 {
 cout<<"ghItlh Qap"<<endl;
 string newop;
 getline(cin,newop);
 if(check(newop) || newop.length()>80) cout<<"Qagh"<<endl;
 else op[3]=newop;
 }

 void Prompt::get()
 {
 cout<<"ghItlh Qap (0..3)"<<endl;
 int opNum;
 cin>>opNum;
 cin.get();
 if(opNum<0 || opNum>3) cout<<"Qagh"<<endl;
 else data.get(op[opNum]);
 } 

Another piece of information we gather from this is the fact that we want to read “flag.txt”. And we can define our own operation on the data we put in. The addOp method checks our string somehow. We looked through all files we could access, but could not find the filter function. Blind guessing showed that we could use none of the interesting operations like system, fopen, popen, …
Our idea now was to try and inject our own code, evading the filter. So, we entered the following function code:

char* t;scanf("%s",t);doOp(t);

Now, when executing the “tlh” call, we were prompted again for a string. We just used

system("cat&lt;flag.txt")

and could retrieve the flag “jbvenvinvpek2envi2n”.

3 Responses to “PoliCTF Write-Up: bin-pwn 400”

  1. Guys, this was bin-pwn 400, not 300

  2. You are right, will fix that later

  3. Huh, didn’t notice the filter at all.
    I simply used streams for reading (copied the stuff from dump function):
    string line; ifstream in(“flag.txt”); while(getline(in,line)) cout<<line<<endl;

Leave a Reply




Get Adobe Flash player