PCredz/ 0000755 0001750 0001750 00000000000 12357313767 011301 5 ustar gwolf gwolf PCredz/Pcredz 0000755 0001750 0001750 00000063017 12357101320 012441 0 ustar gwolf gwolf #! /usr/bin/env python
# Pcredz 0.9
# Created by Laurent Gaffie
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
try:
import pcap
except ImportError:
print 'libpcap not installed.\ntry : apt-get remove python-pypcap && apt-get install python-libpcap\nOn Mac OS X download http://downloads.sourceforge.net/project/pylibpcap/pylibpcap/0.6.4/pylibpcap-0.6.4.tar.gz?r=&ts=1396732918&use_mirror=softlayer-dal \ntar xvf pylibpcap-0.6.4.tar.gz && cd pylibpcap-0.6.4\n./setup.py install'
exit()
import logging
import optparse
import os
import re
import socket
import struct
import subprocess
import sys
import threading
import time
from base64 import b64decode
from threading import Thread
def ShowWelcome():
Message = 'Pcredz 0.9\nAuthor: Laurent Gaffie\nPlease send bugs/comments/pcaps to: lgaffie@trustwave.com\nThis script will extract NTLM (http,ldap,smb,sql,etc), Kerberos,\nFTP, HTTP Basic and credit card data from a given pcap file or from a live interface.\n'
print Message
parser = optparse.OptionParser(usage='\npython %prog -f file.pcap\n%prog -d /tmp/pcap/\n%prog -i eth0',prog=sys.argv[0],)
parser.add_option('-f', action="store", dest="fname", help = "Pcap file to parse", metavar="capture.pcap")
parser.add_option('-d', action="store", dest="dir_path", help = "Pcap directory to parse recursivly", metavar="/home/pnt/pcap/")
parser.add_option('-i', action="store", dest="interface", help = "interface for live capture", metavar="eth0")
parser.add_option('-v', action="store_true", help="More verbose.", dest="Verbose")
parser.add_option('-c', action="store_false", default='True', help = "deactivate CC number scanning (Can gives false positives!)", dest="activate_cc")
parser.add_option('-t', action="store_true", help = "Include a timestamp in all generated messages (useful for correlation)", dest="timestamp")
options, args = parser.parse_args()
if options.fname is None and options.dir_path is None and options.interface is None:
print '\n\033[1m\033[31m -f or -d or -i mandatory option missing.\033[0m\n'
parser.print_help()
exit(-1)
if options.fname and options.dir_path:
print '\n\033[1m\033[31mYou can\'t use -f and -d at the same time.\033[0m\n'
parser.print_help()
exit(-1)
if options.fname and options.interface:
print '\n\033[1m\033[31mYou can\'t use -f and -i at the same time.\033[0m\n'
parser.print_help()
exit(-1)
if options.dir_path and options.interface:
print '\n\033[1m\033[31mYou can\'t use -i and -d at the same time.\033[0m\n'
parser.print_help()
exit(-1)
ShowWelcome()
Verbose = options.Verbose
fname = options.fname
dir_path = options.dir_path
interface = options.interface
activate_cc = options.activate_cc
timestamp = options.timestamp
start_time = time.time()
Filename = str(os.path.join(os.path.dirname(__file__),"CredentialDump-Session.log"))
l= logging.getLogger('Credential-Session')
l.addHandler(logging.FileHandler(Filename,'a'))
if activate_cc:
print 'CC number scanning activated\n'
else:
print 'CC number scanning is deactivated\n'
def PrintPacket(Filename,Message):
if Verbose == True:
return True
if os.path.isfile(Filename) == True:
with open(Filename,"r") as filestr:
if re.search(re.escape(Message), filestr.read()):
filestr.close()
return False
else:
return True
else:
return True
def IsCookedPcap(version):
Cooked = re.search('Linux \"cooked\"', version)
TcpDump = re.search('Ethernet', version)
Wifi = re.search('802.11', version)
if Wifi:
print 'Using 802.11 format\n'
return 1
if Cooked:
print 'Using Linux Cooked format\n'
return 2
if TcpDump:
print 'Using TCPDump format\n'
return 3
else:
print 'Unknow format, trying TCPDump format\n'
return 3
protocols={6:'tcp',
17:'udp',
1:'icmp',
2:'igmp',
3:'ggp',
4:'ipcap',
5:'ipstream',
8:'egp',
9:'igrp',
29:'ipv6oipv4',
}
def luhn(n):
r = [int(ch) for ch in str(n)][::-1]
return (sum(r[0::2]) + sum(sum(divmod(d*2,10)) for d in r[1::2])) % 10 == 0
def Is_Anonymous(data):
LMhashLen = struct.unpack(' 0:
SSPIStart = data[:]
LMhashLen = struct.unpack(' 60:
NtHash = SSPIStart[NthashOffset:NthashOffset+NthashLen].encode("hex").upper()
DomainLen = struct.unpack('1:
if Basestr.decode('ascii'):
return 'SMTP decoded Base64 string: %s\n'%(Basestr)
except:
pass
def Decode_Ip_Packet(s):
d={}
d['version']=(ord(s[0]) & 0xf0) >> 4
d['header_len']=ord(s[0]) & 0x0f
d['tos']=ord(s[1])
d['total_len']=socket.ntohs(struct.unpack('H',s[2:4])[0])
d['id']=socket.ntohs(struct.unpack('H',s[4:6])[0])
d['flags']=(ord(s[6]) & 0xe0) >> 5
d['fragment_offset']=socket.ntohs(struct.unpack('H',s[6:8])[0] & 0x1f)
d['ttl']=ord(s[8])
d['protocol']=ord(s[9])
d['checksum']=socket.ntohs(struct.unpack('H',s[10:12])[0])
d['source_address']=pcap.ntoa(struct.unpack('i',s[12:16])[0])
d['destination_address']=pcap.ntoa(struct.unpack('i',s[16:20])[0])
if d['header_len']>5:
d['options']=s[20:4*(d['header_len']-5)]
else:
d['options']=None
d['data']=s[4*d['header_len']:]
return d
def Print_Packet_Details(decoded,SrcPort,DstPort):
if timestamp:
ts = '[%f] ' % time.time()
else:
ts = ''
try:
return '%sprotocol: %s %s:%s > %s:%s' % (ts, protocols[decoded['protocol']],decoded['source_address'],SrcPort,
decoded['destination_address'], DstPort)
except:
return '%s%s:%s > %s:%s' % (ts,decoded['source_address'],SrcPort,
decoded['destination_address'], DstPort)
def ParseDataRegex(decoded, SrcPort, DstPort):
SMTPAuth = re.search('AUTH LOGIN|AUTH PLAIN', decoded['data'])
Basic64 = re.findall('(?<=Authorization: Basic )[^\n]*', decoded['data'])
FTPUser = re.findall('(?<=USER )[^\r]*', decoded['data'])
FTPPass = re.findall('(?<=PASS )[^\r]*', decoded['data'])
HTTPNTLM2 = re.findall('(?<=WWW-Authenticate: NTLM )[^\\r]*', decoded['data'])
HTTPNTLM3 = re.findall('(?<=Authorization: NTLM )[^\\r]*', decoded['data'])
NTLMSSP2 = re.findall('NTLMSSP\x00\x02\x00\x00\x00.*[^EOF]*', decoded['data'])
NTLMSSP3 = re.findall('NTLMSSP\x00\x03\x00\x00\x00.*[^EOF]*', decoded['data'],re.DOTALL)
if activate_cc:
CCMatch = re.findall('.{30}[^\d][3456][0-9]{3}[\s-]*[0-9]{4}[\s-]*[0-9]{4}[\s-]*[0-9]{4}[^\d]', decoded['data'],re.DOTALL)
CC = re.findall('[^\d][456][0-9]{3}[\s-]*[0-9]{4}[\s-]*[0-9]{4}[\s-]*[0-9]{4}[^\d]', decoded['data'])
else:
CCMatch = False
CC = False
if Basic64:
basic = ''.join(Basic64)
HeadMessage = Print_Packet_Details(decoded,SrcPort,DstPort)
try:
Message = 'Found HTTP Basic authentication: %s\n'%(b64decode(basic))
if PrintPacket(Filename,Message):
l.warning(HeadMessage)
l.warning(Message)
print HeadMessage+'\n'+Message
except:
pass
if DstPort == 88 and protocols.has_key(decoded['protocol']) and protocols[decoded['protocol']] == 'tcp':
Message = ParseMSKerbv5TCP(decoded['data'][20:])
if Message:
HeadMessage = Print_Packet_Details(decoded,SrcPort,DstPort)
if PrintPacket(Filename,Message[1]):
l.warning(HeadMessage)
l.warning(Message[0])
print HeadMessage+'\n'+Message[0]
if DstPort == 88 and protocols.has_key(decoded['protocol']) and protocols[decoded['protocol']] == 'udp':
Message = ParseMSKerbv5UDP(decoded['data'][8:])
if Message:
HeadMessage = Print_Packet_Details(decoded,SrcPort,DstPort)
if PrintPacket(Filename,Message[1]):
l.warning(HeadMessage)
l.warning(Message[0])
print HeadMessage+'\n'+Message[0]
if DstPort == 161:
Message = ParseSNMP(decoded['data'][8:])
if Message:
HeadMessage = Print_Packet_Details(decoded,SrcPort,DstPort)
if PrintPacket(Filename,Message):
l.warning(HeadMessage)
l.warning(Message)
print HeadMessage+'\n'+Message
if DstPort == 143:
IMAPAuth = re.findall('(?<=LOGIN \")[^\r]*', decoded['data'])
if IMAPAuth:
HeadMessage = Print_Packet_Details(decoded,SrcPort,DstPort)
Message = 'Found IMAP login: "%s\n'%(''.join(IMAPAuth))
if PrintPacket(Filename,Message):
l.warning(HeadMessage)
l.warning(Message)
print HeadMessage+'\n'+Message
if DstPort == 110:
if FTPUser:
global POPUser
POPUser = ''.join(FTPUser)
if FTPPass:
try:
POPUser
HeadMessage = Print_Packet_Details(decoded,SrcPort,DstPort)
Message = 'Found POP credentials %s:%s\n'%(POPUser,''.join(FTPPass))
del POPUser
if PrintPacket(Filename,Message):
l.warning(HeadMessage)
l.warning(Message)
print HeadMessage+'\n'+Message
except NameError:
pass
if DstPort == 25 and SMTPAuth or DstPort == 587 and SMTPAuth:
global SMTPAuthentication
SMTPAuthentication = '1'
if DstPort == 25 or DstPort == 587:
try:
SMTPAuthentication
Message = ParseSMTP(decoded['data'][20:])
if Message:
HeadMessage = Print_Packet_Details(decoded,SrcPort,DstPort)
del SMTPAuthentication
if PrintPacket(Filename,Message):
l.warning(HeadMessage)
l.warning(Message)
print HeadMessage+'\n'+Message
except NameError:
pass
if FTPUser:
global UserID
UserID = ''.join(FTPUser)
if FTPPass and DstPort == 21:
try:
HeadMessage = Print_Packet_Details(decoded,SrcPort,DstPort)
Message = 'FTP User: %s\n'%(UserID)
Message+= 'FTP Pass: %s\n'%(''.join(FTPPass))
del UserID
if PrintPacket(Filename,Message):
l.warning(HeadMessage)
l.warning(Message)
print HeadMessage+'\n'+Message
except:
pass
if NTLMSSP2:
global Chall
Chall = ''.join(NTLMSSP2)[24:32].encode('hex')
if NTLMSSP3:
try:
NTLMPacket = ''.join(NTLMSSP3)
if Is_Anonymous(NTLMPacket):
try:
Chall
except NameError:
pass
else:
HeadMessage = Print_Packet_Details(decoded,SrcPort,DstPort)
Message = ParseNTLMHash(NTLMPacket,Chall)
del Chall
if PrintPacket(Filename,Message[1]):
l.warning(HeadMessage)
l.warning(Message[0])
print HeadMessage+'\n'+Message[0]
except:
pass
if HTTPNTLM2:
try:
Packet = b64decode(''.join(HTTPNTLM2))
global HTTPChall
if re.findall('NTLMSSP\x00\x02\x00\x00\x00.*[^EOF]*', Packet,re.DOTALL):
HTTPChall = ''.join(Packet)[24:32].encode('hex')
except:
pass
if HTTPNTLM3:
try:
Packet = b64decode(''.join(HTTPNTLM3))
if re.findall('NTLMSSP\x00\x03\x00\x00\x00.*[^EOF]*', Packet,re.DOTALL):
if Is_Anonymous(Packet):
try:
HTTPChall
except NameError:
pass
else:
HeadMessage = Print_Packet_Details(decoded,SrcPort,DstPort)
Message = ParseNTLMHash(Packet,HTTPChall)
del HTTPChall
if PrintPacket(Filename,Message[1]):
l.warning(HeadMessage)
l.warning(Message[0])
print HeadMessage+'\n'+Message
except:
pass
if CC:
CreditCard = re.sub("\D", "", ''.join(CC).strip())
CMatch = ''.join(CCMatch).strip()
if len(CreditCard)<=16:
if luhn(CreditCard):
HeadMessage = Print_Packet_Details(decoded,SrcPort,DstPort)
MessageCC = 'Possible valid CC (Luhn check OK): %s\n'%(CreditCard)
MessageMatch= 'Please verify this match ( %s )\n'%('\033[1m\033[31m'+CMatch+'\033[0m')
if PrintPacket(Filename,MessageCC):
l.warning(HeadMessage)
l.warning(MessageCC+MessageMatch)
print HeadMessage+'\n'+MessageCC+'\n'+MessageMatch
else:
pass
def Print_Packet_Cooked(pktlen, data, timestamp):
if not data:
return
if data[14:16]=='\x08\x00':
decoded=Decode_Ip_Packet(data[16:])
SrcPort = struct.unpack('>H',decoded['data'][0:2])[0]
DstPort = struct.unpack('>H',decoded['data'][2:4])[0]
ParseDataRegex(decoded, SrcPort, DstPort)
def Print_Packet_800dot11(pktlen, data, timestamp):
if not data:
return
if data[32:34]=='\x08\x00':
decoded=Decode_Ip_Packet(data[34:])
SrcPort = struct.unpack('>H',decoded['data'][0:2])[0]
DstPort = struct.unpack('>H',decoded['data'][2:4])[0]
ParseDataRegex(decoded, SrcPort, DstPort)
def Print_Packet_Tcpdump(pktlen, data, timestamp):
if not data:
return
if data[12:14]=='\x08\x00':
decoded= Decode_Ip_Packet(data[14:])
if len(decoded['data']) >= 2:
SrcPort= struct.unpack('>H',decoded['data'][0:2])[0]
else:
SrcPort = 0
if len(decoded['data']) > 2:
DstPort = struct.unpack('>H',decoded['data'][2:4])[0]
else:
DstPort = 0
ParseDataRegex(decoded, SrcPort, DstPort)
def decode_file(fname,res):
if interface != None:
try:
p = pcap.pcapObject()
net, mask = pcap.lookupnet(interface)
p.open_live(interface, 1600, 0, 100)
Message = "Pcredz live capture started, using:%s\nStarting timestamp (%s) corresponds to %s"%(interface, time.time(), time.strftime('%x %X'))
print Message
l.warning(Message)
while 1:
p.dispatch(1, Print_Packet_Tcpdump)
except (KeyboardInterrupt, SystemExit):
print '\n\nCRTL-C hit...\nCleaning up...'
sys.exit()
else:
try:
p = pcap.pcapObject()
p.open_offline(fname)
l.warning('\n\nPcredz started, using:%s file'%(fname))
Version = IsCookedPcap(res)
if Version == 1:
thread = Thread(target = p.dispatch, args = (0, Print_Packet_Cooked))
thread.daemon=True
thread.start()
try:
while thread.is_alive():
thread.join(timeout=1)
except (KeyboardInterrupt, SystemExit):
print '\n\nCRTL-C hit..Cleaning up...'
threading.Event().set()
if Version == 2:
thread = Thread(target = p.dispatch, args = (0, Print_Packet_Cooked))
thread.daemon=True
thread.start()
try:
while thread.is_alive():
thread.join(timeout=1)
except (KeyboardInterrupt, SystemExit):
print '\n\nCRTL-C hit..Cleaning up...'
threading.Event().set()
if Version == 3:
thread = Thread(target = p.dispatch, args = (0, Print_Packet_Tcpdump))
thread.daemon=True
thread.start()
try:
while thread.is_alive():
thread.join(timeout=1)
except (KeyboardInterrupt, SystemExit):
print '\n\nCRTL-C hit..Cleaning up...'
threading.Event().set()
except Exception:
print 'Can\'t parse %s'%(fname)
def Run():
try:
if dir_path != None:
for root, dirs, files in os.walk(dir_path, topdown=False):
for capfile in files:
FilePath = os.path.join(root, capfile)
Start_Time = time.time()
print '\nParsing: %s'%(FilePath)
p = subprocess.Popen(["file", FilePath], stdout=subprocess.PIPE)
res, err = p.communicate()
decode_file(FilePath,res)
Seconds = time.time() - Start_Time
FileSize = 'File size %.3g Mo'%(os.stat(FilePath).st_size/(1024*1024.0))
if Seconds>60:
minutes = Seconds/60
Message = '\n%s parsed in: %.3g minutes (%s).\n'%(FilePath, minutes, FileSize)
print Message
l.warning(Message)
if Seconds<60:
Message = '\n%s parsed in: %.3g seconds (%s).\n'%(FilePath, Seconds, FileSize)
print Message
l.warning(Message)
if fname != None:
p = subprocess.Popen(["file", fname], stdout=subprocess.PIPE)
res, err = p.communicate()
decode_file(fname,res)
Seconds = time.time() - start_time
FileSize = 'File size %.3g Mo'%(os.stat(fname).st_size/(1024*1024.0))
if Seconds>60:
minutes = Seconds/60
Message = '\n%s parsed in: %.3g minutes (%s).\n'%(fname, minutes, FileSize)
print Message
l.warning(Message)
if Seconds<60:
Message = '\n%s parsed in: %.3g seconds (%s).\n'%(fname, Seconds, FileSize)
print Message
l.warning(Message)
if interface != None:
decode_file(fname,'')
except:
raise
Run()
PCredz/Readme.md 0000644 0001750 0001750 00000002231 12357101320 012772 0 ustar gwolf gwolf #Features:
- Extract from a pcap file or from a live interface:
- Credit card numbers
- POP
- SMTP
- IMAP
- SNMP community string
- FTP
- HTTP Basic
- NTLMv1/v2 (DCE-RPC,SMBv1/2,LDAP, MSSQL, HTTP, etc)
- Kerberos (AS-REQ Pre-Auth etype 23) hashes.
- All hashes are displayed in a hashcat format (use -m 7500 for kerberos, -m 5500 for NTLMv1, -m 5600 for NTLMv2).
- Log all credentials to a file (CredentialDump-Session.log).
#Install:
- Linux:
On a debian based OS: apt-get install python-libpcap
On Kali, you will need to: apt-get remove python-pypcap && apt-get install python-libpcap
- Os X and other distributions:
wget http://downloads.sourceforge.net/project/pylibpcap/pylibpcap/0.6.4/pylibpcap-0.6.4.tar.gz
tar xvf pylibpcap-0.6.4.tar.gz
cd pylibpcap-0.6.4
python setup.py install
#Usage:
./Pcredz -f file-to-parse.pcap
./Pcredz -d /tmp/pcap-directory-to-parse/
./Pcredz -i eth0
Options:
-h, --help show this help message and exit
-f capture.pcap Pcap file to parse
-d /home/pnt/pcap/ Pcap directory to parse recursivly
-i eth0 interface for live capture
-v More verbose.