OLD | NEW |
(Empty) | |
| 1 #!/usr/bin/python |
| 2 ##!/usr/bin/env python |
| 3 """CGI shell server |
| 4 |
| 5 This exposes a shell terminal on a web page. |
| 6 It uses AJAX to send keys and receive screen updates. |
| 7 The client web browser needs nothing but CSS and Javascript. |
| 8 |
| 9 --hostname : sets the remote host name to open an ssh connection to. |
| 10 --username : sets the user name to login with |
| 11 --password : (optional) sets the password to login with |
| 12 --port : set the local port for the server to listen on |
| 13 --watch : show the virtual screen after each client request |
| 14 |
| 15 This project is probably not the most security concious thing I've ever built. |
| 16 This should be considered an experimental tool -- at best. |
| 17 """ |
| 18 |
| 19 from __future__ import absolute_import |
| 20 from __future__ import print_function |
| 21 |
| 22 import sys,os |
| 23 sys.path.insert (0,os.getcwd()) # let local modules precede any installed module
s |
| 24 import socket, random, string, traceback, cgi, time, getopt, getpass, threading,
resource, signal |
| 25 import pxssh, pexpect, ANSI |
| 26 |
| 27 def exit_with_usage(exit_code=1): |
| 28 print(globals()['__doc__']) |
| 29 os._exit(exit_code) |
| 30 |
| 31 def client (command, host='localhost', port=-1): |
| 32 """This sends a request to the server and returns the response. |
| 33 If port <= 0 then host is assumed to be the filename of a Unix domain socket
. |
| 34 If port > 0 then host is an inet hostname. |
| 35 """ |
| 36 if port <= 0: |
| 37 s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) |
| 38 s.connect(host) |
| 39 else: |
| 40 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
| 41 s.connect((host, port)) |
| 42 s.send(command) |
| 43 data = s.recv (2500) |
| 44 s.close() |
| 45 return data |
| 46 |
| 47 def server (hostname, username, password, socket_filename='/tmp/server_sock', da
emon_mode = True, verbose=False): |
| 48 """This starts and services requests from a client. |
| 49 If daemon_mode is True then this forks off a separate daemon process and
returns the daemon's pid. |
| 50 If daemon_mode is False then this does not return until the server is do
ne. |
| 51 """ |
| 52 if daemon_mode: |
| 53 mypid_name = '/tmp/%d.pid' % os.getpid() |
| 54 daemon_pid = daemonize(daemon_pid_filename=mypid_name) |
| 55 time.sleep(1) |
| 56 if daemon_pid != 0: |
| 57 os.unlink(mypid_name) |
| 58 return daemon_pid |
| 59 |
| 60 virtual_screen = ANSI.ANSI (24,80) |
| 61 child = pxssh.pxssh() |
| 62 try: |
| 63 child.login (hostname, username, password, login_naked=True) |
| 64 except: |
| 65 return |
| 66 if verbose: print('login OK') |
| 67 virtual_screen.write (child.before) |
| 68 virtual_screen.write (child.after) |
| 69 |
| 70 if os.path.exists(socket_filename): os.remove(socket_filename) |
| 71 s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) |
| 72 s.bind(socket_filename) |
| 73 os.chmod(socket_filename, 0o777) |
| 74 if verbose: print('Listen') |
| 75 s.listen(1) |
| 76 |
| 77 r = roller (endless_poll, (child, child.PROMPT, virtual_screen)) |
| 78 r.start() |
| 79 if verbose: print("started screen-poll-updater in background thread") |
| 80 sys.stdout.flush() |
| 81 try: |
| 82 while True: |
| 83 conn, addr = s.accept() |
| 84 if verbose: print('Connected by', addr) |
| 85 data = conn.recv(1024) |
| 86 request = data.split(' ', 1) |
| 87 if len(request)>1: |
| 88 cmd = request[0].strip() |
| 89 arg = request[1].strip() |
| 90 else: |
| 91 cmd = request[0].strip() |
| 92 arg = '' |
| 93 |
| 94 if cmd == 'exit': |
| 95 r.cancel() |
| 96 break |
| 97 elif cmd == 'sendline': |
| 98 child.sendline (arg) |
| 99 time.sleep(0.1) |
| 100 shell_window = str(virtual_screen) |
| 101 elif cmd == 'send' or cmd=='xsend': |
| 102 if cmd=='xsend': |
| 103 arg = arg.decode("hex") |
| 104 child.send (arg) |
| 105 time.sleep(0.1) |
| 106 shell_window = str(virtual_screen) |
| 107 elif cmd == 'cursor': |
| 108 shell_window = '%x,%x' % (virtual_screen.cur_r, virtual_screen.c
ur_c) |
| 109 elif cmd == 'refresh': |
| 110 shell_window = str(virtual_screen) |
| 111 elif cmd == 'hash': |
| 112 shell_window = str(hash(str(virtual_screen))) |
| 113 |
| 114 response = [] |
| 115 response.append (shell_window) |
| 116 if verbose: print('\n'.join(response)) |
| 117 sent = conn.send('\n'.join(response)) |
| 118 if sent < len (response): |
| 119 if verbose: print("Sent is too short. Some data was cut off.") |
| 120 conn.close() |
| 121 except e: |
| 122 pass |
| 123 r.cancel() |
| 124 if verbose: print("cleaning up socket") |
| 125 s.close() |
| 126 if os.path.exists(socket_filename): os.remove(socket_filename) |
| 127 if verbose: print("server done!") |
| 128 |
| 129 class roller (threading.Thread): |
| 130 """This class continuously loops a function in a thread. |
| 131 This is basically a thin layer around Thread with a |
| 132 while loop and a cancel. |
| 133 """ |
| 134 def __init__(self, function, args=[], kwargs={}): |
| 135 threading.Thread.__init__(self) |
| 136 self.function = function |
| 137 self.args = args |
| 138 self.kwargs = kwargs |
| 139 self.finished = threading.Event() |
| 140 def cancel(self): |
| 141 """Stop the roller.""" |
| 142 self.finished.set() |
| 143 def run(self): |
| 144 while not self.finished.isSet(): |
| 145 self.function(*self.args, **self.kwargs) |
| 146 |
| 147 def endless_poll (child, prompt, screen, refresh_timeout=0.1): |
| 148 """This keeps the screen updated with the output of the child. |
| 149 This will be run in a separate thread. See roller class. |
| 150 """ |
| 151 #child.logfile_read = screen |
| 152 try: |
| 153 s = child.read_nonblocking(4000, 0.1) |
| 154 screen.write(s) |
| 155 except: |
| 156 pass |
| 157 |
| 158 def daemonize (stdin=None, stdout=None, stderr=None, daemon_pid_filename=None): |
| 159 """This runs the current process in the background as a daemon. |
| 160 The arguments stdin, stdout, stderr allow you to set the filename that the d
aemon reads and writes to. |
| 161 If they are set to None then all stdio for the daemon will be directed to /d
ev/null. |
| 162 If daemon_pid_filename is set then the pid of the daemon will be written to
it as plain text |
| 163 and the pid will be returned. If daemon_pid_filename is None then this will
return None. |
| 164 """ |
| 165 UMASK = 0 |
| 166 WORKINGDIR = "/" |
| 167 MAXFD = 1024 |
| 168 |
| 169 # The stdio file descriptors are redirected to /dev/null by default. |
| 170 if hasattr(os, "devnull"): |
| 171 DEVNULL = os.devnull |
| 172 else: |
| 173 DEVNULL = "/dev/null" |
| 174 if stdin is None: stdin = DEVNULL |
| 175 if stdout is None: stdout = DEVNULL |
| 176 if stderr is None: stderr = DEVNULL |
| 177 |
| 178 try: |
| 179 pid = os.fork() # fork first child |
| 180 except OSError as e: |
| 181 raise Exception("%s [%d]" % (e.strerror, e.errno)) |
| 182 |
| 183 if pid != 0: |
| 184 os.waitpid(pid,0) |
| 185 if daemon_pid_filename is not None: |
| 186 daemon_pid = int(file(daemon_pid_filename,'r').read()) |
| 187 return daemon_pid |
| 188 else: |
| 189 return None |
| 190 |
| 191 # first child |
| 192 os.setsid() |
| 193 signal.signal(signal.SIGHUP, signal.SIG_IGN) |
| 194 |
| 195 try: |
| 196 pid = os.fork() # fork second child |
| 197 except OSError as e: |
| 198 raise Exception("%s [%d]" % (e.strerror, e.errno)) |
| 199 |
| 200 if pid != 0: |
| 201 if daemon_pid_filename is not None: |
| 202 file(daemon_pid_filename,'w').write(str(pid)) |
| 203 os._exit(0) # exit parent (the first child) of the second child. |
| 204 |
| 205 # second child |
| 206 os.chdir(WORKINGDIR) |
| 207 os.umask(UMASK) |
| 208 |
| 209 maxfd = resource.getrlimit(resource.RLIMIT_NOFILE)[1] |
| 210 if maxfd == resource.RLIM_INFINITY: |
| 211 maxfd = MAXFD |
| 212 |
| 213 # close all file descriptors |
| 214 for fd in range(0, maxfd): |
| 215 try: |
| 216 os.close(fd) |
| 217 except OSError: # fd wasn't open to begin with (ignored) |
| 218 pass |
| 219 |
| 220 os.open (DEVNULL, os.O_RDWR) # standard input |
| 221 |
| 222 # redirect standard file descriptors |
| 223 si = open(stdin, 'r') |
| 224 so = open(stdout, 'a+') |
| 225 se = open(stderr, 'a+', 0) |
| 226 os.dup2(si.fileno(), sys.stdin.fileno()) |
| 227 os.dup2(so.fileno(), sys.stdout.fileno()) |
| 228 os.dup2(se.fileno(), sys.stderr.fileno()) |
| 229 |
| 230 return 0 |
| 231 |
| 232 def client_cgi (): |
| 233 """This handles the request if this script was called as a cgi. |
| 234 """ |
| 235 sys.stderr = sys.stdout |
| 236 ajax_mode = False |
| 237 TITLE="Shell" |
| 238 SHELL_OUTPUT="" |
| 239 SID="NOT" |
| 240 print("Content-type: text/html;charset=utf-8\r\n") |
| 241 try: |
| 242 form = cgi.FieldStorage() |
| 243 if 'ajax' in form: |
| 244 ajax_mode = True |
| 245 ajax_cmd = form['ajax'].value |
| 246 SID=form['sid'].value |
| 247 if ajax_cmd == 'send': |
| 248 command = 'xsend' |
| 249 arg = form['arg'].value.encode('hex') |
| 250 result = client (command + ' ' + arg, '/tmp/'+SID) |
| 251 print(result) |
| 252 elif ajax_cmd == 'refresh': |
| 253 command = 'refresh' |
| 254 result = client (command, '/tmp/'+SID) |
| 255 print(result) |
| 256 elif ajax_cmd == 'cursor': |
| 257 command = 'cursor' |
| 258 result = client (command, '/tmp/'+SID) |
| 259 print(result) |
| 260 elif ajax_cmd == 'exit': |
| 261 command = 'exit' |
| 262 result = client (command, '/tmp/'+SID) |
| 263 print(result) |
| 264 elif ajax_cmd == 'hash': |
| 265 command = 'hash' |
| 266 result = client (command, '/tmp/'+SID) |
| 267 print(result) |
| 268 elif 'sid' not in form: |
| 269 SID=random_sid() |
| 270 print(LOGIN_HTML % locals()); |
| 271 else: |
| 272 SID=form['sid'].value |
| 273 if 'start_server' in form: |
| 274 USERNAME = form['username'].value |
| 275 PASSWORD = form['password'].value |
| 276 dpid = server ('127.0.0.1', USERNAME, PASSWORD, '/tmp/'+SID) |
| 277 SHELL_OUTPUT="daemon pid: " + str(dpid) |
| 278 else: |
| 279 if 'cli' in form: |
| 280 command = 'sendline ' + form['cli'].value |
| 281 else: |
| 282 command = 'sendline' |
| 283 SHELL_OUTPUT = client (command, '/tmp/'+SID) |
| 284 print(CGISH_HTML % locals()) |
| 285 except: |
| 286 tb_dump = traceback.format_exc() |
| 287 if ajax_mode: |
| 288 print(str(tb_dump)) |
| 289 else: |
| 290 SHELL_OUTPUT=str(tb_dump) |
| 291 print(CGISH_HTML % locals()) |
| 292 |
| 293 def server_cli(): |
| 294 """This is the command line interface to starting the server. |
| 295 This handles things if the script was not called as a CGI |
| 296 (if you run it from the command line). |
| 297 """ |
| 298 try: |
| 299 optlist, args = getopt.getopt(sys.argv[1:], 'h?d', ['help','h','?', 'hos
tname=', 'username=', 'password=', 'port=', 'watch']) |
| 300 except Exception as e: |
| 301 print(str(e)) |
| 302 exit_with_usage() |
| 303 |
| 304 command_line_options = dict(optlist) |
| 305 options = dict(optlist) |
| 306 # There are a million ways to cry for help. These are but a few of them. |
| 307 if [elem for elem in command_line_options if elem in ['-h','--h','-?','--?',
'--help']]: |
| 308 exit_with_usage(0) |
| 309 |
| 310 hostname = "127.0.0.1" |
| 311 #port = 1664 |
| 312 username = os.getenv('USER') |
| 313 password = "" |
| 314 daemon_mode = False |
| 315 if '-d' in options: |
| 316 daemon_mode = True |
| 317 if '--watch' in options: |
| 318 watch_mode = True |
| 319 else: |
| 320 watch_mode = False |
| 321 if '--hostname' in options: |
| 322 hostname = options['--hostname'] |
| 323 if '--port' in options: |
| 324 port = int(options['--port']) |
| 325 if '--username' in options: |
| 326 username = options['--username'] |
| 327 if '--password' in options: |
| 328 password = options['--password'] |
| 329 else: |
| 330 password = getpass.getpass('password: ') |
| 331 |
| 332 server (hostname, username, password, '/tmp/mysock', daemon_mode) |
| 333 |
| 334 def random_sid (): |
| 335 a=random.randint(0,65535) |
| 336 b=random.randint(0,65535) |
| 337 return '%04x%04x.sid' % (a,b) |
| 338 |
| 339 def parse_host_connect_string (hcs): |
| 340 """This parses a host connection string in the form |
| 341 username:password@hostname:port. All fields are options expcet hostname. A |
| 342 dictionary is returned with all four keys. Keys that were not included are |
| 343 set to empty strings ''. Note that if your password has the '@' character |
| 344 then you must backslash escape it. |
| 345 """ |
| 346 if '@' in hcs: |
| 347 p = re.compile (r'(?P<username>[^@:]*)(:?)(?P<password>.*)(?!\\)@(?P<hos
tname>[^:]*):?(?P<port>[0-9]*)') |
| 348 else: |
| 349 p = re.compile (r'(?P<username>)(?P<password>)(?P<hostname>[^:]*):?(?P<p
ort>[0-9]*)') |
| 350 m = p.search (hcs) |
| 351 d = m.groupdict() |
| 352 d['password'] = d['password'].replace('\\@','@') |
| 353 return d |
| 354 |
| 355 def pretty_box (s, rows=24, cols=80): |
| 356 """This puts an ASCII text box around the given string. |
| 357 """ |
| 358 top_bot = '+' + '-'*cols + '+\n' |
| 359 return top_bot + '\n'.join(['|'+line+'|' for line in s.split('\n')]) + '\n'
+ top_bot |
| 360 |
| 361 def main (): |
| 362 if os.getenv('REQUEST_METHOD') is None: |
| 363 server_cli() |
| 364 else: |
| 365 client_cgi() |
| 366 |
| 367 # It's mostly HTML and Javascript from here on out. |
| 368 CGISH_HTML="""<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> |
| 369 <html> |
| 370 <head> |
| 371 <title>%(TITLE)s %(SID)s</title> |
| 372 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> |
| 373 <style type=text/css> |
| 374 a {color: #9f9; text-decoration: none} |
| 375 a:hover {color: #0f0} |
| 376 hr {color: #0f0} |
| 377 html,body,textarea,input,form |
| 378 { |
| 379 font-family: "Courier New", Courier, mono; |
| 380 font-size: 8pt; |
| 381 color: #0c0; |
| 382 background-color: #020; |
| 383 margin:0; |
| 384 padding:0; |
| 385 border:0; |
| 386 } |
| 387 input { background-color: #010; } |
| 388 textarea { |
| 389 border-width:1; |
| 390 border-style:solid; |
| 391 border-color:#0c0; |
| 392 padding:3; |
| 393 margin:3; |
| 394 } |
| 395 </style> |
| 396 |
| 397 <script language="JavaScript"> |
| 398 function focus_first() |
| 399 {if (document.forms.length > 0) |
| 400 {var TForm = document.forms[0]; |
| 401 for (i=0;i<TForm.length;i++){ |
| 402 if ((TForm.elements[i].type=="text")|| |
| 403 (TForm.elements[i].type=="textarea")|| |
| 404 (TForm.elements[i].type.toString().charAt(0)=="s")) |
| 405 {document.forms[0].elements[i].focus();break;}}}} |
| 406 |
| 407 // JavaScript Virtual Keyboard |
| 408 // If you like this code then buy me a sandwich. |
| 409 // Noah Spurrier <noah@noah.org> |
| 410 var flag_shift=0; |
| 411 var flag_shiftlock=0; |
| 412 var flag_ctrl=0; |
| 413 var ButtonOnColor="#ee0"; |
| 414 |
| 415 function init () |
| 416 { |
| 417 // hack to set quote key to show both single quote and double quote |
| 418 document.form['quote'].value = "'" + ' "'; |
| 419 //refresh_screen(); |
| 420 poll(); |
| 421 document.form["cli"].focus(); |
| 422 } |
| 423 function get_password () |
| 424 { |
| 425 var username = prompt("username?",""); |
| 426 var password = prompt("password?",""); |
| 427 start_server (username, password); |
| 428 } |
| 429 function multibrowser_ajax () |
| 430 { |
| 431 var xmlHttp = false; |
| 432 /*@cc_on @*/ |
| 433 /*@if (@_jscript_version >= 5) |
| 434 try |
| 435 { |
| 436 xmlHttp = new ActiveXObject("Msxml2.XMLHTTP"); |
| 437 } |
| 438 catch (e) |
| 439 { |
| 440 try |
| 441 { |
| 442 xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); |
| 443 } |
| 444 catch (e2) |
| 445 { |
| 446 xmlHttp = false; |
| 447 } |
| 448 } |
| 449 @end @*/ |
| 450 |
| 451 if (!xmlHttp && typeof XMLHttpRequest != 'undefined') |
| 452 { |
| 453 xmlHttp = new XMLHttpRequest(); |
| 454 } |
| 455 return xmlHttp; |
| 456 } |
| 457 function load_url_to_screen(url) |
| 458 { |
| 459 xmlhttp = multibrowser_ajax(); |
| 460 //window.XMLHttpRequest?new XMLHttpRequest(): new ActiveXObject("Microsoft.X
MLHTTP"); |
| 461 xmlhttp.onreadystatechange = update_virtual_screen; |
| 462 xmlhttp.open("GET", url); |
| 463 xmlhttp.setRequestHeader("If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT"
); |
| 464 xmlhttp.send(null); |
| 465 } |
| 466 function update_virtual_screen() |
| 467 { |
| 468 if ((xmlhttp.readyState == 4) && (xmlhttp.status == 200)) |
| 469 { |
| 470 var screen_text = xmlhttp.responseText; |
| 471 document.form["screen_text"].value = screen_text; |
| 472 //var json_data = json_parse(xmlhttp.responseText); |
| 473 } |
| 474 } |
| 475 function poll() |
| 476 { |
| 477 refresh_screen(); |
| 478 timerID = setTimeout("poll()", 2000); |
| 479 // clearTimeout(timerID); |
| 480 } |
| 481 //function start_server (username, password) |
| 482 //{ |
| 483 // load_url_to_screen('cgishell.cgi?ajax=serverstart&username=' + escape(user
name) + '&password=' + escape(password); |
| 484 //} |
| 485 function refresh_screen() |
| 486 { |
| 487 load_url_to_screen('cgishell.cgi?ajax=refresh&sid=%(SID)s'); |
| 488 } |
| 489 function query_hash() |
| 490 { |
| 491 load_url_to_screen('cgishell.cgi?ajax=hash&sid=%(SID)s'); |
| 492 } |
| 493 function query_cursor() |
| 494 { |
| 495 load_url_to_screen('cgishell.cgi?ajax=cursor&sid=%(SID)s'); |
| 496 } |
| 497 function exit_server() |
| 498 { |
| 499 load_url_to_screen('cgishell.cgi?ajax=exit&sid=%(SID)s'); |
| 500 } |
| 501 function type_key (chars) |
| 502 { |
| 503 var ch = '?'; |
| 504 if (flag_shiftlock || flag_shift) |
| 505 { |
| 506 ch = chars.substr(1,1); |
| 507 } |
| 508 else if (flag_ctrl) |
| 509 { |
| 510 ch = chars.substr(2,1); |
| 511 } |
| 512 else |
| 513 { |
| 514 ch = chars.substr(0,1); |
| 515 } |
| 516 load_url_to_screen('cgishell.cgi?ajax=send&sid=%(SID)s&arg=' + escape(ch)); |
| 517 if (flag_shift || flag_ctrl) |
| 518 { |
| 519 flag_shift = 0; |
| 520 flag_ctrl = 0; |
| 521 } |
| 522 update_button_colors(); |
| 523 } |
| 524 |
| 525 function key_shiftlock() |
| 526 { |
| 527 flag_ctrl = 0; |
| 528 flag_shift = 0; |
| 529 if (flag_shiftlock) |
| 530 { |
| 531 flag_shiftlock = 0; |
| 532 } |
| 533 else |
| 534 { |
| 535 flag_shiftlock = 1; |
| 536 } |
| 537 update_button_colors(); |
| 538 } |
| 539 |
| 540 function key_shift() |
| 541 { |
| 542 if (flag_shift) |
| 543 { |
| 544 flag_shift = 0; |
| 545 } |
| 546 else |
| 547 { |
| 548 flag_ctrl = 0; |
| 549 flag_shiftlock = 0; |
| 550 flag_shift = 1; |
| 551 } |
| 552 update_button_colors(); |
| 553 } |
| 554 function key_ctrl () |
| 555 { |
| 556 if (flag_ctrl) |
| 557 { |
| 558 flag_ctrl = 0; |
| 559 } |
| 560 else |
| 561 { |
| 562 flag_ctrl = 1; |
| 563 flag_shiftlock = 0; |
| 564 flag_shift = 0; |
| 565 } |
| 566 |
| 567 update_button_colors(); |
| 568 } |
| 569 function update_button_colors () |
| 570 { |
| 571 if (flag_ctrl) |
| 572 { |
| 573 document.form['Ctrl'].style.backgroundColor = ButtonOnColor; |
| 574 document.form['Ctrl2'].style.backgroundColor = ButtonOnColor; |
| 575 } |
| 576 else |
| 577 { |
| 578 document.form['Ctrl'].style.backgroundColor = document.form.style.backgr
oundColor; |
| 579 document.form['Ctrl2'].style.backgroundColor = document.form.style.backg
roundColor; |
| 580 } |
| 581 if (flag_shift) |
| 582 { |
| 583 document.form['Shift'].style.backgroundColor = ButtonOnColor; |
| 584 document.form['Shift2'].style.backgroundColor = ButtonOnColor; |
| 585 } |
| 586 else |
| 587 { |
| 588 document.form['Shift'].style.backgroundColor = document.form.style.backg
roundColor; |
| 589 document.form['Shift2'].style.backgroundColor = document.form.style.back
groundColor; |
| 590 } |
| 591 if (flag_shiftlock) |
| 592 { |
| 593 document.form['ShiftLock'].style.backgroundColor = ButtonOnColor; |
| 594 } |
| 595 else |
| 596 { |
| 597 document.form['ShiftLock'].style.backgroundColor = document.form.style.b
ackgroundColor; |
| 598 } |
| 599 |
| 600 } |
| 601 function keyHandler(e) |
| 602 { |
| 603 var pressedKey; |
| 604 if (document.all) { e = window.event; } |
| 605 if (document.layers) { pressedKey = e.which; } |
| 606 if (document.all) { pressedKey = e.keyCode; } |
| 607 pressedCharacter = String.fromCharCode(pressedKey); |
| 608 type_key(pressedCharacter+pressedCharacter+pressedCharacter); |
| 609 alert(pressedCharacter); |
| 610 // alert(' Character = ' + pressedCharacter + ' [Decimal value = ' + pressedK
ey + ']'); |
| 611 } |
| 612 //document.onkeypress = keyHandler; |
| 613 //if (document.layers) |
| 614 // document.captureEvents(Event.KEYPRESS); |
| 615 //http://sniptools.com/jskeys |
| 616 //document.onkeyup = KeyCheck; |
| 617 function KeyCheck(e) |
| 618 { |
| 619 var KeyID = (window.event) ? event.keyCode : e.keyCode; |
| 620 type_key(String.fromCharCode(KeyID)); |
| 621 e.cancelBubble = true; |
| 622 window.event.cancelBubble = true; |
| 623 } |
| 624 </script> |
| 625 |
| 626 </head> |
| 627 |
| 628 <body onload="init()"> |
| 629 <form id="form" name="form" action="/cgi-bin/cgishell.cgi" method="POST"> |
| 630 <input name="sid" value="%(SID)s" type="hidden"> |
| 631 <textarea name="screen_text" cols="81" rows="25">%(SHELL_OUTPUT)s</textarea> |
| 632 <hr noshade="1"> |
| 633 <input name="cli" id="cli" type="text" size="80"><br> |
| 634 <table border="0" align="left"> |
| 635 <tr> |
| 636 <td width="86%%" align="center"> |
| 637 <input name="submit" type="submit" value="Submit"> |
| 638 <input name="refresh" type="button" value="REFRESH" onclick="refresh_screen(
)"> |
| 639 <input name="refresh" type="button" value="CURSOR" onclick="query_cursor()"> |
| 640 <input name="hash" type="button" value="HASH" onclick="query_hash()"> |
| 641 <input name="exit" type="button" value="EXIT" onclick="exit_server()"> |
| 642 <br> |
| 643 <input type="button" value="Esc" onclick="type_key('\\x1b\\x1b')" /> |
| 644 <input type="button" value="` ~" onclick="type_key('`~')" /> |
| 645 <input type="button" value="1!" onclick="type_key('1!')" /> |
| 646 <input type="button" value="2@" onclick="type_key('2@\\x00')" /> |
| 647 <input type="button" value="3#" onclick="type_key('3#')" /> |
| 648 <input type="button" value="4$" onclick="type_key('4$')" /> |
| 649 <input type="button" value="5%%" onclick="type_key('5%%')" /> |
| 650 <input type="button" value="6^" onclick="type_key('6^\\x1E')" /> |
| 651 <input type="button" value="7&" onclick="type_key('7&')" /> |
| 652 <input type="button" value="8*" onclick="type_key('8*')" /> |
| 653 <input type="button" value="9(" onclick="type_key('9(')" /> |
| 654 <input type="button" value="0)" onclick="type_key('0)')" /> |
| 655 <input type="button" value="-_" onclick="type_key('-_\\x1F')" /> |
| 656 <input type="button" value="=+" onclick="type_key('=+')" /> |
| 657 <input type="button" value="BkSp" onclick="type_key('\\x08\\x08\\x08')" /> |
| 658 <br> |
| 659 <input type="button" value="Tab" onclick="type_key('\\t\\t')" /> |
| 660 <input type="button" value="Q" onclick="type_key('qQ\\x11')" /> |
| 661 <input type="button" value="W" onclick="type_key('wW\\x17')" /> |
| 662 <input type="button" value="E" onclick="type_key('eE\\x05')" /> |
| 663 <input type="button" value="R" onclick="type_key('rR\\x12')" /> |
| 664 <input type="button" value="T" onclick="type_key('tT\\x14')" /> |
| 665 <input type="button" value="Y" onclick="type_key('yY\\x19')" /> |
| 666 <input type="button" value="U" onclick="type_key('uU\\x15')" /> |
| 667 <input type="button" value="I" onclick="type_key('iI\\x09')" /> |
| 668 <input type="button" value="O" onclick="type_key('oO\\x0F')" /> |
| 669 <input type="button" value="P" onclick="type_key('pP\\x10')" /> |
| 670 <input type="button" value="[ {" onclick="type_key('[{\\x1b')" /> |
| 671 <input type="button" value="] }" onclick="type_key(']}\\x1d')" /> |
| 672 <input type="button" value="\\ |" onclick="type_key('\\\\|\\x1c')" /> |
| 673 <br> |
| 674 <input type="button" id="Ctrl" value="Ctrl" onclick="key_ctrl()" /> |
| 675 <input type="button" value="A" onclick="type_key('aA\\x01')" /> |
| 676 <input type="button" value="S" onclick="type_key('sS\\x13')" /> |
| 677 <input type="button" value="D" onclick="type_key('dD\\x04')" /> |
| 678 <input type="button" value="F" onclick="type_key('fF\\x06')" /> |
| 679 <input type="button" value="G" onclick="type_key('gG\\x07')" /> |
| 680 <input type="button" value="H" onclick="type_key('hH\\x08')" /> |
| 681 <input type="button" value="J" onclick="type_key('jJ\\x0A')" /> |
| 682 <input type="button" value="K" onclick="type_key('kK\\x0B')" /> |
| 683 <input type="button" value="L" onclick="type_key('lL\\x0C')" /> |
| 684 <input type="button" value="; :" onclick="type_key(';:')" /> |
| 685 <input type="button" id="quote" value="'" onclick="type_key('\\x27\\x22')" /
> |
| 686 <input type="button" value="Enter" onclick="type_key('\\n\\n')" /> |
| 687 <br> |
| 688 <input type="button" id="ShiftLock" value="Caps Lock" onclick="key_shiftlock
()" /> |
| 689 <input type="button" id="Shift" value="Shift" onclick="key_shift()" /> |
| 690 <input type="button" value="Z" onclick="type_key('zZ\\x1A')" /> |
| 691 <input type="button" value="X" onclick="type_key('xX\\x18')" /> |
| 692 <input type="button" value="C" onclick="type_key('cC\\x03')" /> |
| 693 <input type="button" value="V" onclick="type_key('vV\\x16')" /> |
| 694 <input type="button" value="B" onclick="type_key('bB\\x02')" /> |
| 695 <input type="button" value="N" onclick="type_key('nN\\x0E')" /> |
| 696 <input type="button" value="M" onclick="type_key('mM\\x0D')" /> |
| 697 <input type="button" value=", <" onclick="type_key(',<')" /> |
| 698 <input type="button" value=". >" onclick="type_key('.>')" /> |
| 699 <input type="button" value="/ ?" onclick="type_key('/?')" /> |
| 700 <input type="button" id="Shift2" value="Shift" onclick="key_shift()" /> |
| 701 <input type="button" id="Ctrl2" value="Ctrl" onclick="key_ctrl()" /> |
| 702 <br> |
| 703 <input type="button" value=" FINAL FRONTIER " onclick="type_ke
y(' ')" /> |
| 704 </td> |
| 705 </tr> |
| 706 </table> |
| 707 </form> |
| 708 </body> |
| 709 </html> |
| 710 """ |
| 711 |
| 712 LOGIN_HTML="""<html> |
| 713 <head> |
| 714 <title>Shell Login</title> |
| 715 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> |
| 716 <style type=text/css> |
| 717 a {color: #9f9; text-decoration: none} |
| 718 a:hover {color: #0f0} |
| 719 hr {color: #0f0} |
| 720 html,body,textarea,input,form |
| 721 { |
| 722 font-family: "Courier New", Courier, mono; |
| 723 font-size: 8pt; |
| 724 color: #0c0; |
| 725 background-color: #020; |
| 726 margin:3; |
| 727 padding:0; |
| 728 border:0; |
| 729 } |
| 730 input { background-color: #010; } |
| 731 input,textarea { |
| 732 border-width:1; |
| 733 border-style:solid; |
| 734 border-color:#0c0; |
| 735 padding:3; |
| 736 margin:3; |
| 737 } |
| 738 </style> |
| 739 <script language="JavaScript"> |
| 740 function init () |
| 741 { |
| 742 document.login_form["username"].focus(); |
| 743 } |
| 744 </script> |
| 745 </head> |
| 746 <body onload="init()"> |
| 747 <form name="login_form" method="POST"> |
| 748 <input name="start_server" value="1" type="hidden"> |
| 749 <input name="sid" value="%(SID)s" type="hidden"> |
| 750 username: <input name="username" type="text" size="30"><br> |
| 751 password: <input name="password" type="password" size="30"><br> |
| 752 <input name="submit" type="submit" value="enter"> |
| 753 </form> |
| 754 <br> |
| 755 </body> |
| 756 </html> |
| 757 """ |
| 758 |
| 759 if __name__ == "__main__": |
| 760 try: |
| 761 main() |
| 762 except Exception as e: |
| 763 print(str(e)) |
| 764 tb_dump = traceback.format_exc() |
| 765 print(str(tb_dump)) |
| 766 |
OLD | NEW |