Honeypot done.
This commit is contained in:
parent
c1a08ba821
commit
c968cf1e64
1 changed files with 395 additions and 14 deletions
409
fakeftp.py
409
fakeftp.py
|
@ -2,16 +2,169 @@ import SocketServer
|
|||
import threading
|
||||
import socket
|
||||
from random import randint
|
||||
import datetime
|
||||
|
||||
def mask(rights):
|
||||
m = ""
|
||||
if rights&4 != 0:
|
||||
m += "r"
|
||||
else:
|
||||
m += "-"
|
||||
|
||||
if rights&2 != 0:
|
||||
m += "w"
|
||||
else:
|
||||
m += "-"
|
||||
|
||||
if rights&1 != 0:
|
||||
m += "x"
|
||||
else:
|
||||
m+= "-"
|
||||
|
||||
return m
|
||||
|
||||
class FSNode:
|
||||
def __init__(self,name,owner="nobody",group="nobody",rights=384,size=0, iun=1):
|
||||
self.name = name
|
||||
self.owner = owner
|
||||
self.group = group
|
||||
self.rights = rights
|
||||
self.size = size
|
||||
self.parent = None
|
||||
self.iun = iun
|
||||
|
||||
def is_dir(self):
|
||||
return False
|
||||
|
||||
def is_file(self):
|
||||
return False
|
||||
|
||||
def get_name(self):
|
||||
return self.name
|
||||
|
||||
def get_size(self):
|
||||
return self.size
|
||||
|
||||
def get_rights(self):
|
||||
return self.rights
|
||||
|
||||
def get_last_change(self):
|
||||
return datetime.date(2013,8,22)
|
||||
|
||||
#Thanks to a mumble session with lod :3
|
||||
def get_boner(self):
|
||||
return "large"
|
||||
|
||||
def get_parent_directory(self):
|
||||
return self.parent
|
||||
|
||||
def get_owner(self):
|
||||
return self.owner
|
||||
|
||||
def get_group(self):
|
||||
return self.group
|
||||
|
||||
def get_imaginary_unicorn_number(self):
|
||||
return self.iun
|
||||
|
||||
def get_mask(self):
|
||||
m = ""
|
||||
if self.is_dir():
|
||||
m += "d"
|
||||
else:
|
||||
m += "-"
|
||||
|
||||
rights = self.get_rights()
|
||||
m += mask((rights >> 6)&7)
|
||||
m += mask((rights >> 3)&7)
|
||||
m += mask(rights&7)
|
||||
|
||||
return m
|
||||
|
||||
def get_absolute_path(self):
|
||||
if self.parent is None:
|
||||
if self.is_dir():
|
||||
return "/"
|
||||
else:
|
||||
return self.get_name()
|
||||
else:
|
||||
p = self.parent.get_absolute_path()
|
||||
if p[-1] != "/":
|
||||
p+= "/"
|
||||
p+=self.get_name()
|
||||
return p
|
||||
|
||||
class Directory(FSNode):
|
||||
def __init__(self,name,owner="nobody",group="nobody",rights=384,size=4096,files=[]):
|
||||
FSNode.__init__(self, name=name, owner=owner, group=group,rights=rights, size=size, iun=randint(2,10))
|
||||
|
||||
self.files = files
|
||||
|
||||
for f in self.files:
|
||||
f.parent = self
|
||||
|
||||
def is_dir(self):
|
||||
return True
|
||||
|
||||
def get_node(self,name):
|
||||
for f in self.files:
|
||||
if f.name == name:
|
||||
return f
|
||||
return None
|
||||
|
||||
class File(FSNode):
|
||||
def __init__(self,name,owner="nobody",group="nobody",rights=384,size=4096, content=None):
|
||||
FSNode.__init__(self, name=name, owner=owner, group=group,rights=rights, size=size, iun=1)
|
||||
if content is None:
|
||||
content = TextFileContent()
|
||||
self.content = content
|
||||
|
||||
def is_file(self):
|
||||
return True
|
||||
|
||||
def send_content(self,socket):
|
||||
self.content.send_content(socket)
|
||||
|
||||
class FileContent:
|
||||
def send_content(self, socket):
|
||||
pass
|
||||
|
||||
class TextFileContent(FileContent):
|
||||
def __init__(self, text=""):
|
||||
self.text = text
|
||||
|
||||
def send_content(self, socket):
|
||||
socket.send(self.text)
|
||||
|
||||
class FileFileContent(FileContent):
|
||||
def __init__(self, filepath):
|
||||
self.filepath = filepath
|
||||
|
||||
def send_content(self, socket):
|
||||
fh = file(self.filepath,"r")
|
||||
buf = fh.read(1024)
|
||||
while len(buf) > 0:
|
||||
socket.send(buf)
|
||||
buf = fh.read(1024)
|
||||
|
||||
class HoneypotFileContent(FileContent):
|
||||
def send_content(self, socket):
|
||||
for i in range(4000):
|
||||
socket.send('HONEYPOT');
|
||||
|
||||
class URandomFileContent(FileFileContent):
|
||||
def __init__(self):
|
||||
FileFileContent.__init__(self, "/dev/urandom")
|
||||
|
||||
class DataConnection:
|
||||
def run(self, dchandler):
|
||||
pass
|
||||
|
||||
|
||||
class PassiveDataConnection(DataConnection):
|
||||
def __init__(self, port):
|
||||
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self.socket.bind(("",port))
|
||||
self.connection = None
|
||||
threading.Thread(target=self.waitForConnection).start()
|
||||
|
||||
def waitForConnection(self):
|
||||
|
@ -19,6 +172,8 @@ class PassiveDataConnection(DataConnection):
|
|||
self.connection, _ = self.socket.accept()
|
||||
|
||||
def run(self, dchandler):
|
||||
while self.connection is None:
|
||||
pass
|
||||
threading.Thread(target=self.runHandler, args=(dchandler,) ).start()
|
||||
|
||||
def runHandler(self, dchandler):
|
||||
|
@ -26,9 +181,9 @@ class PassiveDataConnection(DataConnection):
|
|||
self.connection.close()
|
||||
|
||||
class ActiveDataConnection(DataConnection):
|
||||
def __init__(self, host, port):
|
||||
def __init__(self, addr):
|
||||
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self.socket.connect( (host,port) )
|
||||
self.socket.connect( addr )
|
||||
|
||||
def run(self, dchandler):
|
||||
threading.Thread(target=self.runHandler, args=(dchandler,)).start()
|
||||
|
@ -106,10 +261,94 @@ class EnteringPassiveModeMessage(FTPMessage):
|
|||
def __init__(self,addrtuple):
|
||||
FTPMessage.__init__(self,"227","Entering Passive Mode %s." % addrtuple)
|
||||
|
||||
class BeginDirectoryListingMessage(FTPMessage):
|
||||
def __init__(self):
|
||||
FTPMessage.__init__(self,"150","Here comes the directory listing.")
|
||||
|
||||
class EndDirectoryListingMessage(FTPMessage):
|
||||
def __init__(self):
|
||||
FTPMessage.__init__(self,"226","Directory send OK.")
|
||||
|
||||
class WorkingDirectoryMessage(FTPMessage):
|
||||
def __init__(self, workingDirectory):
|
||||
FTPMessage.__init__(self,"257","\"%s\" is the current directory" % workingDirectory)
|
||||
|
||||
class ChangeDirectorySuccessfulMessage(FTPMessage):
|
||||
def __init__(self):
|
||||
FTPMessage.__init__(self,"250","command successful")
|
||||
|
||||
class ChangeDirectoryFailedMessage(FTPMessage):
|
||||
def __init__(self):
|
||||
FTPMessage.__init__(self,"550","No such directory")
|
||||
|
||||
class InvalidParametersMessage(FTPMessage):
|
||||
def __init__(self):
|
||||
FTPMessage.__init__(self,"504","Command not implemented for that parameter")
|
||||
|
||||
class InvalidPortCommandMessage(FTPMessage):
|
||||
def __init__(self):
|
||||
FTPMessage.__init__(self,"500","Illegal port command")
|
||||
|
||||
class CommandSuccessfulMessage(FTPMessage):
|
||||
def __init__(self,cmd):
|
||||
FTPMessage.__init__(self,"200","%s command successful" % cmd)
|
||||
|
||||
class OperationNotPermittedMessage(FTPMessage):
|
||||
def __init__(self):
|
||||
FTPMessage.__init__(self,"550","Operation not permitted")
|
||||
|
||||
class TypeSetMessage(FTPMessage):
|
||||
def __init__(self,val):
|
||||
FTPMessage.__init__(self,"200","Type set to %s" % val)
|
||||
|
||||
class BeginFileRetrieve(FTPMessage):
|
||||
def __init__(self,node):
|
||||
FTPMessage.__init__(self,"150","Opening ASCII mode data connection for %s (%d bytes)" % (node.get_name(),node.get_size()))
|
||||
|
||||
class EndFileRetrieve(FTPMessage):
|
||||
def __init__(self):
|
||||
FTPMessage.__init__(self,"226","Transfer complete")
|
||||
|
||||
# Data Connection Handler
|
||||
class HeloHandler:
|
||||
class NListHandler:
|
||||
def __init__(self, directory, handler):
|
||||
self.directory = directory
|
||||
self.handler = handler
|
||||
|
||||
def handle(self, socket):
|
||||
socket.send("Hello World")
|
||||
for f in self.directory.files:
|
||||
socket.send(f.get_name()+"\n")
|
||||
|
||||
class ListHandler:
|
||||
def __init__(self, directory, handler):
|
||||
self.directory = directory
|
||||
self.handler = handler
|
||||
|
||||
def handle(self, socket):
|
||||
self.handler.send( BeginDirectoryListingMessage() )
|
||||
for f in self.directory.files:
|
||||
socket.send( "%10s %3d %-8s %-8s %8d %3s %2d %5d %s\n" % (
|
||||
f.get_mask(),
|
||||
f.get_imaginary_unicorn_number(),
|
||||
f.get_owner(),
|
||||
f.get_group(),
|
||||
f.get_size(),
|
||||
f.get_last_change().strftime("%b"),
|
||||
f.get_last_change().day,
|
||||
f.get_last_change().year,
|
||||
f.get_name()
|
||||
) )
|
||||
self.handler.send( EndDirectoryListingMessage() )
|
||||
|
||||
class RetrieveHandler:
|
||||
def __init__(self, node, handler):
|
||||
self.node = node
|
||||
self.handler = handler
|
||||
|
||||
def handle(self, socket):
|
||||
self.handler.send( BeginFileRetrieve(self.node) )
|
||||
self.node.send_content(socket)
|
||||
self.handler.send( EndFileRetrieve() )
|
||||
|
||||
# State classes
|
||||
class State:
|
||||
|
@ -160,12 +399,70 @@ class AuthorizedState(MainState):
|
|||
port = handler.createPassiveDataConnection()
|
||||
handler.debug("Created passive data connection")
|
||||
handler.send( EnteringPassiveModeMessage( self.addrtuple("127.0.0.1",port) ) )
|
||||
elif message.cmd == "HELO":
|
||||
handler.debug("Running Helo on data connection")
|
||||
if handler.runDataConnection(HeloHandler()):
|
||||
elif message.cmd in ["DELE","RMD","RNFR","RNTO","STOR"]:
|
||||
handler.send( OperationNotPermittedMessage() )
|
||||
elif message.cmd == "RETR":
|
||||
node = handler.get_node(message.parameter)
|
||||
if node.is_file():
|
||||
handler.runDataConnection( RetrieveHandler(node, handler) )
|
||||
else:
|
||||
handler.send( OperationNotPermittedMessage() )
|
||||
elif message.cmd == "PORT":
|
||||
hp = message.parameter.split(",")
|
||||
if len(hp) != 6:
|
||||
handler.debug( "Invalid port information" )
|
||||
handler.send( InvalidParametersMessage() )
|
||||
return
|
||||
|
||||
if int(hp[0]) == 10 or int(hp[0]) == 127 or int(hp[0]) == 192: #Prevent local scanning
|
||||
handler.send( InvalidPortCommandMessage() )
|
||||
return
|
||||
|
||||
addr = ( ".".join(hp[:4]), int(hp[4])<<8+int(hp[5]) )
|
||||
|
||||
handler.createActiveDataConnection(addr)
|
||||
|
||||
handler.debug("Created active data connection to %s:%d" % addr)
|
||||
|
||||
handler.send( CommandSuccessfulMessage("PORT") )
|
||||
elif message.cmd == "LIST":
|
||||
handler.debug("Listing current directory")
|
||||
if handler.runDataConnection(ListHandler(handler.currentDirectory, handler)):
|
||||
handler.debug("successful")
|
||||
else:
|
||||
handler.debug("failed")
|
||||
elif message.cmd == "NLST":
|
||||
handler.debug("Listing current directory (simple)")
|
||||
if handler.runDataConnection(NListHandler(handler.currentDirectory)):
|
||||
handler.debug("successful")
|
||||
else:
|
||||
handler.debug("failed")
|
||||
elif message.cmd == "CWD":
|
||||
node = handler.get_node(message.parameter)
|
||||
if node is None or not node.is_dir():
|
||||
handler.debug("Error trying to switch into non-existent directory")
|
||||
handler.send( ChangeDirectoryFailedMessage() )
|
||||
else:
|
||||
handler.currentDirectory = node
|
||||
handler.debug("Changed working directory to "+node.get_absolute_path())
|
||||
handler.send( ChangeDirectorySuccessfulMessage() )
|
||||
elif message.cmd == "CDUP":
|
||||
node = handler.currentDirectory.get_parent_directory()
|
||||
if node is None or not node.is_dir():
|
||||
handler.debug("Error trying to switch to parent directory")
|
||||
else:
|
||||
handler.debug("Changed working directory to "+node.get_absolute_path())
|
||||
handler.currentDirectory = node
|
||||
handler.send( ChangeDirectorySuccessfulMessage() )
|
||||
elif message.cmd == "PWD":
|
||||
handler.send( WorkingDirectoryMessage(handler.currentDirectory.get_absolute_path()) )
|
||||
elif message.cmd == "TYPE":
|
||||
if message.parameter == "A":
|
||||
handler.send( TypeSetMessage(message.parameter) )
|
||||
else:
|
||||
handler.send( InvalidCommandMessage("TYPE") )
|
||||
elif message.cmd == "NOOP":
|
||||
handler.send( CommandSuccessfulMessage("NOOP") )
|
||||
else:
|
||||
MainState.process(self, handler, message)
|
||||
|
||||
|
@ -181,7 +478,7 @@ class LineReader:
|
|||
while pos != -1:
|
||||
line = self.buf[:pos]
|
||||
if line[-1] == "\r":
|
||||
line = line[:-2]
|
||||
line = line[:-1]
|
||||
yield line
|
||||
self.buf = self.buf[pos+1:]
|
||||
pos = self.buf.find("\n")
|
||||
|
@ -191,15 +488,39 @@ class FTPHandler(SocketServer.BaseRequestHandler):
|
|||
print ("[%s] " % self.client_address[0]) + text
|
||||
|
||||
def send(self, message):
|
||||
self.request.send( str(message) )
|
||||
line = str(message)
|
||||
self.debug("< "+line)
|
||||
self.request.send( line )
|
||||
|
||||
def createPassiveDataConnection(self):
|
||||
port = randint(60000,63000)
|
||||
self.connection = PassiveDataConnection(port)
|
||||
return port
|
||||
|
||||
def createActiveDataConnection(self,port):
|
||||
self.connection = ActiveDataConnection(self.client_address[0],port)
|
||||
def createActiveDataConnection(self,addr):
|
||||
self.connection = ActiveDataConnection(addr)
|
||||
|
||||
def get_node(self,path):
|
||||
if path == "/":
|
||||
return self.rootDirectory
|
||||
|
||||
if path[0] == "/":
|
||||
cnode = self.rootDirectory
|
||||
path = path[1:]
|
||||
else:
|
||||
cnode = self.currentDirectory
|
||||
|
||||
if path[-1] == "/":
|
||||
path = path[:-1]
|
||||
|
||||
parts = path.split("/")
|
||||
for part in parts:
|
||||
if cnode == None or not cnode.is_dir():
|
||||
return None
|
||||
|
||||
cnode = cnode.get_node(part)
|
||||
|
||||
return cnode
|
||||
|
||||
def runDataConnection(self, dchandler):
|
||||
if self.connection is None:
|
||||
|
@ -210,6 +531,8 @@ class FTPHandler(SocketServer.BaseRequestHandler):
|
|||
return True
|
||||
|
||||
def handle(self):
|
||||
self.currentDirectory = self.rootDirectory
|
||||
|
||||
self.connection = None
|
||||
|
||||
self.state = NonAuthorizedState()
|
||||
|
@ -230,6 +553,7 @@ class FTPHandler(SocketServer.BaseRequestHandler):
|
|||
linereader.push(data)
|
||||
|
||||
for line in linereader.get_lines():
|
||||
self.debug("> "+line)
|
||||
message = FTPMessage.parse(line)
|
||||
self.state.process(self,message)
|
||||
|
||||
|
@ -238,6 +562,63 @@ class FTPHandler(SocketServer.BaseRequestHandler):
|
|||
handler = FTPHandler
|
||||
handler.authorizer = AnonymousAuthorizer()
|
||||
|
||||
server = SocketServer.ThreadingTCPServer(("",1234),handler)
|
||||
recdir = Directory("recursive",files=[
|
||||
File("is")
|
||||
])
|
||||
recdir.files.append(recdir)
|
||||
|
||||
server.serve_forever()
|
||||
handler.rootDirectory = Directory("",files=[
|
||||
Directory("etc", files=[
|
||||
File("passwd",content=URandomFileContent()),
|
||||
File("shadow",content=URandomFileContent()),
|
||||
recdir
|
||||
]),
|
||||
Directory("usr", files=[
|
||||
Directory("share"),
|
||||
Directory("bin", files=[
|
||||
File("sh")
|
||||
])
|
||||
]),
|
||||
Directory("home", files=[
|
||||
Directory("john",owner="john"),
|
||||
Directory("jane",owner="jane"),
|
||||
Directory("peter",owner="peter")
|
||||
]),
|
||||
Directory("root", files=[
|
||||
Directory("ssh",files=[
|
||||
File("authorized_keys",content=URandomFileContent())
|
||||
]),
|
||||
File("db.dump", content=URandomFileContent())
|
||||
]),
|
||||
Directory("dev"),
|
||||
Directory("mnt"),
|
||||
Directory("var", files=[
|
||||
Directory("www")
|
||||
]),
|
||||
Directory("bin"),
|
||||
Directory("tmp"),
|
||||
Directory("lost+found"),
|
||||
Directory("boot"),
|
||||
Directory("lib"),
|
||||
Directory("lib32"),
|
||||
Directory("proc"),
|
||||
Directory("src"),
|
||||
File("vmlinuz",size=4000000),
|
||||
Directory("selinux"),
|
||||
Directory("opt"),
|
||||
File("initrd.img",size=4000000)
|
||||
])
|
||||
|
||||
port = 1234
|
||||
while True:
|
||||
try:
|
||||
server = SocketServer.ThreadingTCPServer(("",port),handler)
|
||||
print "Listening on port %d" % port
|
||||
server.serve_forever()
|
||||
break
|
||||
except Exception:
|
||||
if port < 1500:
|
||||
port += 1
|
||||
else:
|
||||
print "Failed to find a port"
|
||||
break
|
Loading…
Reference in a new issue