Ghede's hackme

My hackme is now no longer online. I had over 200MB of pcap files files with over 500 IP addresses for what I had planned to publish a report, something that has been on my todo list for way to long. It's a tedious job to do by hand, so I've removed it from my todo list for now. I've anonomized the pcap files and will give them to anyone who is interested.

For those of you that participated in the hackme challenge here follows a description of the setup, I will publish the interesting parts of the successful and pathetic unsuccessful attempts here shortly.

Goal

The goal of this hackme was to provide a challenge for people that are interested in 'real' hacking, what in my definition means people that know how to read code, write and secure code and have some additional system and security knowledge. The way to accomplish this, and to keep off the 'exploit collector' type of dumb-ass hackers I first had to set up a completely secure environment with no vulnerabilities that would be entries to the exploit collectors.
In order not to scare off junior hackers, and in order for the challenge to be also worthy for the hacking gods I tried to make the hackme consist of a chain of holes that were supposed to be getting more difficult with each step (or at least should request an additional skill from the attacker.
I divided the hackme challenge up into 4 different challenges meant for different (cumulative) skill levels: As it later turned out the 4th challenge was taken in almost no time by most people who got trough step 3, and some of those people tolled me it was the easiest step, so I kinda got the difficulty of the 4th step wrong.

Secure environment

In order to set up the environment for the hackme there had to be a way in trough the internet, using a webserver seemed like a good choice as many security problems are with webservers and putting in a bit of pseudo-reality seemed like a good idea.
Next to a way in, there had to be a way out of the secure environment, a place to punch some holes in, and the tools for the contenders to open these holes wide up. For these reasons I set up a chrooted environment with the following software installed in it: Finally in an attempt to prevent people from not using the tools provided and compiling their own I put the hackme on an old sun solaris box, I later did find some binaries in the pcap files, but mostly it has been effective a.f.a.i.c.s.

First challenge

The first challenge was the 'exploit collector filter', it exist of a set of 2 cgi scripts from what the second one had a hole so big that I was surprised at how many people that I assumed until now to be reasonably competent did not get trough.
The hole actually existed out of 3 different security hazards: The first script generated html output containing a line like:

<IMG  SRC="logit.pl?hour=2001_05_27_21&line=993672416:192.168.1.3:Mozilla/4.76%20[en]%20(X11;%20U;%20Linux%202.2.17-21mdksecure%20i686)">

This html made a image be loaded that was generated by the script 'logit.pl' . This script also used the info being fed by the first script by doing some simple decoding. As you can see the parameters are divided in a 'hour' and a 'line' parameter. The hour actually was also the filename used for the logfile that the script logit.pl was writing to. The 'line' parameter was an 'url encoded' line that was decoded by the script and than written to the log file.
Next to writing to a definable file the file that was written to actually had its execute bits all set to one, thus the file would be executable if the webserver allowed it.

The url encoding is a quite simple encoding, basically any non alphanumeric character is replaced by its hex-code preceded by the '%' sign.

So it was possible to 'log' an executable file, the next question was what to log. The answer was a 'perl' or 'tcl' script, both perl and tcl were installed in the /usr/local/bin/, so the way to get trough the first challenge was basically by logging a perl of tcl script.

Second challenge

The first challenge weeded out all the lame-brains (and some of the people with just to little time, I've seen some people getting real close with #!/usr/bin/perl instead of the needed #!/usr/local/bin/perl), now the second challenge was there to see if you were in the big-league.
The second challenge existed out of a broken sgid binary with its source available, and a renamed parser. The program run_parser had the following source that had to be interpreted (I've made the important parts Bold:
/* run_parser.c                                                       */
/* This program spawns a logfile parser after doing some basic checks */
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
 
int main(int argc, char *argv[])
{
  char logfilename[256];
  char confline[4096];
  char parserfilename[256];
  char command[768];
  char buf[1025];
  char hd[256];
  char hcf[512];
  struct stat parser_stat;
  int i,c;
  FILE *conf,*process1;
  if (argc != 2)
  {
    printf("usage: %s <logfile>\n\n",argv[0]);
    exit(0);
  }
  sprintf(hcf,"%s/.parser_config",getenv("HOME"));
  strncpy(logfilename,argv[1],255);
  if ((conf=fopen(hcf,"r"))||(conf=fopen("/challenge2/etc/parser_config","r")))
  {
    printf("Reading conf\n");
    while ((fscanf(conf,"%[a-zA-Z0-9/. ]\n",confline)>0))
    {
      printf("%s\n",confline); 
      if (strlen(confline) < 256)
      {
        
        if (!(sscanf(confline,"parser %s",parserfilename)))
        {
          parserfilename[0]=0;
        }
        
      }
    }
    fclose(conf);
    printf("Checking for parser\n");
    if (parserfilename[0]==0)
    {
       printf("Error: no parser configured\n");
       return(1);
    }
    printf("getting file stats for parser %s\n",parserfilename);
    if (stat(parserfilename,&parser_stat)==0) 
    {
      printf("checking staff\n");
      if (parser_stat.st_gid == 10)
      {
         sprintf(command,"%s %s",parserfilename,logfilename);
         printf("spawning %s\n",command);
         fflush(stdout);
         execl(parserfilename, parserfilename, logfilename, (char *)0);
         fflush(stdout);
         return(0);
      }
      else
      {
        printf("No you don't ;-)\n");
        return(1);
      }
    } 
    else
    {
       printf("Error: can't stat parser %s\n",parserfilename);
       return(1);
    }
  }
  else
  {
    printf("ERR\n");
    return(1);
  }
}   

The way to get truegh this was basically simple, the attacker had to create a config file with the name .parser_config in a directory writable to him, and next had to put a entry parser in this file to point to a parser. However this parser would have to have a groupid 10 of the staff group. With this config file the attacker could call the run_parser program when the environment variable HOME was set to the attackers home directory.
The finding of a suitable parser was added so that both system analysis skills and code reading skills would be needed, further the kinda exotic parser was chosen to force the attacker to do some background research.
The directory /challenge2/tmp contained the parser, this parser was actually a pike binary renamed to ps.
Summarizing the challenge could be taken in the following way:

Third challenge

The second challenge was meant to separate the junior hackers from the Senior-Hacker/Junior-Specialist, after this the th challenge would be there for the Hacking-Guru/Senior-Specialist to proof themselves.
(i>There initial were some minor migration bugs in this setup that I did not test after migrating from the test box to the hackme box, I would like to thank Dvorak for pointing them out and helping me to fix them).
This challenge consisted out of a sudo configuration that allowed the attacker to run a simple interactive script as root. The script had a hole in it that would only be accessible after 8 simple multiple choice questions. The problem however would be that the attacker would not have an interactive access to the system, thus the attacker would either need to find a way to gain interactive access, or write a script that would be able to fake being an interactive user.
I have tried (and somewhat failed looking at the pcap files that do have interactive sessions in them) to prevent the way of interactive access to the system, forcing the attacker to bend himself into narrow holes in order to write a script that could simulate an interactive user. For making this attack possible and not to easy the following action had been taken: The script that had to be analyzed was the following:
#!/usr/local/bin/perl
$|=1;
@belong=("horse,cow,chicken","dog,cat,goldfish","lion,monkey,zebra",
         "shark,seal,dolphin","fly,spider,butterfly","vacuum-cleaner,sheep,rubber-doll",
         "virus,bacteria,infection","tree,bush,plant","bike,car,bus",
         "lake,sea,river","mountain,hill,bump","lamer,gamer,mcse-er",
         "food,sex,perl","argv,argc,getenv");
print "This script will allow staff members to edit a configuration script\n";
print "\n\n\n\n\nTo establish you are human, and not a script, you need to answer\n";
print "8 stupid questions that only a human or a real bad-ass script\n";
print "could answer\n\n";
$anoy=int(rand(6))+1;
foreach $x (1 .. 8)
{
  if ($x == $anoy)
  {
     $line="";
     print "We interrupt this program to anoy you and make things generally irritating\n";
     sleep(10);
  }
  $rand=int(rand(14-$x));
  $question=splice(@belong,$rand,1);
  @nobel=(@belong,@old);
  $nobel2=$nobel[rand(13)];
  @nobel3=split(/\,/,$nobel2);
  $nobel4=$nobel3[int(rand(3))];
  push(@old,$question);
  @nobel5=split(/\,/,$question);
  $nobel6[0]=splice(@nobel5,int(rand(3)),1);
  $nobel6[1]=splice(@nobel5,int(rand(2)),1);
  $nobel6[2]=$nobel5[0];
  $answer=int(rand(4));
  $alist.=$answer;
  splice(@nobel6,$answer,0,$nobel4);
  print "Which does not belong?\n";
  foreach $index (0 .. 3)
  {
    $cnt=$index+1;
    print "   $cnt) $nobel6[$index]\n";
  }
  print "\n:";
  $starttime=time();
  $userline=<>;
  $speed=time()-$starttime;
  if ($speed < 2)
  {
    print "Piss off stupid script, no human reads+chooses+types that fast\n";
    exit;
  }
  $speed{$speed}++;
  if ($speed{$speed} > 6)
  {
     print "Ok, you're a smart script, but I'm smarter, you're not human, no human reads+chooses+types with such a constant 
speed\n";     exit;
  }
  chomp($userline);
  print "Ok I'll do a complex computation to see if you're right\n";
  sleep(1);
  if ($userline == ($answer+1))
  {
    print "Briljant\n\n\n";
  }
  else
  {
    print "Duh\n";
    print "You're a script or a lamer, that is WRONG\n";
    exit;
  }
}
print "OK, Your human (or a badd-ass script)\n";
open(CONF,"/challenge3/conf/dummy.conf");
$count=0;
while(<CONF>)
{
  if (/^(\w+)\s+(\w+)/)
  {
    $conf[$count]="$1 $2";
    $count++;
  }
}
close(CONF);
print "What parameter needs changing ?\n";
foreach $count (0 .. $count-1)
{
  ($p,$v)=split(/\s+/,$conf[$count]);
  print "  ${count}) $p\n";
}
print ":";
$parnr=<>;
chomp($parnr);
print "New value:";
$nv=<>;
chomp($nv);
$aa=$conf[$parnr];
($p,$v)=split(/\s+/,$conf[$parnr]);
$es="\$aa =~ s/$v/$nv/;1;";
$ok=eval($es);
if ($ok)
{
  $conf[$parnr]=$aa;
  open(CONF,">/challenge3/conf/dummy.conf");
  foreach $count (0 .. $count-1)
  {
    print CONF "$conf[$count]\n";
  }
}
else
{
  print "Eval err $ok $!\n";
} 

Basically this script would test if you are a human by asking 8 questions like:
Which does not belong?
   1) virus
   2) bacteria
   3) infection
   4) zebra
 
:
That would all have to be answered correctly. To make simulating being human more difficult the script took the following measures: After successful fooling the script in believing your script to be human the part of the script that is shown bold would be accessible, allowing for exploitation of a simple unchecked eval bug.
Unfortunately my closing of the system from interactive sessions proofed insufficient, and some people came truegh by getting some kind of interactive shell (what is also kinda impressive taking into account that there were no pty's available, and the platform was Sparc-Solaris, but requires a bit less skill than the path I designed).

The last challenge

The 4th and last challenge was a challenge that proofed to be not much of a challenge for the people. After completing the 3th challenge the attacker would be in a chrooted environment as the user root. I was under the impression that having the chrooted environment on an other file system would make this rather difficult (The only technique I knew to break out of a chrooted environment only works when the real root is on the same partition), I knew it would be theoretically possible to break out, but I thought it wasn't widespread knowledge. Anyway it was meant as a last challenge for the people who broke truegh the first 3 challenges with their coding and analysis skills, and the first challenge that did not need coding skills but rather needed system knowledge, the last challenge on itself may not have been so hard on itself, but I believe that having the knowledge for completing this tasks combined with the analysis and coding skills needed for the first 3 tasks proofs the people who complete all the tasks to be part of the league of Hacking gods.