Honeypot done.
This commit is contained in:
parent
c1a08ba821
commit
c968cf1e64
1 changed files with 395 additions and 14 deletions
407
fakeftp.py
407
fakeftp.py
|
@ -2,16 +2,169 @@ import SocketServer
|
||||||
import threading
|
import threading
|
||||||
import socket
|
import socket
|
||||||
from random import randint
|
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:
|
class DataConnection:
|
||||||
def run(self, dchandler):
|
def run(self, dchandler):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class PassiveDataConnection(DataConnection):
|
class PassiveDataConnection(DataConnection):
|
||||||
def __init__(self, port):
|
def __init__(self, port):
|
||||||
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
self.socket.bind(("",port))
|
self.socket.bind(("",port))
|
||||||
|
self.connection = None
|
||||||
threading.Thread(target=self.waitForConnection).start()
|
threading.Thread(target=self.waitForConnection).start()
|
||||||
|
|
||||||
def waitForConnection(self):
|
def waitForConnection(self):
|
||||||
|
@ -19,6 +172,8 @@ class PassiveDataConnection(DataConnection):
|
||||||
self.connection, _ = self.socket.accept()
|
self.connection, _ = self.socket.accept()
|
||||||
|
|
||||||
def run(self, dchandler):
|
def run(self, dchandler):
|
||||||
|
while self.connection is None:
|
||||||
|
pass
|
||||||
threading.Thread(target=self.runHandler, args=(dchandler,) ).start()
|
threading.Thread(target=self.runHandler, args=(dchandler,) ).start()
|
||||||
|
|
||||||
def runHandler(self, dchandler):
|
def runHandler(self, dchandler):
|
||||||
|
@ -26,9 +181,9 @@ class PassiveDataConnection(DataConnection):
|
||||||
self.connection.close()
|
self.connection.close()
|
||||||
|
|
||||||
class ActiveDataConnection(DataConnection):
|
class ActiveDataConnection(DataConnection):
|
||||||
def __init__(self, host, port):
|
def __init__(self, addr):
|
||||||
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
self.socket.connect( (host,port) )
|
self.socket.connect( addr )
|
||||||
|
|
||||||
def run(self, dchandler):
|
def run(self, dchandler):
|
||||||
threading.Thread(target=self.runHandler, args=(dchandler,)).start()
|
threading.Thread(target=self.runHandler, args=(dchandler,)).start()
|
||||||
|
@ -106,10 +261,94 @@ class EnteringPassiveModeMessage(FTPMessage):
|
||||||
def __init__(self,addrtuple):
|
def __init__(self,addrtuple):
|
||||||
FTPMessage.__init__(self,"227","Entering Passive Mode %s." % 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
|
# Data Connection Handler
|
||||||
class HeloHandler:
|
class NListHandler:
|
||||||
|
def __init__(self, directory, handler):
|
||||||
|
self.directory = directory
|
||||||
|
self.handler = handler
|
||||||
|
|
||||||
def handle(self, socket):
|
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
|
# State classes
|
||||||
class State:
|
class State:
|
||||||
|
@ -160,12 +399,70 @@ class AuthorizedState(MainState):
|
||||||
port = handler.createPassiveDataConnection()
|
port = handler.createPassiveDataConnection()
|
||||||
handler.debug("Created passive data connection")
|
handler.debug("Created passive data connection")
|
||||||
handler.send( EnteringPassiveModeMessage( self.addrtuple("127.0.0.1",port) ) )
|
handler.send( EnteringPassiveModeMessage( self.addrtuple("127.0.0.1",port) ) )
|
||||||
elif message.cmd == "HELO":
|
elif message.cmd in ["DELE","RMD","RNFR","RNTO","STOR"]:
|
||||||
handler.debug("Running Helo on data connection")
|
handler.send( OperationNotPermittedMessage() )
|
||||||
if handler.runDataConnection(HeloHandler()):
|
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")
|
handler.debug("successful")
|
||||||
else:
|
else:
|
||||||
handler.debug("failed")
|
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:
|
else:
|
||||||
MainState.process(self, handler, message)
|
MainState.process(self, handler, message)
|
||||||
|
|
||||||
|
@ -181,7 +478,7 @@ class LineReader:
|
||||||
while pos != -1:
|
while pos != -1:
|
||||||
line = self.buf[:pos]
|
line = self.buf[:pos]
|
||||||
if line[-1] == "\r":
|
if line[-1] == "\r":
|
||||||
line = line[:-2]
|
line = line[:-1]
|
||||||
yield line
|
yield line
|
||||||
self.buf = self.buf[pos+1:]
|
self.buf = self.buf[pos+1:]
|
||||||
pos = self.buf.find("\n")
|
pos = self.buf.find("\n")
|
||||||
|
@ -191,15 +488,39 @@ class FTPHandler(SocketServer.BaseRequestHandler):
|
||||||
print ("[%s] " % self.client_address[0]) + text
|
print ("[%s] " % self.client_address[0]) + text
|
||||||
|
|
||||||
def send(self, message):
|
def send(self, message):
|
||||||
self.request.send( str(message) )
|
line = str(message)
|
||||||
|
self.debug("< "+line)
|
||||||
|
self.request.send( line )
|
||||||
|
|
||||||
def createPassiveDataConnection(self):
|
def createPassiveDataConnection(self):
|
||||||
port = randint(60000,63000)
|
port = randint(60000,63000)
|
||||||
self.connection = PassiveDataConnection(port)
|
self.connection = PassiveDataConnection(port)
|
||||||
return port
|
return port
|
||||||
|
|
||||||
def createActiveDataConnection(self,port):
|
def createActiveDataConnection(self,addr):
|
||||||
self.connection = ActiveDataConnection(self.client_address[0],port)
|
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):
|
def runDataConnection(self, dchandler):
|
||||||
if self.connection is None:
|
if self.connection is None:
|
||||||
|
@ -210,6 +531,8 @@ class FTPHandler(SocketServer.BaseRequestHandler):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def handle(self):
|
def handle(self):
|
||||||
|
self.currentDirectory = self.rootDirectory
|
||||||
|
|
||||||
self.connection = None
|
self.connection = None
|
||||||
|
|
||||||
self.state = NonAuthorizedState()
|
self.state = NonAuthorizedState()
|
||||||
|
@ -230,6 +553,7 @@ class FTPHandler(SocketServer.BaseRequestHandler):
|
||||||
linereader.push(data)
|
linereader.push(data)
|
||||||
|
|
||||||
for line in linereader.get_lines():
|
for line in linereader.get_lines():
|
||||||
|
self.debug("> "+line)
|
||||||
message = FTPMessage.parse(line)
|
message = FTPMessage.parse(line)
|
||||||
self.state.process(self,message)
|
self.state.process(self,message)
|
||||||
|
|
||||||
|
@ -238,6 +562,63 @@ class FTPHandler(SocketServer.BaseRequestHandler):
|
||||||
handler = FTPHandler
|
handler = FTPHandler
|
||||||
handler.authorizer = AnonymousAuthorizer()
|
handler.authorizer = AnonymousAuthorizer()
|
||||||
|
|
||||||
server = SocketServer.ThreadingTCPServer(("",1234),handler)
|
recdir = Directory("recursive",files=[
|
||||||
|
File("is")
|
||||||
|
])
|
||||||
|
recdir.files.append(recdir)
|
||||||
|
|
||||||
|
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()
|
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