Safer CGI Shell
This is a CGI Shell for Unix servers with a bash shell. It has authentication and state management. It needs the session module. The latest version can be downloaded from the project's site. Get help in this topic.
#!/usr/bin/python2.4 import cgitb; cgitb.enable() import sys, os sys.path.append(os.path.dirname(os.environ['SCRIPT_FILENAME'])) import session, time, cgi, urllib, subprocess as sub def login(form, sess): # You absolutely need to change these !!! passwords = {'me':'mine', 'friend':'his'} username = form.getfirst('username', '') password = form.getfirst('password', '') if username and passwords.get(username) == password: sess.set_expires(365 * 24 * 60 * 60) sess.data['logged'] = True sess.data['logged_until'] = time.time() + 10 * 60 sess.data['empty_cmd'] = False return True if not username or not password: message = 'Enter user name and password to log into CGI Shell' elif username not in passwords or passwords.get(username) != password: message = 'Wrong username or password' onload = """var el = document.getElementById('un'); el.focus(); el.select()""" header(sess, onload) print """\ <div style="border:3px solid gray;width:350px;height:130px; margin:auto;padding:20px;" class="shell"> <p>%s</p> <form method="post" action="./cgi-shell.py"> <p>Username: <input type="text" name="username" id="un" value="%s" class="shell" style="border:1px lime solid;padding:2px 4px;" /></p> <p>Password: <input type="password" name="password" class="shell" style="border:1px lime solid;padding:2px 4px;" /></p> <p style="text-align:center;"><input type="submit" value="Login" class="button" /></p> </form> </div> """ % (message, username) return False def end(sess): print '</body>\n</html>' sess.close() sys.exit(0) def shell(form, sess): sess.data['logged_until'] = time.time() + 10 * 60 sess.data.setdefault('output', []) cmd = form.getfirst('cmd', '') cur_dir = sess.data.setdefault('pwd', os.environ['DOCUMENT_ROOT']) if cmd or cmd == '' and sess.data['empty_cmd']: sess.data['cmd'] = cmd cmd = urllib.unquote(cmd) p = sub.Popen(['/bin/bash', '-c', cmd + '\necho $PWD'], stdout=sub.PIPE, stderr=sub.STDOUT, cwd=cur_dir) prompt = '[@' + os.environ['SERVER_NAME'] + ' ' prompt += os.path.basename(cur_dir) + ']$ ' output = [prompt + cmd + '\n'] + p.stdout.readlines() sess.data['pwd'] = (output[-1:])[0].rstrip() sess.data['output'] = (sess.data['output'] + output)[-501:-1] else: cmd = urllib.unquote(sess.data.setdefault('cmd', '')) sess.data['empty_cmd'] = True cur_dir = sess.data['pwd'] output = cgi.escape(''.join(sess.data['output']).rstrip(), True) onload = """window.location.href = '#last'; var el = document.getElementById('cmd');el.focus();el.select();""" prompt = '[@' + os.environ['SERVER_NAME'] + ' ' prompt += os.path.basename(cur_dir) + ']$ ' header(sess, onload) print """\ <div style="width:98%%;margin:0;"> <pre style="border-bottom:0;margin:0;padding:6px;width:100%%; overflow:auto;height:430px;border:3px solid gray;border-bottom:0;" class="shell" id="output">%s<span id="last"></span></pre> <form method="post" action="#last"> <p style="margin:0;padding:6px 6px 8px;width:100%%;border:3px solid gray; border-top:0;" class="shell">%s <input type="text" name="cmd" value="%s" class="shell" id="cmd" style="width:55%%;border:1px lime solid;padding:2px 4px;" /> <input type="submit" value="Submit" name="submit" class="button" /> <input type="submit" value="Logout" name="submit" class="button" /></p> </form> </div> """ % (output, prompt, cgi.escape(cmd, True)) end(sess) def header(sess, onload=''): print """\ %s Content-Type: text/html\n <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html>\n<head><title>CGI Shell</title> <style type="text/css"> .shell {font-size:12px;font-family:monospace;background-color:black;color:lime;} </style>\n</head> <body onload="%s" style="background-color:lightgray;font-family:monospace;"> <h2 style="text-align:center;margin:8px auto">CGI Shell</h2> """ % (sess.cookie, onload) def main(): sess = session.Session() form = cgi.FieldStorage() if form.getfirst('submit') == 'Logout' or \ sess.data.get('logged_until', 0) < time.time(): sess.data['logged'] = False if not sess.data.get('logged') and not login(form, sess): end(sess) shell(form, sess) main()