def prepare_loggers(logLevel): """ Sets up the "liveplayer" and "liveplayer.ui" loggers to print messages and send notifications on connect. """ log.prepare_pyrdp_logger(logLevel) log.prepare_ssl_session_logger() if not os.path.exists("log"): os.makedirs("log") liveplayer_logger = getLoggerPassFilters(LOGGER_NAMES.LIVEPLAYER) liveplayer_logger.setLevel(logLevel) liveplayer_ui_logger = getLoggerPassFilters( f"{LOGGER_NAMES.LIVEPLAYER}.ui") liveplayer_ui_logger.setLevel(logLevel) formatter = log.get_formatter() stream_handler = logging.StreamHandler() file_handler = logging.FileHandler("log/liveplayer.log") stream_handler.setFormatter(formatter) file_handler.setFormatter(formatter) liveplayer_logger.addHandler(stream_handler) liveplayer_logger.addHandler(file_handler) notify_handler = NotifyHandler() notify_handler.setFormatter( logging.Formatter("[%(asctime)s] - %(message)s")) liveplayer_ui_logger.addHandler(notify_handler)
def __init__(self, layer: Layer, recorder: Recorder, logger: Logger, **kwargs): Observer.__init__(self, **kwargs) self.clipboardParser = ClipboardParser() self.peer = None self.layer = layer self.recorder = recorder self.forwardNextDataResponse = True self.mitm_log = getLoggerPassFilters(f"{logger.name}.clipboard") self.clipboard_log = getLoggerPassFilters(f"{self.mitm_log.name}.data")
def __init__(self, maxTabCount=250): QTabWidget.__init__(self) self.closeTabShortcut = QShortcut(QKeySequence("Ctrl+W"), self, self.closeCurrentTab) self.maxTabCount = maxTabCount self.setTabsClosable(True) self.tabCloseRequested.connect(self.onTabClosed) self.log = getLoggerPassFilters(LOGGER_NAMES.LIVEPLAYER)
def dataReceived(self, data): """ When a PSH TCP packet is received, call the next layer to receive the data. :param data: The byte stream (without the TCP header) :type data: bytes """ try: if self.logSSLRequired: self.logSSLParameters() self.logSSLRequired = False self.next.recv(data) except KeyboardInterrupt: raise except Exception as e: getLoggerPassFilters(LOGGER_NAMES.PYRDP_EXCEPTIONS).exception(e) raise
def prepare_loggers(logLevel, sensorID): """ Sets up the "mitm" and the "mitm.connections" loggers. """ log.prepare_pyrdp_logger(logLevel) log.prepare_ssl_session_logger() if not os.path.exists("log"): os.makedirs("log") mitm_logger = getLoggerPassFilters(LOGGER_NAMES.MITM) mitm_logger.setLevel(logLevel) mitm_connections_logger = getLoggerPassFilters( LOGGER_NAMES.MITM_CONNECTIONS) mitm_connections_logger.setLevel(logLevel) formatter = log.get_formatter() stream_handler = logging.StreamHandler() file_handler = logging.handlers.TimedRotatingFileHandler("log/mitm.log", when="D") stream_handler.setFormatter(formatter) file_handler.setFormatter(formatter) mitm_logger.addHandler(stream_handler) mitm_logger.addHandler(file_handler) # Make sure that the library writes to the file as well pyrdp_logger = log.get_logger() pyrdp_logger.addHandler(file_handler) exceptions_logger = getLoggerPassFilters(LOGGER_NAMES.PYRDP_EXCEPTIONS) exceptions_logger.propagate = False exceptions_logger.addHandler(file_handler) jsonFormatter = JSONFormatter() jsonFileHandler = logging.FileHandler("log/mitm.json") sensorFilter = SensorFilter(sensorID) jsonFileHandler.setFormatter(jsonFormatter) jsonFileHandler.setLevel(logging.INFO) jsonFileHandler.addFilter(sensorFilter) getLoggerPassFilters( LOGGER_NAMES.MITM_CONNECTIONS).addHandler(jsonFileHandler)
def __init__(self, layer: Layer, recorder: Recorder, logger: logging.Logger, **kwargs): super().__init__(**kwargs) self.peer: PassiveFileStealer = None self.layer = layer self.recorder = recorder self.mitm_log = getLoggerPassFilters(f"{logger.name}.deviceRedirection") self.deviceRedirectionParser = DeviceRedirectionParser() self.completionIdInProgress: Dict[MajorFunction, DeviceIORequestPDU] = {} self.reconstructedFilesTemp: Dict[int, BytesIO] = {} self.openedFiles: Dict[int, bytes] = {} self.finalFiles: Dict[str, BytesIO] = {} self.pduToSend = None # Needed since the PDU changes if it's a response.
def prepare_ssl_session_logger(): """ Prepares the SSL master secret logger. Used to log TLS session secrets to decrypt traffic later. """ ssl_logger = getLoggerPassFilters("ssl") ssl_logger.setLevel(logging.INFO) os.makedirs("log", exist_ok=True) handler = logging.FileHandler("log/ssl_master_secret.log") formatter = SSLSecretFormatter() handler.setFormatter(formatter) ssl_logger.addHandler(handler) stream_handler = logging.StreamHandler() stream_handler.setFormatter(formatter) ssl_logger.addHandler(stream_handler)
def prepare_pyrdp_logger(logLevel=logging.INFO): """ Prepare the PyRDP logger to be used by the library. """ logger = getLoggerPassFilters(LOGGER_NAMES.PYRDP) logger.setLevel(logLevel) stream_handler = logging.StreamHandler() formatter = get_formatter() stream_handler.setFormatter(formatter) stream_handler.setLevel(logLevel) logger.addHandler(stream_handler)
def __init__(self, viewer): """ :type viewer: QWidget """ QWidget.__init__(self, None, Qt.WindowFlags()) self.widget = viewer self.writeInCaps = False self.text = QTextEdit() self.text.setReadOnly(True) self.text.setMinimumHeight(150) self.log = getLoggerPassFilters(LOGGER_NAMES.LIVEPLAYER) scrollViewer = QScrollArea() scrollViewer.setWidget(self.widget) layout = QVBoxLayout() layout.addWidget(scrollViewer, 8) layout.addWidget(self.text, 2) self.setLayout(layout)
def __init__(self, duration: float, parent: QWidget = None): QWidget.__init__(self, parent) self.log = getLoggerPassFilters(LOGGER_NAMES.LIVEPLAYER) self.button = PlayPauseButton() self.button.setMaximumWidth(100) self.button.clicked.connect(self.onButtonClicked) self.timeSlider = ClickableProgressBar() self.timeSlider.setMinimum(0) self.timeSlider.setMaximum(int(duration * 1000)) self.timeSlider.valueChanged.connect(self.onSeek) self.speedLabel = QLabel("Speed: 1x") self.speedSlider = QSlider(Qt.Horizontal) self.speedSlider.setMaximumWidth(300) self.speedSlider.setMinimum(1) self.speedSlider.setMaximum(10) self.speedSlider.valueChanged.connect(self.onSpeedChanged) vertical = QVBoxLayout() horizontal = QHBoxLayout() horizontal.addWidget(self.speedLabel) horizontal.addWidget(self.speedSlider) horizontal.addItem( QSpacerItem(20, 40, QSizePolicy.Expanding, QSizePolicy.Expanding)) vertical.addLayout(horizontal) horizontal = QHBoxLayout() horizontal.addWidget(self.button) horizontal.addWidget(self.timeSlider) vertical.addLayout(horizontal) self.setLayout(vertical) self.setGeometry(0, 0, 80, 60)
def __init__(self, friendlyName: str, targetHost: str, targetPort: int, certificateFileName: str, privateKeyFileName: str, recordHost: str, recordPort: int, replacementUsername: str, replacementPassword: str): MCSUserObserver.__init__(self) self.sessionId = f"{friendlyName}{random.randrange(100000,999999)}" self.log = getLoggerPassFilters( f"{LOGGER_NAMES.MITM_CONNECTIONS}.{self.sessionId}.server") self.metadataFilter = ConnectionMetadataFilter(self, self.sessionId) self.log.addFilter(self.metadataFilter) self.replacementPassword = replacementPassword self.replacementUsername = replacementUsername self.targetHost = targetHost self.targetPort = targetPort self.certificateFileName = certificateFileName self.privateKeyFileName = privateKeyFileName self.clipboardObserver = None self.useTLS = False self.client: MITMClient = None self.clientConnector = None self.originalNegotiationPDU = None self.targetNegotiationPDU = None self.serverData = None self.rc4RSAKey = RSA.generate(2048) self.crypter = RC4CrypterProxy() self.socket = None self.fileHandle = open( "out/rdp_replay_{}_{}.pyrdp".format( datetime.datetime.now().strftime('%Y%m%d_%H-%M-%S'), random.randint(0, 1000)), "wb") rc4Log = getLoggerPassFilters(f"{self.log.name}.rc4") self.securitySettings = SecuritySettings(SecuritySettings.Mode.SERVER) self.securitySettings.addObserver(self.crypter) self.securitySettings.addObserver(RC4LoggingObserver(rc4Log)) self.tcp = TwistedTCPLayer() self.tcp.createObserver(onConnection=self.onConnection, onDisconnection=self.onDisconnection) self.segmentation = SegmentationLayer() self.segmentation.createObserver( onUnknownHeader=self.onUnknownTPKTHeader) self.tpkt = TPKTLayer() self.x224 = X224Layer() self.x224.createObserver(onConnectionRequest=self.onConnectionRequest, onDisconnectRequest=self.onDisconnectRequest) self.mcs = MCSLayer() self.router = MITMServerRouter(self.mcs, self) self.mcs.addObserver(self.router) self.router.createObserver( onConnectionReceived=self.onConnectInitial, onDisconnectProviderUltimatum=self.onDisconnectProviderUltimatum, onAttachUserRequest=self.onAttachUserRequest, onChannelJoinRequest=self.onChannelJoinRequest) self.gcc = GCCParser() self.rdpClientInfoParser = ClientInfoParser() self.rdpClientConnectionParser = ClientConnectionParser() self.rdpServerConnectionParser = ServerConnectionParser() self.securityLayer = None self.slowPathLayer = SlowPathLayer() self.fastPathLayer = None self.tcp.setNext(self.segmentation) self.segmentation.attachLayer(SegmentationPDUType.TPKT, self.tpkt) Layer.chain(self.tpkt, self.x224, self.mcs) if recordHost is not None and recordPort is not None: self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: self.socket.connect((recordHost, recordPort)) except socket.error as e: logging.getLogger(LOGGER_NAMES.MITM).error( "Could not connect to liveplayer: %(error)s", {"error": e}) self.socket.close() self.socket = None recordingLayers = [FileLayer(self.fileHandle)] if self.socket is not None: recordingLayers.append(SocketLayer(self.socket)) # Since we're intercepting communications from the original client (so we're a server), # We need to write back the packets as if they came from the client. self.recorder = Recorder(recordingLayers)
def get_ssl_logger(): """ Get the SSL logger. """ return getLoggerPassFilters("ssl")
def get_logger(): """ Get the main logger. """ return getLoggerPassFilters(LOGGER_NAMES.PYRDP)
def __init__(self, server, fileHandle: BinaryIO, livePlayerSocket: socket, replacementUsername=None, replacementPassword=None): MCSChannelFactory.__init__(self) self.log = getLoggerPassFilters( f"{LOGGER_NAMES.MITM_CONNECTIONS}.{server.getSessionId()}.client") self.log.addFilter(server.metadataFilter) self.replacementUsername = replacementUsername self.replacementPassword = replacementPassword self.server = server self.channelMap: Dict[int, str] = {} self.channelDefinitions = [] self.channelObservers = {} self.deviceRedirectionObserver = None self.useTLS = False self.user = None self.fastPathObserver = None self.conferenceCreateResponse = None self.serverData = None self.crypter = RC4CrypterProxy() rc4Log = getLoggerPassFilters(f"{self.log.name}.rc4") self.securitySettings = SecuritySettings(SecuritySettings.Mode.CLIENT) self.securitySettings.addObserver(self.crypter) self.securitySettings.addObserver(RC4LoggingObserver(rc4Log)) self.tcp = TwistedTCPLayer() self.tcp.createObserver(onConnection=self.startConnection, onDisconnection=self.onDisconnection) self.segmentation = SegmentationLayer() self.segmentation.createObserver( onUnknownHeader=self.onUnknownTPKTHeader) self.tpkt = TPKTLayer() self.x224 = X224Layer() self.x224.createObserver(onConnectionConfirm=self.onConnectionConfirm, onDisconnectRequest=self.onDisconnectRequest) self.mcs = MCSLayer() self.router = MCSClientRouter(self.mcs, self) self.mcs.addObserver(self.router) self.router.createObserver( onConnectResponse=self.onConnectResponse, onDisconnectProviderUltimatum=self.onDisconnectProviderUltimatum) self.mcsConnect = MCSClientConnectionLayer(self.mcs) self.gccConnect = GCCClientConnectionLayer(b"1") self.gccConnect.createObserver( onPDUReceived=self.onConferenceCreateResponse) self.rdpConnect = ClientConnectionLayer() self.rdpConnect.createObserver(onPDUReceived=self.onServerData) self.securityLayer = None self.slowPathLayer = SlowPathLayer() self.fastPathLayer = None self.tcp.setNext(self.segmentation) self.segmentation.attachLayer(SegmentationPDUType.TPKT, self.tpkt) Layer.chain(self.tpkt, self.x224, self.mcs) Layer.chain(self.mcsConnect, self.gccConnect, self.rdpConnect) record_layers = [FileLayer(fileHandle)] if livePlayerSocket is not None: record_layers.append(SocketLayer(livePlayerSocket)) self.recorder = Recorder(record_layers)
def main(): parser = argparse.ArgumentParser() parser.add_argument( "target", help="IP:port of the target RDP machine (ex: 192.168.1.10:3390)") parser.add_argument("-l", "--listen", help="Port number to listen on (default: 3389)", default=3389) parser.add_argument("-o", "--output", help="Output folder for replay files") parser.add_argument( "-i", "--destination-ip", help= "Destination IP address of the PyRDP player.If not specified, RDP events are not sent over the network." ) parser.add_argument( "-d", "--destination-port", help="Listening port of the PyRDP player (default: 3000).", default=3000) parser.add_argument("-k", "--private-key", help="Path to private key (for SSL)") parser.add_argument("-c", "--certificate", help="Path to certificate (for SSL)") parser.add_argument( "-n", "--nla", help="For NLA client authentication (need to provide credentials)", action="store_true") parser.add_argument( "-u", "--username", help="Username that will replace the client's username", default=None) parser.add_argument( "-p", "--password", help="Password that will replace the client's password", default=None) parser.add_argument( "-L", "--log-level", help="Log level", default="INFO", choices=["INFO", "DEBUG", "WARNING", "ERROR", "CRITICAL"]) parser.add_argument( "-s", "--sensor-id", help= "Sensor ID (to differentiate multiple instances of the MITM where logs are aggregated at one place)", default="PyRDP") args = parser.parse_args() logLevel = getattr(logging, args.log_level) prepare_loggers(logLevel, args.sensor_id) os.makedirs("out", exist_ok=True) mitm_log = getLoggerPassFilters(LOGGER_NAMES.MITM) target = args.target if ":" in target: targetHost = target[:target.index(":")] targetPort = int(target[target.index(":") + 1:]) else: targetHost = target targetPort = 3389 if (args.private_key is None) != (args.certificate is None): mitm_log.error( "You must provide both the private key and the certificate") sys.exit(1) elif args.private_key is None: key, certificate = getSSLPaths() handleKeyAndCertificates(certificate, key, mitm_log) else: key, certificate = args.private_key, args.certificate listenPort = int(args.listen) reactor.listenTCP( listenPort, MITMServerFactory(targetHost, targetPort, key, certificate, args.destination_ip, int(args.destination_port), args.username, args.password)) mitm_log.info("MITM Server listening on port %(port)d", {"port": listenPort}) reactor.run()
parser.add_argument("-p", "--port", help="Bind port (default: 3000)", default=3000) parser.add_argument( "-L", "--log-level", help="Log level", default="INFO", choices=["INFO", "DEBUG", "WARNING", "ERROR", "CRITICAL"], nargs="?") arguments = parser.parse_args() logLevel = getattr(logging, arguments.log_level) prepare_loggers(logLevel) app = QApplication(sys.argv) mainWindow = player.MainWindow(arguments.bind, int(arguments.port), arguments.replay) mainWindow.show() return app.exec_() if __name__ == '__main__': mlog = getLoggerPassFilters(LOGGER_NAMES.LIVEPLAYER) ulog = getLoggerPassFilters(f"{LOGGER_NAMES.LIVEPLAYER}.ui") sys.exit(main())