找回密码
 注册账户
查看: 1990|回复: 0

Fake FTP Server

[复制链接]
棋子 发表于 2007-8-29 21:15:13 | 显示全部楼层 |阅读模式
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-

  3. """
  4. Fake FTP Server
  5. ~~~~~~~~~~~~~~~

  6. This is a simple fake FTP daemon. It stores the login data
  7. (username and password) it is given and then terminates the
  8. connection.

  9. It was made to easily recover forgotten passwords which are
  10. still stored (but scrambled) by an FTP client without the need
  11. for using a sniffer tool.

  12. Beware: Although the script reacts on `Ctrl-C`, it won't exit
  13. until another connect has happened because `socket.accept()`
  14. is blocking. Also, due to the use of threads, it may take some
  15. time until the port will be free again.

  16. Some useful resources for implementing this were the IETF's
  17. `RFC 959`_ and the `FTP reference`_ by D. J. Bernstein.

  18. .. _RFC 959:        [url]http://tools.ietf.org/rfc/rfc959.txt[/url]
  19. .. _FTP reference:  [url]http://cr.yp.to/ftp.html[/url]
  20. """

  21. from datetime import datetime
  22. from optparse import OptionParser
  23. from SocketServer import BaseRequestHandler, ThreadingTCPServer
  24. from sys import stdout


  25. class FTPLoginHandler(BaseRequestHandler):
  26.     """Handler for FTP authentication."""

  27.     def debug(self, message):
  28.         """Show log message."""
  29.         if self.server.debug:
  30.             print '***', message

  31.     def respond(self, code, explanation):
  32.         """Send a response to the client."""
  33.         self.request.send('%d %s\r\n' % (code, explanation))

  34.     def process_request(self):
  35.         """Parse input into a command and an argument."""
  36.         data = self.request.recv(64)
  37.         parts = data.strip().split(' ')
  38.         return parts.pop(0), parts

  39.     def log_auth(self, user, password):
  40.         """Write username and password to logfile."""
  41.         now = datetime.now().isoformat(' ')[:19]
  42.         client = '%s:%d' % self.client_address
  43.         line = ' '.join((now, client, user, password))
  44.         self.server.logfile.write(line + '\n')
  45.         self.server.logfile.flush()

  46.     def handle(self):
  47.         """Handle incoming data."""
  48.         self.debug('Connection from %s:%d.'
  49.             % self.client_address)
  50.         self.respond(220, self.server.banner)
  51.         user = None
  52.         while True:
  53.             cmd, args = self.process_request()
  54.             if cmd == 'USER':
  55.                 if user is not None:
  56.                     self.respond(503, 'Incorrect sequence of'
  57.                         ' commands: PASS required after USER.')
  58.                     continue
  59.                 user = (args and args[0] or '*missing*')
  60.                 self.debug('User "%s" has identified.' % user)
  61.                 self.respond(331, 'Please specify the password.')
  62.                 continue
  63.             elif cmd == 'PASS':
  64.                 if user is None:
  65.                     self.respond(503, 'Incorrect sequence of'
  66.                         ' commands: USER required before PASS.')
  67.                     continue
  68.                 password = (args and args[0] or '*missing*')
  69.                 self.debug('User "%s" supplied password "%s",'
  70.                     ' storing.' % (user, password))
  71.                 self.log_auth(user, password)
  72.                 self.respond(530, 'Login incorrect.')
  73.                 break
  74.             else:
  75.                 self.debug('Rejecting request "%s".'
  76.                     % ' '.join(args))
  77.                 self.respond(530,
  78.                     'Please login with USER and PASS.')
  79.                 break
  80.         self.request.close()
  81.         self.debug('Connection with %s:%d closed.'
  82.             % self.client_address)


  83. class FTPLoginServer(ThreadingTCPServer):

  84.     def __init__(self, host='', port=21, banner='', debug=False,
  85.             logfile=None, append=False):
  86.         ThreadingTCPServer.__init__(self, (host, port),
  87.             FTPLoginHandler)
  88.         self.banner = banner
  89.         self.debug = debug
  90.         mode = (append and 'a' or 'w')
  91.         self.logfile = (logfile and open(logfile, mode) or stdout)

  92.     def server_close(self):
  93.         ThreadingTCPServer.server_close(self)
  94.         self.logfile.close()


  95. if __name__ == '__main__':
  96.     parser = OptionParser(usage='%prog [options] <port>')
  97.     parser.add_option('-a', '--append', dest='append',
  98.         action='store_true',
  99.         help='append to LOGFILE ')
  100.     parser.add_option('-b', '--banner', dest='banner',
  101.         help='custom banner string')
  102.     parser.add_option('-d', '--debug', dest='debug',
  103.         action='store_true',
  104.         help='show debugging messages')
  105.     parser.add_option('-l', '--logfile', dest='logfile',
  106.         help='write collected user/password data to LOGFILE')
  107.     opts, args = parser.parse_args()

  108.     # Parse arguments.
  109.     if len(args) != 1:
  110.         parser.print_help()
  111.         parser.exit()
  112.     try:
  113.         port = int(args[0])
  114.     except ValueError:
  115.         parser.print_help()
  116.         parser.exit()

  117.     # Serve.
  118.     server = FTPLoginServer(port=port, **opts.__dict__)
  119.     try:
  120.         server.serve_forever()
  121.     except KeyboardInterrupt:
  122.         print 'Ctrl-C pressed, exiting...'
  123.     server.server_close()
复制代码
您需要登录后才可以回帖 登录 | 注册账户

本版积分规则

存档|黑屋|手机|网络实验室 本站服务器由美国合租以及IDCLayer国际数据提供!!!

GMT+8, 2026-6-8 22:38 , Processed in 0.011850 second(s), 9 queries , Gzip On, Redis On.

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表