If you have, like I do, a virtual server on hosting service, that support cgi but don’t have access to a shell and php have passthru disabled you still can have access to a shell, even if you can’t install anything on that machine – like anyterm.
There is this project, which I did, called jQuery terminal, that emulate a Unix terminal. All you need is interpreter that will execute shell commands.
Lots of hosting services disable php passthru but leave cgi script, so if you have them you can create simple shell like this one:
UPDATE: If you don’t want to code it yourself (or look at working solution), you can check my project LEASH – Browser Shell. You if you prefer there is also available single file Shell using same library.
#!/bin/bash
echo -en "Content-Type: text/plain\r\n\r\n"
query=$(/usr/bin/python -c "import urllib; print urllib.unquote_plus('$QUERY_STRING')")
eval $query 2>&1
I use python subprocess to decode QUERY_STRING. Probably it can be done using some Unix tools.
On my server I use Python CGI script like this one:.
#!/usr/bin/python
import cgi
import subprocess as sub
try:
from json import dumps as json_serialize
except ImportError:
def json_serialize(obj):
result = ''
t = type(obj)
if t == types.StringType:
result += '"%s"' % obj.replace('\\', '\\\\').replace('"', '\\"').replace('\n', '\\n')
elif t == types.NoneType:
result += 'null'
elif t == types.IntType or t == types.FloatType:
result += str(obj)
elif t == types.LongType:
result += str(int(obj))
elif t == types.TupleType:
result += '[' + ','.join(map(json_serialize, list(obj))) + ']'
elif t == types.ListType:
result += '[' + ','.join(map(json_serialize, obj)) + ']'
elif t == types.DictType:
array = ['"%s":%s' % (k,json_serialize(v)) for k,v in obj.iteritems()]
result += '{' + ','.join(array) + '}'
else:
result += '"unknown type - ' + type(obj).__name__ + '"'
return result
class Singleton(object):
__single = None
def __init__(self):
Singleton.__single = self
def __new__(cls):
if Singleton.__single:
return Singleton.__single
else:
return super(Singleton, cls).__new__(cls)
class Form(Singleton):
def __init__(self):
super(Form)
self.form = cgi.FieldStorage()
def __getitem__(self, name):
return self.form.getvalue(name)
def execv(command, path):
command = 'cd %s && %s && pwd 1>&2' % (path, command)
proc = sub.Popen(['/bin/bash', '-c', command],
stdout=sub.PIPE, stderr=sub.PIPE)
stderr = proc.stderr.read()[:-1]
stdout = proc.stdout.read()[:-1]
if not os.path.exists(stderr):
raise Exception(stdout, stderr)
return {
"cwd": stderr,
"stdout": re.sub('.\x08', '', stdout)
}
if __name__ == '__main__':
print "Content-Type: text/plain"
print
form = Form()
if token() == form['token']:
response = {}
try:
response['result'] = execv(form['command'], form['path'])
except Exception, e:
response['error'] = e.args[1]
response['result'] = {'stdout': e.args[0], 'cwd': form['path']}
else:
response['error'] = None
else:
response = {'error': 'You are not authorized', 'result': None}
stdout.write(json_serialize(response))
You have enabled passthru in php you can write your shell in php.
Now when you have access to a shell you need to setup interface using jQuery terminal.
<!DOCTYPE HTML>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<title>Shell</title>
http://code.jquery.com/jquery-1.7.1.min.js
http://terminal/js/jquery.mousewheel-min.js
http://terminal/js/jquery.terminal.js
<link href="terminal/css/jquery.terminal.css" rel="stylesheet"/>
<style>
.terminal a.ui-slider-handle:focus { outline: none; }
body { margin: 0; padding: 0; }
html { background-color: #000; }
.clear { clear: both; }
/* This works only in Safari and Google Chrome */
@media screen and (-webkit-min-device-pixel-ratio:0) {
.terminal, .terminal .terminal-output, .terminal .terminal-output div,
.terminal .terminal-output div div, .cmd, .terminal .cmd span, .terminal .cmd div {
font-weight: bold;
}
}
</style>
<script>
$(function() {
var pwd, last_dir, home_dir;
var terminal = $('#shell').terminal(function(command, term) {
if (command.replace(/^ *(.*) *$/, '$1') == '-') {
pwd = last_dir;
return;
}
term.pause();
$.post("/cgi-bin/cmd.py", {
token: term.token(),
command: command.replace(/(\\)?~/, function($0,$1) {
return $1 ? $0 : home_dir;
}),
path: pwd
}, function(response) {
term.echo(response.result.stdout);
pwd = response.result.cwd;
term.resume();
});
}, {
login: function(user, password, authenticate) {
$.post("/cgi-bin/cmd.py", {
user: user,
password: password
}, function(token) {
if (token) {
home_dir = pwd = last_dir = '/home/ + user;
}
authenticate(token);
});
},
prompt: function(callback) {
var username = terminal.login_name();
var re = new RegExp("^" + '/home/' + username);
var username = '[[;#44D544;]' + username + ']';
var path = '[[;#5555FF;]' + pwd.replace(re, '~') + ']';
callback(username + '[[;#989898;]:]' + path + '[[;#989898;]$] ');
},
name: 'shell'
}).css({
overflow: 'auto'
});
$(window).resize(function() {
terminal.css('height', $(window).height()-20);
}).resize();
});
</script>
</head>
<body>
<div id="shell"></div>
</body>
</html>