# Copyright (c) 2004 Thomas Apel # # Date: 2004-12-22 # # This is a Honeyd plugin that uses Vmap's fingerprint files to emulate # a network service. It can fool Vmap, but as it can only respond to commands # used by Vmap other tools will probably detect the fake. # # Particularly weak points are: # - No case conversions are performed. It can only properly respond to # command in exactly the same case as in Vmap's fingerprint file. # - Vmap's fingerprint files do not contain any banner strings. You have # define your own. # - Only fingerprints without login (wo) can be used. Emulation of login # sequences is not implemented. # ----- begin configuration ----- cmdpath = "vmap/commands/" loglevel = 1 #proto = "ftp" #fingerprintfile = "vmap/ftp/wo/FreeBSD-FTP-6.00LS" #banner = "220 FTP server ready.\r\n" #proto = "smtp" #fingerprintfile = "vmap/smtp/wo/Lotus-Domino-5.0.10" #banner = "220 SMTP server ready.\r\n" proto = "pop3" fingerprintfile = "vmap/pop3/wo/Microsoft-Exchange-6.0" #fingerprintfile = "vmap/pop3/wo/Cyrus-2.1.11" banner = "+OK POP3 server ready.\r\n" #proto = "imap" #fingerprintfile = "vmap/imap/wo/courier-2.0.0" #banner = "* OK IMAP server ready.\r\n" # ----- end configuration ----- import honeyd import sys import re def honeyd_init(data): """Initialize plugin. Load server definition.""" if proto == "ftp": emu = FtpEmu(fingerprintfile, banner) elif proto == "smtp": emu = SmtpEmu(fingerprintfile, banner) elif proto == "pop3": emu = Pop3Emu(fingerprintfile, banner) elif proto == "imap": emu = ImapEmu(fingerprintfile, banner) else: raise Exception("Wrong protocol:", proto) honeyd.write_selector(honeyd.EVENT_ON) return emu def honeyd_readdata(emu, data): """Called on read event. Pass data to service emulator.""" if loglevel >= 1: honeyd.log("C:" + repr(data)) # log cmd emu.handlethis(data) if emu.waitingresp(): honeyd.write_selector(honeyd.EVENT_ON) else: honeyd.read_selector(honeyd.EVENT_ON) return 0 def honeyd_writedata(emu): """Called on write event. Send contents from response queue.""" data = emu.getresp() if loglevel >= 1: honeyd.log("S:" + repr(data)) # log response if emu.waitingresp(): honeyd.write_selector(honeyd.EVENT_ON) else: honeyd.read_selector(honeyd.EVENT_ON) return data def honeyd_end(emu): """Called when connection is terminated.""" del emu return 0 class Emu: def __init__(self, rfname, proto, banner): cmdlist = self.readcf(cmdpath + proto) resplist = self.readrf(rfname) self.fp = self.mkdict(cmdlist, resplist) self.add_resps_to_fp(banner) self.cmdqueue = [] self.respqueue = [self.handle_banr()] def handlethis(self, cmd): lines = cmd.splitlines() self.cmdqueue.extend(lines) while len(self.cmdqueue) > 0: cmd = self.cmdqueue.pop(0) resp = self.getcmdhandler(cmd)(cmd) self.addresp(resp) def addresp(self, resp): lines = resp.splitlines() for line in lines: if line == "TerminateConnection": line = None if line: line += "\r\n" self.respqueue.append(line) def getresp(self): return self.respqueue.pop(0) def waitingresp(self): return len(self.respqueue) > 0 def readcf(self, cfname): """Read commands from file.""" cf = open(cfname, "r") cmds = [] for line in cf: line = line.rstrip("\r\n") cmds.append(line) cf.close() return cmds def readrf(self, rfname): """Read responses from file.""" rf = open(rfname, "r") resps = [] buf = "" for line in rf: line = line.replace("\\", "") line = line.rstrip("\r\n") if line.endswith("+"): line = line.rstrip("+") buf = buf + line + "\r\n" else: buf = buf + line + "\r\n" resps.append(buf) buf = "" rf.close() return resps def mkdict(self, cmds, resps): """Combine commands and responses in a dictionary.""" fp = {} i = 0 for cmd in cmds: fp[cmd] = resps[i] i = i + 1 return fp def getcmdhandler(self, cmd): if cmd.upper() == "QUIT": handler = self.handle_quit else: handler = self.handle_generic return handler def handle_banr(self): """Send a server banner.""" return self.fp["BANR"] def handle_quit(self, cmd): """QUIT command handler.""" return self.fp["QUIT"] + "TerminateConnection" def handle_generic(self, cmd): """Generic command handler.""" try: resp = self.fp[cmd] except KeyError: resp = self.fp["EROR"] % cmd if resp == "\r\n": resp = self.fp["EROR"] % cmd return resp class FtpEmu(Emu): def __init__(self, rfname, banner): Emu.__init__(self, rfname, "ftp", banner) def add_resps_to_fp(self, banner): self.fp["BANR"] = banner self.fp["QUIT"] = "221 Goodbye.\r\n" self.fp["USER username"] = "331 Password required for %s.\r\n" self.fp["PASS password"] = "530 Login incorrect.\r\n" self.fp["EROR"] = "500 '%s': command not understood.\r\n" def getcmdhandler(self, cmd): if cmd.upper() == "QUIT": handler = self.handle_quit elif cmd.startswith("USER"): handler = self.handle_user elif cmd.startswith("PASS"): handler = self.handle_pass else: handler = self.handle_generic return handler def handle_user(self, cmd): """USER command handler.""" try: username = re.search(r"^USER (.*)$", cmd).group(1) except AttributeError: username = None if username: resp = self.fp["USER username"] % username else: resp = self.fp["EROR"] % cmd return resp def handle_pass(self, cmd): """PASS command handler.""" return self.fp["PASS password"] class SmtpEmu(Emu): def __init__(self, rfname, banner): Emu.__init__(self, rfname, "smtp", banner) def add_resps_to_fp(self, banner): self.fp["BANR"] = banner self.fp["QUIT"] = "221 Goodbye.\r\n" self.fp["EROR"] = "500 '%s': command not understood.\r\n" class Pop3Emu(Emu): def __init__(self, rfname, banner): Emu.__init__(self, rfname, "pop3", banner) def add_resps_to_fp(self, banner): self.fp["BANR"] = banner self.fp["QUIT"] = "+OK Goodbye.\r\n" self.fp["EROR"] = "-ERR '%s': command not understood.\r\n" class ImapEmu(Emu): def __init__(self, rfname, banner): Emu.__init__(self, rfname, "imap", banner) def add_resps_to_fp(self, banner): self.fp["BANR"] = banner self.fp["QUIT"] = "* BYE LOGOUT received\r\nA023 OK Completed\r\n" self.fp["EROR"] = "A042 BAD Please login first\r\n" def getcmdhandler(self, cmd): if cmd.endswith("LOGOUT"): handler = self.handle_quit else: handler = self.handle_generic return handler