mirror of https://github.com/infosecn1nja/C3.git
update in response to merge comments. Covenant connector now looks for C3Bridge listener before creating one. User now only supplies listener port, url, username and password
parent
6a7598c814
commit
86244b322d
|
@ -136,9 +136,54 @@ namespace MWR::C3::Interfaces::Connectors
|
||||||
|
|
||||||
/// Map of all connections.
|
/// Map of all connections.
|
||||||
std::unordered_map<std::string, std::unique_ptr<Connection>> m_ConnectionMap;
|
std::unordered_map<std::string, std::unique_ptr<Connection>> m_ConnectionMap;
|
||||||
|
|
||||||
|
bool GetListenerId();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MWR::C3::Interfaces::Connectors::Covenant::GetListenerId()
|
||||||
|
{
|
||||||
|
std::string url = this->m_webHost + OBF("/api/listeners");
|
||||||
|
json response;
|
||||||
|
|
||||||
|
web::http::client::http_client_config config;
|
||||||
|
config.set_validate_certificates(false); //Covenant framework is unlikely to have a valid cert.
|
||||||
|
|
||||||
|
web::http::client::http_client webClient(utility::conversions::to_string_t(url), config);
|
||||||
|
web::http::http_request request;
|
||||||
|
|
||||||
|
request = web::http::http_request(web::http::methods::GET);
|
||||||
|
|
||||||
|
std::string authHeader = OBF("Bearer ") + this->m_token;
|
||||||
|
request.headers().add(OBF_W(L"Authorization"), utility::conversions::to_string_t(authHeader));
|
||||||
|
pplx::task<web::http::http_response> task = webClient.request(request);
|
||||||
|
|
||||||
|
web::http::http_response resp = task.get();
|
||||||
|
|
||||||
|
if (resp.status_code() == web::http::status_codes::OK)
|
||||||
|
{
|
||||||
|
//Get the json response
|
||||||
|
auto respData = resp.extract_string();
|
||||||
|
response = json::parse(respData.get());
|
||||||
|
|
||||||
|
for (auto& listeners : response)
|
||||||
|
{
|
||||||
|
if (listeners[OBF("name")] == OBF("C3Bridge"))
|
||||||
|
{
|
||||||
|
this->m_ListenerId = listeners[OBF("id")].get<int>();
|
||||||
|
this->m_ListeningPostAddress = listeners[OBF("connectAddresses")][0].get<std::string>();
|
||||||
|
this->m_ListeningPostPort = listeners[OBF("connectPort")];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false; //we didn't find the listener
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw std::exception((OBF("[Covenant] Error getting Listeners, HTTP resp: ") + std::to_string(resp.status_code())).c_str());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
MWR::C3::Interfaces::Connectors::Covenant::Covenant(ByteView arguments)
|
MWR::C3::Interfaces::Connectors::Covenant::Covenant(ByteView arguments)
|
||||||
|
@ -146,7 +191,12 @@ MWR::C3::Interfaces::Connectors::Covenant::Covenant(ByteView arguments)
|
||||||
json postData;
|
json postData;
|
||||||
json response;
|
json response;
|
||||||
|
|
||||||
std::tie(m_ListeningPostAddress, m_ListeningPostPort, m_webHost, m_username, m_password) = arguments.Read<std::string, uint16_t, std::string, std::string, std::string>();
|
std::tie(m_ListeningPostPort, m_webHost, m_username, m_password) = arguments.Read<uint16_t, std::string, std::string, std::string>();
|
||||||
|
|
||||||
|
// if the last character is '/' remove it
|
||||||
|
if (this->m_webHost.back() == '/')
|
||||||
|
this->m_webHost.pop_back();
|
||||||
|
|
||||||
|
|
||||||
/***Authenticate to Web API ***/
|
/***Authenticate to Web API ***/
|
||||||
std::string url = this->m_webHost + OBF("/api/users/login");
|
std::string url = this->m_webHost + OBF("/api/users/login");
|
||||||
|
@ -182,69 +232,40 @@ MWR::C3::Interfaces::Connectors::Covenant::Covenant(ByteView arguments)
|
||||||
else
|
else
|
||||||
throw std::exception(OBF("[Covenant] Could not get token, invalid logon"));
|
throw std::exception(OBF("[Covenant] Could not get token, invalid logon"));
|
||||||
|
|
||||||
///Create the bridge listener
|
//If the listener doesn't already exist create it.
|
||||||
url = this->m_webHost + OBF("/listener/createbridge");
|
if (!GetListenerId())
|
||||||
web::http::client::http_client webClientBridge(utility::conversions::to_string_t(url), config);
|
|
||||||
request = web::http::http_request(web::http::methods::POST);
|
|
||||||
request.headers().set_content_type(utility::conversions::to_string_t(OBF("application/x-www-form-urlencoded")));
|
|
||||||
|
|
||||||
std::string authHeader = OBF("Bearer ") + this->m_token;
|
|
||||||
request.headers().add(OBF_W(L"Authorization"), utility::conversions::to_string_t(authHeader));
|
|
||||||
|
|
||||||
std::string createBridgeString = "Id=0&GUID=b85ea642f2&ListenerTypeId=2&Status=Active&CovenantToken=&Description=A+Bridge+for+custom+listeners.&Name=C3Bridge&BindAddress=0.0.0.0&BindPort=" + \
|
|
||||||
std::to_string(this->m_ListeningPostPort) + "&ConnectPort=" + std::to_string(this->m_ListeningPostPort) + "&ConnectAddresses%5B0%5D=" + \
|
|
||||||
this->m_ListeningPostAddress + "&ProfileId=3";
|
|
||||||
request.set_body(utility::conversions::to_string_t(createBridgeString));
|
|
||||||
|
|
||||||
task = webClientBridge.request(request);
|
|
||||||
resp = task.get();
|
|
||||||
|
|
||||||
if (resp.status_code() == web::http::status_codes::OK)
|
|
||||||
{
|
{
|
||||||
//Find the listener we just created
|
//extract ip address from url
|
||||||
url = this->m_webHost + OBF("/api/listeners");
|
size_t start = 0, end = 0;
|
||||||
web::http::client::http_client webClientListeners(utility::conversions::to_string_t(url), config);
|
start = url.find("://") + 3;
|
||||||
|
end = url.find(":", start + 1);
|
||||||
|
|
||||||
request = web::http::http_request(web::http::methods::GET);
|
this->m_ListeningPostAddress = url.substr(start, end - start);
|
||||||
|
|
||||||
|
///Create the bridge listener
|
||||||
|
url = this->m_webHost + OBF("/listener/createbridge");
|
||||||
|
web::http::client::http_client webClientBridge(utility::conversions::to_string_t(url), config);
|
||||||
|
request = web::http::http_request(web::http::methods::POST);
|
||||||
|
request.headers().set_content_type(utility::conversions::to_string_t(OBF("application/x-www-form-urlencoded")));
|
||||||
|
|
||||||
std::string authHeader = OBF("Bearer ") + this->m_token;
|
std::string authHeader = OBF("Bearer ") + this->m_token;
|
||||||
request.headers().add(OBF_W(L"Authorization"), utility::conversions::to_string_t(authHeader));
|
request.headers().add(OBF_W(L"Authorization"), utility::conversions::to_string_t(authHeader));
|
||||||
|
|
||||||
task = webClientListeners.request(request);
|
std::string createBridgeString = "Id=0&GUID=b85ea642f2&ListenerTypeId=2&Status=Active&CovenantToken=&Description=A+Bridge+for+custom+listeners.&Name=C3Bridge&BindAddress=0.0.0.0&BindPort=" + \
|
||||||
|
std::to_string(this->m_ListeningPostPort) + "&ConnectPort=" + std::to_string(this->m_ListeningPostPort) + "&ConnectAddresses%5B0%5D=" + \
|
||||||
|
this->m_ListeningPostAddress + "&ProfileId=3";
|
||||||
|
request.set_body(utility::conversions::to_string_t(createBridgeString));
|
||||||
|
|
||||||
|
task = webClientBridge.request(request);
|
||||||
resp = task.get();
|
resp = task.get();
|
||||||
|
|
||||||
bool found = false;
|
|
||||||
|
|
||||||
|
|
||||||
if (resp.status_code() == web::http::status_codes::OK)
|
if (resp.status_code() == web::http::status_codes::OK)
|
||||||
{
|
GetListenerId(); //now get the id of the listener
|
||||||
//Get the json response
|
else
|
||||||
auto respData = resp.extract_string();
|
throw std::exception((OBF("[Covenant] Error setting up BridgeListener, HTTP resp: ") + std::to_string(resp.status_code())).c_str());
|
||||||
response = json::parse(respData.get());
|
|
||||||
|
|
||||||
for (auto& listeners : response)
|
|
||||||
{
|
|
||||||
if (listeners[OBF("name")] == OBF("C3Bridge"))
|
|
||||||
{
|
|
||||||
this->m_ListenerId = listeners[OBF("id")].get<int>();
|
|
||||||
found = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//will be true if status_code != OK or C3Bridge wasn't found
|
|
||||||
if (!found)
|
|
||||||
{
|
|
||||||
throw std::exception(OBF("[Covenant] unable to identify ID of Bridge Listener"));
|
|
||||||
}
|
|
||||||
|
|
||||||
InitializeSockets();
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
throw std::exception((OBF("[Covenant] Error setting up BridgeListener, HTTP resp: ") + std::to_string(resp.status_code())).c_str());
|
|
||||||
|
|
||||||
|
|
||||||
|
InitializeSockets();
|
||||||
}
|
}
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
MWR::C3::Interfaces::Connectors::Covenant::~Covenant()
|
MWR::C3::Interfaces::Connectors::Covenant::~Covenant()
|
||||||
|
@ -328,10 +349,17 @@ MWR::ByteVector MWR::C3::Interfaces::Connectors::Covenant::GeneratePayload(ByteV
|
||||||
task = webClient.request(request);
|
task = webClient.request(request);
|
||||||
resp = task.get();
|
resp = task.get();
|
||||||
|
|
||||||
auto respData = resp.extract_string();
|
if (resp.status_code() == web::http::status_codes::OK)
|
||||||
json resp = json::parse(respData.get());
|
{
|
||||||
binary = resp[OBF("base64ILByteString")].get<std::string>(); //Contains the base64 encoded .NET assembly.
|
auto respData = resp.extract_string();
|
||||||
|
json resp = json::parse(respData.get());
|
||||||
|
binary = resp[OBF("base64ILByteString")].get<std::string>(); //Contains the base64 encoded .NET assembly.
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw std::runtime_error(OBF("[Covenant] Non-200 HTTP code returned: ") + std::to_string(resp.status_code()));
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
throw std::runtime_error(OBF("[Covenant] Non-200 HTTP code returned: ") + std::to_string(resp.status_code()));
|
||||||
|
|
||||||
auto payload = cppcodec::base64_rfc4648::decode(binary);
|
auto payload = cppcodec::base64_rfc4648::decode(binary);
|
||||||
|
|
||||||
|
@ -348,8 +376,7 @@ MWR::ByteVector MWR::C3::Interfaces::Connectors::Covenant::GeneratePayload(ByteV
|
||||||
|
|
||||||
MWR::ByteVector MWR::C3::Interfaces::Connectors::Covenant::CloseConnection(ByteView arguments)
|
MWR::ByteVector MWR::C3::Interfaces::Connectors::Covenant::CloseConnection(ByteView arguments)
|
||||||
{
|
{
|
||||||
auto id = arguments.Read<std::string>();
|
m_ConnectionMap.erase(arguments);
|
||||||
m_ConnectionMap.erase(id);
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -377,16 +404,11 @@ MWR::ByteView MWR::C3::Interfaces::Connectors::Covenant::GetCapability()
|
||||||
{
|
{
|
||||||
"arguments":
|
"arguments":
|
||||||
[
|
[
|
||||||
{
|
|
||||||
"type": "ip",
|
|
||||||
"name": "Address",
|
|
||||||
"description": "C2Bridge ip address - this will be setup automatically"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"type": "uint16",
|
"type": "uint16",
|
||||||
"name": "Port",
|
"name": "C2BridgePort",
|
||||||
"min": 1,
|
"min": 1,
|
||||||
"description": "C2Bridge port - this will be setup automatically"
|
"description": "The port for the C2Bridge Listener if it doesn't already exist."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
@ -560,3 +582,4 @@ MWR::ByteVector MWR::C3::Interfaces::Connectors::Covenant::PeripheralCreationCom
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -193,7 +193,7 @@ MWR::C3::Interfaces::Peripherals::Grunt::Grunt(ByteView arguments)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::runtime_error{ OBF("Grunt creation failed") };
|
throw std::runtime_error{ OBF("Grunt creation failed") };
|
||||||
}
|
}
|
||||||
|
|
||||||
void MWR::C3::Interfaces::Peripherals::Grunt::OnCommandFromConnector(ByteView data)
|
void MWR::C3::Interfaces::Peripherals::Grunt::OnCommandFromConnector(ByteView data)
|
||||||
|
|
Loading…
Reference in New Issue