From aa0a319234347bfc226cbb243f32726eba82a36a Mon Sep 17 00:00:00 2001 From: trollhase Date: Fri, 23 Aug 2013 07:45:53 +0200 Subject: [PATCH] Some fixes :3 --- fakeftp.py | 122 ++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 89 insertions(+), 33 deletions(-) diff --git a/fakeftp.py b/fakeftp.py index 17d9a97..f07ef68 100644 --- a/fakeftp.py +++ b/fakeftp.py @@ -23,13 +23,24 @@ def mask(rights): return m +def _r( (u,g,o) ): + return ( (u&7) << 6 ) + ( (g&7) << 3 ) + (o&7) + class FSNode: - def __init__(self,name,owner="nobody",group="nobody",rights=384,size=0, iun=1): + def __init__(self,name,owner="nobody",group="nobody",rights=(6,4,4),size=0, iun=1): self.name = name self.owner = owner self.group = group - self.rights = rights + + if type(rights) == tuple and len(rights) == 3: + self.rights = _r( rights ) + elif type(rights) == int: + self.rights = rights + else: + self.rights = _r( (6,4,4) ) + self.size = size + self.parent = None self.iun = iun @@ -95,7 +106,7 @@ class FSNode: return p class Directory(FSNode): - def __init__(self,name,owner="nobody",group="nobody",rights=384,size=4096,files=[]): + def __init__(self,name,owner="nobody",group="nobody",rights=(6,4,4),size=4096,files=[]): FSNode.__init__(self, name=name, owner=owner, group=group,rights=rights, size=size, iun=randint(2,10)) self.files = files @@ -258,8 +269,12 @@ class WelcomeMessage(FTPMessage): FTPMessage.__init__(self,"220","FTP Server ready") class EnteringPassiveModeMessage(FTPMessage): - def __init__(self,addrtuple): - FTPMessage.__init__(self,"227","Entering Passive Mode %s." % addrtuple) + def __init__(self,(ip,port)): + addr = ip.split(".") + addr.append( str( (port >> 8) & 0xFF ) ) + addr.append( str( port & 0xFF ) ) + + FTPMessage.__init__(self,"227","Entering Passive Mode (%s)." % (",".join(addr) ) ) class BeginDirectoryListingMessage(FTPMessage): def __init__(self): @@ -309,6 +324,22 @@ class EndFileRetrieve(FTPMessage): def __init__(self): FTPMessage.__init__(self,"226","Transfer complete") +class UnableToBuildConnectionMessage(FTPMessage): + def __init__(self): + FTPMessage.__init__(self,"425","Unable to build data connection") + +class CommandNotAllowedInAscii(FTPMessage): + def __init__(self,cmd): + FTPMessage.__init__(self,"550","%s not allowed in ASCII mode") + +class AbortSuccessfulMessage(FTPMessage): + def __init__(self): + FTPMessage.__init__(self,"226","Abort successful") + +class SystemTypeMessage(FTPMessage): + def __init__(self, sys="UNIX",typ="L8"): + FTPMessage.__init__(self,"215","%s Type: %s" % ( sys.upper(), typ )) + # Data Connection Handler class NListHandler: def __init__(self, directory, handler): @@ -358,6 +389,7 @@ class State: class MainState(State): def process(self, handler, message): if message.cmd == "QUIT": + handler.debug( "Quitting" ) handler.send( QuitMessage() ) handler.running = False else: @@ -366,6 +398,7 @@ class MainState(State): class NonAuthorizedState(MainState): def process(self, handler, message): if message.cmd == "USER": + handler.debug("Setting user to %s" % message.parameter) handler.user = message.parameter handler.state = AuthorizingState() handler.send( PasswordRequiredMessage(handler.user) ) @@ -374,69 +407,81 @@ class NonAuthorizedState(MainState): class AuthorizingState(MainState): def process(self, handler, message): - if message.cmd == "PASS": + if message.cmd == "USER": + handler.debug("Changing user to %s" % message.parameter) + handler.user = message.parameter + handler.send( PasswordRequiredMessage(handler.user) ) + elif message.cmd == "PASS": password = message.parameter if handler.authorizer.authorize(handler.user, password, handler): - handler.debug("User login %s successful" % handler.user) + handler.debug("User login %s successful using password %s" % (handler.user,password)) handler.state = AuthorizedState() handler.send( AuthorizationSuccessfulMessage() ) else: - handler.debug("User login %s failed" % handler.user) + handler.debug("User login %s failed using password %s" % (handler.user, password) ) handler.state = NonAuthorizedState() handler.send( AuthorizationFailedMessage() ) else: MainState.process(self, handler, message) class AuthorizedState(MainState): - def addrtuple(self, ip, port): - b = ip.split(".") - b.append( str( (port >> 8) & 0xFF ) ) - b.append( str( port & 0xFF ) ) - return "(" + ",".join(b)+ ")" - def process(self, handler, message): if message.cmd == "PASV": - port = handler.createPassiveDataConnection() + addr = handler.createPassiveDataConnection() handler.debug("Created passive data connection") - handler.send( EnteringPassiveModeMessage( self.addrtuple("127.0.0.1",port) ) ) - elif message.cmd in ["DELE","RMD","RNFR","RNTO","STOR"]: + handler.send( EnteringPassiveModeMessage( addr ) ) + elif message.cmd == "DELE": + handler.debug( "Attempt to delete file %s" % message.parameter ) + handler.send( OperationNotPermittedMessage() ) + elif message.cmd == "RMD": + handler.debug( "Attempt to delete directory %s" % message.parameter ) + handler.send( OperationNotPermittedMessage() ) + elif message.cmd == "RNFR": + handler.debug( "Attempt to rename %s" % message.parameter ) + handler.send( OperationNotPermittedMessage() ) + elif message.cmd == "RNTO": + handler.debug( "Attempt to rename to %s" % message.parameter ) + handler.send( OperationNotPermittedMessage() ) + elif message.cmd == "STOR": + handler.debug( "Attempt to store a file %s" % message.parameter ) handler.send( OperationNotPermittedMessage() ) elif message.cmd == "RETR": node = handler.get_node(message.parameter) if node.is_file(): - handler.runDataConnection( RetrieveHandler(node, handler) ) + if handler.runDataConnection( RetrieveHandler(node, handler) ): + handler.debug( "Retrieving file %s" % message.parameter ) + else: + handler.send( UnableToBuildConnectionMessage() ) 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.debug( "Attempt to port to local network." ) handler.send( InvalidPortCommandMessage() ) return addr = ( ".".join(hp[:4]), int(hp[4])<<8+int(hp[5]) ) - handler.createActiveDataConnection(addr) + handler.debug( "Creating active data connection to %s:%d" % addr ) - handler.debug("Created active data connection to %s:%d" % addr) + handler.createActiveDataConnection(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("Listing current directory") else: - handler.debug("failed") + handler.send( UnableToBuildConnectionMessage() ) elif message.cmd == "NLST": - handler.debug("Listing current directory (simple)") if handler.runDataConnection(NListHandler(handler.currentDirectory)): - handler.debug("successful") + handler.debug("Listing current directory (simple)") else: - handler.debug("failed") + handler.send( UnableToBuildConnectionMessage() ) elif message.cmd == "CWD": node = handler.get_node(message.parameter) if node is None or not node.is_dir(): @@ -449,20 +494,33 @@ class AuthorizedState(MainState): 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") + handler.debug("Error trying to switch to non-existent parent directory") else: handler.debug("Changed working directory to "+node.get_absolute_path()) handler.currentDirectory = node handler.send( ChangeDirectorySuccessfulMessage() ) elif message.cmd == "PWD": + handler.debug( "Printing working directory" ) handler.send( WorkingDirectoryMessage(handler.currentDirectory.get_absolute_path()) ) elif message.cmd == "TYPE": if message.parameter == "A": + handler.debug("Setting type to ASCII") handler.send( TypeSetMessage(message.parameter) ) else: + handler.debug("Unrecognized type %s" % message.parameter) handler.send( InvalidCommandMessage("TYPE") ) elif message.cmd == "NOOP": + handler.debug("No operation") handler.send( CommandSuccessfulMessage("NOOP") ) + elif message.cmd == "SIZE": + handler.debug("Requested size of %s" % message.parameter) + handler.send( CommandNotAllowedInAscii("SIZE") ) + elif message.cmd == "ABOR": + handler.debug("Aborting data connection") + handler.send( AbortSuccessfulMessage() ) + elif message.cmd == "SYST": + handler.debug("Requested system type") + handler.send( SystemTypeMessage() ) else: MainState.process(self, handler, message) @@ -488,14 +546,13 @@ class FTPHandler(SocketServer.BaseRequestHandler): print ("[%s] " % self.client_address[0]) + text def send(self, message): - line = str(message) - self.debug("< "+line) - self.request.send( line ) + self.request.send( str(message) ) def createPassiveDataConnection(self): port = randint(60000,63000) self.connection = PassiveDataConnection(port) - return port + myaddr = self.request.getsockname() + return (myaddr[0],port) def createActiveDataConnection(self,addr): self.connection = ActiveDataConnection(addr) @@ -553,7 +610,6 @@ 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)