From 66f2db86bf06d229a48bfa197cf93cb41e59953d Mon Sep 17 00:00:00 2001 From: Ruben <ruben@rubenkerkhof.com> Date: Sun, 17 Oct 2010 17:38:55 +0200 Subject: [PATCH 11/14] 25_CVE-2009-1629.diff from Debian --- ajaxterm.js | 17 ++++++++++++++- ajaxterm.py | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 74 insertions(+), 8 deletions(-) diff --git a/ajaxterm.js b/ajaxterm.js index 4edcb6c..2579a8f 100644 --- a/ajaxterm.js +++ b/ajaxterm.js @@ -6,7 +6,22 @@ ajaxterm.Terminal_ctor=function(id,width,height) { ie=1; if (navigator.userAgent.indexOf("WebKit") >= 0) webkit=1; - var sid=""+Math.round(Math.random()*1000000000); + var sid=""; + + for (var i=0; i < 255; i++) { + var r = 0; + // now get a random number between 0 and 255 + // numbers not in the range are intentionally discarded + // as it reduces the chance of predicting the seed, by not + // using all of the numbers generated by the PRNG + do { + r = Math.round(Math.random()*1000); + } while(r >= 255); + r = r.toString(16); + if (r.length == 1) + r = "0"+r; + sid += "%" + r; + } if (width==0) { width=80; diff --git a/ajaxterm.py b/ajaxterm.py index 962e685..8695590 100755 --- a/ajaxterm.py +++ b/ajaxterm.py @@ -8,8 +8,14 @@ try: except: pass -import array,cgi,fcntl,glob,mimetypes,optparse,os,pty,random,re,signal,select,sys,threading,time,termios,struct,pwd -from datetime import datetime +import array,cgi,fcntl,glob,mimetypes,optparse,os,pty,random,re,signal,select,sys,threading,time,termios,struct,pwd,Cookie +from datetime import datetime, timedelta + +try: + from hashlib import sha1 +except ImportError: + import sha + sha1 = sha.new os.chdir(os.path.normpath(os.path.dirname(__file__))) # Optional: Add QWeb in sys path @@ -517,30 +523,61 @@ class AjaxTerm: self.multi = Multiplex(cmd,serverport) self.reaper = Reaper(self.multi) self.session = {} + self.session_ip = {} + self.sessions_limit = 20 + self.sessions_user_limit = 4 + m = sha1() + m.update(os.urandom(128)) + self.cookie_name = m.hexdigest() def __call__(self, environ, start_response): req = qweb.QWebRequest(environ, start_response,session=None) if req.PATH_INFO.endswith('/u'): + req.response_headers['Content-Type']='text/xml' + uid="" + if self.cookie_name not in req.request_cookies: + req.write('<?xml version="1.0"?><idem></idem>') + return req + uid = req.request_cookies[self.cookie_name].value s=req.REQUEST["s"] k=req.REQUEST["k"] c=req.REQUEST["c"] w=req.REQUEST.int("w") h=req.REQUEST.int("h") - if s in self.session: - term=self.session[s] + ip="unknown" + if environ.has_key("REMOTE_ADDR"): + ip=environ['REMOTE_ADDR'] + if ip == "127.0.0.1" and environ.has_key("HTTP_X_FORWARDED_FOR"): + ip=environ["HTTP_X_FORWARDED_FOR"] + + if (uid+s) in self.session: + term=self.session[uid+s] + req.response_cookies.load(req.request_cookies[self.cookie_name].OutputString()) + req.response_cookies[self.cookie_name]['expires'] = datetime.utcnow()+timedelta(seconds=60) else: if not (w>2 and w<256 and h>2 and h<100): w,h=80,25 - term=self.session[s]=self.multi.create(w,h) + # check if there aren't too many open sessions + if len(self.session) < self.sessions_limit: + count=0 + for i in self.session_ip.keys(): + if self.session_ip[i] == ip: + count+=1 + if count <= self.sessions_user_limit: + term=self.session[uid+s]=self.multi.create(w,h) + self.session_ip[uid+s]=ip + else: + req.write('<?xml version="1.0"?><idem></idem>') + return req if k: self.multi.proc_write(term,k) time.sleep(0.002) dump=self.multi.dump(term,c) - req.response_headers['Content-Type']='text/xml' if isinstance(dump,str): req.write(dump) req.response_gzencode=1 else: - del self.session[s] + del self.session[uid+s] + del self.session_ip[uid+s] req.write('<?xml version="1.0"?><idem></idem>') # print "sessions %r"%self.session else: @@ -549,9 +586,23 @@ class AjaxTerm: req.response_headers['Content-Type'] = self.mime.get(os.path.splitext(n)[1].lower(), 'application/octet-stream') req.write(self.files[n]) else: + if self.cookie_name not in req.request_cookies: + self.genSidCookie(req) req.response_headers['Content-Type'] = 'text/html; charset=UTF-8' req.write(self.files['index']) return req + def genSidCookie(self, req): + m = sha1() + m.update(os.urandom(160)) + req.response_cookies[self.cookie_name] = m.hexdigest() + # try to set httponly if supported (added in 2.6) + try: + req.response_cookies[self.cookie_name]['httponly'] = 1 + except (Cookie.CookieError): + pass + req.response_cookies[self.cookie_name]['path'] = req.PATH_INFO + req.response_cookies[self.cookie_name]['expires'] = datetime.utcnow()+timedelta(seconds=60) + return req def main(): parser = optparse.OptionParser() -- 1.7.3.1