Aaroniker
Aaroniker

Reputation: 190

phpseclib live console/terminal using AJAX

I'm trying to code a live console/terminal. For that I am using phpseclib library, at first I include all stuff & login:

use phpseclib\Net\SSH2;

include('vendor/autoload.php');

$ssh = new SSH2('127.0.0.1');
if(!$ssh->login('user', 'pass')) {
    exit('Login Failed');
}

$ssh->setTimeout(1);

after that I check for an Ajax request (read for display, write for execute):

if(!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
    if($_POST['request'] == 'read') {
        echo $ssh->read();
    } elseif($_POST['request'] == 'write') {
        $ssh->write($_POST['command']."\n");
        echo $ssh->read();
    }
    exit();
}

HTML markup:

<textarea readonly>...</textarea>
<div>
    <input type="text" placeholder="Command">
    <button>
        Do it
    </button>
</div>

Some jQuery:

$('div button').click(function(e) {
    $('div button').text('Loading...');
    e.preventDefault();
    $.ajax({
        type: 'POST',
        url: 'index.php',
        data: {
            request: 'write',
            command: $('div input').val()
        },
        success: function(data) {
            $('textarea').append(data);
            $('textarea').scrollTop($('textarea')[0].scrollHeight - $('textarea').height());
            $('div input').val('');
            $('div button').text('Do it');
        }
    });
});

The Problem(s) every time I request cmd with write() it will show the Debian login message (and if I change the current directory using cd and after that I use ls it resets - because the new login I think), also im not sure how to create an interval so I get the current output continually - e.x. if I ping a website. Tried smth. like this:

setInterval(function() {
    $.ajax({
        type: 'POST',
        url: 'index.php',
        data: {
            request: 'read'
        },
        success: function(data) {
            $('textarea').append(data);
            $('textarea').scrollTop($('textarea')[0].scrollHeight - $('textarea').height());
        }
    });
}, 300);

Im thankful for any help!

Upvotes: 2

Views: 1158

Answers (1)

Tim
Tim

Reputation: 2187

I have done it!

I was able to do this but without SSH lib. You should be able to take this answer and work it into your existing code.

Information First

Yes, the reason why you keep seeing the login, and why the directory changes do not persist is because you are reconnecting and creating a new session each time. Additionally, since PHP removes all resources (your SSH connection) on exit, you cannot make it persist by serialization or anything.

Basically, what you need is a bash session that stays up that you can interact with, using PHP. You can do this with netcat and a fifo and some PHP system() calls.

Example with a "run command" script (which persists!):

  • SSH to your server.
  • Run screen (this is so the netcat command keeps running even after you logout)
  • Run the following (persistently listens to port 1234 on localhost, writes to fifo, and cat's the fifo contents into a shell).

    rm /tmp/f
    mkfifo /tmp/f
    cat /tmp/f | /bin/sh -i 2>&1 | nc -k -l 127.0.0.1 1234 > /tmp/f
    
  • Use CTRL+A+D to detach from the screen session (or make another SSH connection while leaving the above command running)

  • Create the following PHP script and make it executable (chmod +x)

    #!/usr/bin/php
    <?php
    $com = $argv[1];
    
    $junk = system('(echo "'.$com.'") | nc localhost 1234');
    $data = system('(echo "") | nc localhost 1234');
    
    echo $data
    ?>
    

Explanation of the script:

So, we echo the command you want to run into netcat (nc), which connects it to the other persistent netcat running a shell, the output of the command is written to the fifo but not before the current contents of the fifo is read write to the $junk variable. Next we echo "" and pipe that to netcat, which again is sent to the other netcat which writes "" to our fifo, only this time when the fifo is read it contains the result of the previous command we ran. Neat, huh?

Example of script use:

    root@zim:/tmp# ./run_command.php "mkdir /tmp/stackoverflow"
    $ $ $ $root@zim:/tmp# ./run_command.php "cd /tmp/stackoverflow"
    $ $ $root@zim:/tmp# ./run_command.php "ls -al"
    total 8
    drwxrwxr-x  2 ttucker ttucker 4096 May 22 07:38 .
    drwxrwxrwt 11 root    root    4096 May 22 07:39 ..
    $ $ $ $root@zim:/tmp# ./run_command.php "touch a b c d"
    $ $ $ $root@zim:/tmp# ./run_command.php "ls -l"
    total 0
    -rw-rw-r-- 1 ttucker ttucker 0 May 22 07:39 a
    -rw-rw-r-- 1 ttucker ttucker 0 May 22 07:39 b
    -rw-rw-r-- 1 ttucker ttucker 0 May 22 07:39 c
    -rw-rw-r-- 1 ttucker ttucker 0 May 22 07:39 d
    $ $ $ $root@zim:/tmp# ./run_command.php "mkdir subdir"
    $ $ $ $root@zim:/tmp# ./run_command.php "cd subdir"
    $ $ $root@zim:/tmp# ./run_command.php "ls -al"
    total 8
    drwxrwxr-x 2 ttucker ttucker 4096 May 22 07:40 .
    drwxrwxr-x 3 ttucker ttucker 4096 May 22 07:40 ..
    $ $ $ $root@zim:/tmp# ./run_command.php "touch q w e r t y"
    $ $ $ $root@zim:/tmp# ./run_command.php "ls -al"
    total 8
    drwxrwxr-x 2 ttucker ttucker 4096 May 22 07:40 .
    drwxrwxr-x 3 ttucker ttucker 4096 May 22 07:40 ..
    -rw-rw-r-- 1 ttucker ttucker    0 May 22 07:40 e
    -rw-rw-r-- 1 ttucker ttucker    0 May 22 07:40 q
    -rw-rw-r-- 1 ttucker ttucker    0 May 22 07:40 r
    -rw-rw-r-- 1 ttucker ttucker    0 May 22 07:40 t
    -rw-rw-r-- 1 ttucker ttucker    0 May 22 07:40 w
    -rw-rw-r-- 1 ttucker ttucker    0 May 22 07:40 y
    $ $ $ $

One buggy thing:

It does seem to return $ a couple of times when running commands. This is because it still returns the $ for the shell after a command completes. I think you could easily scrub this out though...

Additional Thoughts / Security Concerns:

  • This reeks of hackery.
  • The idea of a webpage shell seems like a super bad idea.
  • Remember that any other users on the system could pipe commands and into port 1234 and run them as the user you are running this script as.
  • Did I mention I thought this was a bad idea?

Upvotes: 2

Related Questions