class HTTPService(ServiceBaseModel): now = datetime.now() timeNow = time.mktime(now.timetuple()) responseHeadersOkStatus = Config.http.response_headers responseHeadersForbidden = {'Date': format_date_time(timeNow)} responseHeadersNotFound = { 'Date': format_date_time(timeNow), 'Content-Type': 'text/html; charset=UTF-8' } okStatus = "HTTP/1.1 200 OK" forbiddenStatus = "HTTP/1.1 403 Forbidden" notFoundStatus = "HTTP/1.1 404 Not Found" htdb = HoneytokenDataBase("HTTP") html_dictionary = Config.http.html_dictionary_content supportedSites = [] def __init__(self): super(HTTPService, self).__init__() self._name = Config.http.name self._port = Config.http.port self._limiter = Limiter(self._fService, Config.http.name, Config.http.connections_per_host) self.protocol = HTTPProtocol self._fService.protocol = self.protocol def startService(self): try: self._stop = False self._transport = reactor.listenTCP(self._port, self._fService, interface=self._address) sites = [] for key in HTTPService.html_dictionary: sites.append(key) HTTPService.supportedSites = sites except Exception as e: self._stop = True raise e def stopService(self): self._stop = True self._transport.stopListening() try: self._transport.connectionLost( "Force close/cleanup due to next service scheduling") except AttributeError as err: log.err("HTTPService.connectionLost threw AttributeError: " + err) def parseHeaderLine(self, line): pdata = line.split(':', 1)[0] if (pdata == "Host"): return pdata elif (pdata == "Accept"): return pdata
class FTPService(ServiceBaseModel): credchecker = HoneytokenDataBase("FTP") # Make name and port accessible for logging in FTPProtocol _name = config.ftpName _port = config.ftpPort def __init__(self): super(FTPService, self).__init__() portal = Portal(FTPRealm('./'), [self.credchecker]) self._fService = FTPFactory(portal) self._name = config.ftpName self._port = config.ftpPort self._limiter = Limiter(self._fService, self._name, config.FTP_conn_per_host) self.protocol = FTPProtocol self._fService.protocol = self.protocol def startService(self): self._stop = False self._transport = reactor.listenTCP(self._port, self._limiter) def stopService(self): self._stop = True self._transport.stopListening()
class SSHService(ServiceBaseModel): honeytokendb = HoneytokenDataBase(servicename=Config.ssh.name) def __init__(self): super(SSHService, self).__init__() self._name = Config.ssh.name self._port = Config.ssh.port p = Portal(SSHRealm()) p.registerChecker(SSHService.honeytokendb) self._fService = factory.SSHFactory() self._fService.services[b'ssh-userauth'] = groveUserAuth self._limiter = Limiter(self._fService, Config.ssh.name, Config.ssh.connections_per_host) self._fService.portal = p # self.protocol = SSHProtocol # self._fService.protocol = self.protocol home = expanduser('~') # XXX: These paths should be configurable privateKeyPath = home + '/.ssh/id_honeygrove' publicKeyPath = home + '/.ssh/id_honeygrove.pub' # Generate RSA keys if they don't exist if not (exists(privateKeyPath) and exists(publicKeyPath)): key = keys.rsa.generate_private_key(public_exponent=65537, key_size=4096, backend=default_backend()) private_key = key.private_bytes( serialization.Encoding.PEM, serialization.PrivateFormat.TraditionalOpenSSL, serialization.NoEncryption()) public_key = key.public_key().public_bytes( serialization.Encoding.OpenSSH, serialization.PublicFormat.OpenSSH) # make .ssh directory, if it doesn't exist os.makedirs(dirname(publicKeyPath), exist_ok=True) with open(privateKeyPath, 'w') as f: f.write(private_key.decode()) with open(publicKeyPath, 'w') as f: f.write(public_key.decode()) self._fService.privateKeys = { b'ssh-rsa': keys.Key.fromFile(privateKeyPath) } self._fService.publicKeys = { b'ssh-rsa': keys.Key.fromFile(publicKeyPath) }
class HoneyTokenDBTest(unittest.TestCase): databasefile = 'testresources/testdatabase.txt' servicename = 'MyServiceName' sep = ':' def addCredentials(self, credstring): with open(self.databasefile, 'w') as file: file.write(credstring) def clearCredentials(self): with open(self.databasefile, 'w') as file: file.seek(0) def setUp(self): HoneytokenDataBase.filepath = self.databasefile self.db = HoneytokenDataBase(self.servicename) def test_validCreds(self): username = '******' pw = 'pass' c = credentials.UsernamePassword(username, pw) # Write them to Database credstring = self.servicename + self.sep + username + self.sep + pw + self.sep self.addCredentials(credstring) # Make sure you got UserName back ==> creds are valid actual = self.db.requestAvatarId(c).result self.assertEqual(username, actual) # Delete creds from file self.clearCredentials() def test_inValidCreds(self): c = credentials.UsernamePassword('idontexist', 'hahahahah') actual = self.db.requestAvatarId(c).result.value self.assertTrue(isinstance(actual, UnauthorizedLogin))
class FTPService(ServiceBaseModel): credchecker = HoneytokenDataBase("FTP") # Make name and port accessible for logging in FTPProtocol _name = Config.ftp.name _port = Config.ftp.port def __init__(self): super(FTPService, self).__init__() portal = Portal(FTPRealm('./'), [self.credchecker]) self._fService = FTPFactory(portal) self._name = Config.ftp.name self._port = Config.ftp.port self._limiter = Limiter(self._fService, self._name, Config.ftp.connections_per_host) self.protocol = FTPProtocol self._fService.protocol = self.protocol
class SSHService(ServiceBaseModel): c = HoneytokenDataBase(servicename=config.sshName) def __init__(self): super(SSHService, self).__init__() self._name = config.sshName self._port = config.sshPort p = Portal(SSHRealm()) p.registerChecker(SSHService.c) self._fService = factory.SSHFactory() self._fService.services[b'ssh-userauth'] = groveUserAuth self._limiter = Limiter(self._fService, config.sshName, config.SSH_conn_per_host) self._fService.portal = p # self.protocol = SSHProtocol # self._fService.protocol = self.protocol home = expanduser('~') privateKeyPath = home + '/.ssh/id_rsa' publicKeyPath = home + '/.ssh/id_rsa.pub' # Generate RSA keys if they don't exist if not (exists(privateKeyPath) and exists(publicKeyPath)): key = keys.rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()) private_key = key.private_bytes( serialization.Encoding.PEM, serialization.PrivateFormat.TraditionalOpenSSL, serialization.NoEncryption()) public_key = key.public_key().public_bytes( serialization.Encoding.OpenSSH, serialization.PublicFormat.OpenSSH) # make .ssh directory, if it doesn't exist os.makedirs(dirname(publicKeyPath), exist_ok=True) with open(privateKeyPath, 'w') as f: f.write(private_key.decode()) with open(publicKeyPath, 'w') as f: f.write(public_key.decode()) self._fService.privateKeys = { b'ssh-rsa': keys.Key.fromFile(privateKeyPath) } self._fService.publicKeys = { b'ssh-rsa': keys.Key.fromFile(publicKeyPath) } def startService(self): self._stop = False self._transport = reactor.listenTCP(self._port, self._limiter) def stopService(self): self._stop = True self._transport.stopListening()
class HTTPService(ServiceBaseModel): now = datetime.now() timeNow = time.mktime(now.timetuple()) responseHeadersOkStatus = config.httpResponseHeader responseHeadersForbidden = {'Date': format_date_time(timeNow)} responseHeadersNotFound = {'Date': format_date_time(timeNow), 'Content-Type': 'text/html; charset=UTF-8'} okStatus = "HTTP/1.1 200 OK" forbiddenStatus = "HTTP/1.1 403 Forbidden" notFoundStatus = "HTTP/1.1 404 Not Found" htdb = HoneytokenDataBase("HTTP") port = "" resourceLocation = config.resources + '/http_resources/' supportedSites = [] def __init__(self): super(HTTPService, self).__init__() self._name = config.httpName self._port = config.httpPort self._fService.protocol = self.protokoll HTTPService.port = self._port # -----Protokoll----# class protokoll(Protocol): def __init__(self): self.state = None self.peerOfAttacker = "" self.page = "" self.path = config.resources self.attackingSite = "" self.loginSuccessfulSite = "" self.notFoundSite = "" self.requestType = "" self.short = "" def connectionMade(self): # Aktuelle Verbindung zum Dict hinzufügen self.factory.clients[self] = ("<" + str(self.transport.getPeer().host) + ":" \ + str(self.transport.getPeer().port) + ">") self.peerOfAttacker = self.transport.getPeer().host def dataReceived(self, data): from honeygrove.services.HTTPService import HTTPService data = data.decode('utf-8') self.requestType = data.split(' ', 1)[0] if self.requestType == "GET": self.page = data[data.find("GET ") + 4: data.find(" HTTP/1.1")] elif self.requestType == "POST": self.page = data[data.find("POST ") + 5: data.find(" HTTP/1.1")] pageNotFound = True for serviceLink in HTTPService.supportedSites: if self.page == serviceLink: pageNotFound = False self.attackingSite = HTTPService.resourceLocation + config.httpHTMLDictionary[serviceLink][0] if config.httpHTMLDictionary[serviceLink].__len__() > 1: self.loginSuccessfulSite = HTTPService.resourceLocation + \ config.httpHTMLDictionary[serviceLink][1] else: self.loginSuccessfulSite = HTTPService.resourceLocation + config.httpHTMLDictionary['404'][0] self.short = serviceLink break if pageNotFound: self.notFoundSite = HTTPService.resourceLocation + config.httpHTMLDictionary['404'][0] # Beantwortung von GET Requests if self.requestType == "GET" and ( '.gif' in self.page or '.png' in self.page or '/dashboard_files/' in self.page or '.jpg' in self.page or '.woff' in self.page or '.ttf' in self.page or '.svg' in self.page): message = HTTPService.notFoundStatus + "\n" for k in HTTPService.responseHeadersNotFound.keys(): message = message + k + ": " + HTTPService.responseHeadersNotFound[k] + "\n" self.transport.write(message.encode('UTF-8')) self.transport.loseConnection() elif self.requestType == "GET" and self.page in HTTPService.supportedSites: log.request("HTTP", self.peerOfAttacker, HTTPService.port, self.page, "", "GET") message = HTTPService.okStatus + "\n" for k in HTTPService.responseHeadersOkStatus.keys(): message = message + k + ": " + HTTPService.responseHeadersOkStatus[k] + "\n" with open(self.attackingSite, encoding='utf8') as file: message = message + "\n" + file.read() self.transport.write(message.encode('UTF-8')) if self.page in HTTPService.supportedSites: log.response("HTTP", self.peerOfAttacker, HTTPService.port, self.page, "", "200 OK") self.transport.loseConnection() # Beantwortung von POST Requests elif (self.requestType == "POST" and self.page in HTTPService.supportedSites): self.page = data[data.find("POST ") + 5: data.find(" HTTP/1.1")] login_string = "" password_string = "" login_index = data.find("log=") + 4 if login_index == 3: login_string = "fritz.box" else: login_string = data[login_index:data.find("&")] password_index = data.find("pwd=") + 4 if data[password_index:data.find("&")] != -1: password_string = data[password_index:len(data)] else: password_string = data[password_index:data.find("&")] log.request("HTTP", self.peerOfAttacker, HTTPService.port, self.page, login_string, "POST") result = HTTPService.htdb.requestAvatarId(HTTPAvatar(login_string, password_string)) if isinstance(result, Deferred): if isinstance(result.result, failure.Failure): # Failure result.addErrback(self.errorBack) log.response("HTTP", self.peerOfAttacker, HTTPService.port, "", login_string, "403 FORBIDDEN") log.login("HTTP", self.peerOfAttacker, HTTPService.port, False, login_string, password_string, str(HTTPService.htdb.getActual(login_string, password_string))) else: # Success message = HTTPService.okStatus + "\n" for k in HTTPService.responseHeadersOkStatus.keys(): message = message + k + ": " + HTTPService.responseHeadersOkStatus[k] + "\n" with open(self.loginSuccessfulSite, encoding='utf8') as file: message = message + "\n" + file.read() self.transport.write(message.encode('UTF-8')) self.page = "wp-admin_content.html" log.response("HTTP", self.peerOfAttacker, HTTPService.port, self.page, login_string, "200 OK") log.login("HTTP", self.peerOfAttacker, HTTPService.port, True, login_string, password_string, str(HTTPService.htdb.getActual(login_string, password_string))) self.transport.loseConnection() else: message = HTTPService.notFoundStatus + "\n" for k in HTTPService.responseHeadersNotFound.keys(): message = message + k + ": " + HTTPService.responseHeadersNotFound[k] + "\n" with open(self.notFoundSite, encoding='utf8') as file: message = message + "\n" + file.read() self.transport.write(message.encode('UTF-8')) log.request("HTTP", self.peerOfAttacker, HTTPService.port, self.page, "", "GET") self.page = "404_login.html" log.response("HTTP", self.peerOfAttacker, HTTPService.port, self.page, "", "404 Not Found") self.transport.loseConnection() def connectionLost(self, reason): # Delete client from dict. del self.factory.clients[self] def errorBack(self, f): f.trap(error.UnauthorizedLogin) message = HTTPService.forbiddenStatus + "\n" for k in HTTPService.responseHeadersForbidden.keys(): message = message + k + ": " + HTTPService.responseHeadersForbidden[k] + "\n" with open(self.attackingSite, encoding='utf8') as file: message = message + "\n" + file.read() self.transport.write(message.encode('UTF-8')) self.transport.loseConnection() def startService(self): try: self._stop = False self._transport = reactor.listenTCP(self._port, self._fService) sites = [] for key in config.httpHTMLDictionary: sites.append(key) HTTPService.supportedSites = sites except Exception as e: self._stop = True raise e def stopService(self): self._stop = True self._transport.stopListening() try: self._transport.connectionLost("Force close/cleanup due to next service scheduling") except AttributeError: log.err("HTTPService connectionLost wirft AttributeError!") def parseHeaderLine(self, line): pdata = line.split(':', 1)[0] if (pdata == "Host"): return pdata elif (pdata == "Accept"): return pdata
def setUp(self): HoneytokenDataBase.filepath = self.databasefile self.db = HoneytokenDataBase(self.servicename)