Permalink
Browse files

- first commit

  • Loading branch information...
0 parents commit 0708ba3d91940900a444f3713ee5d7edea864291 @koto committed Mar 4, 2011
Showing with 298 additions and 0 deletions.
  1. 0 README
  2. +140 −0 WebSocketsClient.py
  3. BIN WebSocketsClient.pyc
  4. +49 −0 colorize.py
  5. BIN colorize.pyc
  6. +9 −0 handshake.bin
  7. +10 −0 payloads.txt
  8. +90 −0 socket_io_client.py
0 README
No changes.
@@ -0,0 +1,140 @@
+#!/usr/bin/env python
+#
+# This file is part of
+# "Hacking HTML 5" training materials
+# @author Krzysztof Kotowicz <kkotowicz at gmail dot com>
+# @copyright Krzysztof Kotowicz <kkotowicz at gmail dot com>
+# @see http://blog.kotowicz.net
+
+import socket
+import select
+import sys
+
+class WebSocketsClient:
+ """WebSockets client"""
+
+ PREFIX = "\x00"
+ SUFFIX = "\xFF"
+
+ def __init__(self, handshake_file='handshake.bin', **kwargs):
+ """Connects to socket and performs the handshake"""
+ self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ self.buf = ''
+ self.handshake(handshake_file, kwargs)
+
+ def __del__(self):
+ self.close()
+
+ def close(self):
+ self.socket.close();
+
+ def handshake(self, handshake_file, kw):
+ """Sends the handshake from the file"""
+ self.socket.connect((kw['host'], kw['port']))
+ handshake = open(handshake_file,'rb').read()
+ handshake = handshake.replace('%HOST%',kw['host'])\
+ .replace('%PORT%',str(kw['port']))\
+ .replace('%ORIGIN%',kw['origin'])\
+ .replace('%PATH%',kw['path'])
+
+ self.socket.sendall(handshake)
+
+ def send_raw(self, s):
+ """Send the message through websocket"""
+ self.socket.sendall(self.ws_encode(s))
+ return s
+
+ def ws_encode(self, s):
+ """Encode the message in WebSockets frame"""
+ return self.PREFIX + s + self.SUFFIX
+
+ def heartbeat(self,bytes=4096):
+ """Sends last heartbeat in buffer back to the server"""
+ self.recv_raw(bytes)
+ msgs = self.buf.split(self.PREFIX)
+ msgs.reverse()
+ for msg in msgs:
+ if self.is_heartbeat(msg):
+ self.send_raw(msg[:-1]) # strip trailing \xFF
+ self.buf = self.buf.replace(msg + self.SUFFIX, '') #remove from buffer
+ break;
+
+ def recv_raw(self, bytes = 4096):
+ """Read bytes from socket into the buffer"""
+ read = self.socket.recv(bytes)
+ self.buf += read
+
+ def recv(self, bytes = 4096):
+ """Return new message from the server (also resends but ignores heartbeats)"""
+ self.recv_raw(bytes)
+ start = self.buf.find(self.PREFIX)
+ if start == -1:
+ return ''
+ end = self.buf.find(self.SUFFIX, start)
+ if end == -1:
+ return ''
+
+ # we have a full message in buffer now
+ msg = self.buf[start+1:end]
+ if start > 0 :
+ sys.stdout.write(self.buf[:start]) # something before the message, probably part of handshake
+ if len(self.buf) == end:
+ self.buf = ''
+ else:
+ self.buf = self.buf[end+1:]
+
+ if self.is_heartbeat(msg): # heartbeat, resend & ignore
+ self.send_raw(msg)
+ msg = ''
+
+ return msg
+
+ def has_msg_in_buffer(self):
+ """Check if there is a complete message in the buffer"""
+ begin = self.buf.find(self.PREFIX)
+ if begin == -1:
+ return False
+ end = self.buf.find(self.SUFFIX, begin)
+ if end == -1:
+ return False
+ return True
+
+ def is_heartbeat(self, s):
+ return False #to be defined in child class
+
+ def json_encode(self,s):
+ return s #to be defined in child class
+
+ def encode(self, s):
+ return s #to be defined in child class
+
+ def send(self, send):
+ """Encode and send the message trough socket"""
+ if send.startswith('~j'):
+ send = send[2:] # strip ~j
+ send = self.encode(self.json_encode(send))
+ elif send.startswith('~r'): # raw message, not neccessarily socket.io compatible
+ send = send[2:]
+ else:
+ send = self.encode(send)
+ return self.send_raw(send)
+
+ def can_recv(self):
+ """Check if we're ready for recv()"""
+ if self.has_msg_in_buffer():
+ return True
+ inputready, outputready,exceptrdy = select.select([self.socket],[],[], 0)
+ return len(inputready) > 0
+
+class SocketIoClient(WebSocketsClient):
+ """Socket.Io compatible client"""
+
+ def is_heartbeat(self, s):
+ return s.startswith('~m~4~m~~h~')
+
+ def json_encode(self,s):
+ return '~j~' + s
+
+ def encode(self, s):
+ return '~m~%d~m~%s' % (len(s), s)
+
Binary file not shown.
@@ -0,0 +1,49 @@
+color_names = ('black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white')
+foreground = dict([(color_names[x], '3%s' % x) for x in range(8)])
+background = dict([(color_names[x], '4%s' % x) for x in range(8)])
+RESET = '0'
+
+def colorize(text='', opts=(), **kwargs):
+ """
+ Returns your text, enclosed in ANSI graphics codes.
+
+ Depends on the keyword arguments 'fg' and 'bg', and the contents of
+ the opts tuple/list.
+
+ Returns the RESET code if no parameters are given.
+
+ Valid colors:
+ 'black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white'
+
+ Valid options:
+ 'bold'
+ 'underscore'
+ 'blink'
+ 'reverse'
+ 'conceal'
+ 'noreset' - string will not be auto-terminated with the RESET code
+
+ Examples:
+ colorize('hello', fg='red', bg='blue', opts=('blink',))
+ colorize()
+ colorize('goodbye', opts=('underscore',))
+ print colorize('first line', fg='red', opts=('noreset',))
+ print 'this should be red too'
+ print colorize('and so should this')
+ print 'this should not be red'
+ """
+ code_list = []
+ if text == '' and len(opts) == 1 and opts[0] == 'reset':
+ return '\x1b[%sm' % RESET
+ for k, v in kwargs.iteritems():
+ if k == 'fg':
+ code_list.append(foreground[v])
+ elif k == 'bg':
+ code_list.append(background[v])
+ for o in opts:
+ if o in opt_dict:
+ code_list.append(opt_dict[o])
+ if 'noreset' not in opts:
+ text = text + '\x1b[%sm' % RESET
+ return ('\x1b[%sm' % ';'.join(code_list)) + text
+
Binary file not shown.
@@ -0,0 +1,9 @@
+GET %PATH% HTTP/1.1
+Upgrade: WebSocket
+Connection: Upgrade
+Host: %HOST%
+Origin: http://%ORIGIN%
+Sec-WebSocket-Key1: 52[6 21 S~H 2 60Or
+Sec-WebSocket-Key2: 4`168 I131 069
+
+F�By�1�
@@ -0,0 +1,10 @@
+~r[{"length":1}]
+~r{"length":1}
+~j{"messages":[{"length":1}]}
+~j{"length":1}
+hello
+hello<script>alert(/xss/)</script>
+hello<img src=x:x onerror=alert(/xss.2/)>
+~j{
+~j
+~r~m~EVJLFDJP~
@@ -0,0 +1,90 @@
+#!/usr/bin/env python
+#
+# This file is part of
+# "Hacking HTML 5" training materials
+# @author Krzysztof Kotowicz <kkotowicz at gmail dot com>
+# @copyright Krzysztof Kotowicz <kkotowicz at gmail dot com>
+# @see http://blog.kotowicz.net
+
+import sys
+import os
+import select
+import WebSocketsClient
+from colorize import colorize, color_names
+
+if __name__ == '__main__': # script part
+ if len(sys.argv) == 1 :
+ print "socket_io_client by Krzysztof Kotowicz, http://blog.kotowicz.net"
+ print
+ print "Usage: "
+ print "socket_io_client host port [origin_to_simulate] [socket_io_path]"
+ print
+ print "Example: socket_io_client websocket.example.org 8888 client.example.org /socket.io/websocket"
+ sys.exit(1)
+
+ HOST = len(sys.argv) <= 1 and 'websocket.security.localhost' or sys.argv[1] # The remote host
+ PORT = len(sys.argv) <= 2 and 8124 or int(sys.argv[2]) # The remote port
+ ORIGIN = len(sys.argv) <= 3 and 'victim.security.localhost' or sys.argv[3] # origin to simulate
+ PATH = len(sys.argv) <= 4 and '/socket.io/websocket' or sys.argv[4]
+
+ interactive = os.isatty(0)
+
+ sys.stderr.write("Connecting to " + HOST + ":" + str(PORT) + "\n")
+ client = WebSocketsClient.SocketIoClient(host=HOST,port=PORT,origin=ORIGIN,path=PATH)
+
+ if (interactive):
+ prompt = colorize("\nWhat to send (nothing: quit, ~jXXX: json object, ~rXXX - raw socket data XXX):", fg='green')
+ else:
+ prompt = ""
+
+ quit = False
+ p = 0
+
+ import random
+ while not quit:
+ try:
+ sys.stderr.flush()
+
+ # Wait for input from stdin & socket
+ inputready, outputready,exceptrdy = select.select([0],[],[], 0)
+ if client.can_recv():
+ inputready.append(client.socket)
+ for i in inputready:
+ if i == client.socket:
+ data = client.recv()
+ if data == False:
+ sys.stderr.write(colorize('Socket empty, quitting',fg='red'))
+ quit = True
+ break
+ else:
+ if len(data) == 0:
+ break
+ sys.stdout.write(client.ws_encode(data))
+ if interactive:
+ sys.stderr.write(prompt)
+ elif i == 0:
+ data = sys.stdin.readline().strip()
+ if not data:
+ sys.stderr.write(colorize('Shutting down.', fg='red'))
+ quit = True
+ break
+ else:
+ sent = client.send(data)
+ if interactive:
+ data = colorize("Sent: " + sent, fg='yellow')
+ sys.stderr.write(data)
+ sys.stderr.write(prompt)
+ else:
+ sys.stderr.write("Sent payload #%i\n" % p)
+ p = p + 1
+ if len(inputready) > 0:
+ sys.stdout.flush()
+ sys.stderr.flush()
+
+ except KeyboardInterrupt:
+ sys.stderr.write(colorize('Interrupted.',fg='red'))
+ quit = True
+ pass
+
+ client.close()
+ sys.stderr.write("\n")

0 comments on commit 0708ba3

Please sign in to comment.