static void ParseErrorResponseUDP(KerberosData KerbData, TDSReader ByteReader) { int TagID = 0, TagLen = 0; do { TagID = ByteReader.ReadByte() & (int)0x1F; TagLen = ReadAsnLen(ByteReader, false); switch (TagID) { case 4: //skip Tag4->Stime, case 5: //skip Tag5->SuSec { ByteReader.ReadBytes(TagLen); break; } case 6: { ReadAsnLen(ByteReader); KerbData.errorCode = ByteReader.ReadByte(); KerbData.ErrorDesc = GetErrorDesc((ErrorCodes)KerbData.errorCode); return; } default: { //throw new Exception("Unexpected Tag " + TagID + " found in KERB UDP error response"); break; } } }while (TagID < 6); //Total 12 tags expected, but we are reading only 6 tags until error code }
static void ParseNonErrorResponseTCP(KerberosData KerbData, TDSReader ByteReader) { //Tag4-TagC //int TagID = 0, TagLen = 0; //do //{ // TagID = ByteReader.ReadByte(); // TagLen = ReadAsnLen(ByteReader, false); // TagID = (TagID & (int)0x1F); // switch (TagID) // { // case 0: // case 1: // case 2: // case 3: // case 4: // case 5: // case 6: // { // ByteReader.ReadBytes(TagLen); // Skip 'Crealm', 'Cname', 'Ticket' and 'EncPart' // break; // } // default: // { // throw new Exception("Unexpected Tag " + TagID + " found in KERB TCP error response" ); // } // } //} //while (TagID < 6); //total 6 tags expected }
static MessageTypes GetMessageType(KerberosData KerbData, TDSReader ByteReader) { int Len = ReadAsnLen(ByteReader); int MsgType = ByteReader.ReadByte(); if (Len == 1) { if (MsgType == (int)MessageTypes.KRB_TGS_REQ) { KerbData.RequestType = MessageTypes.KRB_TGS_REQ; } else if (MsgType == (int)MessageTypes.KRB_ERROR) { KerbData.ResponseType = MessageTypes.KRB_ERROR; } else if (MsgType == (int)MessageTypes.KRB_TGS_REP) { KerbData.ResponseType = MessageTypes.KRB_TGS_REP; } return((MessageTypes)MsgType); } else // bug in the code if we get here ... { throw new Exception("Invalid KERB Request length: " + Len); } }
static void GetVersion(KerberosData KerbData, TDSReader ByteReader) { int Length = ReadAsnLen(ByteReader); if (Length == 1) { KerbData.Version = ByteReader.ReadByte(); } if ((Length != 1) || (KerbData.Version != 5)) { throw new Exception("Invalid Kerberos version and unexpected version or unexpected number of bytes are used for storing the version "); } }
public static void Process(NetworkTrace trace) { foreach (ConversationData c in trace.conversations) { if (c.sourcePort == 88) { TDSParser.reverseSourceDest(c); } if (c.destPort != 88) { continue; } KerberosData KerbData = null; try { if (c.isUDP) // UDP { KerbData = ProcessUDP(c); } else // TCP { KerbData = ProcessTCP(c); } // ignore non KRB_TGS requests // ignore responses without an associated request - we don't want to log errors for unidentified request types // ignore SNames we don't know what they are ... or how to read them //if (KerbData.RequestType == MessageTypes.KRB_TGS_REQ // && (KerbData.SNameType == 2 || KerbData.SNameType == 10)) if (KerbData.RequestType == MessageTypes.KRB_TGS_REQ) { trace.KerbResponses.Add(KerbData); } } catch (Exception ex) { Console.WriteLine("Exception during Kerberos processing." + "\r\n" + ex.Message + "\r\n" + ex.StackTrace); Program.logDiagnostic("Exception during Kerberos processing." + "\r\n" + ex.Message + "\r\n" + ex.StackTrace); } // catch } // foreach } // void Process(...)
static void ParseErrorResponseTCP(KerberosData KerbData, TDSReader ByteReader) { //Tag4-TagC int TagID = 0, TagLen = 0; do { TagID = ByteReader.ReadByte(); TagLen = ReadAsnLen(ByteReader, false); TagID = (TagID & (int)0x1F); switch (TagID) { case 4: case 5: case 9: case 10: case 12: { ByteReader.ReadBytes(TagLen); // Skip 'STime', 'SuSec', 'Realm' break; } case 6: { ReadAsnLen(ByteReader); KerbData.errorCode = ByteReader.ReadByte(); KerbData.ErrorDesc = GetErrorDesc((ErrorCodes)KerbData.errorCode); return; } default: { break; //return; //throw new Exception("Unexpected Tag" + TagID + " found in KERB TCP response"); } } }while (TagID < 6); //Total 12 tags expected, but we are reading only 6 tags until error code }
static KerberosData ParseErrorResponseUDP(TDSReader ByteReader) { int TagID = 10, TagLen = 0, DataLen = 0; KerberosData KerbData = new KerberosData(); ReadAsnLen(ByteReader); //Skip over 4 bytes 'ApplicationTag' ReadAsnLen(ByteReader); //Skip over 4 bytes 'SequenceHeader' do { TagID = ByteReader.ReadByte(); TagLen = ReadAsnLen(ByteReader, false); switch (TagID & 0x1F) { case 0: case 1: case 4: case 5: case 9: break; case 6: { DataLen = ReadAsnLen(ByteReader, false); if (DataLen == 1) { KerbData.errorCode = ByteReader.ReadByte(); KerbData.ErrorDesc = GetErrorDesc((ErrorCodes)KerbData.errorCode); } return(KerbData); } } //Switch }while ((TagID & (int)0x1F) <= 9); return(KerbData); }
public static KerberosData ProcessUDP(ConversationData c) { KerberosData KerbData = new KerberosData(); KerbData.SourcePort = c.sourcePort; KerbData.convData = c; int Len2 = 0; int TagLen = 0; string SPN = null; int TagID = 0; bool IsContinueToNextFrame = false; foreach (FrameData fd in c.frames) { if (fd.payloadLength <= 1) { continue; } TDSReader ByteReader = new TDSReader(fd.payload, 0, -1, fd.payloadLength); //Skip over 4 bytes 'ApplicationTag' ReadAsnLen(ByteReader); //Skip over 4 bytes 'KdcReq->SequenceHeader' ReadAsnLen(ByteReader); //Init vars after every frame processing Len2 = 0; TagLen = 0; SPN = null; TagID = 0; do { TagID = ByteReader.ReadByte(); TagLen = ReadAsnLen(ByteReader, false); TagID = TagID & 0x1F; switch (TagID) //Lower 5 bits { case 0: // version# in Tag 0 for KRB_TGS_REP (response) case 1: case 2: { if ((fd.isFromClient && TagID == 1) || (!fd.isFromClient && TagID == 0)) { GetVersion(KerbData, ByteReader); } else if ((!fd.isFromClient && TagID == 1) || (fd.isFromClient && TagID == 2)) { MessageTypes MsgType = GetMessageType(KerbData, ByteReader); KerbData.frameNo = fd.frameNo; if (MsgType == MessageTypes.KRB_TGS_REP) { //ParseNonErrorResponseUDP(KerbData, ByteReader); IsContinueToNextFrame = true; } else if (MsgType == MessageTypes.KRB_ERROR) { ParseErrorResponseUDP(KerbData, ByteReader); IsContinueToNextFrame = true; } } break; } case 3: { //ByteReader.ReadByte(); Len2 = ReadAsnLen(ByteReader); ByteReader.ReadBytes(Len2); // skip the padata tag. break; } case 4: { //ByteReader.ReadByte(); //skip sequence header of ReqBody ReadAsnLen(ByteReader); int TagId2 = 0; do { TagId2 = ByteReader.ReadByte(); Len2 = ReadAsnLen(ByteReader, false); TagId2 = TagId2 & 0x1F; switch (TagId2) { case 0: { ByteReader.ReadByte(); int Len3 = ReadAsnLen(ByteReader, false); //Read and skip 'padding' ByteReader.ReadBytes(Len3 - 4); KerbData.IsForwardable = (ByteReader.ReadByte() & 0x40) != 0; //Read remaining three bytes ByteReader.ReadBytes(3); break; } case 1: case 2: case 4: case 5: case 7: case 8: //skip these tags. { ByteReader.ReadBytes(Len2); break; } case 3: { // UDP SName implementation - replacing with TCP implementation // ReadAsnLen(ByteReader); //Skip sequence header of sname // int Len3 = ReadAsnLen(ByteReader); //Skip Tag0 of sname // ByteReader.ReadBytes(Len3); //skip nametype // ReadAsnLen(ByteReader); //Skip Tag1 of sname // Len3 = ReadAsnLen(ByteReader); //Skip sequence header of sname->Tag1 // Len3 = ReadAsnLen(ByteReader); // Read SPN Length - same as the TCP implementation // SPN = ByteReader.ReadAnsiString(Len3); // KerbData.SPNRequested = SPN; // TCP SName implementation ReadAsnLen(ByteReader); //Skip sequence header of sname int Len3 = ReadAsnLen(ByteReader); //Skip Tag0 of sname // // Read the Name Type: // // 2 = NT-SRV-INST - has two Strings: Service and Instance. '/' separater is implied // 10 = NT-ENTERPRISE - has one String // // Throw error on all other values // Len3 = ReadAsnLen(ByteReader); if (Len3 != 1) { throw new Exception("Unexpected length (" + Len3 + ") reading SName Name Type."); } byte NameType = ByteReader.ReadByte(); KerbData.SNameType = NameType; if (NameType != 2 && NameType != 10) { IsContinueToNextFrame = true; break; } ReadAsnLen(ByteReader); //Skip Tag1 of sname Len3 = ReadAsnLen(ByteReader); //Skip sequenceheader of sname. SPN = ""; if (NameType == 2) // read service type { Len3 = ReadAsnLen(ByteReader); SPN = ByteReader.ReadAnsiString(Len3) + "/"; } Len3 = ReadAsnLen(ByteReader); // read SPN length SPN += ByteReader.ReadAnsiString(Len3); KerbData.SPNRequested = SPN; break; } default: { throw new Exception("Unknonw tag in kerberos packet"); } } } while (TagId2 < 3); break; } default: { // throw new Exception("Un expected tags in kerberos request/response/ problem in parseing"); break; } } }while ((TagID < 4) && (!IsContinueToNextFrame)); } return(KerbData); }
public static KerberosData ProcessTCP(ConversationData c) { KerberosData KerbData = new KerberosData(); KerbData.SourcePort = c.sourcePort; KerbData.convData = c; ReassembleFrames(c); foreach (FrameData fd in c.frames) { TDSReader ByteReader = null; if ((fd.payloadLength <= 1) && (fd.reassembledPayLoadLength <= 1)) { continue; } if ((fd.flags & (int)(TCPFlag.PUSH)) == 0) { continue; } if (fd.reassembledPayLoad != null) { ByteReader = new TDSReader(fd.reassembledPayLoad, 0, -1, fd.reassembledPayLoad.Length); } else { ByteReader = new TDSReader(fd.payload, 0, -1, fd.payloadLength); } //Read or skip 4 bytes ByteReader.ReadByte(); ByteReader.ReadByte(); ByteReader.ReadByte(); ByteReader.ReadByte(); //Skip over 4 bytes 'ApplicationTag' ReadAsnLen(ByteReader); //Skip over 4 bytes 'KdcReq->SequenceHeader' ReadAsnLen(ByteReader); int Len2 = 0, TagLen = 0, TagID = 0; string SPN = null; KerbData.convData = c; bool IsContinueToNextFrame = false; do { TagID = ByteReader.ReadByte(); TagLen = ReadAsnLen(ByteReader, false); TagID = TagID & 0x1F; switch (TagID) //Lower 5 bits { case 0: // Version# is in Tago in error response. { GetVersion(KerbData, ByteReader); break; } case 1: { //Tag1 contains request type for error and non-error response. //So, read the response type and break. if (!fd.isFromClient) // could KERB error response or normal response { GetMessageType(KerbData, ByteReader); KerbData.frameNo = fd.frameNo; KerbData.TimeStamp = new DateTime(((FrameData)c.frames[c.frames.Count - 1]).ticks).ToString(utility.TIME_FORMAT); if (KerbData.ResponseType == MessageTypes.KRB_ERROR) { //Console.WriteLine(fd.frameNo.ToString()); ParseErrorResponseTCP(KerbData, ByteReader); IsContinueToNextFrame = true; } else if (KerbData.ResponseType == MessageTypes.KRB_TGS_REP) { //ParseNonErrorResponseTCP(KerbData, ByteReader); IsContinueToNextFrame = true; KerbData.ErrorDesc = "No Error."; } // // Looks like a bug here if the Message type is not 12 or 13. e.g. in my trace, it is KRB_AS_REP (11) // We don't go down either of the above paths and then try to parse TAG 2 next time around the loop, which has a different meaning (padata) and then crash. // // Suggested fix: // else { IsContinueToNextFrame = true; // must abort parsing if unexpected message type } // break; } else { GetVersion(KerbData, ByteReader); //Extract version# from KERB TCP request. break; } } case 2: { // Tag2 present only in the request and not in the response and error responses. // Console.WriteLine(fd.frameNo.ToString()); if (GetMessageType(KerbData, ByteReader) != MessageTypes.KRB_TGS_REQ) { return(KerbData); // if not a TGS_REQ, ignore rest of conversation and exit } // IsContinueToNextFrame = true; break; } case 3: { // skip the padata tag. Tag3 present in requet and response. //But we should not hit this case for response and only for request ByteReader.ReadBytes(TagLen); break; } case 4: { //Skip over 4 bytes 'SequenceHeader' ReadAsnLen(ByteReader); int Id2 = 0; int TagNum = 0; do { Id2 = ByteReader.ReadByte(); Len2 = ReadAsnLen(ByteReader, false); TagNum = Id2 & 0x1F; switch (TagNum) { case 0: { ByteReader.ReadByte(); int Len3 = ReadAsnLen(ByteReader, false); //Read and skip 'padding' ByteReader.ReadBytes(Len3 - 4); KerbData.IsForwardable = (ByteReader.ReadByte() & 0x40) != 0; //Read remaining three bytes ByteReader.ReadBytes(3); break; } case 1: case 2: case 4: case 5: case 7: case 8: case 9: case 10: { ByteReader.ReadBytes(Len2); break; } case 3: // outer tag 4 inner tag 3 - Request:SNAME { ReadAsnLen(ByteReader); //Skip sequence header of sname int Len3 = ReadAsnLen(ByteReader); //Skip Tag0 of sname // // Read the Name Type: // // 2 = NT-SRV-INST - has two Strings: Service and Instance. '/' separater is implied // 10 = NT-ENTERPRISE - has one String // // Throw error on all other values // Len3 = ReadAsnLen(ByteReader); if (Len3 != 1) { throw new Exception("Unexpected length (" + Len3 + ") reading SName Name Type."); } byte NameType = ByteReader.ReadByte(); KerbData.SNameType = NameType; //if (NameType != 2 && NameType != 10) //{ // IsContinueToNextFrame = true; // break; //} ReadAsnLen(ByteReader); //Skip Tag1 of sname Len3 = ReadAsnLen(ByteReader); //Skip sequenceheader of sname. SPN = ""; if (NameType == 2) // read service type { Len3 = ReadAsnLen(ByteReader); SPN = ByteReader.ReadAnsiString(Len3) + "/"; } Len3 = ReadAsnLen(ByteReader); // read SPN length SPN += ByteReader.ReadAnsiString(Len3); KerbData.SPNRequested = SPN; //Console.WriteLine("SPN=\t" + SPN); break; } default: { //throw new Exception("Unexpected TAG (" + TagNum + ") found in the KERB TCP request, frame: " + fd.frameNo.ToString()); break; } } } while (TagNum < 3); //Because, we are reading only 1st three tags of requestbody and skip the rest break; } default: { // throw new Exception("Un expected tags in kerberos request/response/ problem in parseing"); break; } } }while ((TagID < 4) && (!IsContinueToNextFrame)); } return(KerbData); }
static void ParseNonErrorResponseUDP(KerberosData KerbData, TDSReader ByteReader) { /* * int TagID = 0, TagLen = 0; * return; * * do * { * TagID = ByteReader.ReadByte(); * TagLen = ReadAsnLen(ByteReader, false); * * TagID = (TagID & (int)0x1F); * switch (TagID) * { * * case 3: * case 4: * { * ByteReader.ReadBytes(TagLen); // Skip 'Crealm', 'Cname', * break; * } * case 5: * { * //Skip Tag5->Ticket->ApplicationTag * ReadAsnLen(ByteReader); * * //Skip Tag5->Ticket->SequenceHeader * ReadAsnLen(ByteReader); * * int InnerTagID = -1; * int InnerTagLen = 0; * * do * { * InnerTagID = ByteReader.ReadByte() & (int)0x1F; * InnerTagLen = ReadAsnLen(ByteReader, false); * * * switch (InnerTagID) * { * * case 0: //Tag0->TktVno * case 1: //Skip Tag1->Realm * { * ByteReader.ReadBytes(InnerTagLen); * break; * } * case 2: //Ticket->Sname * { * //int Length = ReadAsnLen(ByteReader); //Skip sequenceheader of sname. * //ByteReader.ReadByte(); * * * //Skip Tag5->Ticket->Sname->SequenceHeader * ReadAsnLen(ByteReader); * int IInnerTagID = -1; * int IInnerTagLen = 0; * * do * { * IInnerTagID = ByteReader.ReadByte() & (int)0x1F; * IInnerTagLen = ReadAsnLen(ByteReader, false); * switch (IInnerTagID) * { * case 0: * { * ByteReader.ReadBytes(IInnerTagLen); * break; * } * case 1: * { * ByteReader.ReadByte(); * ByteReader.ReadByte(); * * ByteReader.ReadByte(); * * int Length = ByteReader.ReadByte(); * String Class = ByteReader.ReadAnsiString(Length); * * ByteReader.ReadByte(); * Length = ByteReader.ReadByte(); * KerbData.SPNRequested = Class + "/" + ByteReader.ReadAnsiString(Length); * break; * } * * } * } while (IInnerTagID < 1); * //KerbData.SPNRequested = ByteReader.ReadAnsiString(InnerTagLen); * break; * } * } * } * while (InnerTagID < 2); // Read until Sname * * break; * } * default: * { * throw new Exception("Unexpected Tag " + TagID + " found in KERB TCP response"); * } * } * * } * while (TagID < 5); */ }